PHP5 und BiPRO Teil 5: Norm 410

Ich habe diese Woche mal die Zugriffszahlen der von mir geschriebenen BiPRO Artikel in diesem Blog ausgewertet. Das Thema scheint nach wie vor ein ziemlich heißes Eisen zu sein. Aus diesem Grund habe ich mich gestern Abend mal auf mein Hinterteil gesetzt und eine komplette Umsetzung der BiPRO Norm 410 mit PHP5 programmiert. Komplett bedeutet in diesem Fall, dass sowohl Client (Consumer) als auch Server (Provider) umgesetzt wurden. Wie das allein mit PHP und gültigen Web-Standards funktioniert wird im Download haargenau beschrieben.

Vorbereitungen

Dieser Artikel richtet sich an fortgeschrittene PHP Entwickler, da ich auf einer objektorientierten Struktur aufbaue und ich hierzu nicht alles erklären werde. Ihr solltet also wissen, was ein Autoloader ist und warum Class Maps cool sind. Natürlich könnt ihr die Kommentarfunktion unterhalb dieses Artikels nutzen. Fragen finde ich nämlich gut. Für die Umsetzung sind einige Vorbereitungen zu treffen. Folgende Punkte müssen erledigt sein, bevor wir uns auf den Code stürzen:

  1. Für das Verständnis und die richtige Umsetzung ist es vorteilhaft, wenn man die BiPRO Normen zur Hand hat. Diese bekommt ihr auf der Website des BiPRO e.V. als ZIP Archive zum Download angeboten. Dafür ist es notwendig, dass ihr dort registrierte User seid. Der Download der Normen ist lediglich im Passwort-geschützten Mitgliederbereich der Seite möglich. Eine Registrierung auf der Seite ist kostenlos. Ihr benötigt alle Normen, die im Download für die BiPRO Norm 410 enthalten sind.
  2. Wenn ihr das ZIP Archiv zur BiPRO Norm 410 habt, findet ihr darin eine WSDL Datei. Diese Datei muss überarbeitet werden, um ein Problem zu umgehen, welches ich vor einiger Zeit schon hier beschrieben habe. Im Download zu diesem Artikel findet ihr bereits eine angepasste WSDL Datei, in der lediglich der Pfad zum Webservice an Eure Entwicklungsumgebung angepasst werden muss. Die WSDL datei enthält hierzu in Zeile 55 einen entsprechenden Kommentar.
  3. Im Download sind im Unterorder /bipro/norm410/ die Dateien server.php und client.php enthalten. In diesen Dateien muss ebenfalls der Pfad zur WSDL Datei an Eure Entwicklungsumgebung angepasst werden.

Die dokumentierten Normen haben mir bei der Entwicklung einen ganzen Schritt weiter geholfen. Daher empfehle ich Euch dringend, dass ihr diese immer zur Hand habt.

Allgemeines

Der BiPRO e.V. weist in seiner Norm 200 Grundlagen Technik darauf hin, dass sie es sich zum Ziel gesetzt hat vorhandene Standards, wie zB. OASIS und W3C, als Grundlage zu nutzen. Diesen Punkt möchte ich auch strikt in meiner Umsetzung der Normen verfolgen. Dies bedeutet im Zusammenhang mit PHP, dass keine XML Konstrukte als Strings oder Templates im Code hinterlegt werden. Das widerspricht der Natur von SOAP und den damit in PHP vorhanden SoapClient und SoapServer Objekten. Alles, was ich hier umsetze, ist ein Objekt und verfolgt strikt den Grundsatz der objektorientierten Programmierung. Die XML Struktur selbst, wird anhand der programmierten Objekte automatisch vom SoapClient oder SoapServer Objekt erzeugt. Ich nutze bereits vorhandene PHP Technik, um sowohl einen Consumer als auch einen Provider anhand der von der BiPRO bereitgestellten Informationen zu erstellen.

Allein mit den programmierten Objekten halten wir den Aufwand so gering wie möglich und halten die Wiederverwendbarkeit so hoch wie möglich.

Der Provider

Unter einem Provider verstehen wir den Server, der auf eine Anfrage antwortet. In unserem Fall ist es die Datei server.php, die alle Requests entgegen nimmt. Wie das technisch mit PHP funktioniert, seht ihr bei einem Blick in die Datei selbst oder ihr lest einfach ein Stück weiter. Wie sieht also unser SoapServer Objekt aus?

/bipro/norm410/server.php
18
19
20
21
22
23
24
25
$oServer = new \SoapServer(
    $sWsdl,
    [
        'encoding' => 'UTF-8',
        'send_errors' => true,
        'soap_version' => SOAP_1_2,
    ]
);

Der gezeigte PHP Code zeigt die Initialisierung des SoapServer Objekts, wie sie in der server.php Datei stattfindet. Wir übergeben als erstes die Adresse der WSDL Datei als $sWsdl Variable. Dabei legen wir fest, dass der SoapServer aufgetretene Fehler an den Client sendet, das Encoding auf UTF-8 gesetzt ist und die SOAP Version auf 1.2 gesetzt ist. Soweit so gut. Aber wie sagt man dem Soap Server nun, was er mit den eingehenden Anfragen tun soll?

/bipro/norm410/server.php
27
28
29
30
$oService = new AuthDecorator();
$oService->setClassName('\MMNewmedia\BiPRO\Norm410\Model\Response');
$oServer->setObject($oService);
$oServer->handle();

Diese vier Zeilen bearbeiten alle eingehenden Requests. Ja, das war es wirklich schon. Kein Witz! Nein mal im Ernst. Was genau steckt dahinter? Zunächst initialisiere ich hier die Klasse AuthDecorator, die dem Decorator Design Pattern folgt. Klingt erstmal wahnsinnig schwierig, bedeutet aber grob gesagt lediglich, dass unser AuthDecorator erstmal alle Requests auffängt, bevor sie an die dahinterliegende Response Klasse weitergeleitet werden, um eine Response zu erzeugen.

Wieso ist dieser Decorator wichtig? Bei der BiPRO Norm 410 geht es erstmal um Sicherheit. Bei jeder Response, die der Server liefert, müssen wir also erstmal prüfen, ob die im Request enthaltenen Credentials (Username und Password) valide sind. Genau das erledigt die Klasse AuthDecorator. Sie ist quasi der Türsteher, der uns Einlass gewährt, wenn wir cool sind. Erst wenn die Credentials überprüft sind, passiert hier wirklich etwas. Wenn sie nicht stimmen, wird ein SoapFault geworfen. Dieser weicht erstmal von der BiPRO Norm ab, um die Funktionalität des Ganzen zu demonstrieren. Ich denke, dass ich die in den BiPRO Normen beschriebenen Fehlermeldungen in einem der folgenden Artikel nachreichen werde.

Zurück zu unserem Türsteher. So manch einer von Euch wird sich wahrscheinlich schon mal den Kopf zerbrochen haben, wie die Header Daten des Requests, in dem der Username und das Passwort stehen, überhaupt von PHP verarbeitet werden können? PHP macht dies vollkommen automatisch. Sobald wir mit der setObjekt Methode des Servers ein Objekt zur Verarbeitung der Requests setzen, muss in diesem Objekt zwingend eine Methode vorhanden sind, die wie der erste Knoten im Header des gesendeten Requests lautet. In der BiPRO Norm 410 lautet der erste Knoten im Request Header einfach Security. Es muss also zwingend eine Security Methode im gesetzten Objekt vorhanden sind. Um es einfach zu machen, prüft die Security Methode des AuthDecorators nur, ob der Benutzername „Foo“ und das Passwort „Bar“ lauten. Natürlich muss hier eine umfassendere Logik hinterlegt werden.

Sobald wir am Türsteher vorbei sind gelangen wir an die Response Klasse, die die Methode RequestSecurityToken enthält. Genau das ist die Funktion, die in der WSDL Datei beschrieben wird und vom Client aufgerufen wird, um einen Security Token zu erhalten. Allein diese Methode liefert die Response.

/bipro/norm410/model/Response.php
26
27
28
29
public function RequestSecurityToken() {
    ...
    return $oRequestSecurityTokenResponse->encode();
}

Am Ende der Methode erhält der SoapServer ein SoapVar Objekt und sendet es als Response. Die Erstellung des aus dem SoapVar Objekts resultierendem XML Konstrukts übernimmt das SoapServer Objekt. Wir müssen also kein XML manuell kompilieren. Einfach, oder?

Der Consumer

Beim Consumer handelt es sich um ein SoapClient Objekt, welches eine Anfrage an den Provider sendet, um einen Security Token als Antwort zu erhalten. Eigentlich genau das umgekehrte Prinzip des SoapServer Objekts aber mindestens genau so einfach.

/bipro/norm410/client.php
18
19
20
21
22
23
24
25
26
27
$oClient = new \SoapClient(
    $sWsdl,
    [
        'trace' => true,
        'exception' => true,
        'cache_wsdl' => WSDL_CACHE_NONE,
        'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
        'soap_version' => SOAP_1_2,
    ]
);

Der Soap Client funktioniert bei der Initialisierung genau so, wie der Soap Server. Es wird eine WSDL Datei übergeben und als zweiten Parameter nimmt das Objekt einfach ein Array mit verschiedenen Optionen, die für den Client gelten sollen. In unserem Fall sind zum exzessiven Testen die Cache Funktionen abgeschaltet und es werden Exceptions vom Soap Client zurückgegeben, wenn sie denn erfolgen. Da XML immer einen ziemlichen Overhead an Daten produziert, versenden wir diese als GZIP Komprimiertes Format, sofern möglich.  Im Live Betrieb sollte das Caching der WSDL Datei auf jeden Fall aktiviert werden.

Im weiteren Verlauf der client.php Datei wird der Soap Header mit den Credientials (Benutzername und Passwort) gesetzt. Diese Aufgabe übernimmt die in meinem Beispiel enthaltene WsseHeader Klasse, die zu Teilen auch schon mal hier gezeigt wurde. Im Download Beispiel ist der Password Knoten ein bisschen speziell. In der BiPRO Norm 260 wird der Request anhand eines Beispiels beschrieben. In diesem Beispiel hat der Password Knoten ein Type Attribut. Nach W3C Standards kann man das so machen bzw. wird auch so akzeptiert. Im Download Beispiel wird es ein wenig richtiger gemacht.

/bipro/norm410/model/WsseHeader.php
54
55
56
57
58
59
60
61
$oUsernamerToken->setPassword(new \SoapVar(
    $sPassword,
    XSD_STRING,
    'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-375 username-token-profile-1.0#PasswordText',
    null,
    'Password',
    $this->sWsseNs
));

Mit PHP kann man mit dem SoapVar Objekt grundsätzlich ein Type Attribut setzen. Dieses Type Attribut wird aber im XML Schema als xsi:type notiert. Dies entspricht absolut den aktuell gültigen W3C Standards und ist keineswegs falsch. Eigentlich ist es sogar ein kleines bisschen richtiger, als es die BiPRO in ihrer Norm notiert hat. Das Attribut wird anstandslos verarbeitet.

Die client.php empfängt einen Security Token und gibt diesen dann zusammen mit dem gesendeten Request und der empfangenen Response auf dem Bildschirm aus.

Fazit

Lässt man mal die ganzen schrägen, abweichenden Umsetzungen der Versicherer und Dienstleister außer Acht, so gestaltet sich die Umsetzung der reinen BiPRO Norm 410 als solche für einen PHP Entwickler wie mich extrem einfach. Wenn man sich die Dokumentation der Norm durchliest und die in der Norm beschriebenen Fakten sauber umsetzt, kommt man relativ schnell zum Ziel. Allerdings rede ich hier von der reinen Norm. Schaut man sich im Vergleich dazu mal den ein oder anderen Versicherer an, wird es einem PHP Entwickler extrem schwierig gemacht.

Normalerweise sollten die Umsetzungen der Versicherer die BiPRO Norm 410 als Basis haben. Das haben sie auch. Im Allerweitesten Sinne. Hier mal ein Attribut mehr. Hier mal ein Knoten mehr. Oder einfach mal den Content Type auf text/xml anstatt application/soap+xml setzen und schon können wir das mit der Wiederverwendbarkeit an den Haken hängen. Denn genau dann sind wir wieder bei der Realisierung für jeden einzelnen Provider. Die Norm als solche, wenn man sie quasi jungfräulich von der BiPRO bezieht, ist relativ einfach gehalten.

Download

Bitte beachtet beim Download, dass es sich dabei lediglich um eine Demo handelt. Bitte setzt diese Umsetzung nicht produktiv ein. Ich übernehme keinerlei Haftung, falls es doch jemand probieren sollte. Versteht die Umsetzung eher als Denkanstoß, als ein Beispiel von vielen anderen. Eine Möglichkeit, wie man einen Security Token Service mit PHP aufziehen kann.

Bitte beachtet auch, dass die im Archiv enthaltene Umsetzung keine Out of the box Lösung ist. Ihr müsst hier noch ein paar kleine Anpassungen vornehmen, um es bei Euch ans Laufen zu bekommen. Bitte beachtet hier die Hinweise, die unter Vorbereitungen aufgelistet wurden.

So! Und jetzt viel Spaß!

Download “BiPRO Norm410 mit PHP5” mmnewmedia-bipro.zip – 188-mal heruntergeladen – 26 KB

Für Fragen und Anregungen steht Euch die Kommentarfunktion unter diesem Artikel zur Verfügung. Ich bin für jedes Feedback dankbar.

Bildquelle: weinstock / CCO Public Domain

About Author: Marcel
Ich bin Senior PHP Developer bei MM Newmedia. Seit 2005 bin ich begeisterter Webentwickler und arbeite als Freelancer für namenhafte Firmen und entwickle jede Menge abgefahrenes Zeug und berichte darüber in meinem Blog.

One thought on “PHP5 und BiPRO Teil 5: Norm 410

Kommentar verfassen