Usermanagement-Modul

Bitte beachten Sie, dass die vorliegende Dokumentation teilweise verwaltet ist. Bitte nutzen Sie daher die Beschreibung unter Benutzer-Verwaltung. Sollten Sie dort die gewünschten Informationen nicht finden, ziehen Sie bitte diese Seite zu rate oder stellen Sie Ihre Frage im Forum.

Das Modul usermanagement beinhaltet ein Backend zur Benutzerverwaltung und eine generische Business-Komponente - basierend auf dem Generischer O/R-Mapper - die zur Authentifizierung und zur Verwaltung von Benutzern, Gruppen, Rollen, Berechtigungen und Berechtigungsschemata verwendet werden kann. Weiterhin ist es seit dem Release 1.12 möglich, Sichtbarkeits-Berechtigungen für beliebige Anwendungen zu verwalten.

Das Modul dient einerseits dazu, Benutzer-Verwaltung zu standardisieren, andererseits, dem Entwickler für eine so zentrale Aufgabe ein fertiges und verlässliches Tool an die Hand zu geben.

Die folgenden Kapitel zeigen den Aufbau des Moduls und geben Beispiele für die Verwendung des Business-Komponente und die Einbindung des Backends.

1. Design des Moduls

Das Modul besteht aus einer Business-Komponente, dem UmgtManager, und einem Backend. Der Manager nutzt den GenericORMapper als Datenkomponente. Das Backend basiert komplett auf der Business-Schicht des Moduls. Das bedeutet, dass diese in anderen Anwendungen für die Authentifizierung und Benutzerverwaltung als vollwertige Komponente eingesetzt werden kann.

1.1. Datenmodell

Das Datenmodell des Benutzer-Managements sieht die Gliederung in

  • Benutzer (users)
  • Gruppen (groups)
  • Rollen (roles)
  • Funktions-Berechtigungs-Schemen (permission sets)
  • Funktions-Berechtigungen (permissions)
  • Sichtbarkeits-Berechtigungen (visibility definitions)
  • Sichtbarkeits-Berechtigungs-Typen (visibility definitions types)

vor. Dieses Trennung ermöglicht es, eine granulare und allgemeingültige Benutzerverwaltung bereitzustellen. Das folgende UML-Diagramm zeigt die Bedeutung der Objekte und deren Beziehungen:

Usermanagement UML Diagramm (APF)

Gruppen werden in der Regel zur Vergabe von Berechtigungen auf Objekte einer Anwendung verwendet, Rollen kommen dann zum Einsatz, wenn Berechtigungen auf das Ausführen von Funktionen vergeben werden sollen. Zur Granularisierung und Wiederverwendbarkeit von "Funktionsberechtigungen" wurden Berechtigungsschemen eingeführt. Diese können wiederum mehrere Berechtigungen kapseln und werden selbst einer Rolle zugewiesen.

1.2. UmgtManager

Die Business-Komponente besitzt eine Reihe von Methoden, die dem Entwickler einen abstrahierten Zugriff auf das Datenmodell geben. Darunter befinden sich nicht nur Methoden zum Erzeugen, Lesen, Manipulieren und Löschen von einzelnen Objekten, sondern auch zum Erzeugen, Lesen, Manipulieren und Löschen der Beziehungen zwischen den Objekten. Im Besonderen wurden Methoden inkludiert, die das Authentifizieren und Verwenden von Benutzern erleichtert um die Implementierung von Anwendungen, basierend auf dem Benutzermanagement, möglichst effektiv zu gestalten.

Die folgende Liste zeigt eine Übersicht über die API-Methoden der Komponente. Details können der API-Dokumentation der Klasse UmgtManager entnommen werden:
  • loadUserByEMailAndPassword(): Läd einen Benutzer per E-Mail und Passwort.
  • loadUserByUsernameAndPassword(): Läd einen Benutzer per Benutzername und Passwort.
  • loadUserPermissions(): Läd die Berechtigungen, die ein Benutzer besitzt.
  • saveUser($user): Speichert einen Benutzer in der aktuellen Instanz der Benutzerverwaltung.
  • saveGroup($group): Speichert eine Gruppe in der aktuellen Instanz der Benutzerverwaltung.
  • saveRole($role): Speichert eine Rolle in der aktuellen Instanz der Benutzerverwaltung.
  • savePermissionSet($permissionSet): Speichert ein Berechtigungsschema in der aktuellen Instanz der Benutzerverwaltung.
  • savePermission($permission): Speichert eine Berechtigung in der aktuellen Instanz der Benutzerverwaltung.
  • getPagedUserList(): Gibt eine Liste von Benutzern zurück.
  • getPagedGroupList(): Gibt eine Liste von Gruppen zurück.
  • getPagedRoleList(): Gibt eine Liste von Rollen zurück.
  • getPagedPermissionSetList(): Gibt eine Liste von Berechtigungsschemen zurück.
  • getPagedPermissionList(): Gibt eine Liste von Berechtigungen zurück.
  • loadUserByID($userID): Läd einen Benutzer per ID.
  • loadGroupByID($groupID): Läd eine Gruppe per ID.
  • loadRoleByID($roleID): Läd eine Rolle per ID.
  • loadPermissionSetByID($permissionSetID): Läd ein Berechtigungsschema per ID.
  • loadPermissionByID($permID): Läd ein Berechtigung per ID.
  • loadPermissionList(): Gibt eine Liste von Berechtigungen zurück.
  • loadRolesNotWithPermissionSet($permissionSet): Läd eine Liste von Rollen, die nicht das übergebene Berechtigungsschema haben.
  • loadRolesWithPermissionSet($permissionSet): Läd eine Liste von Rollen, die das übergebene Berechtigungsschema haben.
  • assignPermissionSet2Roles($permissionSet,$roles): Weist ein Berechtigungsschema mehreren Rollen zu.
  • detachPermissionSetFromRoles($permissionSet,$roles): Entfernt ein Berechtigungsschema von einer Liste von Rollen.
  • deleteUser($user): Löscht einen Benutzer.
  • deleteGroup($group): Löscht eine Gruppe.
  • deleteRole($role): Löscht eine Rolle.
  • deletePermissionSet($permissionSet): Löscht ein Berechtigungsschema.
  • deletePermission($permission): Löscht eine Berechtigung.
  • assignUser2Groups($user,$groups): Nimmt einen Benutzer in mehrere Gruppen auf.
  • assignUsers2Group($users,$group): Nimmt mehrere Benutzer in eine Gruppe auf.
  • assignRole2Users($role,$users): Weist eine Rolle mehreren Benutzern zu.
  • loadGroupsWithUser(&$user): Läd alle Gruppen, die einem Benutzer zugewiesen wurden.
  • loadGroupsNotWithUser(&$user): Läd alle Gruppen, die einem Benutzer nicht zugewiesen wurden.
  • loadUsersWithGroup(&$group): Läd alle Benutzer, die einer Gruppe angehören.
  • loadUsersNotWithGroup(&$group): Läd alle Benutzer, die nicht einer Gruppe angehören.
  • loadRolesWithUser(&$user): Läd alle Rollen, die einem Benutzer zugewiesen wurden.
  • loadRolesNotWithUser(&$user): Läd alle Rollen, die einem Benutzer nicht zugewiesen wurden.
  • loadUsersWithRole(&$role): Läd alle Benutzer, die einer Rolle angehören.
  • loadUsersNotWithRole(&$role): Läd alle Benutzer, die einer Rolle nicht angehören.
  • loadPermissionsOfPermissionSet(&$permissionSet): Läd alle Berechtigungen eines Schemas.
  • detachUserFromRole($user,$role): Entfernt die Zuweisung eines Benutzers zu einer Rolle.
  • detachUsersFromRole($users,$role): Entfernt die Zuweisung mehrerer Benutzer zu einer Rolle.
  • detachUserFromGroup($user,$group): Entfernt einen Benutzer aus einer Gruppe.
  • detachUserFromGroups($user,$groups): Entfernt einen Benutzer aus mehrern Gruppen.
  • detachUsersFromGroup($users,$group): Entfernt mehrere Benutzer aus einer Gruppe.
  • loadUserByFirstName($firstName): Läd einen Benutzer an Hand des Vornamens.
  • loadUserByLastName($lastName): Läd einen Benutzer an Hand des Nachnamens.
  • loadUserByEMail($email): Läd einen Benutzer an Hand seiner E-Mail.
  • loadUserByFirstNameAndLastName($firstName,$lastName): Läd einen Benutzer an Hand des Vor- und Nachnamens.
  • loadUserByUserName($username): Läd einen Benutzer an Hand des Benutzer-Namens.
Weitere Methoden und deren Signatur können in der API-Dokumentation nachgelesen werden.

2. Installation

Die Installation des Moduls umfasst folgende Schritte:
  • Konfiguration des Moduls bereitstellen
  • Konfiguration des GenericORMappers bereitstellen
  • Installation der Datenbank

2.1. Konfiguration des Moduls

Die Konfiguration des Moduls umfasst mindestens drei Parameter: den Schlüssel der Datenbankverbindung, die ID des zu verwendenden Applikationscontainers und den Service-Mode, mit dem der O/R-Mapper erzeugt werden soll:
APF-Konfiguration
[InstanceName] ConnectionKey = "" ApplicationID = "" ServiceMode = ""
Mit 1.14 ist noch ein weiterer, optionaler Wert hinzugekommen, welcher als statischer Salt für den PasswordHashProvider verwendet wird. Wird kein Salt definiert wird ein Standardsalt des APF verwendet. Zur Erhöhung der Sicherheit ist es jedoch ratsam einen eigenen, langen und mit Sonderzeichen bestückten Salt zu definieren.
APF-Konfiguration
Salt = ""
ACHTUNG! Bei Verlust oder Änderung des Salts werden vorhandene Hashes in der Datenbank unbrauchbar! Ihre Benutzer können sich dann nicht mehr einloggen! Ein Backup des Salts ist daher unbedingt notwendig!
Im apf-configpack-*-Package ist eine Beispiel-Konfigurationsdatei mit einer Bescheibung der Werte enthalten.

Da das Datenmodell ein Objekt Application besitzt, kann das Usermanagement für mehrere Anwendungen gleichzeitig auf der selben Datenquelle verwendet werden. So ist es möglich eine gemeinsame Datenhaltung für Benutzer in unterschiedlichen Applikationen oder Modulen aufzubauen. Bei der Verwendung muss dem UmgtManager deshalb die ApplicationID mitgegeben werden, damit bekannt ist, welcher Container adressiert werden soll. Durch die Konfiguration können innrhalb eines Contextes mehrere Instanzen definiert und verwendet werden.


2.2. Konfiguration des O/R-Mappers

Da das Modul auf dem Generischer O/R-Mapper basiert, muss für das oben abgebildete UML eine Konfiguration für den Mapper vorhanden sein. Um das Setup zu erleichtern sind die fertigen Konfigurationsdateien bereits im apf-configpack-*-Package unter /modules/usermanagement/ enthalten. Diese müssen lediglich in den config-Namespace in den richtigen Ordner kopiert werden. Hierbei muss darauf geachtet werden, dass die Konfigurationsdateien im korrekten Context-Pfad liegen und entsprechend benannt sind. Details können dem Kapitel Konfigurations-Schema entnommen werden.

Wie der Dokumentation des generischen O/R-Mappers zu entnehmen ist, müssen für die verwendeten Objekte und die Beziehungen der Objekte Konfigurationen vorgehalten werden.

2.3. Installation der Datenbank

Als letzter Schritt muss die Datenbank vorbereitet werden. Dazu muss das unter /modules/usermanagement/data/scripts/setup.sql gegen die gewünschte Datenbank ausgeführt werden. Anschließend ist das Modul voll einsatzbereit.

Es empfiehlt sich, für das Modul eine eigene Datenbank zu nutzen, grundsätzlich spricht jedoch nichts gegen eine bereits bestehende Datenbank zu befüllen. Durch den Einsatz des ConnectionManager entsteht in keinem Fall ein Nachteil, da mit diesem innerhalb einer Applikation mehrere Datenbanken adressiert werden können.


3. Anwendung

3.1. Backend

Um das integrierte Backend nutzen zu können, muss für das Modul eine eigene Bootstrap erstellt oder dieses per Tag in eine bestehende Anwendung eingebaut werden. Durch die generische Implementierung werden bei der Erzeugung der URLs des Moduls externe Parameter (z.B. zur Navigation) mit eingebunden.

Da das Backend auf dem Front-Controller basiert (Anzeige der Icons wird über die <*:mediastream />-Tags realisiert), kann folgende index.php eingesetzt werden:
PHP-Code
include('./apps/core/pagecontroller/pagecontroller.php'); import('core::frontcontroller','Frontcontroller'); $fC = &Singleton::getInstance('Frontcontroller'); $fC->setContext({CONTEXT}); echo $fC->start('modules::usermanagement::pres::templates','main');
Soll das Backend als View in einer bestehenden Anwendung integriert werden, kann folgende Tag-Definition verwendet werden:
APF-Template
<core:importdesign namespace="modules::usermanagement::pres::templates" template="main" />
Sollte die bestehende Anwendung eine Front-Controller-Action zur Navigation nutzen, so muss das Modul mit dem <generic:importdesign />-Tag eingebaut und die Navigations-Action mit $keepInURL = true definiert werden. Andernfalls wird die Action-Information nicht in die Links des Moduls eingebunden und die Navigation funktioniert unter Umständen nicht.
APF-Template
<core::addtaglib namespace="tools::html::taglib" prefix="generic" class="importdesign" /> <generic:importdesign modelnamespace="namespace::to::application::model" modelfile="ModelName" modelclass="ModelName" modelmode="SINGLETON" namespaceparam="..." templateparam="..." dependentactionnamespace="namespace::to::dependent::action" dependentactionname="DependentActionName" dependentactionparams="param1:value1|param2:value2" />

Details zum generischen importdesign-Tag können dem Kapitel Spezielle TagLibs entnommen werden.

Wie weiter oben erwähnt, wird die Auslieferung der Icons und Bilder des Moduls über <*:mediastream />-Tags realisiert. Diese generieren eine Ziel-URL, die eine Front-Controller-Anweisung enthält. Wie im Kapitel Front-Controller beschrieben ist, benötigt jede Action eine Konfiguration. Um die Anzeige der Bilder zu ermöglichen ist es notwendig eine Action-Konfigurationsdatei mit dem Namen
Code
{ENVIRONMENT}_actionconfig.ini
unter dem Namespace
Code
/APF/config/tools/media/actions/{CONTEXT}/
angelegt werden. Der Inhalt der Datei ist
APF-Konfiguration
[streamMedia] ActionClass = "APF\tools\media\actions\StreamMediaAction"

Details zur Bennenung von Konfigurationsdateien können im Kapitel Konfigurations-Schema nachgelesen werden.

Hier sehen Sie ein Beispiel für die Installation des Backends:

User-Management-Backend-Installation

3.2. Business-Komponente

Die API der Klasse UmgtManager arbeitet grundsätzlich mit Objekten. Das bedeutet, dass als Argumente weitestgehend Objekte des Typs GenericDomainObject erwartet werden. Als Rückgabewerte dienen ebenfalls Instanzen der Klasse GenericDomainObject oder der Wert null.

3.2.1. Login via Benutzer und Passwort
Das folgende Beispiel zeigt, wie eine einfache Authentifizierung mit Hilfe von URL-Werten durchgeführt werden kann:
PHP-Code
// include business component prior to use import('modules::usermanagement::biz','UmgtManager'); // get the business object $uM = &$this->getAndInitServiceObject('modules::usermanagement::biz','UmgtManager','Default'); // retrieve the username and password from the request $username = RequestHandler::getValue('user'); $password = RequestHandler::getValue('pass'); // try to get the user object. if null ist returned, the credentials are not correct $user = $uM->loadUserByUsernameAndPassword($username,$password); if($user !== null){ echo 'user "'.$user->getProperty('DisplayName').'" is logged in'; } else{ echo 'user could not be logged in with the given credentials'; }

3.2.2. Login via E-Mail und Passwort
Um einen Benutzer nicht über seinen Benutzernamen sondern seiner E-Mail-Adresse und seinem Passwort zu authentifizieren, muss der Methodenaufruf
PHP-Code
$user = $uM->loadUserByUsernameAndPassword($username,$password);
durch
PHP-Code
$user = $uM->loadUserByEMailAndPassword($email,$password);
ersetzt werden.


3.2.3. Laden von Gruppen und Rollen
Wurde ein Benutzer erfolgreich über die in 3.2.1 und 3.2.1 geschilderte Methoden geladen, so kann wie folgt auf dessen Gruppen und Rollen zugegriffen werden:
PHP-Code
// load groups $groups = $uM->loadGroupsWithUser($user); // load roles $roles = $uM->loadRolesWithUser($user);

3.2.4. Laden von Benutzer-Berechtigungen
Möchte der Entwickler nun auf die dem Benutzer zugeordneten Funktionsberechtigungen (Permissions) zugreifen, kann das über die Rollen, oder direkt über eine dafür vorgesehene API-Methode erledigt werden:
PHP-Code
// load permissions via the relevant relations $roles = $uM->loadRolesWithUser($user); $permissions = array(); for($i = 0; $i < count($roles); $i++){ // load permission sets $permSets = $roles[$i]->loadRelatedObjects('Role2PermissionSet'); for($j = 0; $j < count($permSets); $j++){ $permissions = array_merge($permissions,$permSets[$j]->loadRelatedObjects('PermissionSet2Permission')); } } // call the api method $permissions = $uM->loadUserPermissions($user);
Nachteil der ersten Variante ist die mögliche Mehrfachzuordnung von Funktionsberechtigungen zu Berechtigungsschemen und Rollen zu Benutzern. Die API-Methode berücksicht dies.


3.2.5. Manipulieren von Objekten
Für die Manipulation von Objekten gibt es eine Reihe von API-Funktionen. Das folgende Code-Beispiel zeigt, wie Benutzer, Gruppen und Rollen angelegt, bearbeitet und gelöscht werden können. Da als Business-Objekt jeweils eine Instanz der Klasse GenericDomainObject verwendet wird, muss darauf geachtet werden, dass der Namen eines Objektes, der bei der Instanzierung mitgegeben wird, auch mit den Objekt-Namen in der Konfiguration übereinstimmen. Gleiches gilt für die Bezeichnungen der Attribute. Auch diese müssen mit den Attribut-Namen der Objekt-Konfiguration übereinstimmen. Details können dem Kapitel Objektdefinition entnommen werden.
PHP-Code
// get the business object $uM = &$this->getAndInitServiceObject('modules::usermanagement::biz','UmgtManager','Default'); // create new user $user = new GenericDomainObject('User'); $user->setProperty('FirstName','John'); $user->setProperty('LastName','Doe'); $user->setProperty('Username','jdoe'); $uM->saveUser($user); // create new group $group = new GenericDomainObject('Group'); $group->setProperty('DisplayName','Users'); $uM->saveGroup($group); // load a user and change username $user = $uM->loadUserByID(1); $user->setProperty('Username','johndoe'); $uM->saveUser($user); // load a group and change display name $group = $uM->loadGroupByID(2); $group->setProperty('DisplayName','Forum users'); $uM->saveGroup($group); // delete a user $users = $uM->getPagedUserList(); for($i = 0; $i < count($users); $i++){ if($users[$i]->getProperty('Username') === 'johndoe'){ $user = $users[$i]; } } $uM->deleteUser($user); // delete a group $groups = $uM->getPagedGroupList(); for($i = 0; $i < count($groups); $i++){ if($groups[$i]->getProperty('DisplayName') === 'Forum users'){ $group = $groups[$i]; } } $uM->deleteGroup($group);

3.2.6. Manipulieren von Beziehungen
Für die Erstellung, Manipulation und Löschung von Beziehungen zwischen den Objekten des Usermanagements (siehe UML) stehen dem Entwickler zahlreiche Methoden zur Verfügung. Diese sind auf den konkreten Anwendungsfall des Moduls zugeschnitten und erwarten jeweils Objekte des Type GenericDomainObject. Die folgende Codebox zeigt einige typische Anwendungsfälle für das "Bearbeiten" von Beziehungen:
PHP-Code
// get the business object $uM = &$this->getAndInitServiceObject('modules::usermanagement::biz','UmgtManager','Default'); // add user to group $user = $uM->loadUserByID(1); $group = $uM->loadGroupByID(2); $uM->assignUser2Groups($user,array($group)); // assign a dedicated role to a user $role = $uM->loadRoleByID(3); $uM->assignRole2Users($role,array($user)); // remove user from group $uM->detachUserFromGroups($user,array($group)); // detatch role from user $uM->detachUserFromRole($user,$role);
3.2.7. Sichtbarkeits-Berechtigungen

Das im Release 1.12. hinzugefügte Konzept der Sichtbarkeits-Berechtigungen ermöglicht es einem Entwickler, das Modul komplett in die Anwendung zu integrieren. Neben den Berechtigungen auf das Ausführen von Funktionen (permissions) können nun auch auch Berechtigungen auf die Sichtbarkeit (visibility definition) von Objekten verwaltet werden.

Die Kombination aus Funktions- und Sichtbarkeits-Berechtigung stellt die Basis für eine flexible und skalierbare Benutzer-Verwaltung, die eine Unterscheidung zwischen dem reinen Zugriff auf ein Objekt sowie die Aktionen (Bearbeiten, Löschen, Verknüpfen, ...), die mit einem Objekt verknüpft sind ermöglicht.

Der Wiki-Artikel Anwendung Sichtbarkeits-Berechtigungen beschreibt ein konkretes Beispiel für die Anwendung.

3.2. Direkter Zugriff

Sollte die API des UmgtManager nicht ausreichen, so kann der GenericORMapper direkt verwendet werden. Wichtig dabei ist, dass der gleiche Satz an Konfigurationsdateien benutzt werden. Die folgende Codebox zeigt, wie die Businesskomponente des Usermanagement-Moduls den O/R-Mapper erzeugt:
PHP-Code
$oRMFact = &$this->getServiceObject( 'modules::genericormapper::data', 'GenericORMapperFactory' ); $oRM = &$oRMFact->getGenericORMapper( 'modules::usermanagement', 'umgt', $connectionKey, $serviceMode );
Die Variablen $connectionKey und $serviceMode müssen jeweils mit den Inhalten der Konfiguration des Moduls ersetzt werden. Der ServiceMode ist dabei optional.

Nach dem Erzeugen des Mappers kann dieser gemäß den Konfigurationsdateien des Moduls eingesetzt werden. Die folgende Code-Box zeigt, wie der O/R-Mapper dazu genutzt werden kann um die Benutzer einer Gruppe zu zählen. Die Variable $oRM wurde dabei wie oben erläutert erstellt.
PHP-Code
$group = $oRM->loadObjectByID('Group',1); $count = $oRM->loadRelationMultiplicity($group,'Group2User');
Um zu prüfen, ob ein Benutzer einer bestimmten Gruppe angehört oder ihm eine definierte Rolle zugeordnet ist, kann folgender Code dienen:
PHP-Code
// test, if user is within group $group = $oRM->loadObjectByID('Group',1); $user = $oRM->loadObjectByID('User',2); if($oRM->isAssociated('Group2User',$group,$user)){ echo 'user is in group'; } else{ echo 'user is *not* in group'; } // test, if user is associated with the desired role $role = $oRM->loadObjectByID('Role',3); if($oRM->isAssociated('Role2User',$role,$user)){ echo 'user is associated the desired role'; } else{ echo 'user is *not* associated the desired role'; }
Um andere Ladekriterien als die in der API der Businesskomponente enthaltenen Methoden zu nutzen, können die Methoden
  • loadObjectByStatement()
  • loadObjectByTextStatement()
  • loadObjectByCriterion()
  • loadObjectListByStatement()
  • loadObjectListByTextStatement()
  • loadObjectListByCriterion()
verwendet werden. Diese erwarten jeweils ein SQL-Statement oder ein GenericCriterionObject. Die folgende Codebox zeigt das Laden von Funktionsberechtigungen, die mit einer bestimmten Rolle verknüpft sind:
PHP-Code
// define statement $select = 'SELECT `ent_permission`.* FROM `ent_permission` INNER JOIN ass_permissionset2permission ON ent_permission.PermissionID = ass_permissionset2permission.PermissionID INNER JOIN ent_permissionset ON ass_permissionset2permission.PermissionSetID = ent_permissionset.PermissionSetID INNER JOIN ass_role2permissionset ON ent_permissionset.PermissionSetID = ass_role2permissionset.PermissionSetID INNER JOIN ent_role ON ass_role2permissionset.RoleID = ent_role.RoleID WHERE ent_role.RoleID = '1' GROUP BY ent_permission.PermissionID;'; // load permission list $permissions = $oRM->loadObjectListByTextStatement('Permission',$select);
Um eine Liste von vorhandenen Applikationscontainern zu selektieren, kann folgender Code eingesetzt werden:
PHP-Code
$apps = $oRM->loadObjectListByCriterion('Application');
Details zu den im Modul enthalten Objekten, Attributen und Beziehungen, können den Konfigurationsdateien oder dem obigen UML-Diagramm entnommen werden. Die Verwendung des O/R-Mappers wird im Kapitel Generischer O/R-Mapper genauer beschrieben.


4. Erweiterung

4.1. Passwort-Verschlüsselung

4.1.1. Erweiterung des Managers
Dieser Absatz spiegelt die Vorgehensweise bis einschließlich Version 1.10 wieder. Diese Möglichkeit besteht jedoch auch in höheren Versionen, die präferierte Methode wird jedoch im nächsten Kapitel besprochen.

Die Business-Komponente nutzt aktuell ein Crypt-Verfahren um Passwort-Hashes zu erzeugen. Soll dieses Verhalten geändert werden (z.B. auf SHA1), so kann dies durch ableiten von der Klasse UmgtManager und Überschreiben der privaten Methode createPasswordHash() erfolgen. Dabei ist darauf zu achten, dass die abgeleitete Klasse die init()-Methode nicht überschreibt.

Die neue Klasse kann nach der Überladung exakt gleich verwendet werden. Das folgende Beispiel zeigt eine Änderung des Passwort-Hash-Verfahrens:
PHP-Code
class MyUmgtManager extends UmgtManager { protected function createPasswordHash($password){ return sha1($password); } } $umgt = &$this->getAndInitServiceObject('my::namespace','MyUmgtManager','Default'); $user = $umgt->loadUserByID(5);

4.1.2. Implementierung PasswordHashProvider
Die ab Version 1.11 implementierte Änderung ermöglicht es, einen eigenen PasswordHashProvider in der Konfiguration des Moduls zu definieren. Dieser ist dafür zuständig, dem UmgtManager bei der Erstellung des Password Hash-Wertes behilflich zu sein. Bis einschließlich Version 1.13 wurde hierbei md5 eingesetzt. Mit Version 1.14 wurde diese, nichtmehr dem heutigen Sicherheitsstand entsprechende Methode, durch einen komplexeren und sichereren Hash-Algorythmus ersetzt, der auf der Funktion crypt() in Verbindung mit einem statischen und einem dynamischen Salt beruht. Es wird dringend empfohlen auf den Einsatz des alten Algorythmus zu verzichten. Wie eine bestehende Anwendung auf den neuen Algorythmus migriert werden kann, lesen sie unter 4.1.3. PasswordHashProvider Fallback.
Für den in Version 1.14 hinzugekommenen statischen Salt, ist ein neuer Konfigurationseintrag empfehlenswert, Informationen hierzu finden Sie unter Konfiguration des Moduls. Desweiteren wird eine neue Spalte in der User-Tabelle benötigt, welche einen für jeden Benutzer unterschiedlichen, automatisch generierten DynamicSalt beinhaltet.

Um eine eigene Komponente zur Verfügung zu stellen, muss zunächst eine PHP-Klasse erstellt werden, die das PasswordHashProvider Interface implemeniert. Dieses definiert eine Methode, die für ein übergebenes Password einen Hash berechnet. Führen wir obiges Beispiel weiter, so hat die Klasse folgende Gestalt:
PHP-Code
import('modules::usermanagement::biz','PasswordHashProvider'); class Sha1PasswordHashProvider implements PasswordHashProvider { public function createPasswordHash($password){ return sha1($password); } }
Die Konfiguration muss dann um die zwei Direktiven erweitert werden, die den Namespace und den (Klassen-)Namen der Komponente definieren:
APF-Template
PasswordHashProvider.Namespace = "my::namespace" PasswordHashProvider.Class = "Sha1PasswordHashProvider"
Vollständige Beispiel-Konfigurationen für das Usermanagement finden sich in den apf-configpack-*-Paketen.
4.1.3. PasswordHashProvider Fallback
Seit Version 1.14 ist es möglich mehrere PasswordHashProvider gleichzeitig einzusetzen, um von einem alten Hash-Algorythmus auf einen neuen umsteigen zu können, da sich die Benutzer andernfalls nicht mehr einloggen könnten.
Hierfür werden mehrere PasswordHashProvider in der Konfiguration definiert. Der erste definierte Provider entspricht dabei dem neuen, zu verwendenden Provider. Alle weiteren Provider werden als Fallback angesehen. Bei einem Login wird zuerst versucht das übergebene Passwort mit dem neuen Provider zu hashen, und mit dem gespeicherten zu vergleichen. Gibt es hierbei keine Übereinstimmung, werden der Reihe nach die Fallback-Provider probiert. Wird ein übereinstimmender Hash mit einem der Fallback-Provider gefunden, wird im Hintergrund automatisch der Hashwert in der Datenbank auf das Format des neuen, zuerst definierten Providers aktualisiert. Der Benutzer bekommt hierbei nichts mit, seine Logindaten werden natürlich akzeptiert.
Auf diesem Weg sollten, wenn sich jeder User mindestens ein mal eingeloggt hat, nach einer gewissen Zeit alle Hashwerte auf das neue Verfahren umgestellt sein, und somit sicherer vor Bruteforce- und Rainbowtable-Attacken sein.

Die Konfiguration muss wie folgt angepasst werden, hier am Beispiel der Migration vom alten APF Format (vor 1.14) auf das neue APF Format (ab 1.14):
APF-Konfiguration
PasswordHashProvider.Default.Namespace = "modules::usermanagement::biz::provider::crypt" PasswordHashProvider.Default.Class = "CryptHardcodedSaltPasswordHashProvider" PasswordHashProvider.Fallback.Namespace = "modules::usermanagement::biz::provider::md5" PasswordHashProvider.Fallback.Class = "OldMD5PasswordHashProvider"

Die Bezeichnung der Subsections (Hier Default und Fallback) ist dabei nicht relevant, die Reihenfolge ist ausschlaggebend.

4.2. Anzeige-Name des Benutzers

Der Anzeige-Name eines Benutzers wird aktuell aus

APF-Template
{Nachname}, {Vorname}

zusammengesetzt. Um dieses Verhalten zu beeinflussen kann die Klasse UmgtManager ähnlich wie unter 4.1. beschrieben erweitert werden. Hierbei muss die Methode getDisplayName($user) überschrieben werden. Diese erwartet ein Objekt des Typs GenericDomainObject und gibt den Anzeige-Namen des Benutzers zurück.

Um die E-Mail-Adresse als Anzeige-Namen zu nutzen, ist folgende Erweiterung notwendig:

PHP-Code
class MyUmgtManager extends UmgtManager { protected function getDisplayName($user){ return $user->getProperty('EMail'); } }
Sofern Sie eine Version <= 1.13 verwenden, muss statt getDisplayName() die Methode __getDisplayName() überschrieben werden.

Kommentare

Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
« 1   »
Einträge/Seite: | 5 | 10 | 15 | 20 |
1
Christian 17.07.2010, 12:28:29
Hinweise zur Nutzung der in 1.12 neu hinzugekommenen Sichtbarkeits-Berechtigungen finden sich auf der Wiki-Seite http://wiki.adventure-php-framework.org/de/Usermanagement
2
Christian 14.07.2009, 21:29:10
Unter http://forum.adventure-php-framework.org/de/viewtopic.php?f=1&t=148 finden sich noch einige Hinweise zur Verwendung der Permissions.