/** * 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)); }
public function getAttributes($nameId, $attributes = array()) { // Set up config $config = $this->config; // Setup cURL $url = $this->as_config['api_url'] . '/' . $nameId; $ch = curl_init($url); curl_setopt_array($ch, array(CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => array('Content-Type: application/json'))); // Send the request $response = curl_exec($ch); $http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Check for error; not even redirects are allowed here if ($http_response == 507) { throw new SimpleSAML_Error_Exception("Out of resources: " . $response); } elseif ($response === false || !($http_response >= 200 && $http_response < 300)) { SimpleSAML_Logger::error('[afra] API query failed: HTTP response code: ' . $http_response . ', curl error: "' . curl_error($ch)) . '"'; SimpleSAML_Logger::debug('[afra] API query failed: curl info: ' . var_export(curl_getinfo($ch), 1)); SimpleSAML_Logger::debug('[afra] API query failed: HTTP response: ' . var_export($response, 1)); throw new SimpleSAML_Error_Exception("Error at REST API response: " . $response . $http_response); } else { $data = json_decode($response, true); SimpleSAML_Logger::info('[afra] got reply from API'); SimpleSAML_Logger::debug('[afra] API query url: ' . var_export($url, true)); SimpleSAML_Logger::debug('[afra] API query result: ' . var_export($data, true)); } $attributes = $data['data']; return $attributes; }
protected function _mailTechnicalContact($tag, sspmod_janus_Cron_Logger $logger) { $errorHtml = $this->_getHtmlForMessages($logger->getNamespacedErrors(), 'errors'); $warningHtml = $this->_getHtmlForMessages($logger->getNamespacedWarnings(), 'warnings'); $noticeHtml = $this->_getHtmlForMessages($logger->getNamespacedNotices(), 'notices'); $config = SimpleSAML_Configuration::getInstance(); $time = date(DATE_RFC822); $url = SimpleSAML_Utilities::selfURL(); $message = <<<MESSAGE <h1>Cron report</h1> <p>Cron ran at {$time}</p> <p>URL: <tt>{$url}</tt></p> <p>Tag: {$tag}</p> <h2>Errors</h2> {$errorHtml} <h2>Warnings</h2> {$warningHtml} <h2>Notices</h2> {$noticeHtml} MESSAGE; $toAddress = $config->getString('technicalcontact_email', '*****@*****.**'); if ($toAddress == '*****@*****.**') { SimpleSAML_Logger::error('Cron - Could not send email. [technicalcontact_email] not set in config.'); } else { $email = new SimpleSAML_XHTML_EMail($toAddress, 'JANUS cron report', '*****@*****.**'); $email->setBody($message); $email->send(); } }
/** * When the process logic determines that the user is not * authorized for this service, then forward the user to * an 403 unauthorized page. * * Separated this code into its own method so that child * classes can override it and change the action. Forward * thinking in case a "chained" ACL is needed, more complex * permission logic. * * @param array $request */ protected function unauthorized(&$request) { SimpleSAML_Logger::error('ExpectedAuthnContextClassRef: Invalid authentication context: ' . $this->AuthnContextClassRef . '. Accepted values are: ' . var_export($this->accepted, true)); $id = SimpleSAML_Auth_State::saveState($request, 'saml:ExpectedAuthnContextClassRef:unauthorized'); $url = SimpleSAML_Module::getModuleURL('saml/sp/wrong_authncontextclassref.php'); \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id)); }
public function getAttributes($nameId, $spid, $attributes = array()) { // Generate API key $time = new \DateTime(); date_timezone_set($time, new \DateTimeZone('UTC')); $stamp = $time->format('Y-m-d H:i'); $apiKey = hash('sha256', $this->as_config['hexaa_master_secret'] . $stamp); // Make the call // The data to send to the API $postData = array("apikey" => $apiKey, "fedid" => $nameId, "entityid" => $spid); // Setup cURL $ch = curl_init($this->as_config['hexaa_api_url'] . '/attributes.json'); curl_setopt_array($ch, array(CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_HTTPHEADER => array('Content-Type: application/json'), CURLOPT_POSTFIELDS => json_encode($postData), CURLOPT_FOLLOWLOCATION => TRUE, CURLOPT_POSTREDIR => 3)); // Send the request $response = curl_exec($ch); $http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Check for error; not even redirects are allowed here if ($response === FALSE || !($http_response >= 200 && $http_response < 300)) { SimpleSAML_Logger::error('[aa] HEXAA API query failed: HTTP response code: ' . $http_response . ', curl error: "' . curl_error($ch)) . '"'; SimpleSAML_Logger::debug('[aa] HEXAA API query failed: curl info: ' . var_export(curl_getinfo($ch), 1)); SimpleSAML_Logger::debug('[aa] HEXAA API query failed: HTTP response: ' . var_export($response, 1)); $data = array(); } else { $data = json_decode($response, true); SimpleSAML_Logger::info('[aa] got reply from HEXAA API'); SimpleSAML_Logger::debug('[aa] HEXAA API query postData: ' . var_export($postData, TRUE)); SimpleSAML_Logger::debug('[aa] HEXAA API query result: ' . var_export($data, TRUE)); } return $data; }
/** * Notifies managing contact about updated metadata of entity * * @param sspmod_janus_Entity $entity * @param string $metadataXml * @return void */ protected function _mailUpdatedMetaData(sspmod_janus_Entity $entity, $metadataXml) { $config = SimpleSAML_Configuration::getInstance(); $time = date(DATE_RFC822); $entityName = $entity->getPrettyname(); $entityId = $entity->getEntityId(); $message = <<<MESSAGE <h1>Metadata Change detected</h1> <p>Cron ran at {$time}</p> <p>Name: {$entityName}</p> <p>EntityId: {$entityId}</p> MESSAGE; $toAddress = $config->getString('managingcontact_email'); if (empty($toAddress)) { SimpleSAML_Logger::error('Cron - Could not send email. [managingcontact_email] not set in config.'); } $fromAddress = '*****@*****.**'; $subject = "Metadata Change detected for entity " . $entity->getPrettyname() . " (" . $entity->getEntityId() . "])"; $email = new SimpleSAML_XHTML_EMail($toAddress, $subject, $fromAddress); $email->setBody($message); // Add gzipped metadata $attachmentContent = gzencode($metadataXml); $attachmentFileName = 'metadata-' . $entityName . '.xml.gz'; $email->addAttachment($attachmentContent, $attachmentFileName, 'application/zip'); $email->send(); }
/** * Determine whether a module is enabled. * * Will return false if the given module doesn't exists. * * @param string $module Name of the module * * @return bool True if the given module is enabled, false otherwise. * * @throws Exception If module.enable is set and is not boolean. */ public static function isModuleEnabled($module) { $moduleDir = self::getModuleDir($module); if (!is_dir($moduleDir)) { return false; } $globalConfig = SimpleSAML_Configuration::getOptionalConfig(); $moduleEnable = $globalConfig->getArray('module.enable', array()); if (isset($moduleEnable[$module])) { if (is_bool($moduleEnable[$module]) === true) { return $moduleEnable[$module]; } throw new Exception("Invalid module.enable value for for the module {$module}"); } if (assert_options(ASSERT_ACTIVE) && !file_exists($moduleDir . '/default-enable') && !file_exists($moduleDir . '/default-disable')) { SimpleSAML_Logger::error("Missing default-enable or default-disable file for the module {$module}"); } if (file_exists($moduleDir . '/enable')) { return true; } if (!file_exists($moduleDir . '/disable') && file_exists($moduleDir . '/default-enable')) { return true; } return false; }
/** * Determine whether a module is enabled. * * Will return FALSE if the given module doesn't exists. * * @param string $module Name of the module * @return bool TRUE if the given module is enabled, FALSE if not. */ public static function isModuleEnabled($module) { $moduleDir = self::getModuleDir($module); if (!is_dir($moduleDir)) { return FALSE; } if (assert_options(ASSERT_ACTIVE) && !file_exists($moduleDir . '/default-enable') && !file_exists($moduleDir . '/default-disable')) { SimpleSAML_Logger::error("Missing default-enable or default-disable file for the module {$module}"); } if (file_exists($moduleDir . '/enable')) { return TRUE; } if (!file_exists($moduleDir . '/disable') && file_exists($moduleDir . '/default-enable')) { return TRUE; } return FALSE; }
/** * Load metadata * * Load the metadata from database. The entity id, revision id and the key * must be set. * * @return PDOStatement|false The satatement or false on error * @since Class available since Release 1.0.0 */ public function load() { if (empty($this->_eid) || is_null($this->_revisionid) || empty($this->_key)) { SimpleSAML_Logger::error('JANUS:Metadata:load - eid and revisionid needs to be set.'); return false; } $st = $this->execute('SELECT * FROM ' . self::$prefix . 'metadata WHERE `eid` = ? AND `revisionid` = ? AND `key` = ?;', array($this->_eid, $this->_revisionid, $this->_key)); if ($st === false) { return false; } while ($row = $st->fetchAll(PDO::FETCH_ASSOC)) { $this->_value = $row['0']['value']; if (isset($this->_definition)) { switch ($this->_definition->type) { case 'boolean': if ($this->_value == '1') { $this->_value = true; } elseif ($this->_value == '') { $this->_value = false; } else { $this->_value = false; } break; default: break; } } if (ctype_digit($this->_value)) { $this->_value = (int) $this->_value; } $this->_modified = false; } return $st; }
private function importParsedMetadata($parsedMetadata) { // If metadata was not parsed if ($parsedMetadata === null) { SimpleSAML_Logger::error('Importer - Metadata was not parsed'); return 'error_metadata_not_parsed'; } if (isset($parsedMetadata['expire']) && $parsedMetadata['expire'] < time()) { SimpleSAML_Logger::error('Importer - Metadata was not parsed due expiration'); return 'error_metadata_not_parsed_due_expiration'; } // Remove entity descriptor unset($parsedMetadata['entityDescriptor']); unset($parsedMetadata['metadata-set']); // Validate that entity id is the same for imported metadata and entity if ($parsedMetadata['entityid'] != $this->_entityId) { SimpleSAML_Logger::error('Importer - EntityId does not match'); return 'error_entityid_no_match'; } else { unset($parsedMetadata['entityid']); } $parsedMetadata = $this->_removeUnusedContacts($parsedMetadata); $parsedMetadata = $this->_removeNonSaml2Services($parsedMetadata); $parsedMetadata = $this->_applyRequestedAttributesAsArp($parsedMetadata); $converter = sspmod_janus_DiContainer::getInstance()->getMetaDataConverter(); $parsedMetadata = $converter->execute($parsedMetadata); $msg = $this->_addCertificateMetaData($parsedMetadata); if ($msg) { return $msg; } foreach ($parsedMetadata as $key => $value) { if (!empty($this->_excludedMetadataKeys) && in_array($key, $this->_excludedMetadataKeys)) { continue; } if ($this->_entityController->hasMetadata($key)) { if (!$this->_entityController->updateMetadata($key, $value)) { SimpleSAML_Logger::info('Importer - Metadata field ' . $key . ' with value ' . $value . ' was not added.'); } else { $this->_updated = true; } } else { if (!$this->_entityController->addMetadata($key, $value)) { SimpleSAML_Logger::info('Importer - Metadata field ' . $key . ' with value ' . $value . ' was not added.'); } else { $this->_updated = true; } } } return 'status_metadata_parsed_ok'; }
/** * Retrieves the current session. Will create a new session if there isn't a session. * * @return SimpleSAML_Session The current session. * @throws Exception When session couldn't be initialized and * the session fallback is disabled by configuration. */ public static function getInstance() { /* Check if we already have initialized the session. */ if (isset(self::$instance)) { return self::$instance; } /* Check if we have stored a session stored with the session * handler. */ try { self::$instance = self::getSession(); } catch (Exception $e) { /* For some reason, we were unable to initialize this session. Use a transient session instead. */ self::useTransientSession(); $globalConfig = SimpleSAML_Configuration::getInstance(); if ($globalConfig->getBoolean('session.disable_fallback', FALSE) === TRUE) { throw $e; } if ($e instanceof SimpleSAML_Error_Exception) { SimpleSAML_Logger::error('Error loading session:'); $e->logError(); } else { SimpleSAML_Logger::error('Error loading session: ' . $e->getMessage()); } return self::$instance; } if (self::$instance !== NULL) { return self::$instance; } /* Create a new session. */ self::$instance = new SimpleSAML_Session(); return self::$instance; }
/** * Process a authentication response * * This function saves the state, and redirects the user to the page where * the user can authorize the release of the attributes. * If storage is used and the consent has already been given the user is * passed on. * * @param array &$state The state of the response. * * @return void */ public function process(&$state) { assert('is_array($state)'); assert('array_key_exists("UserID", $state)'); assert('array_key_exists("Destination", $state)'); assert('array_key_exists("entityid", $state["Destination"])'); assert('array_key_exists("metadata-set", $state["Destination"])'); assert('array_key_exists("entityid", $state["Source"])'); assert('array_key_exists("metadata-set", $state["Source"])'); $spEntityId = $state['Destination']['entityid']; $idpEntityId = $state['Source']['entityid']; $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); /** * If the consent module is active on a bridge $state['saml:sp:IdP'] * will contain an entry id for the remote IdP. If not, then the * consent module is active on a local IdP and nothing needs to be * done. */ if (isset($state['saml:sp:IdP'])) { $idpEntityId = $state['saml:sp:IdP']; $idpmeta = $metadata->getMetaData($idpEntityId, 'saml20-idp-remote'); $state['Source'] = $idpmeta; } $statsData = array('spEntityID' => $spEntityId); // Do not use consent if disabled if (isset($state['Source']['consent.disable']) && self::checkDisable($state['Source']['consent.disable'], $spEntityId)) { SimpleSAML_Logger::debug('Consent: Consent disabled for entity ' . $spEntityId . ' with IdP ' . $idpEntityId); SimpleSAML_Stats::log('consent:disabled', $statsData); return; } if (isset($state['Destination']['consent.disable']) && self::checkDisable($state['Destination']['consent.disable'], $idpEntityId)) { SimpleSAML_Logger::debug('Consent: Consent disabled for entity ' . $spEntityId . ' with IdP ' . $idpEntityId); SimpleSAML_Stats::log('consent:disabled', $statsData); return; } if ($this->_store !== null) { $source = $state['Source']['metadata-set'] . '|' . $idpEntityId; $destination = $state['Destination']['metadata-set'] . '|' . $spEntityId; $attributes = $state['Attributes']; // Remove attributes that do not require consent foreach ($attributes as $attrkey => $attrval) { if (in_array($attrkey, $this->_noconsentattributes)) { unset($attributes[$attrkey]); } } SimpleSAML_Logger::debug('Consent: userid: ' . $state['UserID']); SimpleSAML_Logger::debug('Consent: source: ' . $source); SimpleSAML_Logger::debug('Consent: destination: ' . $destination); $userId = self::getHashedUserID($state['UserID'], $source); $targetedId = self::getTargetedID($state['UserID'], $source, $destination); $attributeSet = self::getAttributeHash($attributes, $this->_includeValues); SimpleSAML_Logger::debug('Consent: hasConsent() [' . $userId . '|' . $targetedId . '|' . $attributeSet . ']'); try { if ($this->_store->hasConsent($userId, $targetedId, $attributeSet)) { // Consent already given SimpleSAML_Logger::stats('Consent: Consent found'); SimpleSAML_Stats::log('consent:found', $statsData); return; } SimpleSAML_Logger::stats('Consent: Consent notfound'); SimpleSAML_Stats::log('consent:notfound', $statsData); $state['consent:store'] = $this->_store; $state['consent:store.userId'] = $userId; $state['consent:store.destination'] = $targetedId; $state['consent:store.attributeSet'] = $attributeSet; } catch (Exception $e) { SimpleSAML_Logger::error('Consent: Error reading from storage: ' . $e->getMessage()); SimpleSAML_Logger::stats('Consent: Failed'); SimpleSAML_Stats::log('consent:failed', $statsData); } } else { SimpleSAML_Logger::stats('Consent: No storage'); SimpleSAML_Stats::log('consent:nostorage', $statsData); } $state['consent:focus'] = $this->_focus; $state['consent:checked'] = $this->_checked; $state['consent:hiddenAttributes'] = $this->_hiddenAttributes; $state['consent:noconsentattributes'] = $this->_noconsentattributes; $state['consent:showNoConsentAboutService'] = $this->_showNoConsentAboutService; // User interaction nessesary. Throw exception on isPassive request if (isset($state['isPassive']) && $state['isPassive'] == true) { SimpleSAML_Stats::log('consent:nopassive', $statsData); throw new SimpleSAML_Error_NoPassive('Unable to give consent on passive request.'); } // Save state and redirect $id = SimpleSAML_Auth_State::saveState($state, 'consent:request'); $url = SimpleSAML_Module::getModuleURL('consent/getconsent.php'); SimpleSAML_Utilities::redirectTrustedURL($url, array('StateId' => $id)); }
/** * Enable an entity from the database * * @param int $eid The entitys Eid * * @return void * @since Methos available since Release 1.11.0 */ public function enableEntity($eid) { $st = $this->execute('UPDATE `' . $this->getTablePrefix() . 'connectionRevision` SET `active` = ? WHERE `eid` = ?;', array('yes', $eid)); if ($st === false) { SimpleSAML_Logger::error('JANUS:disableEntity - Not all revisions of entity was enabled.'); } return; }
/** * Initialize consent filter. * * This is the constructor for the consent filter. It validates and parses the 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)'); $this->includeValues = FALSE; if (array_key_exists('includeValues', $config)) { $this->includeValues = $config['includeValues']; } if (array_key_exists('checked', $config)) { $this->checked = $config['checked']; } if (array_key_exists('focus', $config)) { $this->focus = $config['focus']; if (!in_array($this->focus, array('yes', 'no'), TRUE)) { throw new Exception('Invalid value for \'focus\'-parameter to' . ' consent:Consent authentication filter: ' . var_export($this->focus, TRUE)); } } else { $this->focus = NULL; } $this->store = NULL; if (array_key_exists('store', $config)) { try { $this->store = sspmod_consent_Store::parseStoreConfig($config['store']); } catch (Exception $e) { SimpleSAML_Logger::error('Consent - constructor() : Could not create consent storage: ' . $e->getMessage()); } } if (array_key_exists('hiddenAttributes', $config)) { $this->hiddenAttributes = $config['hiddenAttributes']; } else { $this->hiddenAttributes = array(); } }
/** * @param $table string * @param array $keys * @param array $data */ private function insertOrUpdate($table, array $keys, array $data) { assert('is_string($table)'); $colNames = '(' . implode(', ', array_keys($data)) . ')'; $values = 'VALUES(:' . implode(', :', array_keys($data)) . ')'; switch ($this->driver) { case 'mysql': $query = 'REPLACE INTO ' . $table . ' ' . $colNames . ' ' . $values; $query = $this->pdo->prepare($query); $query->execute($data); return; case 'sqlite': $query = 'INSERT OR REPLACE INTO ' . $table . ' ' . $colNames . ' ' . $values; $query = $this->pdo->prepare($query); $query->execute($data); return; } /* Default implementation. Try INSERT, and UPDATE if that fails. */ $insertQuery = 'INSERT INTO ' . $table . ' ' . $colNames . ' ' . $values; $insertQuery = $this->pdo->prepare($insertQuery); try { $insertQuery->execute($data); return; } catch (PDOException $e) { $ecode = (string) $e->getCode(); switch ($ecode) { case '23505': /* PostgreSQL */ break; default: SimpleSAML_Logger::error('casserver: Error while saving data: ' . $e->getMessage()); throw $e; } } $updateCols = array(); $condCols = array(); foreach ($data as $col => $value) { $tmp = $col . ' = :' . $col; if (in_array($col, $keys, true)) { $condCols[] = $tmp; } else { $updateCols[] = $tmp; } } $updateQuery = 'UPDATE ' . $table . ' SET ' . implode(',', $updateCols) . ' WHERE ' . implode(' AND ', $condCols); $updateQuery = $this->pdo->prepare($updateQuery); $updateQuery->execute($data); }
/** * Retrieve entity data from database * * Loads the entity data from the database. If either _eid and _revisionid * is not set or an error occurs and the method returns false. If only * _eid is set, the newest revision will be fetched. * * @return bool */ public function load() { if (empty($this->_eid) && isset($this->_entityid)) { $this->_findEid(); } if (is_null($this->_revisionid)) { if (empty($this->_workflow)) { $this->_newestRevision(); } else { $this->_newestRevision($this->_workflow); } } if (empty($this->_eid) || is_null($this->_revisionid)) { SimpleSAML_Logger::error('JANUS:Entity:load - entityid and revisionid needs to be set.'); return false; } $row = $this->_loadFromCache($this->_eid, $this->_revisionid); if (!$row) { return false; } $this->_id = $row['id']; $this->_eid = $row['eid']; $this->_entityid = $row['entityid']; $this->_revisionid = $row['revisionid']; $this->_workflow = $row['state']; $this->_type = $row['type']; $this->_expiration = $row['expiration']; $this->_metadataurl = $row['metadataurl']; $this->_allowedall = $row['allowedall']; $this->_parent = $row['parent']; $this->_revisionnote = $row['revisionnote']; $this->_arpAttributes = unserialize($row['arp_attributes']); $this->_user = $row['user']; $this->_created = $row['created']; $this->_active = $row['active']; $this->_manipulation = $row['manipulation']; $this->_notes = $row['notes']; $this->_modified = false; return true; }
/** * Attempt to log in using the given username and password. * * On a successful login, this function should return the users attributes. On failure, * it should throw an exception. If the error was caused by the user entering the wrong * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown. * * Note that both the username and the password are UTF-8 encoded. * * @param string $username The username the user wrote. * @param string $password The password the user wrote. * @return array Associative array with the users attributes. */ protected function login($username, $password) { assert('is_string($username)'); assert('is_string($password)'); $db = $this->connect(); try { $sth = $db->prepare($this->query); } catch (PDOException $e) { throw new Exception('sqlauth:' . $this->authId . ': - Failed to prepare query: ' . $e->getMessage()); } try { $res = $sth->execute(array('username' => $username, 'password' => $password)); } catch (PDOException $e) { throw new Exception('sqlauth:' . $this->authId . ': - Failed to execute query: ' . $e->getMessage()); } try { $data = $sth->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { throw new Exception('sqlauth:' . $this->authId . ': - Failed to fetch result set: ' . $e->getMessage()); } SimpleSAML_Logger::info('sqlauth:' . $this->authId . ': Got ' . count($data) . ' rows from database'); if (count($data) === 0) { /* No rows returned - invalid username/password. */ SimpleSAML_Logger::error('sqlauth:' . $this->authId . ': No rows in result set. Probably wrong username/password.'); throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } /* Extract attributes. We allow the resultset to consist of multiple rows. Attributes * which are present in more than one row will become multivalued. NULL values and * duplicate values will be skipped. All values will be converted to strings. */ $attributes = array(); foreach ($data as $row) { foreach ($row as $name => $value) { if ($value === NULL) { continue; } $value = (string) $value; if (!array_key_exists($name, $attributes)) { $attributes[$name] = array(); } if (in_array($value, $attributes[$name], TRUE)) { /* Value already exists in attribute. */ continue; } $attributes[$name][] = $value; } } SimpleSAML_Logger::info('sqlauth:' . $this->authId . ': Attributes: ' . implode(',', array_keys($attributes))); return $attributes; }
/** * Validate certificate and login * * This function try to validate the certificate. * On success, the user is logged in without going through * o login page. * On failure, The authX509:X509error.php template is * loaded. * * @param array &$state Information about the current authentication. */ public function authenticate(&$state) { assert('is_array($state)'); $ldapcf = $this->ldapcf; if (!isset($_SERVER['SSL_CLIENT_CERT']) || $_SERVER['SSL_CLIENT_CERT'] == '') { $state['authX509.error'] = "NOCERT"; $this->authFailed($state); assert('FALSE'); /* NOTREACHED */ 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'); $state['authX509.error'] = "INVALIDCERT"; $this->authFailed($state); assert('FALSE'); /* NOTREACHED */ return; } $dn = NULL; foreach ($this->x509attributes as $x509_attr => $ldap_attr) { /* value is scalar */ if (array_key_exists($x509_attr, $client_cert_data['subject'])) { $value = $client_cert_data['subject'][$x509_attr]; SimpleSAML_Logger::info('authX509: cert ' . $x509_attr . ' = ' . $value); $dn = $ldapcf->searchfordn($ldap_attr, $value, TRUE); if ($dn !== NULL) { break; } } } if ($dn === NULL) { SimpleSAML_Logger::error('authX509: cert has ' . 'no matching user in LDAP'); $state['authX509.error'] = "UNKNOWNCERT"; $this->authFailed($state); assert('FALSE'); /* NOTREACHED */ return; } if ($this->ldapusercert === NULL) { // do not check for certificate match $attributes = $ldapcf->getAttributes($dn); assert('is_array($attributes)'); $state['Attributes'] = $attributes; $this->authSuccesful($state); assert('FALSE'); /* NOTREACHED */ return; } $ldap_certs = $ldapcf->getAttributes($dn, $this->ldapusercert); if ($ldap_certs === FALSE) { SimpleSAML_Logger::error('authX509: no certificate ' . 'found in LDAP for dn=' . $dn); $state['authX509.error'] = "UNKNOWNCERT"; $this->authFailed($state); assert('FALSE'); /* NOTREACHED */ return; } $merged_ldapcerts = array(); foreach ($this->ldapusercert as $attr) { $merged_ldapcerts = array_merge($merged_ldapcerts, $ldap_certs[$attr]); } $ldap_certs = $merged_ldapcerts; foreach ($ldap_certs as $ldap_cert) { $pem = $this->der2pem($ldap_cert); $ldap_cert_data = openssl_x509_parse($pem); if ($ldap_cert_data == FALSE) { SimpleSAML_Logger::error('authX509: cert in ' . 'LDAP in invalid for ' . 'dn = ' . $dn); continue; } if ($ldap_cert_data === $client_cert_data) { $attributes = $ldapcf->getAttributes($dn); assert('is_array($attributes)'); $state['Attributes'] = $attributes; $this->authSuccesful($state); assert('FALSE'); /* NOTREACHED */ return; } } SimpleSAML_Logger::error('authX509: no matching cert in ' . 'LDAP for dn = ' . $dn); $state['authX509.error'] = "UNKNOWNCERT"; $this->authFailed($state); assert('FALSE'); /* NOTREACHED */ return; }
/** * Calculate the NameID value that should be used. * * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP. * @param SimpleSAML_Configuration $dstMetadata The metadata of the SP. * @param array &$state The authentication state of the user. * @return string The NameID value. */ private static function generateNameIdValue(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array &$state) { $attribute = $spMetadata->getString('simplesaml.nameidattribute', NULL); if ($attribute === NULL) { $attribute = $idpMetadata->getString('simplesaml.nameidattribute', NULL); if ($attribute === NULL) { if (!isset($state['UserID'])) { SimpleSAML_Logger::error('Unable to generate NameID. Check the userid.attribute option.'); } $attributeValue = $state['UserID']; $idpEntityId = $idpMetadata->getString('entityid'); $spEntityId = $spMetadata->getString('entityid'); $secretSalt = SimpleSAML\Utils\Config::getSecretSalt(); $uidData = 'uidhashbase' . $secretSalt; $uidData .= strlen($idpEntityId) . ':' . $idpEntityId; $uidData .= strlen($spEntityId) . ':' . $spEntityId; $uidData .= strlen($attributeValue) . ':' . $attributeValue; $uidData .= $secretSalt; return hash('sha1', $uidData); } } $attributes = $state['Attributes']; if (!array_key_exists($attribute, $attributes)) { SimpleSAML_Logger::error('Unable to add NameID: Missing ' . var_export($attribute, TRUE) . ' in the attributes of the user.'); return NULL; } return $attributes[$attribute][0]; }
/** * Delete a metadata entry. * * @param string $entityId The entityId of the metadata entry. * @param string $set The metadata set this metadata entry belongs to. */ public function deleteMetadata($entityId, $set) { assert('is_string($entityId)'); assert('is_string($set)'); $filePath = $this->getMetadataPath($entityId, $set); if (!file_exists($filePath)) { SimpleSAML_Logger::warning('Attempted to erase non-existant metadata entry ' . var_export($entityId, TRUE) . ' in set ' . var_export($set, TRUE) . '.'); return; } $res = unlink($filePath); if ($res === FALSE) { $error = error_get_last(); SimpleSAML_Logger::error('Failed to delete file ' . $filePath . ': ' . $error['message']); } }
/** * Read a dictionary file. * * @param $filename The absolute path to the dictionary file. * @return The translation array which was found in the dictionary file. */ private function readDictionaryFile($filename) { assert('is_string($filename)'); SimpleSAML_Logger::debug('Template: Reading [' . $filename . ']'); $jsonFile = $filename . '.definition.json'; if (file_exists($jsonFile)) { return $this->readDictionaryJSON($filename); } $phpFile = $filename . '.php'; if (file_exists($phpFile)) { return $this->readDictionaryPHP($filename); } SimpleSAML_Logger::error($_SERVER['PHP_SELF'] . ' - Template: Could not find template file [' . $this->template . '] at [' . $filename . ']'); return array(); }
/** * Retrieve the metadata file. * * This function will check its cached copy, to see whether it can be used. * * @return SAML2_XML_md_EntityDescriptor|SAML2_XML_md_EntitiesDescriptor|NULL The downloaded metadata. */ public function getMetadata() { if ($this->metadata !== NULL) { /* We have already downloaded the metdata. */ return $this->metadata; } if (!$this->aggregator->isCacheValid($this->cacheId, $this->cacheTag)) { $this->updateCache(); if ($this->metadata !== NULL) { return $this->metadata; } /* We were unable to update the cache - use cached metadata. */ } $cacheFile = $this->aggregator->getCacheFile($this->cacheId); if (!file_exists($cacheFile)) { SimpleSAML_Logger::error($this->logLoc . 'No cached metadata available.'); return NULL; } SimpleSAML_Logger::debug($this->logLoc . 'Using cached metadata from ' . var_export($cacheFile, TRUE)); $metadata = file_get_contents($cacheFile); if ($metadata !== NULL) { $this->metadata = unserialize($metadata); return $this->metadata; } return NULL; }
<?php /** * * * @author Mathias Meisfjordskar, University of Oslo. * <*****@*****.**> * @package simpleSAMLphp */ $state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], sspmod_negotiate_Auth_Source_Negotiate::STAGEID); $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $idpid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted', 'metaindex'); $idpmeta = $metadata->getMetaData($idpid, 'saml20-idp-hosted'); if (isset($idpmeta['auth'])) { $source = SimpleSAML_Auth_Source::getById($idpmeta['auth']); if ($source === NULL) { throw new SimpleSAML_Error_BadRequest('Invalid AuthId "' . $idpmeta['auth'] . '" - not found.'); } $session = SimpleSAML_Session::getSessionFromRequest(); $session->setData('negotiate:disable', 'session', FALSE, 24 * 60 * 60); SimpleSAML_Logger::debug('Negotiate(retry) - session enabled, retrying.'); $source->authenticate($state); assert('FALSE'); } else { SimpleSAML_Logger::error('Negotiate - retry - no "auth" parameter found in IdP metadata.'); assert('FALSE'); }
/** * Save the session to the session handler. * * This function will check the dirty-flag to check if the session has changed. */ public function saveSession() { if (!$this->dirty) { /* Session hasn't changed - don't bother saving it. */ return; } $this->dirty = FALSE; $sh = SimpleSAML_SessionHandler::getSessionHandler(); try { $sh->saveSession($this); } catch (Exception $e) { if (!$e instanceof SimpleSAML_Error_Exception) { $e = new SimpleSAML_Error_UnserializableException($e); } SimpleSAML_Logger::error('Unable to save session.'); $e->logError(); } }
/** * Save an error report. * * @return array The array with the error report data. */ protected function saveError() { $data = $this->format(); $emsg = array_shift($data); $etrace = implode("\n", $data); $reportId = bin2hex(openssl_random_pseudo_bytes(4)); SimpleSAML_Logger::error('Error report with id ' . $reportId . ' generated.'); $config = SimpleSAML_Configuration::getInstance(); $session = SimpleSAML_Session::getSessionFromRequest(); if (isset($_SERVER['HTTP_REFERER'])) { $referer = $_SERVER['HTTP_REFERER']; // remove anything after the first '?' or ';', just in case it contains any sensitive data $referer = explode('?', $referer, 2); $referer = $referer[0]; $referer = explode(';', $referer, 2); $referer = $referer[0]; } else { $referer = 'unknown'; } $errorData = array('exceptionMsg' => $emsg, 'exceptionTrace' => $etrace, 'reportId' => $reportId, 'trackId' => $session->getTrackID(), 'url' => \SimpleSAML\Utils\HTTP::getSelfURLNoQuery(), 'version' => $config->getVersion(), 'referer' => $referer); $session->setData('core:errorreport', $reportId, $errorData); return $errorData; }
<p>Version: <tt>' . $data['version'] . '</tt></p> <p>Report ID: <tt>' . $data['reportId'] . '</tt></p> <p>Referer: <tt>' . htmlspecialchars($data['referer']) . '</tt></p> <hr /> <div class="footer">This message was sent using simpleSAMLphp. Visit the <a href="http://simplesamlphp.org/">simpleSAMLphp homepage</a>.</div> '; /* Add the email address of the submitter as the Reply-To address. */ $email = trim($email); /* Check that it looks like a valid email address. */ if (!preg_match('/\\s/', $email) && strpos($email, '@') !== FALSE) { $replyto = $email; $from = $email; } else { $replyto = NULL; $from = '*****@*****.**'; } /* Send the email. */ $toAddress = $config->getString('technicalcontact_email', '*****@*****.**'); if ($config->getBoolean('errorreporting', TRUE) && $toAddress !== '*****@*****.**') { $email = new SimpleSAML_XHTML_EMail($toAddress, 'simpleSAMLphp error report', $from); $email->setBody($message); $email->send(); SimpleSAML_Logger::error('Report with id ' . $reportId . ' sent to <' . $toAddress . '>.'); } /* Redirect the user back to this page to clear the POST request. */ SimpleSAML_Utilities::redirectTrustedURL(SimpleSAML_Utilities::selfURLNoQuery());
SimpleSAML_Logger::error('Cron - Illegal tag [' . $_REQUEST['tag'] . '].'); exit; } } $summary = array(); $croninfo = array('summary' => &$summary, 'tag' => $_REQUEST['tag']); $url = SimpleSAML_Utilities::selfURL(); $time = date(DATE_RFC822); SimpleSAML_Module::callHooks('cron', $croninfo); foreach ($summary as $s) { SimpleSAML_Logger::debug('Cron - Summary: ' . $s); } if ($cronconfig->getValue('sendemail', TRUE) && count($summary) > 0) { $message = '<h1>Cron report</h1><p>Cron ran at ' . $time . '</p>' . '<p>URL: <tt>' . $url . '</tt></p>' . '<p>Tag: ' . $croninfo['tag'] . "</p>\n\n" . '<ul><li>' . join('</li><li>', $summary) . '</li></ul>'; $toaddress = $config->getString('technicalcontact_email', '*****@*****.**'); if ($toaddress == '*****@*****.**') { SimpleSAML_Logger::error('Cron - Could not send email. [technicalcontact_email] not set in config.'); } else { $email = new SimpleSAML_XHTML_EMail($toaddress, 'simpleSAMLphp cron report', '*****@*****.**'); $email->setBody($message); $email->send(); } } if (isset($_REQUEST['output']) && $_REQUEST['output'] == "xhtml") { $t = new SimpleSAML_XHTML_Template($config, 'cron:croninfo-result.php', 'cron:cron'); $t->data['tag'] = $croninfo['tag']; $t->data['time'] = $time; $t->data['url'] = $url; $t->data['summary'] = $summary; $t->show(); }
$statsInfo = array('remember' => array_key_exists('saveconsent', $_REQUEST)); if (isset($state['Destination']['entityid'])) { $statsInfo['spEntityID'] = $state['Destination']['entityid']; } SimpleSAML_Stats::log('consent:accept', $statsInfo); if (array_key_exists('consent:store', $state) && array_key_exists('saveconsent', $_REQUEST) && $_REQUEST['saveconsent'] === '1') { /* Save consent. */ $store = $state['consent:store']; $userId = $state['consent:store.userId']; $targetedId = $state['consent:store.destination']; $attributeSet = $state['consent:store.attributeSet']; SimpleSAML_Logger::debug('Consent - saveConsent() : [' . $userId . '|' . $targetedId . '|' . $attributeSet . ']'); try { $store->saveConsent($userId, $targetedId, $attributeSet); } catch (Exception $e) { SimpleSAML_Logger::error('Consent: Error writing to storage: ' . $e->getMessage()); } } SimpleSAML_Auth_ProcessingChain::resumeProcessing($state); } // Prepare attributes for presentation $attributes = $state['Attributes']; $noconsentattributes = $state['consent:noconsentattributes']; // Remove attributes that do not require consent foreach ($attributes as $attrkey => $attrval) { if (in_array($attrkey, $noconsentattributes)) { unset($attributes[$attrkey]); } } $para = array('attributes' => &$attributes); // Reorder attributes according to attributepresentation hooks
/** * Convenience method to create an LDAPException as well as log the * description. * * @param string $description * The exception's description * @return Exception */ private function makeException($description, $type = NULL) { $errNo = 0x0; // Log LDAP code and description, if possible. if (empty($this->ldap)) { SimpleSAML_Logger::error($description); } else { $errNo = @ldap_errno($this->ldap); } // Decide exception type and return if ($type) { if ($errNo !== 0) { // Only log real LDAP errors; not success. SimpleSAML_Logger::error($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'); } else { SimpleSAML_Logger::error($description); } switch ($type) { case ERR_INTERNAL: // 1 - ExInternal return new SimpleSAML_Error_Exception($description, $errNo); case ERR_NO_USER: // 2 - ExUserNotFound return new SimpleSAML_Error_UserNotFound($description, $errNo); case ERR_WRONG_PW: // 3 - ExInvalidCredential return new SimpleSAML_Error_InvalidCredential($description, $errNo); case ERR_AS_DATA_INCONSIST: // 4 - ExAsDataInconsist return new SimpleSAML_Error_AuthSource('ldap', $description); case ERR_AS_INTERNAL: // 5 - ExAsInternal return new SimpleSAML_Error_AuthSource('ldap', $description); } } else { if ($errNo !== 0) { $description .= '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'; } switch ($errNo) { case 0x20: //LDAP_NO_SUCH_OBJECT SimpleSAML_Logger::warning($description); return new SimpleSAML_Error_UserNotFound($description, $errNo); case 0x31: //LDAP_INVALID_CREDENTIALS SimpleSAML_Logger::info($description); return new SimpleSAML_Error_InvalidCredential($description, $errNo); case -1: //NO_SERVER_CONNECTION SimpleSAML_Logger::error($description); return new SimpleSAML_Error_AuthSource('ldap', $description); default: SimpleSAML_Logger::error($description); return new SimpleSAML_Error_AuthSource('ldap', $description); } } }
/** * Apply filter * * @param array &$state The current state. */ public function process(&$state) { /* * UTC format: 20090527080352Z */ $netId = $state['Attributes'][$this->netid_attr][0]; $expireOnDate = strtotime($state['Attributes'][$this->expirydate_attr][0]); if (self::shWarning($state, $expireOnDate, $this->warndaysbefore)) { assert('is_array($state)'); if (isset($state['isPassive']) && $state['isPassive'] === TRUE) { /* We have a passive request. Skip the warning. */ return; } SimpleSAML_Logger::warning('expirycheck: NetID ' . $netId . ' is about to expire!'); /* Save state and redirect. */ $state['expireOnDate'] = date($this->date_format, $expireOnDate); $state['netId'] = $netId; $id = SimpleSAML_Auth_State::saveState($state, 'expirywarning:about2expire'); $url = SimpleSAML_Module::getModuleURL('expirycheck/about2expire.php'); SimpleSAML_Utilities::redirectTrustedURL($url, array('StateId' => $id)); } if (!self::checkDate($expireOnDate)) { SimpleSAML_Logger::error('expirycheck: NetID ' . $netId . ' has expired [' . date($this->date_format, $expireOnDate) . ']. Access denied!'); $globalConfig = SimpleSAML_Configuration::getInstance(); /* Save state and redirect. */ $state['expireOnDate'] = date($this->date_format, $expireOnDate); $state['netId'] = $netId; $id = SimpleSAML_Auth_State::saveState($state, 'expirywarning:expired'); $url = SimpleSAML_Module::getModuleURL('expirycheck/expired.php'); SimpleSAML_Utilities::redirectTrustedURL($url, array('StateId' => $id)); } }