diff --git a/config-templates/config.php b/config-templates/config.php index 2379369c16ed98871534f3cd48d8c434f4055aad..4a286d3fd731b1e97fab74885f61a78be8fb1fb7 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -290,6 +290,14 @@ $config = array ( */ 'session.authtoken.cookiename' => 'SimpleSAMLAuthToken', + /** + * Custom function for session checking called on session init and loading. + * See docs/simplesamlphp-advancedfeatures.txt for function code example. + * + * Example: + * 'session.check_function' => array('sspmod_example_Util', 'checkSession'), + */ + /* * Languages available, RTL languages, and what language is default */ diff --git a/docs/simplesamlphp-advancedfeatures.txt b/docs/simplesamlphp-advancedfeatures.txt index e5bac450c7d16e623207f3bbda1b1466338263cc..c1af38f4f614c798a10ffe427102ab31629aee45 100644 --- a/docs/simplesamlphp-advancedfeatures.txt +++ b/docs/simplesamlphp-advancedfeatures.txt @@ -171,6 +171,56 @@ There is also an additional fallback for the private key and the certificate. If +Session checking function +------------------------- + +Optional session checking function, called on session init and loading, defined with 'session.check_function' in config.php. + +Example code for the function with GeoIP country check: + + + public static function checkSession($session, $init = FALSE) { + $data_type = 'example:check_session'; + $data_key = 'remote_addr'; + + $remote_addr = NULL; + if (!empty($_SERVER['REMOTE_ADDR'])) { + $remote_addr = (string)$_SERVER['REMOTE_ADDR']; + } + + if ($init) { + $session->setData($data_type, $data_key, $remote_addr); + return; + } + + if (!function_exists('geoip_country_code_by_name')) { + SimpleSAML_Logger::warning('geoip php module required.'); + return TRUE; + } + + $stored_remote_addr = $session->getData($data_type, $data_key); + if ($stored_remote_addr === NULL) { + SimpleSAML_Logger::warning('Stored data not found.'); + return FALSE; + } + + $country_a = geoip_country_code_by_name($remote_addr); + $country_b = geoip_country_code_by_name($stored_remote_addr); + + if ($country_a === $country_b) { + if ($stored_remote_addr !== $remote_addr) { + $session->setData($data_type, $data_key, $remote_addr); + } + + return TRUE; + } + + return FALSE; + } + + + + Support ------- diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php index d586e5104bea037e2cad277add1afc70b3a4e929..e373dc4f4350563e2dd1abb8b108392db3c77193 100644 --- a/lib/SimpleSAML/Session.php +++ b/lib/SimpleSAML/Session.php @@ -169,6 +169,14 @@ class SimpleSAML_Session { $this->dirty = TRUE; $this->addShutdownFunction(); + + /* Initialize data for session check function if defined */ + $globalConfig = SimpleSAML_Configuration::getInstance(); + $checkFunction = $globalConfig->getArray('session.check_function', NULL); + if (isset($checkFunction)) { + assert('is_callable($checkFunction)'); + call_user_func($checkFunction, $this, TRUE); + } } @@ -1030,16 +1038,30 @@ class SimpleSAML_Session { $session->sessionId = $sh->getCookieSessionId(); } - if ($checkToken && $session->authToken !== NULL) { + if ($checkToken) { $globalConfig = SimpleSAML_Configuration::getInstance(); - $authTokenCookieName = $globalConfig->getString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'); - if (!isset($_COOKIE[$authTokenCookieName])) { - SimpleSAML_Logger::warning('Missing AuthToken cookie.'); - return NULL; + + if ($session->authToken !== NULL) { + $authTokenCookieName = $globalConfig->getString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'); + if (!isset($_COOKIE[$authTokenCookieName])) { + SimpleSAML_Logger::warning('Missing AuthToken cookie.'); + return NULL; + } + if ($_COOKIE[$authTokenCookieName] !== $session->authToken) { + SimpleSAML_Logger::warning('Invalid AuthToken cookie.'); + return NULL; + } } - if ($_COOKIE[$authTokenCookieName] !== $session->authToken) { - SimpleSAML_Logger::warning('Invalid AuthToken cookie.'); - return NULL; + + /* Run session check function if defined */ + $checkFunction = $globalConfig->getArray('session.check_function', NULL); + if (isset($checkFunction)) { + assert('is_callable($checkFunction)'); + $check = call_user_func($checkFunction, $session); + if ($check !== TRUE) { + SimpleSAML_Logger::warning('Session did not pass check function.'); + return NULL; + } } }