11.2 Einbindung in die Applikation 

In der Applikation soll der Besucher der Webseite beim Hinterlassen eines Kommentars zu einem Weblog-Eintrag entweder gegen einen OpenID-Server oder eine passwd-Datei im config/-Verzeichnis authentifiziert werden.
Dazu wird zuerst das Kommentarformular um ein optionales Passwortfeld und eine Beschreibung der dem Besucher zur Verfügung stehenden Authentifizierungsmechanismen erweitert. Die Aktion, die den Kommentar abspeichert, muss anschließend Gebrauch von diesen Informationen machen und dafür entsprechend erweitert werden. Die Behandlung der Eingaben, auf denen hier aufgebaut wird, wurde in Kapitel 10, »Benutzereingaben validieren«, beschrieben.
11.2.1 Eingabeformulare 

Wie angesprochen, muss das Formular um ein Passwortfeld erweitert werden. Der betroffene Teil des Templates templates/comment_form.ezt sieht nach der Modifikation wie folgt aus:
<p> {gp_translate( 'To leave a comment you may either authenticate against the local authentication mechanisms using a password, or use an OpenID and leave the password blank.', 'comment/new')} </p> <form name="comment_form" id="comment_form" action="{$base}save_comment" method="POST"> <input type="hidden" name="entryId" id="entryId" value="{$entry->id}" /> <input name="name" id="name" type="text" /><br /> <input name="password" id="password" type="password" /><br /> <input name="email" id="email" type="text" /><br /> <textarea name="body" id="body"></textarea><br /> <input name="save" id="save" type="submit" value="{gp_translate('Store entry', 'comment/new')}" /><br /> </form>
Listing 11.1 Passwort ins Kommentarformular einfügen
Die Aufrufe der Template-Funktionen gp_translate() dienen lediglich der Übersetzung der Texte im Template und sollen hier nicht weiter irritieren. Wesentlich sind der fett markierte Einleitungstext zu Beginn, eingefasst in ein <p>-Element, sowie das neue Input-Feld zur optionalen Eingabe eines Passworts.
Der einleitende Text beschreibt dem Besucher des Blogs das Verhalten, das in der Applikation erzielt werden soll. Unter der Angabe eines Passworts wird der Besucher gegen eine Liste lokal gespeicherter Benutzer authentifiziert. Wir werden, um das Beispiel einfach zu halten, lediglich gegen eine passwd-Datei authentifizieren. Andernfalls kann der Besucher das Passwortfeld leer lassen. Der Benutzername wird als OpenID betrachtet und der entsprechende Authentifizierungsmechanismus verwendet. In diesem Fall muss die Webapplikation keine weiteren Daten kennen; der Besucher ist dennoch eindeutig authentifiziert.
Falls die Authentifizierung des Besuchers nicht erfolgreich war, erscheint eine entsprechende Fehlermeldung und der Kommentar wird nicht gespeichert.
11.2.2 Formularverarbeitung anpassen 

Die in Kapitel 10, »Benutzereingaben validieren«, entwickelte Verarbeitung der Formulardaten mittels der UserInput-Komponente muss als Nächstes angepasst werden, um das zusätzliche Eingabefeld verarbeiten zu können. Dazu wird zunächst die Methode gpBlogActionComment::getFormDefinition() in der Datei classes/actions/comment.php um das Passwortfeld erweitert:
'password' => new ezcInputFormDefinitionElement(
ezcInputFormDefinitionElement::OPTIONAL,
'string'
),Listing 11.2 Formulardefinition für das Passwort
Wie zu erwarten, wird das Passwortfeld als optional deklariert und als Wert wird eine Zeichenkette erwartet. Da das Passwort nicht im Kommentar selbst gespeichert werden soll, muss eine entsprechende Ausnahme in der Methode save() eingebaut werden, die die eigentliche Aktion implementiert und den Kommentar speichert.
foreach ( $definition as $elementName => $dummy )
{
if ( $form->hasValidData( $elementName ) )
{
// We do NOT want to store the password
if ( $elementName !== 'password' )
{
$comment->$elementName = $form->$elementName;
}
}
else
{
// Error
}
}Listing 11.3 Passwort verarbeiten
In der Schleife, die die validen Formulardaten dem Kommentarobjekt zuweist, werden ab jetzt entsprechend nur noch die Formularelemente gespeichert, die nicht das Passwort sind, wie in der sechsten Zeile des Codeausschnitts zu sehen ist.
11.2.3 Authentifizierung des Besuchers 

Nachdem nun die notwendigen Daten in der Applikation verfügbar sind, wird der Authentifizierungsmechanismus vor dem tatsächlichen Speichern des Kommentars eingebaut.
if ( !empty( $form->password ) )
{
// Use local auth mechanisms
$credentials = new ezcAuthenticationPasswordCredentials(
$form->name,
$form->password
);
$authentication = new ezcAuthentication( $credentials );
$authentication->addFilter(
new ezcAuthenticationHtpasswdFilter(
dirname( __FILE__ ) . '/../../config/passwd' )
);
// Optionally add more filters here
if ( !$authentication->run() )
{
gpBlogController::getInstance()->mainSignals->emit(
'error',
'Could not authentificate.'
);
return false;
}
}
else
{
// OpenID
}Listing 11.4 Authentifizierung gegen htaccess
Die Authentifizierung besteht bei der Verwendung aller Treiber aus den gleichen Schritten. In der vierten Zeile des Codebeispiels werden zuerst die sogenannte Credentials, die vom Besucher zur Verfügung gestellte Legitimation zum Zugriff, erstellt. Im Falle der Verfügbarkeit von Benutzernamen und Passwort wird ein Objekt der Klasse ezcAuthenticationPasswordCredentials erstellt.
Mit der Legitimation wird ein neues Objekt der Klasse ezcAuthentication erzeugt, dem die Filter, die die Treiber zur eigentlichen Authentifizierung implementieren, hinzugefügt werden. In obigem Beispiel wird nur ein Filter der Klasse ezcAuthenticationHtpasswdFilter hinzugefügt, der auf Basis einer vorhandenen passwd-Datei erzeugt wird.
Nachdem Sie alle gewünschten Filter hinzugefügt haben, wird die eigentliche Authentifizierung über die Methode run() gestartet, die true liefert, wenn diese erfolgreich war. Im Falle eines Fehlers wird erneut ein Signal mit entsprechender Fehlermeldung gesendet, die dem Besucher das Scheitern zeigt. Falls die Authentifizierung erfolgreich war, wird die Ausführung des aus dem vorigen Kapitel bekannten Codes fortgesetzt, der den Kommentar speichert und zur Seite mit der Erfolgsmeldung weiterleitet.
Die passwd-Datei enthält eine einfache Liste von Benutzer-Passwort-Paaren.
user:passwort user2:password
Listing 11.5 Passwörter in der Passwortdatei
Wenn sie eine passwd-Datei mit einem der dafür üblichen Programme (wie htpasswd) erstellen, wird normalerweise ein Hashing-Verfahren verwendet, damit das Passwort nicht im Klartext ersichtlich ist. Sie werden sich selbiges natürlich auch bei der Verwendung der Authentication-Komponente wünschen. Dazu können Sie bei der Übergabe des Passworts an das Legitimationsobjekt mit dem gleichen Verfahren verschlüsseln oder hashen, mit dem die Passwörter in der passwd-Datei abgelegt sind. Normalerweise wird dafür entweder crypt() oder ein MD5-Hash verwendet.
| Hashing-Verfahren |
|
Das Bilden eines Hash-Werts ist eine linkseindeutige Abbildung einer Zeichenkette auf eine andere Zeichenkette. Das heißt, dass eine Zeichenkette immer den gleichen Hash-Wert hat, aber ein Hash-Wert das Resultat mehrerer Zeichenketten sein kann. |
|
Aufgrund dieser Eigenschaft und der bei den meisten Hashing-Algorithmen klar definierten Länge eignen sich Hash-Werte ausgezeichnet, um Passwörter zu speichern, da das originale Passwort nicht mehr ermittelbar ist. |
|
Hashing-Algorithmen zum Einsatz in der Kryptographie werden mit dem Ziel entwickelt, dass sich zu einem Hash möglichst schwer eine Zeichenkette berechnen lässt, die diesen Hash erzeugt. Durch die gewachsene Größe von Datenbanken sind mittlerweile für MD5 sogenannte Rainbowtables verfügbar, die zu nahezu jedem Hash eine erzeugende Zeichenkette beinhalten. Falls die eigene Benutzerdatenbank kompromittiert wurde, ist es so Angreifern trotz gehashter Passwörter möglich, sich erfolgreich anzumelden. Ein einfacher und effektiver Weg dieses Problem zu vermeiden, ist die Verwendung eines applikationseigenen Seeds bei der Generierung des Hashs. |
$passwordHash = md5( 'my_custom_seed' . $password ); |
|
Dies reduziert die Wahrscheinlichkeit, dass der Hash »geknackt« wird, auf die Wahrscheinlichkeit, dass die erzeugende Zeichenkette in der Rainbowtable zufällig mit »my_custom_seed« beginnt. |
// Use local auth mechanisms
$credentials = new ezcAuthenticationPasswordCredentials(
$form->name,
md5( $form->password )
);Listing 11.6 Gehashtes Passwort verwenden
Mit einer entsprechend angepassten passwd-Datei in config/passwd funktioniert die Authentifizierung auch ohne das Vorliegen der Passwörter im Klartext.
user:e22a63fb76874c99488435f26b117e37 user2:5f4dcc3b5aa765d61d8327deb882cf99
Listing 11.7 Passworthashes in Passwortdatei
11.2.4 Gruppierung von Filtern 

Falls mehrere Authentifizierungsmechanismen in einer Applikation verwendet werden sollen, können Sie diese auch kombinieren. Vorstellbar ist, dass ein Besucher sowohl auf LDAP-Servern als auch in der Datenbank der aktuell entwickelten Webapplikation verfügbar sein soll. Das vorige Beispiel wird um eine zweite passwd-Datei mit weiteren Benutzern erweitert.
$authentication->addFilter(
new ezcAuthenticationGroupFilter( array(
new ezcAuthenticationHtpasswdFilter(
dirname( __FILE__ ) . '/../../config/passwd' ),
new ezcAuthenticationHtpasswdFilter(
dirname( __FILE__ ) . '/../../config/users.passwd' )
) )
);Listing 11.8 Filtergruppen verwenden
Wenn Sie mehrere Filter kombinieren, erstellen Sie einen ezcAuthenticationGroupFilter mit einem Array der zu kombinierenden Filter. In der Standardeinstellung muss nur einer der enthaltenen Filter die Besucherlegitimation validieren, damit der Gruppen-Filter validiert, sodass in diesem Beispiel der Besucher entweder in der Datei config/users.passwd oder in config/passwd gelistet sein muss.
Wenn eine Legitimation gegen alle Filter einer Gruppe validieren soll, kann dies über eine Option im Filter eingestellt werden. Über die Verschachtelung von Gruppen-Filtern lassen sich so auch komplexe Authentifizierungslogiken abbilden.
11.2.5 OpenID 

Um OpenID in die Applikation zu integrieren, muss mehr beachtet werden als bei der einfach Authentifizierung gegen eine passwd-Datei. Bei der Authentifizierung gegen OpenID übergibt der Besucher eine ID, die dem Schema einer URL entspricht, so zum Beispiel http://xlogon.net/koredn für einen der Autoren dieses Buches, der sich für eine OpenID bei dem deutschen Service http://xlogon.net registriert hat.
Um die Authentizität des Besuchers sicherzustellen, leitet die Applikation an den OpenID-Service-Provider weiter, der den Besucher dann bittet, sich einzuloggen, also sich bei dem OpenID-Service-Provider selbst zu authentifizieren, und dann zu bestätigen, dass es der anfragenden Webseite erlaubt ist, diesen OpenID-Account zu verwenden. Dies sieht bei http://xlogon.net wie folgt aus.
Nach der Bestätigung des Zugriffs auf die Daten beim OpenID-Service-Provider wird dieser wieder zurück an die Webapplikation weiterleiten, mit der verschlüsselten Bestätigung der Verifizierung der Authentifizierung als GET-Parameter. Durch die Verwendung von ausreichend sicheren kryptographischen Methoden ist eine Vortäuschung der Authentifizierung nahezu ausgeschlossen.
Abbildung 11.1 Bestätigung beim OpenID-Provider
Die Webapplikation selbst muss auf die GET-Parameter reagieren und kann den Vorgang, der durch den Authentifizierungsprozess unterbrochen wurde, abschließend fortsetzen. Entsprechend erweitern wir nun den Quellcode zur Authentifizierung gegen OpenID:
session_start();
if ( count( $_POST ) )
{
$_SESSION['comment'] = $comment;
$_SESSION['openid'] = $form->name;
}
// Use OpenID authentication
$credentials = new ezcAuthenticationIdCredentials(
$_SESSION['openid']
);
$authentication = new ezcAuthentication( $credentials );
$authentication->addFilter(
new ezcAuthenticationOpenidFilter()
);
if ( !$authentication->run() )
{
return gpBlogController::getInstance()->mainSignals->emit(
'error',
'Could not authentificate.'
);
}
$comment = $_SESSION['comment'];Listing 11.9 Authentifizierung gegen OpenID
Weil der Prozess durch Weiterleitungen an den OpenID-Service-Provider unterbrochen wird, müssen Sie das Kommentarobjekt in der Variablen $comment in der Session speichern, um es später wieder zum Speichern zur Verfügung zu haben. Da das Blog bislang keine Sessions verwendet und die Rückleitung wieder in dieser Methode enden wird, ist es für uns ausreichend, die Session nur in dieser Methode zu etablieren.
Für die Authentifizierung gegen OpenID können sie keine Passwort-Legitimation verwenden, da OpenID ja lediglich eine ID verwendet und das Passwort nur beim OpenID-Service-Provider eingegeben werden muss. Aus diesem Grund wird ein Objekt der Klasse ezcAuthenticationIdCredentials erstellt und dem Konstruktor von ezcAuthentication übergeben. Der einzige in diesem Codebeispiel verwendete Filter der Klasse ezcAuthenticationOpenidFilter wird hinzugefügt und die Authentifizierung wie gewohnt über die Methode run() gestartet.
Im Gegensatz zum vorigen Beispiel wird von der Authentication-Komponente nun ein Location-Header zur Weiterleitung zum OpenID-Service-Provider gesendet und die Ausführung der Applikation abgebrochen. Dort muss sich der Besucher nun, falls er es nicht schon vorher getan hat, authentifizieren.
Abbildung 11.2 Notwendige Authentifizierung beim OpenID-Service-Provider
Je nach OpenID-Service-Provider können Sie einer Webseite auch die Verwendung der eigenen ID generell erlauben, sodass nicht bei jedem erneuten Log-in nachgefragt wird, ob Sie diesen Log-in erlauben. Sollten Sie dann bereits beim OpenID-Service-Provider authentifiziert sind, finden zwar auch Weiterleitungen im Hintergrund statt, aber Sie bekommen von dem OpenID-Service-Provider nichts mehr zu sehen, sondern werden direkt authentifiziert. Andernfalls wird eine Bestätigungsanfrage, wie auf dem obigen Screenshot zu sehen, angezeigt.
Wie zuvor bereits angesprochen, werden die Parameter, die die Validierung der Legitimation bestätigen, per GET übertragen. Die originalen POST-Parameter sind in der Anfrage selbstverständlich nicht mehr enthalten, entsprechend muss die Methode diesbezüglich leicht angepasst werden, sodass die Fomularverarbeitung sowie der Versuch der Authentifizierung gegen die passwd-Dateien nur noch bei Existenz der POST-Parameter stattfinden.
if ( count( $_POST ) )
{
// Do the form stuff only, when a post request was sent, and
// not, when we might have an OpenID response
}
// Authentificate user
if ( count( $_POST ) && !empty( $form->password ) )
{
// Authetificate against passwd
}
else
{
// Known OpenID stuff
}Listing 11.10 Veränderte Logik zur Verarbeitung der GET-Parameter
Nach diesen strukturellen Modifikationen ist es dem Besucher nun möglich, sich sowohl per Passwort gegen die passwd-Dateien zu authentifizieren als dies auch über einen OpenID-Service-Provider seiner Wahl zu tun, ohne dass dem Besitzer des Blogs ein Passwort oder der Hash-Wert eines Passworts bekannt sein muss.






Ihre Meinung






