Dies ist eine alte Version des Dokuments!
Prüfscript
Es handelt sich um eine Implementierung auf Basis von PHP und memcached. Das Skript wird unter GPLv3 veröffentlicht. Bitte beachten Sie die voraussetzungen.
- shibchecker.php
<?php /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Copyright 2015 Frank Schreiterer, University of Bamberg, Computing Centre */ #unbegrenzt ausführen set_time_limit(0); #set logging to true or false $logging=true; #Pfad zur Logfile $logfile="/var/log/apache2/map.log"; #apt-get install php5-memchache NICHT php5-memchached! $mcsrv="127.0.0.1"; $mcport="11211"; #Lebenzeit der Einträge in Sekunden -> Wert muss an die SessionLifeTime der Shibboleth-Session und der Anwendungs-Session angepasst sein #hier 12 Stunden $mcExpire=43200; #Das Prüfmuster für die Session-ID der Anwendung $regexappsessionid="/^[a-z0-9]{26}$/"; ### Ende User-Konfig ### #es wird versucht, den Overhead für die Verbingung durch die ständige Verbindung zu minimieren, #schlägt bei memcached die Verbindung fehl, so wird die Verbindung selbständig wieder aufgebaut $mc=new Memcache; $mc->connect($mcsrv,$mcport); $keyboard = fopen("php://stdin","r"); $out = fopen("php://stdout","w"); while (1) { #Variablen initialisieren $shibvalid=false; $appvalid=false ; $valid=true; $return=""; $returnmsg=""; $logstr = ""; $mixedlazy = false; $checkappsessionid = false; $appsessionid=""; $shibcookiesessionid=""; $appsessionidmatch=0; $shibcookiesessionidmatch=0; #Ende Variablen initialisieren $input = trim(fgets($keyboard)); $startts = microtime(true); #input zerlegen $tmp = explode(",",$input); #Context -> Parameter 1 bei Aufruf RewriteMap sessionHook wenn über den LoginHook des Shibd aufgerufen wird, lazy für ausschließlich Lazy Session und normal für normale Shib-Session #Der Parameter 5 ist optional und wird verwendet, um dem shibcheker mitzuteilen, dass es sich um die Prüfung im Modus mixedLazy handelt, d. h. die Anwendung unterstützt neben #Shibboleth Lazy Session und ander Authentifizungen. $context = strtolower(trim($tmp[0])); #Shib-Session-ID -> Parameter 2 bei Aufruf RewriteMap $shibsessionid = trim($tmp[1]); #Name der Anwendungssession -> Parameter 3 bei Aufruf RewriteMap $sesscookie = trim($tmp[2]); #die gesetzen Cookies, aus denen der Wert der Anwendungssession extrahiert werden muss -> Parameter 4 bei Aufruf ReweriteMap $cookies = $tmp[3]; #Parameter 5 mixedLazy für Modus mixedLazy, falls die shibsessionid leer ist if (isset($tmp[4]) && strtolower(trim($tmp[4])) == "mixedlazy") { #Prüfung der übermittelten appsessionid auf Duplikate, wenn im Parameter 5 mixedLazy übergeben wurde $checkappsessionid = true; if ($shibsessionid == "") { $mixedlazy = true; } } #aus den Cookies die ID der Anwendungssession extrahieren $regexapp="/^$sesscookie=.*$/"; $regexshib="/^_shibsession_[a-z0-9]+=_[a-z0-9]{32}/"; $tmp = explode(";",$cookies); foreach ($tmp as $cookie) { $cookie = trim($cookie); if (preg_match($regexapp,$cookie)) { $appsessionid = trim(str_replace($sesscookie."=","",$cookie)); $appsessionidmatch++; } if (preg_match($regexshib,$cookie)) { $shibcookiesessionid = trim(preg_replace("/_shibsession_[a-z0-9]+=/","",$cookie)); $shibcookiesessionidmatch++; } } #Es wurde am Shib-Session-Cookie nichts verändert, Veränderung am Cookienamen werden von Shibd mit einer leeren Session-ID im Header quitiert, jedoch #bleibt das Cookie ansich mit der Session-ID bestehen #wird mehr als einmal versucht, ein Cookie mit der Anwendungssession bzw. Shibbolethsession zu übergeben, ist das auch verboten if ($shibsessionid == $shibcookiesessionid && $appsessionidmatch < 2 && $shibcookiesessionidmatch < 2) { #wenn mixedLazy, dann können wir uns alle weiteren Prüfungen sparen, da die Shibboleth-Checks nur ausgeführt werden können, #wenn auch die Anmeldung über Shibboleth erfolgt. #Anderenfalls liegt Die Prüfung der übergebenen Anwendungssession in der Verantwortung der Anwendung und kann hier nicht geprüft werden. if ($mixedlazy == false) { #grundlegende Prüfungen #shibsessionid if (preg_match("/^_[a-z0-9]{32}$/",$shibsessionid)) { $shibvalid=true; } elseif ($shibsessionid != "") { #eine ungültige ID der Shibboleth-Session wurde übermittelt $logstr = "$logstr\nShibboleth-Session-Id $shibsessionid ungültig"; $valid = false; } #appsessionid - hier ggf. Anpassungen vornehmen (ist für PHP-Session) if (preg_match($regexappsessionid,$appsessionid)) { $appvalid=true; } elseif ($appsessionid != "") { #eine ungültige ID der Anwendungs-Session wurde übermittelt $valid = false; $logstr = "$logstr\nAnwendungs-Session-Id $appsessionid ungültig"; } #ist die Anwendungs-Session gesetzt und noch keine Shib-Session gesetzt ist das böse if ($shibvalid == false && $appvalid == true) { $valid = false; $logstr = "$logstr\nAnwendungs-Session-Id $appsessionid vor Shibboleth-Session gesetzt"; } #wurde über den sessionHook aufgerufen, dann darf im Anwendungscookie nichts drin stehen if ($context == "sessionhook" && $appsessionid != "") { $valid = false; $logstr = "$logstr\nAnwendungs-Session-Id $appsessionid im Modus sessionHook gesetzt - verboten"; } #erweiterte Prüfung nur notwendig, wenn nicht abgemeldet werden soll und nicht der sessonHook geprüft wird if ($valid == true && $context != "sessionhook") { #nur weiter prüfen, wenn die Anwendungs-Session und die Shib-Session gültig sind if ($shibvalid == true && $appvalid == true) { #schauen, ob es die Kombination der Sessions schon gibt $item = $mc->get($shibsessionid); #bei memcached-Cluster hier noch aus den anderen lesen und ggf. Werte lokal schreiben if ($item == false) { $logstr = "$logstr\nneue Shibboleth-Session $shibsessionid"; if ($checkappsessionid == true) { #noch prüfen, ob die Anwendungssession nicht schon einmal vergeben wurde, so kann bei mixedLazy die Gefahr minimiert werden, dass versucht wird, mit einer alten Anwendungssession zuzugreifen $get = $mc->get($appsessionid); if ($get != false) { $valid = false; $logstr = "$logstr\nAnwendungs-Session-Id $appsessionid bereits vergeben - ungültig"; } else { $logstr = "$logstr\nPrüfung auf doppelte Anwendungs-Session-Id $appsessionid erfolgreich - Anwendungs-Session-Id $appsessionid nicht vorhanden"; } } #nur weiter, wenn noch gültig if ($valid == true) { #Eintrag in die Sicherungstabelle zur Session schreiben, wenn auch eine Anwendungssession da ist if ($appsessionid != "") { $mc->set($shibsessionid,$appsessionid,false,$mcExpire); $logstr = "$logstr\nSchreibe Key Shibboleth-Session $shibsessionid mit Wert der Anwendungs-Session $appsessionid"; #bei memcached-Cluster hier noch in die weiteren schreiben if ($checkappsessionid == true ) { #und noch die appsessionid als key $mc->set($appsessionid,"$shibsessionid",false,$mcExpire); $logstr = "$logstr\nSchreibe Sicherungseintrag zur Anwendungs-Session $appsessionid"; } } } } elseif ($valid == true) { #prüfen, ob versucht wurde, zur Shibboleth-Session eine andere Kombination mit der Anwendungs-Session unterzuschieben if ($item != $appsessionid) { $valid = false; $logstr = "$logstr\nAnwendungs-Session $appsessionid zur Shibboleth-Session $shibsessionid übermittelt, aber Wert der Anwendungs-Session $item erwartet - ungültig"; } } } #Anwendungs-Session und die Shib-Session gültig else { $valid = false; #SONDERFÄLLE #erster Aufruf bei Lazy-Session if ($shibsessionid == "" && $appsessionid == "" && $context == "lazy") { $returnmsg = "doLogin"; $valid = true; } #dieser Zustand darf bei normaler und bei lazy Session erreicht werden, bei sessionHook kommen wir gar nicht hier hin #es muss zwingend die Anwendungssession initialisiert werden, sonst ist es möglich, eine falsche Session zu verwenden if ($appsessionid == "" && $shibvalid == true) { $valid = true; $returnmsg = "doAppSession"; $logstr = "$logstr\nShibboleth-Session $shibsessionid ohne Anwendungs-Session gefunden - gültig, aber Initialisierung der Anwendungs-Session erforderlich"; } } } #erweiterte Prüfung } # nicht mixedLazy else { $valid = true; $logstr = "$logstr\nModus mixedLazy ohne Shibboleth-Authentifizierung - Anfrage zugelassen"; } } #$shibsessionid == $shibcookiesessionid else { $shibvalid = false; $valid = false; if ($shibsessionid != $shibcookiesessionid) { $logstr = "$logstr\nShibboleth-Session-Id vom Shibd ungleich Shibboleth-Session-Id aus Cookie"; } else { $logstr = "$logstr\nShibboleth- oder Anwendungs-Cookie mehrfach gesetzt"; } } #die Rückgabewerte if ($valid == false) { $return = "doLogout"; } else { $return = "good"; if ($returnmsg != "") { $return = $returnmsg; } } if ($logging == true) { $log = fopen($logfile,"a+"); $now = date("Y-m-d H:i:s"); $nowts = microtime(true); $extime = ($nowts - $startts)*1000; $logstr="\n$now Ausführungsdauer: $extime Millisekunden \nKontext: $context mixedLazy: $mixedlazy shibvalid: $shibvalid appvalid: $appvalid \nEingabe: $input \nshibsessionid: $shibsessionid \nappsessionid: $appsessionid $logstr \nreturn: $return\n"; fwrite($log,$logstr); fclose($log); } fwrite($out,"$return\n"); } ?>