public function testOpenidWrapperRunModeIdResDbStoreNonceInvalid() { $_GET = self::$requestCheckAuthenticationGet; $_GET['openid_mode'] = 'id_res'; $nonce = '123456'; $_GET['openid_return_to'] = ezcAuthenticationUrl::appendQuery($_GET['openid_return_to'], 'nonce', $nonce); $options = new ezcAuthenticationOpenidOptions(); $options->store = new ezcAuthenticationOpenidDbStore($this->db); $credentials = new ezcAuthenticationIdCredentials(self::$url); $filter = new ezcAuthenticationOpenidWrapper($options); $result = $filter->run($credentials); $this->assertEquals(ezcAuthenticationOpenidFilter::STATUS_NONCE_INCORRECT, $result); }
/** * Runs the filter and returns a status code when finished. * * @throws ezcAuthenticationOpenidModeNotSupportedException * if trying to authenticate with an unsupported OpenID mode * * @param ezcAuthenticationIdCredentials $credentials Authentication credentials * @return int */ public function run($credentials) { $source = $this->options->requestSource; $mode = isset($source['openid_mode']) ? strtolower($source['openid_mode']) : null; switch ($mode) { case null: if (empty($credentials->id)) { return self::STATUS_URL_INCORRECT; } $providers = $this->discover($credentials->id); // @todo add support for multiple URLs in each category if (!isset($providers['openid.server'][0])) { return self::STATUS_URL_INCORRECT; } $provider = $providers['openid.server'][0]; // if a delegate is found, it is used instead of the credentials $identity = isset($providers['openid.delegate'][0]) ? $providers['openid.delegate'][0] : $credentials->id; $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : null; $path = isset($_SERVER["REQUEST_URI"]) ? $_SERVER["REQUEST_URI"] : null; if ($this->options->mode === self::MODE_SMART) { $store = $this->options->store; if ($store !== null) { $association = $store->getAssociation($provider); if ($association === false || time() - $association->issued > $association->validity) { $lib = ezcAuthenticationMath::createBignumLibrary(); $p = self::DEFAULT_P; $q = self::DEFAULT_Q; $private = $lib->rand($p); $public = $lib->powmod($q, $private, $p); $params = array('openid.mode' => 'associate', 'openid.assoc_type' => 'HMAC-SHA1', 'openid.dh_modulus' => urlencode(base64_encode($lib->btwoc($p))), 'openid.dh_gen' => 2, urlencode(base64_encode($lib->btwoc($q))), 'openid.dh_consumer_public' => urlencode(base64_encode($lib->btwoc($public)))); $result = $this->associate($provider, $params); $secret = isset($result['enc_mac_key']) ? $result['enc_mac_key'] : $result['mac_key']; $association = new ezcAuthenticationOpenidAssociation($result['assoc_handle'], $secret, time(), $result['expires_in'], $result['assoc_type']); $store->storeAssociation($provider, $association); } } } $nonce = $this->generateNonce($this->options->nonceLength); $returnUrl = $this->options->returnUrl; if ($returnUrl === null) { $returnUrl = "http://{$host}{$path}"; } $returnTo = ezcAuthenticationUrl::appendQuery($returnUrl, $this->options->nonceKey, $nonce); $trustRoot = "http://{$host}"; if ($this->options->store !== null) { $this->options->store->storeNonce($nonce); } $params = array('openid.return_to' => urlencode($returnTo), 'openid.trust_root' => urlencode($trustRoot), 'openid.identity' => urlencode($identity)); if (count($this->requestedData) > 0) { $params['openid.sreg.optional'] = implode(',', $this->requestedData); } if ($this->options->mode === self::MODE_SMART) { $store = $this->options->store; if ($store !== null) { $association = $store->getAssociation($provider); if ($association !== false && time() - $association->issued <= $association->validity) { $params['openid.assoc_handle'] = urlencode($association->handle); } } } if ($this->options->immediate === true) { $params['openid.mode'] = 'checkid_immediate'; $response = $this->checkImmediate($provider, $params); if ($response !== false) { $this->setupUrl = $response; return self::STATUS_SETUP_URL; } else { return self::STATUS_URL_INCORRECT; } } else { $params['openid.mode'] = 'checkid_setup'; $this->redirectToOpenidProvider($provider, $params); } break; case 'id_res': $assocHandle = isset($source['openid_assoc_handle']) ? $source['openid_assoc_handle'] : null; $identity = isset($source['openid_identity']) ? $source['openid_identity'] : null; $sig = isset($source['openid_sig']) ? $source['openid_sig'] : null; $signed = isset($source['openid_signed']) ? $source['openid_signed'] : null; $returnTo = isset($source['openid_return_to']) ? $source['openid_return_to'] : null; if ($this->options->store !== null) { $nonce = ezcAuthenticationUrl::fetchQuery($returnTo, $this->options->nonceKey); if ($nonce !== null) { $nonceTimestamp = $this->options->store->useNonce($nonce); if ($nonceTimestamp === false || time() - $nonceTimestamp > $this->options->nonceValidity) { return self::STATUS_NONCE_INCORRECT; } } } $params = array('openid.assoc_handle' => $assocHandle, 'openid.signed' => $signed, 'openid.sig' => $sig, 'openid.mode' => 'id_res'); $signed = explode(',', $signed); for ($i = 0; $i < count($signed); $i++) { $s = str_replace('sreg.', 'sreg_', $signed[$i]); $c = $source['openid_' . $s]; $params['openid.' . $signed[$i]] = isset($params['openid.' . $s]) ? $params['openid.' . $s] : $c; if (strpos($s, 'sreg_') !== false) { $this->data[str_replace('sreg_', '', $s)] = array($c); } } if (isset($source['openid_op_endpoint'])) { // if the endpoint is available then use it, otherwise discover it $provider = $source['openid_op_endpoint']; } else { // @todo cache this somewhere (in the request URL for example) $providers = $this->discover($credentials->id); if (!isset($providers['openid.server'][0])) { return self::STATUS_URL_INCORRECT; } $provider = $providers['openid.server'][0]; } if ($this->options->mode === self::MODE_SMART) { $store = $this->options->store; if ($store !== null) { $association = $store->getAssociation($provider); if ($association !== false && time() - $association->issued <= $association->validity) { if ($this->checkSignatureSmart($association, $params)) { return self::STATUS_OK; } else { return self::STATUS_SIGNATURE_INCORRECT; } } } } // if smart mode didn't succeed continue with the dumb mode as usual $params['openid.mode'] = 'check_authentication'; foreach ($params as $key => $value) { $params[$key] = urlencode($value); } if ($this->checkSignature($provider, $params)) { return self::STATUS_OK; } break; case 'checkid_setup': return self::STATUS_CANCELLED; case 'cancel': return self::STATUS_CANCELLED; default: throw new ezcAuthenticationOpenidModeNotSupportedException($mode); } return self::STATUS_SIGNATURE_INCORRECT; }
public function testUrlAppendQueryEmpty() { $url = self::$urlEmpty; $result = ezcAuthenticationUrl::appendQuery($url, 'nonce', '123456'); $expected = '?nonce=123456'; $this->assertEquals($expected, $result); }
/** * Returns an array of parameters for use in an OpenID check_id request. * * @param string $id The OpenID identifier from the user * @param array(string) $providers OpenID providers retrieved during discovery * @return array(string=>array) */ public function createCheckidRequest($id, array $providers) { $provider = $providers['openid.server'][0]; // if a delegate is found, it is used instead of the credentials $identity = isset($providers['openid.delegate'][0]) ? $providers['openid.delegate'][0] : $id; $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : null; $path = isset($_SERVER["REQUEST_URI"]) ? $_SERVER["REQUEST_URI"] : null; if ($this->options->mode === self::MODE_SMART) { $store = $this->options->store; if ($store !== null) { $association = $store->getAssociation($provider); if ($association === false || time() - $association->issued > $association->validity) { $params = $this->createAssociateRequest(); $result = $this->associate($provider, $params); $secret = isset($result['enc_mac_key']) ? $result['enc_mac_key'] : $result['mac_key']; $association = new ezcAuthenticationOpenidAssociation($result['assoc_handle'], $secret, time(), $result['expires_in'], $result['assoc_type']); $store->storeAssociation($provider, $association); } } } $returnUrl = $this->options->returnUrl; if ($returnUrl === null) { $returnUrl = "http://{$host}{$path}"; } $nonce = $this->generateNonce($this->options->nonceLength); $returnTo = ezcAuthenticationUrl::appendQuery($returnUrl, $this->options->nonceKey, $nonce); $trustRoot = "http://{$host}"; if ($this->options->mode === self::MODE_SMART && $store !== null) { $store->storeNonce($nonce); } $params = array('openid.return_to' => urlencode($returnTo), 'openid.trust_root' => urlencode($trustRoot), 'openid.identity' => urlencode($id)); if ($this->options->openidVersion === self::VERSION_2_0) { $params['openid.identity'] = urlencode('http://specs.openid.net/auth/2.0/identifier_select'); $params['openid.claimed_id'] = urlencode('http://specs.openid.net/auth/2.0/identifier_select'); $params['openid.realm'] = urlencode($trustRoot); $params['openid.ns'] = urlencode('http://specs.openid.net/auth/2.0'); } if (count($this->requestedData) > 0) { $params['openid.sreg.optional'] = implode(',', $this->requestedData); $params['openid.ns.sreg'] = urlencode('http://openid.net/sreg/1.0'); } if ($this->options->mode === self::MODE_SMART && $store !== null) { $association = $store->getAssociation($provider); if ($association !== false && time() - $association->issued <= $association->validity) { $params['openid.assoc_handle'] = urlencode($association->handle); } } return $params; }