/** * Get an association * * @param string $server_url The identity server endpoint * @param string $handle The association handle * @return Auth_OpenID_Association */ public function getAssociation($server_url, $handle = null) { $assocs = $this->getAssociations($server_url, $handle); if (!$assocs || count($assocs) == 0) { return null; } else { $associations = array(); foreach ($assocs as $object) { $assoc = new Auth_OpenID_Association($object->handle, base64_decode($object->secret), $object->issued, $object->lifetime, $object->assoc_type); if ($assoc->getExpiresIn() == 0) { $this->removeAssociation($server_url, $assoc->handle); } else { $associations[] = array($assoc->issued, $assoc); } } if ($associations) { $issued = array(); $assocs = array(); foreach ($associations as $key => $assoc) { $issued[$key] = $assoc[0]; $assocs[$key] = $assoc[1]; } array_multisort($issued, SORT_DESC, $assocs, SORT_DESC, $associations); // return the most recently issued one. list($issued, $assoc) = $associations[0]; return $assoc; } else { return null; } } }
function test_me() { $issued = time(); $lifetime = 600; $assoc = new Auth_OpenID_Association('handle', 'secret', $issued, $lifetime, 'HMAC-SHA1'); $s = $assoc->serialize(); $assoc2 = Auth_OpenID_Association::deserialize('Auth_OpenID_Association', $s); if ($assoc2 === null) { $this->fail('deserialize returned null'); } else { $this->assertTrue($assoc2->equal($assoc)); } }
function getAssociation($server_url, $handle = null) { if (isset($handle)) { $meta_array = array('server_url' => $server_url, 'handle' => $handle); $assocs = elgg_get_entities_from_metadata(array('metadata_name_value_pairs' => $meta_array, 'types' => 'object', 'subtypes' => 'openid_client::association', 'metadata_name_value_pairs_operator' => 'and')); } else { $assocs = elgg_get_entities_from_metadata(array('metadata_names' => 'server_url', 'metadata_values' => $server_url, 'types' => 'object', 'subtypes' => 'openid_client::association', 'metadata_case_sensitive' => FALSE)); } if (!$assocs || count($assocs) == 0) { return null; } else { $associations = array(); foreach ($assocs as $assoc_row) { $assoc = new Auth_OpenID_Association($assoc_row->handle, base64_decode($assoc_row->secret), $assoc_row->issued, $assoc_row->lifetime, $assoc_row->assoc_type); if ($assoc->getExpiresIn() == 0) { OpenIDServer_ElggStore::removeAssociation($server_url, $assoc->handle); } else { $associations[] = array($assoc->issued, $assoc); } } if ($associations) { $issued = array(); $assocs = array(); foreach ($associations as $key => $assoc) { $issued[$key] = $assoc[0]; $assocs[$key] = $assoc[1]; } array_multisort($issued, SORT_DESC, $assocs, SORT_DESC, $associations); // return the most recently issued one. list($issued, $assoc) = $associations[0]; return $assoc; } else { return null; } } }
function getAssociation($server_url, $handle = null) { if ($handle !== null) { $assoc = $this->_get_assoc($server_url, $handle); $assocs = array(); if ($assoc) { $assocs[] = $assoc; } } else { $assocs = $this->_get_assocs($server_url); } if (!$assocs || count($assocs) == 0) { return null; } else { $associations = array(); foreach ($assocs as $assoc_row) { $assoc = new Auth_OpenID_Association($assoc_row['handle'], $assoc_row['secret'], $assoc_row['issued'], $assoc_row['lifetime'], $assoc_row['assoc_type']); $assoc->secret = $this->blobDecode($assoc->secret); if ($assoc->getExpiresIn() == 0) { $this->removeAssociation($server_url, $assoc->handle); } else { $associations[] = array($assoc->issued, $assoc); } } if ($associations) { $issued = array(); $assocs = array(); foreach ($associations as $key => $assoc) { $issued[$key] = $assoc[0]; $assocs[$key] = $assoc[1]; } array_multisort($issued, SORT_DESC, $assocs, SORT_DESC, $associations); // return the most recently issued one. list($issued, $assoc) = $associations[0]; return $assoc; } else { return null; } } }
/** * Make a new association. */ function createAssociation($dumb = true, $assoc_type = 'HMAC-SHA1') { $secret = Auth_OpenID_CryptUtil::getBytes( Auth_OpenID_getSecretSize($assoc_type)); $uniq = base64_encode(Auth_OpenID_CryptUtil::getBytes(4)); $handle = sprintf('{%s}{%x}{%s}', $assoc_type, intval(time()), $uniq); $assoc = Auth_OpenID_Association::fromExpiresIn( $this->SECRET_LIFETIME, $handle, $secret, $assoc_type); if ($dumb) { $key = $this->dumb_key; } else { $key = $this->normal_key; } $this->store->storeAssociation($key, $assoc); return $assoc; }
function cleanupAssociations() { $associations = get_option('openid_associations'); foreach ($associations as $key => $assoc_s) { $assoc = Auth_OpenID_Association::deserialize('Auth_OpenID_Association', $assoc_s); if ( $assoc->getExpiresIn() == 0) { unset($associations[$key]); } } update_option('openid_associations', $associations); }
/** * @access private */ function _extractAssociation($assoc_response, $assoc_session) { // Extract the common fields from the response, raising an // exception if they are not found $assoc_type = $assoc_response->getArg(Auth_OpenID_OPENID_NS, 'assoc_type', Auth_OpenID_NO_DEFAULT); if (Auth_OpenID::isFailure($assoc_type)) { return $assoc_type; } $assoc_handle = $assoc_response->getArg(Auth_OpenID_OPENID_NS, 'assoc_handle', Auth_OpenID_NO_DEFAULT); if (Auth_OpenID::isFailure($assoc_handle)) { return $assoc_handle; } // expires_in is a base-10 string. The Python parsing will // accept literals that have whitespace around them and will // accept negative values. Neither of these are really in-spec, // but we think it's OK to accept them. $expires_in_str = $assoc_response->getArg(Auth_OpenID_OPENID_NS, 'expires_in', Auth_OpenID_NO_DEFAULT); if (Auth_OpenID::isFailure($expires_in_str)) { return $expires_in_str; } $expires_in = Auth_OpenID::intval($expires_in_str); if ($expires_in === false) { $err = sprintf("Could not parse expires_in from association " . "response %s", print_r($assoc_response, true)); return new Auth_OpenID_FailureResponse(null, $err); } // OpenID 1 has funny association session behaviour. if ($assoc_response->isOpenID1()) { $session_type = $this->_getOpenID1SessionType($assoc_response); } else { $session_type = $assoc_response->getArg(Auth_OpenID_OPENID2_NS, 'session_type', Auth_OpenID_NO_DEFAULT); if (Auth_OpenID::isFailure($session_type)) { return $session_type; } } // Session type mismatch if ($assoc_session->session_type != $session_type) { if ($assoc_response->isOpenID1() && $session_type == 'no-encryption') { // In OpenID 1, any association request can result in // a 'no-encryption' association response. Setting // assoc_session to a new no-encryption session should // make the rest of this function work properly for // that case. $assoc_session = new Auth_OpenID_PlainTextConsumerSession(); } else { // Any other mismatch, regardless of protocol version // results in the failure of the association session // altogether. return null; } } // Make sure assoc_type is valid for session_type if (!in_array($assoc_type, $assoc_session->allowed_assoc_types)) { return null; } // Delegate to the association session to extract the secret // from the response, however is appropriate for that session // type. $secret = $assoc_session->extractSecret($assoc_response); if ($secret === null) { return null; } return Auth_OpenID_Association::fromExpiresIn($expires_in, $assoc_handle, $secret, $assoc_type); }
/** * Store an association. * * This function stores an association. * @param string $server_url The server. * @param Auth_OpenID_Association $association The association which should be stored. * @return bool TRUE if the association is stored, FALSE if not. */ public function storeAssociation($server_url, Auth_OpenID_Association $association) { assert('is_string($server_url)'); if (!array_key_exists($server_url, $this->associations)) { $this->associations[$server_url] = array(); } $handle = $association->handle; assert('is_string($handle)'); $this->associations[$server_url][$handle] = $association->serialize(); /* We rely on saveState saving with the same id as before. */ SimpleSAML_Auth_State::saveState($this->state, 'openid:auth'); return TRUE; }
/** * Remove expired entries from the database. This is potentially * expensive, so only run when it is acceptable to take time. * * @access private */ function _allAssocs() { $all_associations = array(); $association_filenames = Auth_OpenID_FileStore::_listdir($this->association_dir); foreach ($association_filenames as $association_filename) { $association_file = fopen($association_filename, 'rb'); if ($association_file !== false) { $assoc_s = fread($association_file, filesize($association_filename)); fclose($association_file); // Remove expired or corrupted associations $association = Auth_OpenID_Association::deserialize('Auth_OpenID_Association', $assoc_s); if ($association === null) { Auth_OpenID_FileStore::_removeIfPresent($association_filename); } else { if ($association->getExpiresIn() == 0) { $all_associations[] = array($association_filename, $association); } } } } return $all_associations; }
function test_expiredAssoc() { // Store an expired association for the server with the handle // that is in the query $issued = time() - 10; $lifetime = 0; $handle = 'handle'; $assoc = new Auth_OpenID_Association($handle, 'secret', $issued, $lifetime, 'HMAC-SHA1'); $this->assertTrue($assoc->getExpiresIn() <= 0); $this->store->storeAssociation($this->server_url, $assoc); $query = array('openid.return_to' => $this->return_to, 'openid.identity' => $this->server_id, 'openid.sig' => 'bogus', 'openid.signed' => 'identity,return_to', 'openid.assoc_handle' => $handle); $message = Auth_OpenID_Message::fromPostArgs($query); $this->consumer->disableReturnToChecking(); $info = $this->_doIdRes($message, $this->endpoint, null); $this->assertEquals('failure', $info->status); $this->assertTrue(strpos($info->message, 'expired') !== false); }
function test_invalidate() { $assoc_handle = '-squash-'; $assoc = Auth_OpenID_Association::fromExpiresIn(60, $assoc_handle, 'sekrit', 'HMAC-SHA1'); $this->store->storeAssociation($this->dumb_key, $assoc); $assoc = $this->signatory->getAssociation($assoc_handle, true); $this->assertTrue($assoc); $assoc = $this->signatory->getAssociation($assoc_handle, true); $this->assertTrue($assoc); $this->signatory->invalidate($assoc_handle, true); $assoc = $this->signatory->getAssociation($assoc_handle, true); $this->assertFalse($assoc); }
/** * @access private */ function _parseAssociation($results, $assoc_session, $server_url) { $required_keys = array('assoc_type', 'assoc_handle', 'expires_in'); foreach ($required_keys as $key) { if (!array_key_exists($key, $results)) { return null; } } $assoc_type = $results['assoc_type']; $assoc_handle = $results['assoc_handle']; $expires_in_str = $results['expires_in']; if ($assoc_type != 'HMAC-SHA1') { return null; } $expires_in = intval($expires_in_str); if ($expires_in <= 0) { return null; } $session_type = Auth_OpenID::arrayGet($results, 'session_type'); if ($session_type != $assoc_session->session_type) { if ($session_type === null) { $assoc_session = new Auth_OpenID_PlainTextConsumerSession(); } else { return null; } } $secret = $assoc_session->extractSecret($results); if (!$secret) { return null; } $assoc = Auth_OpenID_Association::fromExpiresIn($expires_in, $assoc_handle, $secret, $assoc_type); $this->store->storeAssociation($server_url, $assoc); return $assoc; }
function test_expiredAssoc() { // Store an expired association for the server with the handle // that is in the query $issued = time() - 10; $lifetime = 0; $handle = 'handle'; $assoc = new Auth_OpenID_Association($handle, 'secret', $issued, $lifetime, 'HMAC-SHA1'); $this->assertTrue($assoc->getExpiresIn() <= 0); $this->store->storeAssociation($this->server_url, $assoc); $query = array('openid.return_to' => $this->return_to, 'openid.identity' => $this->server_id, 'openid.assoc_handle' => $handle); $info = $this->_doIdRes($query); $this->assertEquals('failure', $info->status); $this->assertEquals($this->consumer_id, $info->identity_url); $this->assertTrue(strpos($info->message, 'expired') !== false); }
/** * Remove expired entries from the database. This is potentially * expensive, so only run when it is acceptable to take time. */ function clean() { if (!$this->active) { trigger_error("FileStore no longer active", E_USER_ERROR); return null; } $nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir); $now = time(); // Check all nonces for expiry foreach ($nonces as $nonce) { $filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce; $st = @stat($filename); if ($st !== false) { // Remove the nonce if it has expired $nonce_age = $now - $st[9]; if ($nonce_age > $this->max_nonce_age) { Auth_OpenID_FileStore::_removeIfPresent($filename); } } } $association_filenames = Auth_OpenID_FileStore::_listdir($this->association_dir); foreach ($association_filenames as $association_filename) { $association_file = fopen($association_filename, 'rb'); if ($association_file !== false) { $assoc_s = fread($association_file, filesize($association_filename)); fclose($association_file); // Remove expired or corrupted associations $association = Auth_OpenID_Association::deserialize('Auth_OpenID_Association', $assoc_s); if ($association === null) { Auth_OpenID_FileStore::_removeIfPresent($association_filename); } else { if ($association->getExpiresIn() == 0) { Auth_OpenID_FileStore::_removeIfPresent($association_filename); } } } } }
function _getKnownAssociation($server_url, $handle) { global $wgMemc; $k = $this->_associationKey($server_url, $handle); $v = $wgMemc->get($k); if ($v !== false && strlen($v) > 0) { # FIXME: why is this nl getting lost? $v .= "\n"; $assoc = Auth_OpenID_Association::deserialize('Auth_OpenID_Association', $v); if ($assoc->getExpiresIn() > 0) { return $assoc; } else { return null; } } }