From edd1709ebfa651ed2b20ec4f53beeb6d915710ba Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Tue, 16 Nov 2010 14:30:23 +0000 Subject: [PATCH] Session: Add support for multiple authentication sessions. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2636 44740490-163a-0410-bde0-09ae8108e29a --- lib/SimpleSAML/Session.php | 286 +++++++++++++++++++++++++++++-------- 1 file changed, 227 insertions(+), 59 deletions(-) diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php index 6720e7f7d..79ecd025c 100644 --- a/lib/SimpleSAML/Session.php +++ b/lib/SimpleSAML/Session.php @@ -131,15 +131,22 @@ class SimpleSAML_Session { private $authToken; + /** + * Authentication data. + * + * This is an array with authentication data for the various authsources. + * + * @var array|NULL Associative array of associative arrays. + */ + private $authData; + + /** * private constructor restricts instantiaton to getInstance() */ private function __construct($transient = FALSE) { - - $configuration = SimpleSAML_Configuration::getInstance(); - $this->sessionduration = $configuration->getInteger('session.duration', 8*60*60); - + $this->authData = array(); if ($transient) { $this->trackid = 'XXXXXXXXXX'; @@ -156,11 +163,70 @@ class SimpleSAML_Session { } + /** + * Upgrade this session object to use the $authData property. + * + * TODO: Remove in version 1.8. + */ + private function upgradeAuthData() { + $this->authData = array(); + + if ($this->authority === NULL || !$this->authenticated) { + return; + } + + if ($this->authState !== NULL) { + $data = $this->authState; + } else { + $data = array(); + } + + if ($this->attributes !== NULL) { + $data['Attributes'] = $this->attributes; + } else { + $data['Attributes'] = array(); + } + + if ($this->idp !== NULL) { + $data['saml:sp:IdP'] = $this->idp; + } + + if ($this->sessionindex !== NULL) { + $data['saml:sp:SessionIndex'] = $this->sessionindex; + } + + if ($this->nameid !== NULL) { + $data['saml:sp:NameID'] = $this->nameid; + } + + $data['AuthnInstant'] = $this->sessionstarted; + $data['Expire'] = $this->sessionstarted + $this->sessionduration; + $this->sessionstarted = NULL; + $this->sessionduration = NULL; + + if ($this->logoutState !== NULL) { + $data['LogoutState'] = $this->logoutState; + } + + + if (!empty($this->logout_handlers)) { + $data['LogoutHandlers'] = $this->logout_handlers; + } + + $this->authData[$this->authority] = $data; + } + + /** * This function is called after this class has been deserialized. */ public function __wakeup() { $this->addShutdownFunction(); + + /* TODO: Remove for version 1.8. */ + if ($this->authData === NULL) { + $this->upgradeAuthData(); + } } @@ -303,10 +369,16 @@ class SimpleSAML_Session { */ public function setIdP($idp) { assert('is_string($idp) || is_null($idp)'); + assert('isset($this->authData[$this->authority])'); SimpleSAML_Logger::debug('Library - Session: Set IdP to : ' . $idp); $this->dirty = true; - $this->idp = $idp; + if ($idp !== NULL) { + $this->authData[$this->authority]['saml:sp:IdP'] = $idp; + } else { + unset($this->authData[$this->authority]['saml:sp:IdP']); + } + } @@ -316,7 +388,10 @@ class SimpleSAML_Session { * @return string|NULL Our current IdP, or NULL if we aren't authenticated with an IdP. */ public function getIdP() { - return $this->idp; + if (!isset($this->authData[$this->authority]['saml:sp:IdP'])) { + return NULL; + } + return $this->authData[$this->authority]['saml:sp:IdP']; } @@ -327,10 +402,15 @@ class SimpleSAML_Session { */ public function setSessionIndex($sessionindex) { assert('is_string($sessionindex) || is_null($sessionindex)'); + assert('isset($this->authData[$this->authority])'); SimpleSAML_Logger::debug('Library - Session: Set sessionindex: ' . $sessionindex); $this->dirty = true; - $this->sessionindex = $sessionindex; + if ($sessionindex !== NULL) { + $this->authData[$this->authority]['saml:sp:SessionIndex'] = $sessionindex; + } else { + unset($this->authData[$this->authority]['saml:sp:SessionIndex']); + } } @@ -340,7 +420,10 @@ class SimpleSAML_Session { * @return string|NULL Our SessionIndex. */ public function getSessionIndex() { - return $this->sessionindex; + if (!isset($this->authData[$this->authority]['saml:sp:SessionIndex'])) { + return NULL; + } + return $this->authData[$this->authority]['saml:sp:SessionIndex']; } @@ -351,10 +434,15 @@ class SimpleSAML_Session { */ public function setNameID($nameid) { assert('is_array($nameid) || is_null($nameid)'); + assert('isset($this->authData[$this->authority])'); SimpleSAML_Logger::debug('Library - Session: Set nameID: '); $this->dirty = true; - $this->nameid = $nameid; + if ($nameid !== NULL) { + $this->authData[$this->authority]['saml:sp:NameID'] = $nameid; + } else { + unset($this->authData[$this->authority]['saml:sp:NameID']); + } } @@ -364,7 +452,10 @@ class SimpleSAML_Session { * @return array|NULL The NameID we received from the IdP. */ public function getNameID() { - return $this->nameid; + if (!isset($this->authData[$this->authority]['saml:sp:NameID'])) { + return NULL; + } + return $this->authData[$this->authority]['saml:sp:NameID']; } @@ -374,25 +465,36 @@ class SimpleSAML_Session { * If the user already has logged in, the user will be logged out first. * * @param string $authority The authority the user logged in with. - * @param array|NULL $authState The persistent auth state for this authority. + * @param array|NULL $data The authentication data for this authority. */ - public function doLogin($authority, array $authState = NULL) { + public function doLogin($authority, array $data = NULL) { assert('is_string($authority)'); + assert('is_array($data) || is_null($data)'); SimpleSAML_Logger::debug('Session: doLogin("' . $authority . '")'); $this->dirty = TRUE; - if($this->authenticated) { + if (isset($this->authData[$authority])) { /* We are already logged in. Log the user out first. */ - $this->doLogout(); + $this->doLogout($authority); } - $this->authenticated = TRUE; - $this->authority = $authority; - $this->authState = $authState; - $this->sessionstarted = time(); + if ($data === NULL) { + $data = array(); + } + + if (!isset($data['AuthnInstant'])) { + $data['AuthnInstant'] = time(); + } + if (!isset($data['Expire'])) { + $globalConfig = SimpleSAML_Configuration::getInstance(); + $data['Expire'] = time() + $globalConfig->getInteger('session.duration', 8*60*60); + } + + $this->authData[$authority] = $data; + $this->authority = $authority; $this->authToken = SimpleSAML_Utilities::generateID(); $sessionHandler = SimpleSAML_SessionHandler::getSessionHandler(); @@ -404,21 +506,33 @@ class SimpleSAML_Session { * Marks the user as logged out. * * This function will call any registered logout handlers before marking the user as logged out. + * + * @param string|NULL $authority The authentication source we are logging out of. */ - public function doLogout() { + public function doLogout($authority = NULL) { - SimpleSAML_Logger::debug('Session: doLogout()'); + SimpleSAML_Logger::debug('Session: doLogout(' . var_export($authority, TRUE) . ')'); - $this->dirty = TRUE; + if ($authority === NULL) { + if ($this->authority === NULL) { + SimpleSAML_Logger::debug('Session: No current authsource - not logging out.'); + return; + } + $authority = $this->authority; + } - $this->callLogoutHandlers(); + if (!isset($this->authData[$authority])) { + SimpleSAML_Logger::debug('Session: Already logged out of ' . $authority . '.'); + return; + } + + $this->dirty = TRUE; - $this->authenticated = FALSE; - $this->authority = NULL; - $this->attributes = NULL; - $this->logoutState = NULL; - $this->authState = NULL; - $this->idp = NULL; + $this->callLogoutHandlers($authority); + unset($this->authData[$authority]); + if ($this->authority === $authority) { + $this->authority = NULL; + } /* Delete data which expires on logout. */ $this->expireDataLogout(); @@ -432,10 +546,13 @@ class SimpleSAML_Session { */ public function setSessionDuration($duration) { assert('is_int($duration)'); + assert('isset($this->authData[$this->authority])'); SimpleSAML_Logger::debug('Library - Session: Set session duration ' . $duration); $this->dirty = true; $this->sessionduration = $duration; + + $this->authData[$this->authority]['Expire'] = time() + $duration; } @@ -449,19 +566,19 @@ class SimpleSAML_Session { public function isValid($authority) { assert('is_string($authority)'); - SimpleSAML_Logger::debug('Library - Session: Check if session is valid.' . - ' checkauthority:' . $authority . - ' thisauthority:' . (isset($this->authority) ? $this->authority : 'null') . - ' isauthenticated:' . ($this->isAuthenticated() ? 'yes' : 'no') . - ' remainingtime:' . $this->remainingTime()); - - if (!$this->isAuthenticated()) return false; + if (!isset($this->authData[$authority])) { + SimpleSAML_Logger::debug('Session: '. var_export($authority, TRUE) .' not valid because we are not authenticated.'); + return FALSE; + } - if ($authority !== $this->authority) { + if ($this->authData[$authority]['Expire'] <= time()) { + SimpleSAML_Logger::debug('Session: ' . var_export($authority, TRUE) .' not valid because it is expired.'); return FALSE; } - return $this->remainingTime() > 0; + SimpleSAML_Logger::debug('Session: Valid session found with ' . var_export($authority, TRUE) . '.'); + + return TRUE; } @@ -471,7 +588,14 @@ class SimpleSAML_Session { * @return int The number of seconds until the session expires. */ public function remainingTime() { - return $this->sessionduration - (time() - $this->sessionstarted); + + if (!isset($this->authData[$this->authority])) { + /* Not authenticated. */ + return -1; + } + + assert('isset($this->authData[$this->authority]["Expire"])'); + return $this->authData[$this->authority]['Expire'] - time(); } /** @@ -480,7 +604,7 @@ class SimpleSAML_Session { * @return bool TRUE if the user is authenticated, FALSE otherwise. */ public function isAuthenticated() { - return $this->authenticated; + return isset($this->authData[$this->authority]); } @@ -490,11 +614,14 @@ class SimpleSAML_Session { * @return int|NULL The timestamp for when the user was authenticated. NULL if the user hasn't authenticated. */ public function getAuthnInstant() { - if (!$this->isAuthenticated()) { + + if (!isset($this->authData[$this->authority])) { + /* Not authenticated. */ return NULL; } - return $this->sessionstarted; + assert('isset($this->authData[$this->authority]["AuthnInstant"])'); + return $this->authData[$this->authority]['AuthnInstant']; } @@ -504,7 +631,10 @@ class SimpleSAML_Session { * @return array|NULL The attributes. */ public function getAttributes() { - return $this->attributes; + if (!isset($this->authData[$this->authority]['Attributes'])) { + return NULL; + } + return $this->authData[$this->authority]['Attributes']; } @@ -515,7 +645,10 @@ class SimpleSAML_Session { * @return array|NULL The values of the given attribute. */ public function getAttribute($name) { - return $this->attributes[$name]; + if (!isset($this->authData[$this->authority]['Attributes'][$name])) { + return NULL; + } + return $this->authData[$this->authority]['Attributes'][$name]; } @@ -525,8 +658,10 @@ class SimpleSAML_Session { * @param array|NULL $attributes The attributes of this session. */ public function setAttributes($attributes) { + assert('isset($this->authData[$this->authority])'); + $this->dirty = true; - $this->attributes = $attributes; + $this->authData[$this->authority]['Attributes'] = $attributes; } @@ -537,8 +672,10 @@ class SimpleSAML_Session { * @param array $value The values of the attribute. */ public function setAttribute($name, $value) { + assert('isset($this->authData[$this->authority])'); + $this->dirty = true; - $this->attributes[$name] = $value; + $this->authData[$this->authority]['Attributes'][$name] = $value; } @@ -560,6 +697,7 @@ class SimpleSAML_Session { * @param $functionname The logout handler function. */ public function registerLogoutHandler($classname, $functionname) { + assert('isset($this->authData[$this->authority])'); $logout_handler = array($classname, $functionname); @@ -569,16 +707,24 @@ class SimpleSAML_Session { } - $this->logout_handlers[] = $logout_handler; + $this->authData[$this->authority]['LogoutHandlers'][] = $logout_handler; $this->dirty = TRUE; } /** * This function calls all registered logout handlers. + * + * @param string $authority The authentication source we are logging out from. */ - private function callLogoutHandlers() { - foreach($this->logout_handlers as $handler) { + private function callLogoutHandlers($authority) { + assert('is_string($authority)'); + assert('isset($this->authData[$authority])'); + + if (empty($this->authData[$authority]['LogoutHandlers'])) { + return; + } + foreach($this->authData[$authority]['LogoutHandlers'] as $handler) { /* Verify that the logout handler is a valid function. */ if(!is_callable($handler)) { @@ -595,7 +741,7 @@ class SimpleSAML_Session { } /* We require the logout handlers to register themselves again if they want to be called later. */ - $this->logout_handlers = array(); + unset($this->authData[$authority]['LogoutHandlers']); } @@ -905,9 +1051,10 @@ class SimpleSAML_Session { * @param array $state The state array. */ public function setLogoutState(array $state) { + assert('isset($this->authData[$this->authority])'); $this->dirty = TRUE; - $this->logoutState = $state; + $this->authData[$this->authority]['LogoutState'] = $state; } @@ -917,31 +1064,34 @@ class SimpleSAML_Session { * @return array The logout state. If no logout state is set, an empty array will be returned. */ public function getLogoutState() { + assert('isset($this->authData[$this->authority])'); - if ($this->logoutState === NULL) { + if (!isset($this->authData[$this->authority]['LogoutState'])) { return array(); } - return $this->logoutState; + return $this->authData[$this->authority]['LogoutState']; } /** * Get the current persistent authentication state. * + * @param string|NULL $authority The authority to retrieve the data from. * @return array The current persistent authentication state, or NULL if not authenticated. */ - public function getAuthState() { - if (!$this->isAuthenticated()) { - return NULL; + public function getAuthState($authority = NULL) { + assert('is_string($authority) || is_null($authority)'); + + if ($authority === NULL) { + $authority = $this->authority; } - if (!isset($this->authState)) { - /* No AuthState for this login handler. */ - return array(); + if (!isset($this->authData[$authority])) { + return NULL; } - return $this->authState; + return $this->authData[$authority]; } @@ -1086,4 +1236,22 @@ class SimpleSAML_Session { return $ret; } + + /** + * Retrieve authentication data. + * + * @param string $authority The authentication source we should retrieve data from. + * @param string $name The name of the data we should retrieve. + * @return mixed The value, or NULL if the value wasn't found. + */ + public function getAuthData($authority, $name) { + assert('is_string($authority)'); + assert('is_string($name)'); + + if (!isset($this->authData[$authority][$name])) { + return NULL; + } + return $this->authData[$authority][$name]; + } + } -- GitLab