Self Service Formular für das Active Directory Teil 1 14. Februar 2012

Jede Firma ist einer gewissen Dynamik unterworfen. Einhergehend mit dieser Dynamik ändern sich oft die Eigenschaften von Benutzerkonten. Klassische Beispiele wären z.B. Hochzeiten, Umzüge in ein anderes Büro, Versetzungen in eine andere Abteilung oder nur einfach die Änderung einer Telefonnummer. Sehr oft höre ich in Projekten oder im Gespräch mit Schulungsteilnehmern, dass die IT-Abteilung über solche Änderungen immer zuletzt oder auch gar nicht informiert wird. Meistens bekommt die IT-Abteilung es erst mit, wenn ein verärgerter Benutzer anruft und sich beschwert, dass die Daten im Outlook Adressbuch nicht aktuell sind. Was liegt da näher, als es den Benutzern zu ermöglichen, nicht kritische Eigenschaften des eigenen Benutzerkontos selbst zu ändern.

Diesem Problem haben sich schon einige kommerzielle Anbieter angenommen und bieten dafür auch entsprechende Lösungen an. Allerdings sind diese Lösungen entweder vom Umfang her viel zu mächtig oder auch unverhältnismäßig teuer. Eine andere Möglichkeit wäre, den Benutzer freundlich darauf hinzuweisen, dass er zum Beispiel seine persönlichen Daten bereits über die Outlook Web Application von Exchange Server 2010 ändern kann. Allerdings ist dieser Weg etwas erklärungsbedürftig. Deshalb liegt doch nichts näher, als sich solch eine Lösung selber zu erstellen. Dass dies kein Hexenwerk ist, möchte ich in diesem Artikel darstellen. Bevor wir aber richtig loslegen, müssen wir als Erstes die überschaubare Featureliste der Lösung erstellen.

Folgende Attribute sollen durch den Benutzer änderbar sein:

  • Abteilung (department)
  • Position (title)
  • Nachname (sn)
  • Foto (thumbNailPhoto)

Die Lösung soll webbasiert sein und der Benutzer darf nicht erneut zu einer Authentifizierung aufgefordert werden. Außerdem darf der Benutzer nur seine Daten ändern können.

Was wird benötigt:

Zum Einen benötigen wir für diese Aufgabe einen IIS Webserver und zusätzlich noch ein Visual Studio oder eine der verfügbaren Express Editions. Das war es eigentlich schon. Jetzt stellt sich nur noch die Frage, welche Attribute ein Benutzer an seinem eigenen Benutzerobjekt im Active Directory ändern kann und ob unsere ausgewählten Attribute dabei sind. Um diese Frage zu beantworten, kann man sich die ACL der Benutzerobjekte ansehen oder auch stundenlang die Technet beziehungsweise MSDN wälzen. Viel schneller geht es, wenn man das Active Directory direkt befragt. Das Active Directory verfügt über ein Attribut (allowedAttributesEffective), was wiederum alle Attribute zurückliefert, die durch den aufrufenden Benutzer beschreibbar sind. Um nun relativ fix die durch einen normalen Benutzer beschreibbaren Attribute herauszufinden, kann man einfach als Benutzer über die Powershell eine Abfrage an das Active Directory schicken. Nehmen wir einmal an, dass es einen Benutzer “test” gibt, der sich im Container “Users” befindet. Da würde in der Powershell die Abfrage so aussehen:

PS C:\>$user = [ADSI]LDAP://CN=test,CN=Users,DC=spielwiese,DC=intern
PS C:\>$user.refreshcache(“allowedAttributesEffective”)
PS C:\>$user.invokeget(“allowedAttributesEffective”)

Diese Abfrage sollte so um die 50 Attribute auswerfen, die durch den Benutzer selbst änderbar sind. Das Attribut “thumbnailPhoto” ist durch den Benutzer bereits änderbar, allerdings sind die Attribute “department”, “title”, “sn” nicht dabei. Die Berechtigungen im Active Directory müssen also für diese Attribute angepasst werden. Um den Benutzern die Schreibrechte auf die eigenen Attribute zu gewähren, bietet sich der Principal “Self” an. Diesem Konto müssen wir Schreibrechte auf die oben genannten Attribute geben. Da unser Formular für alle Benutzer in der Domäne funktionieren soll, muss ich die Berechtigungen auf der Ebene der Domäne geben. Ich demonstriere das an dem Attribut “department”:

 

 

 

 

 

 

 

 

 

Nachdem die Rechte konfiguriert wurden, kann man sich an die Erstellung der Webseite machen. Im Visual Studio erstelle ich als Erstes ein neues Webprojekt:

 

 

 

 

 

 

 

 

 

Wenn Visual Studio das neue Projekt erstellt hat, können wir uns an das Layout der Seite machen. Da es nur zu Demonstrationszwecken dient, wähle ich hier ein einfaches Tabellenlayout. Die Tabelle bekommt sechs Zeilen und zwei Spalten. Zusätzlich platziere ich auch gleich die Textboxen für die Attribute “department”, “title” und “Nachname”. Die Controls für Thumbnailfoto setze ich später. Die Seite sollte dann ungefähr so aussehen:

Jetzt können wir uns an den Quellcode machen. Als Erstes müssen wir ermitteln, welcher Benutzer auf die Seite zugreift, um anschließend die Daten des jeweiligen Benutzers aus dem Active Directory zu holen. Dabei hilft uns die .Net Klasse “Page”. Der Aufruf “Page.User.Identity.Name” gibt uns den Benutzernamen des Benutzers zurück, der die Seite gerade aufruft. Der Benutzername wird uns in der Form “domain\username” zurückgegeben. Wir sind nur am eigentlichen Benutzernamen interessiert. Um den zu ermitteln, habe ich eine kleine Hilfsfunktion erstellt, die mir den samAccountName des Benutzers zurückgibt.

private string GetCurrentWindowsUserLogin()
{
	string strSamAccountName="";
	string login = Page.User.Identity.Name;
	int intLogin = login.IndexOf(@"\");
	if (intLogin > 0)
	{
		strSamAccountName = login.Remove(0,intLogin+1);
	}
	return strSamAccountName;
}

Wenn wir den Benutzernamen ermittelt haben, können wir uns jetzt auf die Suche nach den gewünschten Informationen im Active Directory machen. Dazu habe ich zwei Funktionen erstellt. Die eine Funktion (GetUser) ermittelt das zum Benutzernamen korrespondierende Benutzerobjekt, und die andere Funktion (GetADData) füllt dann die entsprechenden Textboxen mit dem Inhalt der Benutzereigenschaften. Der gesamte Quelltext der Seite sieht dann so aus:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.DirectoryServices;
 
namespace ITeach_ADSelfService
{
    public partial class _Default : System.Web.UI.Page
    {
        const string LDAP = "LDAP://dc=spielwiese,dc=intern"; //Anzupassen!
        static DirectoryEntry ADUser;
        private readonly string[] arrProperties = new string[] { "department","sn", "title"};
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
            }
            else
            {
                string strUserName = GetCurrentWindowsUserLogin().ToString();
                ADUser = GetUser(strUserName);
                GetADData(ADUser);
            }
 
        }
 
        private string GetCurrentWindowsUserLogin()
        //Diese Funktion ermittelt fuer uns den aktuellen Benutzernamen damit wir die Suche durchfuehren können
        {
            string strSamAccountName = "";
            string login = Page.User.Identity.Name;
            int intLogin = login.IndexOf(@"\");
            if (intLogin > 0)
            {
              strSamAccountName = login.Remove(0, intLogin + 1);
            }
            return strSamAccountName;
        }
        private DirectoryEntry GetUser(string loginName)
        {
            string strSearchfilter = "(SamAccountName=" + loginName + ")";
 
            DirectoryEntry entry = new DirectoryEntry(LDAP);
 
            System.DirectoryServices.DirectorySearcher search = new System.DirectoryServices.DirectorySearcher(entry, strSearchfilter, arrProperties);
            DirectoryEntry user = null;
            user = new DirectoryEntry(search.FindOne().Path.ToString());
            return user;
        }
         private void GetADData(DirectoryEntry user)
         {
              if (user.Properties["sn"].Value != null)
              {
                  txtSurname.Text = user.Properties["sn"].Value.ToString();
              }
              else
              {
                  txtSurname.Text = "";
              }
              if (user.Properties["department"].Value != null)
              {
                  txtDepartment.Text = user.Properties["department"].Value.ToString();
              }
              else
              {
                  txtDepartment.Text = "";
              }
              if (user.Properties["title"].Value != null)
              {
                  txtPosition.Text = user.Properties["title"].Value.ToString();
 
              }
              else
              {
                  txtPosition.Text = "";
              }
 
         }
 
    }
}

Wenn man die Seite jetzt in Visual Studio ausführt, sollte es ungefähr so aussehen:

 

 

 

 

 

 

 

 

 

 

Folgende Aufgaben sollten vor einem produktiven Einsatz noch erledigt werden:

In der Seite ist keinerlei Fehlerbehandlung implementiert. Das müsste auf jeden Fall noch nachgepflegt werden. Vom optischen Erscheinungsbild her ist es auch nicht schön. Das Formular könnte also noch etwas “stylischer” gestaltet werden.

Der erste Teil kann hier heruntergeladen werden (ITeach-ADSelfService-Teil1 (1108)).

 Self Service Formular für das Active Directory Teil 2

Self Service Formular für das Active Directory Teil 3

Self Service Formular für das Active Directory Teil 4
 

Leave a Reply

*