/** * Verifies authentication response from OpenID server. * * This is the second step of OpenID authentication process. * The function returns true on successful authentication and false on * failure. * * @param array $params HTTP query data from OpenID server * @param string &$identity this argument is set to end-user's claimed * identifier or OpenID provider local identifier. * @param mixed $extensions extension object or array of extensions objects * @return bool */ public function verify($params, &$identity = "", $extensions = null) { $this->_setError(''); $version = 1.1; if (isset($params['openid_ns']) && $params['openid_ns'] == Zend_OpenId::NS_2_0) { $version = 2.0; } if (isset($params["openid_claimed_id"])) { $identity = $params["openid_claimed_id"]; } else { if (isset($params["openid_identity"])) { $identity = $params["openid_identity"]; } else { $identity = ""; } } if ($version < 2.0 && !isset($params["openid_claimed_id"])) { if ($this->_session !== null) { if ($this->_session->identity === $identity) { $identity = $this->_session->claimed_id; } } else { if (defined('SID')) { if (isset($_SESSION["zend_openid"]["identity"]) && isset($_SESSION["zend_openid"]["claimed_id"]) && $_SESSION["zend_openid"]["identity"] === $identity) { $identity = $_SESSION["zend_openid"]["claimed_id"]; } } else { require_once "Zend/Session/Namespace.php"; $this->_session = new Zend_Session_Namespace("zend_openid"); if ($this->_session->identity === $identity) { $identity = $this->_session->claimed_id; } } } } if (empty($params['openid_mode'])) { $this->_setError("Missing openid.mode"); return false; } if (empty($params['openid_return_to'])) { $this->_setError("Missing openid.return_to"); return false; } if (empty($params['openid_signed'])) { $this->_setError("Missing openid.signed"); return false; } if (empty($params['openid_sig'])) { $this->_setError("Missing openid.sig"); return false; } if ($params['openid_mode'] != 'id_res') { $this->_setError("Wrong openid.mode '" . $params['openid_mode'] . "' != 'id_res'"); return false; } if (empty($params['openid_assoc_handle'])) { $this->_setError("Missing openid.assoc_handle"); return false; } if ($params['openid_return_to'] != Zend_OpenId::selfUrl()) { /* Ignore query part in openid.return_to */ $pos = strpos($params['openid_return_to'], '?'); if ($pos === false || SUBSTR($params['openid_return_to'], 0, $pos) != Zend_OpenId::selfUrl()) { $this->_setError("Wrong openid.return_to '" . $params['openid_return_to'] . "' != '" . Zend_OpenId::selfUrl() . "'"); return false; } } if ($version >= 2.0) { if (empty($params['openid_response_nonce'])) { $this->_setError("Missing openid.response_nonce"); return false; } if (empty($params['openid_op_endpoint'])) { $this->_setError("Missing openid.op_endpoint"); return false; /* OpenID 2.0 (11.3) Checking the Nonce */ } else { if (!$this->_storage->isUniqueNonce($params['openid_op_endpoint'], $params['openid_response_nonce'])) { $this->_setError("Duplicate openid.response_nonce"); return false; } } } if (!empty($params['openid_invalidate_handle'])) { if ($this->_storage->getAssociationByHandle($params['openid_invalidate_handle'], $url, $macFunc, $secret, $expires)) { $this->_storage->delAssociation($url); } } if ($this->_storage->getAssociationByHandle($params['openid_assoc_handle'], $url, $macFunc, $secret, $expires)) { // Security fix - check the association bewteen op_endpoint and assoc_handle if (isset($params['openid_op_endpoint']) && $url !== $params['openid_op_endpoint']) { $this->_setError("The op_endpoint URI is not the same of URI associated with the assoc_handle"); return false; } $signed = explode(',', $params['openid_signed']); // Check the parameters for the signature // @see https://openid.net/specs/openid-authentication-2_0.html#positive_assertions $toCheck = $this->_signParams; if (isset($params['openid_claimed_id']) && isset($params['openid_identity'])) { $toCheck = array_merge($toCheck, array('claimed_id', 'identity')); } foreach ($toCheck as $param) { if (!in_array($param, $signed, true)) { $this->_setError("The required parameter {$param} is missing in the signed"); return false; } } $data = ''; foreach ($signed as $key) { $data .= $key . ':' . $params['openid_' . strtr($key, '.', '_')] . "\n"; } if (base64_decode($params['openid_sig']) == Zend_OpenId::hashHmac($macFunc, $data, $secret)) { if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) { $this->_setError("Extension::parseResponse failure"); return false; } /* OpenID 2.0 (11.2) Verifying Discovered Information */ if (isset($params['openid_claimed_id'])) { $id = $params['openid_claimed_id']; if (!Zend_OpenId::normalize($id)) { $this->_setError("Normalization failed"); return false; } else { if (!$this->_discovery($id, $discovered_server, $discovered_version)) { $this->_setError("Discovery failed: " . $this->getError()); return false; } else { if (!empty($params['openid_identity']) && $params["openid_identity"] != $id || !empty($params['openid_op_endpoint']) && $params['openid_op_endpoint'] != $discovered_server || $discovered_version != $version) { $this->_setError("Discovery information verification failed"); return false; } } } } return true; } $this->_storage->delAssociation($url); $this->_setError("Signature check failed"); return false; } else { /* Use dumb mode */ if (isset($params['openid_claimed_id'])) { $id = $params['openid_claimed_id']; } else { if (isset($params['openid_identity'])) { $id = $params['openid_identity']; } else { $this->_setError("Missing openid.claimed_id and openid.identity"); return false; } } if (!Zend_OpenId::normalize($id)) { $this->_setError("Normalization failed"); return false; } else { if (!$this->_discovery($id, $server, $discovered_version)) { $this->_setError("Discovery failed: " . $this->getError()); return false; } } /* OpenID 2.0 (11.2) Verifying Discovered Information */ if (isset($params['openid_identity']) && $params["openid_identity"] != $id || isset($params['openid_op_endpoint']) && $params['openid_op_endpoint'] != $server || $discovered_version != $version) { $this->_setError("Discovery information verification failed"); return false; } $params2 = array(); foreach ($params as $key => $val) { if (strpos($key, 'openid_ns_') === 0) { $key = 'openid.ns.' . substr($key, strlen('openid_ns_')); } else { if (strpos($key, 'openid_sreg_') === 0) { $key = 'openid.sreg.' . substr($key, strlen('openid_sreg_')); } else { if (strpos($key, 'openid_') === 0) { $key = 'openid.' . substr($key, strlen('openid_')); } } } $params2[$key] = $val; } $params2['openid.mode'] = 'check_authentication'; $ret = $this->_httpRequest($server, 'POST', $params2, $status); if ($status != 200) { $this->_setError("'Dumb' signature verification HTTP request failed"); return false; } $r = array(); if (is_string($ret)) { foreach (explode("\n", $ret) as $line) { $line = trim($line); if (!empty($line)) { $x = explode(':', $line, 2); if (is_array($x) && count($x) == 2) { list($key, $value) = $x; $r[trim($key)] = trim($value); } } } } $ret = $r; if (!empty($ret['invalidate_handle'])) { if ($this->_storage->getAssociationByHandle($ret['invalidate_handle'], $url, $macFunc, $secret, $expires)) { $this->_storage->delAssociation($url); } } if (isset($ret['is_valid']) && $ret['is_valid'] == 'true') { if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) { $this->_setError("Extension::parseResponse failure"); return false; } return true; } $this->_setError("'Dumb' signature verification failed"); return false; } }
/** * Verifies authentication response from OpenID server. * * This is the second step of OpenID authentication process. * The function returns true on successful authentication and false on * failure. * * @param array $params HTTP query data from OpenID server * @param string &$identity this argument is set to end-user's claimed * identifier or OpenID provider local identifier. * @param mixed $extensions extension object or array of extensions objects * @return bool */ public function verify($params, &$identity = "", $extensions = null) { $version = 1.1; if (isset($params['openid_ns']) && $params['openid_ns'] == Zend_OpenId::NS_2_0) { $version = 2.0; } if (isset($params["openid_claimed_id"])) { $identity = $params["openid_claimed_id"]; } else { if (isset($params["openid_identity"])) { $identity = $params["openid_identity"]; } else { $identity = ""; } } if ($version < 2.0 && !isset($params["openid_claimed_id"])) { if ($this->_session === null) { require_once "Zend/Session/Namespace.php"; $this->_session = new Zend_Session_Namespace("zend_openid"); } $session = $this->_session; if ($session->identity == $identity) { $identity = $session->claimed_id; } } if (empty($params['openid_return_to']) || empty($params['openid_signed']) || empty($params['openid_sig']) || empty($params['openid_mode']) || empty($params['openid_assoc_handle']) || $params['openid_mode'] != 'id_res' || $params['openid_return_to'] != Zend_OpenId::selfUrl()) { return false; } if ($version >= 2.0) { if (empty($params['openid_response_nonce']) || empty($params['openid_op_endpoint'])) { return false; /* OpenID 2.0 (11.3) Checking the Nonce */ } else { if (!$this->_storage->isUniqueNonce($params['openid_op_endpoint'], $params['openid_response_nonce'])) { return false; } } } if (!empty($params['openid_invalidate_handle'])) { if ($this->_storage->getAssociationByHandle($params['openid_invalidate_handle'], $url, $macFunc, $secret, $expires)) { $this->_storage->delAssociation($url); } } if ($this->_storage->getAssociationByHandle($params['openid_assoc_handle'], $url, $macFunc, $secret, $expires)) { $signed = explode(',', $params['openid_signed']); $data = ''; foreach ($signed as $key) { $data .= $key . ':' . $params['openid_' . strtr($key, '.', '_')] . "\n"; } if (base64_decode($params['openid_sig']) == Zend_OpenId::hashHmac($macFunc, $data, $secret)) { if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) { return false; } /* OpenID 2.0 (11.2) Verifying Discovered Information */ if (isset($params['openid_claimed_id'])) { $id = $params['openid_claimed_id']; if (!Zend_OpenId::normalize($id) || !$this->_discovery($id, $discovered_server, $discovered_version) || isset($params['openid_identity']) && $params["openid_identity"] != $id || isset($params['openid_op_endpoint']) && $params['openid_op_endpoint'] != $discovered_server || $discovered_version != $version) { return false; } } return true; } $this->_storage->delAssociation($url); return false; } else { /* Use dumb mode */ if (isset($params['openid_claimed_id'])) { $id = $params['openid_claimed_id']; } else { if (isset($params['openid_identity'])) { $id = $params['openid_identity']; } else { return false; } } if (!$this->_discovery($id, $server, $discovered_version)) { return false; } /* OpenID 2.0 (11.2) Verifying Discovered Information */ if (isset($params['openid_identity']) && $params["openid_identity"] != $id || isset($params['openid_op_endpoint']) && $params['openid_op_endpoint'] != $server || $discovered_version != $version) { return false; } $params2 = array(); foreach ($params as $key => $val) { if (strpos($key, 'openid_ns_') === 0) { $key = 'openid.ns.' . substr($key, strlen('openid_ns_')); } else { if (strpos($key, 'openid_sreg_') === 0) { $key = 'openid.sreg.' . substr($key, strlen('openid_sreg_')); } else { if (strpos($key, 'openid_') === 0) { $key = 'openid.' . substr($key, strlen('openid_')); } } } $params2[$key] = $val; } $params2['openid.mode'] = 'check_authentication'; $ret = $this->_httpRequest($server, 'POST', $params2, $status); if ($status != 200) { return false; } $r = array(); if (is_string($ret)) { foreach (explode("\n", $ret) as $line) { $line = trim($line); if (!empty($line)) { $x = explode(':', $line, 2); if (is_array($x) && count($x) == 2) { list($key, $value) = $x; $r[trim($key)] = trim($value); } } } } $ret = $r; if (!empty($ret['invalidate_handle'])) { if ($this->_storage->getAssociationByHandle($ret['invalidate_handle'], $url, $macFunc, $secret, $expires)) { $this->_storage->delAssociation($url); } } if (isset($ret['is_valid']) && $ret['is_valid'] == 'true') { if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) { return false; } return true; } return false; } }