/** * This function performs some sanity checks on XML documents, and optionally validates them against their schema * if the 'debug.validatexml' option is enabled. A warning will be printed to the log if validation fails. * * @param string $message The SAML document we want to check. * @param string $type The type of document. Can be one of: * - 'saml20' * - 'saml11' * - 'saml-meta' * * @throws \InvalidArgumentException If $message is not a string or $type is not a string containing one of the * values allowed. * @throws \SimpleSAML_Error_Exception If $message contains a doctype declaration. * * @author Olav Morken, UNINETT AS <*****@*****.**> * @author Jaime Perez, UNINETT AS <*****@*****.**> */ public static function checkSAMLMessage($message, $type) { $allowed_types = array('saml20', 'saml11', 'saml-meta'); if (!(is_string($message) && in_array($type, $allowed_types))) { throw new \InvalidArgumentException('Invalid input parameters.'); } // a SAML message should not contain a doctype-declaration if (strpos($message, '<!DOCTYPE') !== false) { throw new \SimpleSAML_Error_Exception('XML contained a doctype declaration.'); } $enabled = \SimpleSAML_Configuration::getInstance()->getBoolean('debug.validatexml', null); if (!$enabled) { return; } $result = true; switch ($type) { case 'saml11': $result = self::isValid($message, 'oasis-sstc-saml-schema-protocol-1.1.xsd'); break; case 'saml20': $result = self::isValid($message, 'saml-schema-protocol-2.0.xsd'); break; case 'saml-meta': $result = self::isValid($message, 'saml-schema-metadata-2.0.xsd'); } if ($result !== true) { \SimpleSAML_Logger::warning($result); } }
/** * Process a authentication response. * * This function checks how long it is since the last time the user was authenticated. * If it is to short a while since, we will show a warning to the user. * * @param array $state The state of the response. */ public function process(&$state) { assert('is_array($state)'); if (!array_key_exists('PreviousSSOTimestamp', $state)) { /* * No timestamp from the previous SSO to this SP. This is the first * time during this session. */ return; } $timeDelta = time() - $state['PreviousSSOTimestamp']; if ($timeDelta >= 10) { /* At least 10 seconds since last attempt. */ return; } if (array_key_exists('Destination', $state) && array_key_exists('entityid', $state['Destination'])) { $entityId = $state['Destination']['entityid']; } else { $entityId = 'UNKNOWN'; } SimpleSAML_Logger::warning('WarnShortSSOInterval: Only ' . $timeDelta . ' seconds since last SSO for this user from the SP ' . var_export($entityId, TRUE)); /* Save state and redirect. */ $id = SimpleSAML_Auth_State::saveState($state, 'core:short_sso_interval'); $url = SimpleSAML_Module::getModuleURL('core/short_sso_interval.php'); SimpleSAML_Utilities::redirectTrustedURL($url, array('StateId' => $id)); }
/** * Process an authentication response. * * This function saves the state, and if necessary redirects the user to the page where the user * is informed about the expiry date of his/her certificate. * * @param array $state The state of the response. */ public function process(&$state) { assert('is_array($state)'); if (isset($state['isPassive']) && $state['isPassive'] === TRUE) { /* We have a passive request. Skip the warning. */ return; } if (!isset($_SERVER['SSL_CLIENT_CERT']) || $_SERVER['SSL_CLIENT_CERT'] == '') { return; } $client_cert = $_SERVER['SSL_CLIENT_CERT']; $client_cert_data = openssl_x509_parse($client_cert); if ($client_cert_data == FALSE) { SimpleSAML_Logger::error('authX509: invalid cert'); return; } $validTo = $client_cert_data['validTo_time_t']; $now = time(); $daysleft = (int) (($validTo - $now) / (24 * 60 * 60)); if ($daysleft > $this->warndaysbefore) { /* We have a certificate that will be valid for some time. Skip the warning. */ return; } SimpleSAML_Logger::warning('authX509: user certificate expires in ' . $daysleft . ' days'); $state['daysleft'] = $daysleft; $state['renewurl'] = $this->renewurl; /* Save state and redirect. */ $id = SimpleSAML_Auth_State::saveState($state, 'warning:expire'); $url = SimpleSAML_Module::getModuleURL('authX509/expirywarning.php'); \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id)); }
/** * Get the NameID value. * * @return string|NULL The NameID value. */ protected function getValue(array &$state) { if (!isset($state['Destination']['entityid'])) { SimpleSAML_Logger::warning('No SP entity ID - not generating persistent NameID.'); return NULL; } $spEntityId = $state['Destination']['entityid']; if (!isset($state['Source']['entityid'])) { SimpleSAML_Logger::warning('No IdP entity ID - not generating persistent NameID.'); return NULL; } $idpEntityId = $state['Source']['entityid']; if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) { SimpleSAML_Logger::warning('Missing attribute ' . var_export($this->attribute, TRUE) . ' on user - not generating persistent NameID.'); return NULL; } if (count($state['Attributes'][$this->attribute]) > 1) { SimpleSAML_Logger::warning('More than one value in attribute ' . var_export($this->attribute, TRUE) . ' on user - not generating persistent NameID.'); return NULL; } $uid = array_values($state['Attributes'][$this->attribute]); /* Just in case the first index is no longer 0. */ $uid = $uid[0]; $secretSalt = SimpleSAML_Utilities::getSecretSalt(); $uidData = 'uidhashbase' . $secretSalt; $uidData .= strlen($idpEntityId) . ':' . $idpEntityId; $uidData .= strlen($spEntityId) . ':' . $spEntityId; $uidData .= strlen($uid) . ':' . $uid; $uidData .= $secretSalt; return sha1($uidData); }
/** * This function generates a binary string containing random bytes. * * It will use /dev/urandom if available, and fall back to the builtin mt_rand()-function if not. * * @param $length The number of random bytes to return. * @return A string of lenght $length with random bytes. */ public static function generateRandomBytes($length, $fallback = TRUE) { static $fp = NULL; assert('is_int($length)'); if ($fp === NULL) { if (file_exists('/dev/urandom')) { $fp = fopen('/dev/urandom', 'rb'); } else { $fp = FALSE; } } if ($fp !== FALSE) { /* Read random bytes from /dev/urandom. */ $data = fread($fp, $length); if ($data === FALSE) { throw new Exception('Error reading random data.'); } if (strlen($data) != $length) { SimpleSAML_Logger::warning('Did not get requested number of bytes from random source. Requested (' . $length . ') got (' . strlen($data) . ')'); if ($fallback) { $data = self::generateRandomBytesMTrand($length); } else { throw new Exception('Did not get requested number of bytes from random source. Requested (' . $length . ') got (' . strlen($data) . ')'); } } } else { /* Use mt_rand to generate $length random bytes. */ $data = self::generateRandomBytesMTrand($length); } return $data; }
/** * Apply this filter. * * @param array &$request The current request */ public function process(&$request) { assert('is_array($request)'); assert('array_key_exists("Attributes", $request)'); $attributes =& $request['Attributes']; if (!isset($attributes[$this->sourceAttribute])) { return; } // will not overwrite existing attribute if (isset($attributes[$this->targetAttribute])) { return; } $sourceAttrVal = $attributes[$this->sourceAttribute][0]; /* the last position of an @ is usually the beginning of the scope * string */ $scopeIndex = strrpos($sourceAttrVal, '@'); if ($scopeIndex !== FALSE) { $attributes[$this->targetAttribute] = array(); $scope = substr($sourceAttrVal, $scopeIndex + 1); $attributes[$this->targetAttribute][] = $scope; SimpleSAML_Logger::debug('ScopeFromAttribute: Inserted new attribute ' . $this->targetAttribute . ', with scope ' . $scope); } else { SimpleSAML_Logger::warning('ScopeFromAttribute: The configured source attribute ' . $this->sourceAttribute . ' does not have a scope. Did not add attribute ' . $this->targetAttribute . '.'); } }
/** * Autoload function for SimpleSAMLphp modules following PSR-0. * * @param string $className Name of the class. * @deprecated This method will be removed in SSP 2.0. * * TODO: this autoloader should be removed once everything has been migrated to namespaces. */ public static function autoloadPSR0($className) { $modulePrefixLength = strlen('sspmod_'); $classPrefix = substr($className, 0, $modulePrefixLength); if ($classPrefix !== 'sspmod_') { return; } $modNameEnd = strpos($className, '_', $modulePrefixLength); $module = substr($className, $modulePrefixLength, $modNameEnd - $modulePrefixLength); $path = explode('_', substr($className, $modNameEnd + 1)); if (!self::isModuleEnabled($module)) { return; } $file = self::getModuleDir($module) . '/lib/' . join('/', $path) . '.php'; if (!file_exists($file)) { return; } require_once $file; if (!class_exists($className, false)) { // the file exists, but the class is not defined. Is it using namespaces? $nspath = join('\\', $path); if (class_exists('SimpleSAML\\Module\\' . $module . '\\' . $nspath)) { // the class has been migrated, create an alias and warn about it \SimpleSAML_Logger::warning("The class '{$className}' is now using namespaces, please use 'SimpleSAML\\Module\\{$module}\\" . "{$nspath}' instead."); class_alias("SimpleSAML\\Module\\{$module}\\{$nspath}", $className); } } }
protected function login($username, $password) { /* Connect to the database. */ $dsn = 'mysql:host=' . $_ENV["DB_HOST"] . ';dbname=twofactor'; $username = $_ENV["DB_USER"]; $password = $_ENV["DB_PASS"]; $db = new PDO($dsn, $username, $password); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); /* Ensure that we are operating with UTF-8 encoding. * This command is for MySQL. Other databases may need different commands. */ $db->exec("SET NAMES 'utf8'"); /* With PDO we use prepared statements. This saves us from having to escape * the username in the database query. */ $st = $db->prepare('SELECT username, password_hash, full_name FROM userdb WHERE username=:username'); if (!$st->execute(array('username' => $username))) { throw new Exception('Failed to query database for user.'); } /* Retrieve the row from the database. */ $row = $st->fetch(PDO::FETCH_ASSOC); if (!$row) { /* User not found. */ SimpleSAML_Logger::warning('MyAuth: Could not find user ' . var_export($username, TRUE) . '.'); throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } /* Check the password. */ if (!$this->checkPassword($row['password_hash'], $password)) { /* Invalid password. */ SimpleSAML_Logger::warning('MyAuth: Wrong password for user ' . var_export($username, TRUE) . '.'); throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } /* Create the attribute array of the user. */ $attributes = array('uid' => array($username), 'urn:dk:ddl:borger:displayName' => array($row['full_name']), 'urn:dk:gov:saml:cprNumberIdentifier' => array('0102031AB2')); }
/** * Hook to run a cron job. * * @param array &$croninfo Output */ function statistics_hook_cron(&$croninfo) { assert('is_array($croninfo)'); assert('array_key_exists("summary", $croninfo)'); assert('array_key_exists("tag", $croninfo)'); $statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php'); if (is_null($statconfig->getValue('cron_tag', NULL))) { return; } if ($statconfig->getValue('cron_tag', NULL) !== $croninfo['tag']) { return; } $maxtime = $statconfig->getInteger('time_limit', NULL); if ($maxtime) { set_time_limit($maxtime); } try { $aggregator = new sspmod_statistics_Aggregator(); $results = $aggregator->aggregate(); if (empty($results)) { SimpleSAML_Logger::notice('Output from statistics aggregator was empty.'); } else { $aggregator->store($results); } } catch (Exception $e) { $message = 'Loganalyzer threw exception: ' . $e->getMessage(); SimpleSAML_Logger::warning($message); $croninfo['summary'][] = $message; } }
/** * This function retrieves the logout info with the given ID. * * @param $id The identifier of the logout info. */ function fetchLogoutInfo($id) { global $session; global $logoutInfo; $logoutInfo = $session->getData('idplogoutresponsedata', $id); if ($logoutInfo === NULL) { SimpleSAML_Logger::warning('SAML2.0 - IdP.SingleLogoutService: Lost logout information.'); } }
/** * Apply filter to add or replace attributes. * * Add or replace existing attributes with the configured values. * * @param array &$request The current request */ public function process(&$request) { assert('is_array($request)'); assert('array_key_exists("Attributes", $request)'); SimpleSAML_Logger::warning('You are using the deprecated smartnameattribute:SmartName filter. You should replace it with smartattributes:SmartName instead.'); $attributes =& $request['Attributes']; $fullname = $this->getFullName($attributes); if (isset($fullname)) { $request['Attributes']['smartname-fullname'] = array($fullname); } }
/** * Redirect to page setting CDC. * * @param array &$state The request state. */ public function process(&$state) { assert('is_array($state)'); if (!isset($state['Source']['entityid'])) { SimpleSAML_Logger::warning('saml:CDC: Could not find IdP entityID.'); return; } /* Save state and build request. */ $id = SimpleSAML_Auth_State::saveState($state, 'cdc:resume'); $returnTo = SimpleSAML_Module::getModuleURL('cdc/resume.php', array('domain' => $this->domain)); $params = array('id' => $id, 'entityID' => $state['Source']['entityid']); $this->client->sendRequest($returnTo, 'append', $params); }
/** * Get the NameID value. * * @return string|NULL The NameID value. */ protected function getValue(array &$state) { if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) { SimpleSAML_Logger::warning('Missing attribute ' . var_export($this->attribute, TRUE) . ' on user - not generating attribute NameID.'); return NULL; } if (count($state['Attributes'][$this->attribute]) > 1) { SimpleSAML_Logger::warning('More than one value in attribute ' . var_export($this->attribute, TRUE) . ' on user - not generating attribute NameID.'); } $value = array_values($state['Attributes'][$this->attribute]); /* Just in case the first index is no longer 0. */ $value = $value[0]; return $value; }
/** * This function is used to find an existing storage object. It will return NULL if no storage object * with the given id is found. * * @param $id The id of the storage object we are looking for. A id consists of lowercase * alphanumeric characters. * @return The corresponding MemcacheStorage object if the data is found or NULL if it isn't found. */ public static function find($id) { assert(self::isValidID($id)); $serializedData = SimpleSAML_Memcache::get($id); if ($serializedData === NULL) { return NULL; } $data = unserialize($serializedData); if (!$data instanceof self) { SimpleSAML_Logger::warning('Retrieved key from memcache did not contain a MemcacheStore object.'); return NULL; } return $data; }
/** * Initialize this filter, parse configuration * * @param array $config Configuration information about this filter. * @param mixed $reserved For future use. */ public function __construct($config, $reserved) { parent::__construct($config, $reserved); assert('is_array($config)'); if (isset($config['function'])) { $this->function = $config['function']; } else { // TODO: remove this branch after removing the 'code' option. if (!isset($config['code'])) { throw new SimpleSAML_Error_Exception("core:PHP: Neither 'function' nor 'code' options defined."); } SimpleSAML_Logger::warning("Deprecated 'code' configuration option in PHP authentication processing filter."); $this->code = (string) $config['code']; } }
/** * Attempt to log in using the given username and password. * * @param string $username The username the user wrote. * @param string $password The password the user wrote. * @param string $org The organization the user chose. * @return array Associative array with the users attributes. */ protected function login($username, $password, $org, array $sasl_args = NULL) { assert('is_string($username)'); assert('is_string($password)'); assert('is_string($org)'); if (!array_key_exists($org, $this->ldapOrgs)) { // The user has selected an organization which doesn't exist anymore. SimpleSAML_Logger::warning('Authentication source ' . var_export($this->authId, TRUE) . ': Organization seems to have disappeared while the user logged in.' . ' Organization was ' . var_export($org, TRUE)); throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } if ($this->includeOrgInUsername) { $username = $username . '@' . $org; } return $this->ldapOrgs[$org]->login($username, $password, $sasl_args); }
/** * This temporary autoloader allows loading classes with their old-style names (SimpleSAML_Path_Something) even if they * have been migrated to namespaces, by registering an alias for the new class. If the class has not yet been migrated, * the autoloader will then try to load it. * * @param string $class The full name of the class using underscores to separate the elements of the path, and starting * with 'SimpleSAML_'. * @deprecated This function will be removed in SSP 2.0. */ function temporaryLoader($class) { if (!strstr($class, 'SimpleSAML_')) { return; // not a valid class name for old classes } $path = explode('_', $class); $new = join('\\', $path); if (class_exists($new, false)) { SimpleSAML_Logger::warning("The class '{$class}' is now using namespaces, please use '{$new}'."); class_alias($new, $class); } $file = dirname(__FILE__) . DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, $path) . '.php'; if (file_exists($file)) { require_once $file; } }
/** * Continue the logout operation. * * This function will never return. * * @param string $assocId The association that is terminated. * @param string|null $relayState The RelayState from the start of the logout. * @param SimpleSAML_Error_Exception|null $error The error that occurred during session termination (if any). * * @throws SimpleSAML_Error_Exception If the RelayState was lost during logout. */ public function onResponse($assocId, $relayState, SimpleSAML_Error_Exception $error = null) { assert('is_string($assocId)'); assert('is_string($relayState) || is_null($relayState)'); if ($relayState === null) { throw new SimpleSAML_Error_Exception('RelayState lost during logout.'); } $state = SimpleSAML_Auth_State::loadState($relayState, 'core:LogoutTraditional'); if ($error === null) { SimpleSAML_Logger::info('Logged out of ' . var_export($assocId, true) . '.'); $this->idp->terminateAssociation($assocId); } else { SimpleSAML_Logger::warning('Error received from ' . var_export($assocId, true) . ' during logout:'); $error->logWarning(); $state['core:Failed'] = true; } self::logoutNextSP($state); }
/** * Store a NameID to attribute. * * @param array &$state The request state. */ public function process(&$state) { assert('is_array($state)'); if (!isset($state['saml:NameID'][SAML2_Const::NAMEID_PERSISTENT])) { SimpleSAML_Logger::warning('Unable to generate eduPersonTargetedID because no persistent NameID was available.'); return; } $nameID = $state['saml:NameID'][SAML2_Const::NAMEID_PERSISTENT]; if ($this->nameId) { $doc = new DOMDocument(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $nameID); $value = $doc->saveXML($root->firstChild); } else { $value = $nameID['Value']; } $state['Attributes'][$this->attribute] = array($value); }
/** * Get the NameID value. * * @return string|NULL The NameID value. */ protected function getValue(array &$state) { if (!isset($state['Destination']['entityid'])) { SimpleSAML_Logger::warning('No SP entity ID - not generating persistent NameID.'); return; } $spEntityId = $state['Destination']['entityid']; if (!isset($state['Source']['entityid'])) { SimpleSAML_Logger::warning('No IdP entity ID - not generating persistent NameID.'); return; } $idpEntityId = $state['Source']['entityid']; if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) { SimpleSAML_Logger::warning('Missing attribute ' . var_export($this->attribute, true) . ' on user - not generating persistent NameID.'); return; } if (count($state['Attributes'][$this->attribute]) > 1) { SimpleSAML_Logger::warning('More than one value in attribute ' . var_export($this->attribute, true) . ' on user - not generating persistent NameID.'); return; } $uid = array_values($state['Attributes'][$this->attribute]); /* Just in case the first index is no longer 0. */ $uid = $uid[0]; $secretSalt = SimpleSAML_Utilities::getSecretSalt(); $uidData = $spEntityId . '!' . $uid . '!' . $secretSalt; $uid = base64_encode(hash('sha1', $uidData, true)); // Convert the targeted ID to a SAML 2.0 name identifier element. $nameId = array('Format' => SAML2_Const::NAMEID_PERSISTENT, 'Value' => $uid); if (isset($state['Source']['entityid'])) { $nameId['NameQualifier'] = $state['Source']['entityid']; } if (isset($state['Destination']['entityid'])) { $nameId['SPNameQualifier'] = $state['Destination']['entityid']; } $doc = new DOMDocument(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $nameId); $uid = $doc->saveXML($root->firstChild); $state['Attributes']['eduPersonTargetedID'] = array($uid); }
/** * Get the NameID value. * * @return string|NULL The NameID value. */ protected function getValue(array &$state) { if (!isset($state['saml:NameIDFormat']) || $state['saml:NameIDFormat'] !== $this->format) { SimpleSAML_Logger::debug('SQLPersistentNameID: Request did not specify persistent NameID format - not generating persistent NameID.'); return NULL; } if (!isset($state['Destination']['entityid'])) { SimpleSAML_Logger::warning('SQLPersistentNameID: No SP entity ID - not generating persistent NameID.'); return NULL; } $spEntityId = $state['Destination']['entityid']; if (!isset($state['Source']['entityid'])) { SimpleSAML_Logger::warning('SQLPersistentNameID: No IdP entity ID - not generating persistent NameID.'); return NULL; } $idpEntityId = $state['Source']['entityid']; if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) { SimpleSAML_Logger::warning('SQLPersistentNameID: Missing attribute ' . var_export($this->attribute, TRUE) . ' on user - not generating persistent NameID.'); return NULL; } if (count($state['Attributes'][$this->attribute]) > 1) { SimpleSAML_Logger::warning('SQLPersistentNameID: More than one value in attribute ' . var_export($this->attribute, TRUE) . ' on user - not generating persistent NameID.'); return NULL; } $uid = array_values($state['Attributes'][$this->attribute]); /* Just in case the first index is no longer 0. */ $uid = $uid[0]; $value = sspmod_saml_IdP_SQLNameID::get($idpEntityId, $spEntityId, $uid); if ($value !== NULL) { SimpleSAML_Logger::debug('SQLPersistentNameID: Found persistent NameID ' . var_export($value, TRUE) . ' for user ' . var_export($uid, TRUE) . '.'); return $value; } if (!isset($state['saml:AllowCreate']) || !$state['saml:AllowCreate']) { SimpleSAML_Logger::warning('SQLPersistentNameID: Did not find persistent NameID for user, and not allowed to create new NameID.'); throw new sspmod_saml_Error(SAML2_Const::STATUS_RESPONDER, 'urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy'); } $value = SimpleSAML_Utilities::stringToHex(SimpleSAML_Utilities::generateRandomBytes(20)); SimpleSAML_Logger::debug('SQLPersistentNameID: Created persistent NameID ' . var_export($value, TRUE) . ' for user ' . var_export($uid, TRUE) . '.'); sspmod_saml_IdP_SQLNameID::add($idpEntityId, $spEntityId, $uid, $value); return $value; }
/** * Hook to run a cron job. * * @param array &$croninfo Output */ function riak_hook_cron(&$croninfo) { assert('is_array($croninfo)'); assert('array_key_exists("summary", $croninfo)'); assert('array_key_exists("tag", $croninfo)'); if ($croninfo['tag'] !== 'hourly') { return; } try { $store = new sspmod_riak_Store_Store(); $result = $store->bucket->indexSearch('expires', 'int', 1, time() - 30); foreach ($result as $link) { $link->getBinary()->delete(); } SimpleSAML_Logger::info(sprintf("deleted %s riak key%s", sizeof($result), sizeof($result) == 1 ? '' : 's')); } catch (Exception $e) { $message = 'riak threw exception: ' . $e->getMessage(); SimpleSAML_Logger::warning($message); $croninfo['summary'][] = $message; } }
/** * Helper function for handling exception/errors. * * This function will send an error response to the SP which contacted this IdP. * * @param Exception $exception The exception. */ function handleError(Exception $exception) { global $requestcache, $config, $metadata, $idpentityid; assert('is_array($requestcache)'); assert('array_key_exists("Issuer", $requestcache)'); $issuer = $requestcache['Issuer']; if (array_key_exists('RequestID', $requestcache)) { $requestID = $requestcache['RequestID']; } else { $requestID = NULL; } if (array_key_exists('RelayState', $requestcache)) { $relayState = $requestcache['RelayState']; } else { $relayState = NULL; } $error = sspmod_saml2_Error::fromException($exception); SimpleSAML_Logger::warning('Returning error to sp: ' . var_export($issuer, TRUE)); $error->logWarning(); try { $idpMetadata = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted'); $spMetadata = $metadata->getMetaDataConfig($issuer, 'saml20-sp-remote'); if (array_key_exists('ConsumerURL', $requestcache)) { $consumerURL = $requestcache['ConsumerURL']; } else { $urlArray = $spMetadata->getArrayizeString('AssertionConsumerService'); $consumerURL = $urlArray[0]; } $ar = sspmod_saml2_Message::buildResponse($idpMetadata, $spMetadata, $consumerURL); $ar->setInResponseTo($requestID); $ar->setRelayState($relayState); $ar->setStatus(array('Code' => $error->getStatus(), 'SubCode' => $error->getSubStatus(), 'Message' => $error->getStatusMessage())); $binding = new SAML2_HTTPPost(); $binding->setDestination(sspmod_SAML2_Message::getDebugDestination()); $binding->send($ar); } catch (Exception $e) { SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $e); } }
public static function redirectUri($url) { /* Set the HTTP result code. This is either 303 See Other or * 302 Found. HTTP 303 See Other is sent if the HTTP version * is HTTP/1.1 and the request type was a POST request. */ if ($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1' && $_SERVER['REQUEST_METHOD'] === 'POST') { $code = 303; } else { $code = 302; } if (strlen($url) > 2048) { SimpleSAML_Logger::warning('Redirecting to a URL longer than 2048 bytes.'); } /* Set the location header. */ header('Location: ' . $url, true, $code); /* Disable caching of this response. */ header('Pragma: no-cache'); header('Cache-Control: no-cache, must-revalidate'); /* Show a minimal web page with a clickable link to the URL. */ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n"; echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n"; echo '<html xmlns="http://www.w3.org/1999/xhtml">'; echo '<head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>Redirect</title> </head>'; echo '<body>'; echo '<h1>Redirect</h1>'; echo '<p>'; echo 'You were redirected to: '; echo '<a id="redirlink" href="' . htmlspecialchars($url) . '">' . htmlspecialchars($url) . '</a>'; echo '<script type="text/javascript">document.getElementById("redirlink").focus();</script>'; echo '</p>'; echo '</body>'; echo '</html>'; /* End script execution. */ exit; }
/** * Hook to run a cron job. * * @param array &$croninfo Output */ function oauth_hook_cron(&$croninfo) { assert('is_array($croninfo)'); assert('array_key_exists("summary", $croninfo)'); assert('array_key_exists("tag", $croninfo)'); $oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_statistics.php'); if (is_null($oauthconfig->getValue('cron_tag', 'hourly'))) { return; } if ($oauthconfig->getValue('cron_tag', NULL) !== $croninfo['tag']) { return; } try { $store = new sspmod_core_Storage_SQLPermanentStorage('oauth'); $cleaned = $store->removeExpired(); # if ($cleaned > 0) $croninfo['summary'][] = 'OAuth clean up. Removed ' . $cleaned . ' expired entries from OAuth storage.'; } catch (Exception $e) { $message = 'OAuth clean up cron script failed: ' . $e->getMessage(); SimpleSAML_Logger::warning($message); $croninfo['summary'][] = $message; } }
/** * Continue the logout operation. * * This function will never return. * * @param string $assocId The association that is terminated. * @param string|NULL $relayState The RelayState from the start of the logout. * @param SimpleSAML_Error_Exception|NULL $error The error that occurred during session termination (if any). */ public function onResponse($assocId, $relayState, SimpleSAML_Error_Exception $error = NULL) { assert('is_string($assocId)'); assert('is_string($relayState) || is_null($relayState)'); if ($relayState === NULL) { throw new SimpleSAML_Error_Exception('RelayState lost during logout.'); } // sanitize the input $sid = SimpleSAML_Utilities::parseStateID($relayState); if (!is_null($sid['url'])) { SimpleSAML_Utilities::checkURLAllowed($sid['url']); } $state = SimpleSAML_Auth_State::loadState($relayState, 'core:LogoutTraditional'); if ($error === NULL) { SimpleSAML_Logger::info('Logged out of ' . var_export($assocId, TRUE) . '.'); $this->idp->terminateAssociation($assocId); } else { SimpleSAML_Logger::warning('Error received from ' . var_export($assocId, TRUE) . ' during logout:'); $error->logWarning(); $state['core:Failed'] = TRUE; } self::logoutNextSP($state); }
/** * Initialize this filter, parse configuration. * * @param array $config Configuration information about this filter. * @param mixed $reserved For future use. * @throws SimpleSAML_Error_Exception */ public function __construct($config, $reserved) { parent::__construct($config, $reserved); assert('is_array($config)'); foreach ($config as $origName => $newName) { if (is_int($origName)) { switch ($newName) { case '%replace': $this->replace = true; break; case '%ignore': $this->ignore = true; break; case '%skipsource': case '%sourceskip': array_push($this->skip, 'Source'); break; case '%skipdest': case '%destskip': array_push($this->skip, 'Destination'); break; default: /* might want to make this handle loadable maps, a`la core:AttributeMap */ } } elseif (is_string($origName)) { $this->map[$origName] = $newName; } else { throw new SimpleSAML_Error_Exception('AttributeFromEntity: invalid config object, cannot create map'); } } if ($this->replace and $this->ignore) { SimpleSAML_Logger::warning('AttributeFromEntity: %replace and %ignore are mutually exclusive, behaving as though only %replace was given.'); } if (count($this->map) === 0) { throw new SimpleSAML_Error_Exception('AttributeFromEntity: attribute map is empty. Config error?'); } }
/** * Constructor for SAML 2.0 SP authentication source. * * @param array $info Information about this authentication source. * @param array $config Configuration. */ public function __construct($info, $config) { assert('is_array($info)'); assert('is_array($config)'); /* Call the parent constructor first, as required by the interface. */ parent::__construct($info, $config); /* For compatibility with code that assumes that $metadata->getString('entityid') gives the entity id. */ if (array_key_exists('entityId', $config)) { $config['entityid'] = $config['entityId']; } else { $config['entityid'] = SimpleSAML_Module::getModuleURL('saml2/sp/metadata.php?source=' . urlencode($this->authId)); } /* For backwards-compatibility with configuration in saml20-sp-hosted. */ try { $metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $oldMetadata = $metadataHandler->getMetaData($config['entityid'], 'saml20-sp-hosted'); SimpleSAML_Logger::warning('Depreceated metadata for ' . var_export($config['entityid'], TRUE) . ' in saml20-sp-hosted. The metadata in should be moved into authsources.php.'); $config = array_merge($oldMetadata, $config); } catch (Exception $e) { } $this->metadata = SimpleSAML_Configuration::loadFromArray($config, 'authsources[' . var_export($this->authId, TRUE) . ']'); $this->entityId = $this->metadata->getString('entityid'); $this->idp = $this->metadata->getString('idp', NULL); }
/** * Retrieve saved state. * * This function retrieves saved state information. If the state information has been lost, * it will attempt to restart the request by calling the restart URL which is embedded in the * state information. If there is no restart information available, an exception will be thrown. * * @param string $id State identifier (with embedded restart information). * @param string $stage The stage the state should have been saved in. * @return array State information. */ public static function loadState($id, $stage) { assert('is_string($id)'); assert('is_string($stage)'); $tmp = explode(':', $id, 2); $id = $tmp[0]; if (count($tmp) === 2) { $restartURL = $tmp[1]; } else { $restartURL = NULL; } $session = SimpleSAML_Session::getInstance(); $state = $session->getData('SimpleSAML_Auth_State', $id); if ($state === NULL) { /* Could not find saved data. Attempt to restart. */ if ($restartURL === NULL) { throw new Exception('State information lost, and no way to restart the request.'); } SimpleSAML_Utilities::redirect($restartURL); } $state = unserialize($state); assert('is_array($state)'); assert('array_key_exists(self::ID, $state)'); assert('array_key_exists(self::STAGE, $state)'); /* Verify stage. */ if ($state[self::STAGE] !== $stage) { /* This could be a user trying to bypass security, but most likely it is just * someone using the back-button in the browser. We try to restart the * request if that is possible. If not, show an error. */ $msg = 'Wrong stage in state. Was \'' . $state[self::STAGE] . '\', shoud be \'' . $stage . '\'.'; SimpleSAML_Logger::warning($msg); if ($restartURL === NULL) { throw new Exception($msg); } SimpleSAML_Utilities::redirect($restartURL); } return $state; }
/** * Search a given DN for attributes, and return the resulting associative * array. * * @param string $dn * The DN of an element. * @param string|array $attributes * The names of the attribute(s) to retrieve. Defaults to NULL; that is, * all available attributes. Note that this is not very effective. * @param int $maxsize * The maximum size of any attribute's value(s). If exceeded, the attribute * will not be returned. * @return array * The array of attributes and their values. * @see http://no.php.net/manual/en/function.ldap-read.php */ public function getAttributes($dn, $attributes = NULL, $maxsize = NULL) { // Preparations, including a pretty debug message... $description = 'all attributes'; if (is_array($attributes)) { $description = '\'' . join(',', $attributes) . '\''; } else { // Get all attributes... // TODO: Verify that this originally was the intended behaviour. Could $attributes be a string? $attributes = array(); } SimpleSAML_Logger::debug('Library - LDAP getAttributes(): Getting ' . $description . ' from DN \'' . $dn . '\''); // Attempt to get attributes. // TODO: Should aliases be dereferenced? $result = @ldap_read($this->ldap, $dn, 'objectClass=*', $attributes, 0, 0, $this->timeout); if ($result === false) { throw $this->makeException('Library - LDAP getAttributes(): Failed to get attributes from DN \'' . $dn . '\''); } $entry = @ldap_first_entry($this->ldap, $result); if ($entry === false) { throw $this->makeException('Library - LDAP getAttributes(): Could not get first entry from DN \'' . $dn . '\''); } $attributes = @ldap_get_attributes($this->ldap, $entry); // Recycling $attributes... Possibly bad practice. if ($attributes === false) { throw $this->makeException('Library - LDAP getAttributes(): Could not get attributes of first entry from DN \'' . $dn . '\''); } // Parsing each found attribute into our result set. $result = array(); // Recycling $result... Possibly bad practice. for ($i = 0; $i < $attributes['count']; $i++) { // Ignore attributes that exceed the maximum allowed size. $name = $attributes[$i]; $attribute = $attributes[$name]; // Deciding whether to base64 encode. $values = array(); for ($j = 0; $j < $attribute['count']; $j++) { $value = $attribute[$j]; if (!empty($maxsize) && strlen($value) >= $maxsize) { // Ignoring and warning. SimpleSAML_Logger::warning('Library - LDAP getAttributes(): Attribute \'' . $name . '\' exceeded maximum allowed size by ' + ($maxsize - strlen($value))); continue; } // Base64 encode jpegPhoto. if (strtolower($name) === 'jpegphoto') { $values[] = base64_encode($value); } else { $values[] = $value; } } // Adding. $result[$name] = $values; } // We're done. SimpleSAML_Logger::debug('Library - LDAP getAttributes(): Found attributes \'(' . join(',', array_keys($result)) . ')\''); return $result; }