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");
}
?>
  • Zuletzt geändert: vor 8 Jahren