function verify($assoc_handle, $sig, $signed_pairs) { $assoc = $this->getAssociation($assoc_handle, true); if (!$assoc) { // oidutil.log("failed to get assoc with handle %r to verify sig %r" // % (assoc_handle, sig)) return false; } $expected_sig = base64_encode($assoc->sign($signed_pairs)); return $sig == $expected_sig; } /** * Given a response, sign the fields in the response's 'signed' * list, and insert the signature into the response. */ function sign($response) { $signed_response = $response; $assoc_handle = $response->request->assoc_handle; if ($assoc_handle) { // normal mode $assoc = $this->getAssociation($assoc_handle, false); if (!$assoc) { // fall back to dumb mode $signed_response->fields['invalidate_handle'] = $assoc_handle; $assoc = $this->createAssociation(true); } } else { // dumb mode. $assoc = $this->createAssociation(true); } $signed_response->fields['assoc_handle'] = $assoc->handle; $assoc->addSignature($signed_response->signed, $signed_response->fields, ''); return $signed_response; } /** * Make a new association. */ function createAssociation($dumb = true, $assoc_type = 'HMAC-SHA1') { $secret = Auth_OpenID_CryptUtil::getBytes(20); $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; } /** * Given an association handle, get the association from the * store, or return a ServerError or null if something goes wrong. */ function getAssociation($assoc_handle, $dumb) { if ($assoc_handle === null) { return new Auth_OpenID_ServerError(null, "assoc_handle must not be null"); } if ($dumb) { $key = $this->dumb_key; } else { $key = $this->normal_key; } $assoc = $this->store->getAssociation($key, $assoc_handle); if (($assoc !== null) && ($assoc->getExpiresIn() <= 0)) { $this->store->removeAssociation($key, $assoc_handle); $assoc = null; } return $assoc; } /** * Invalidate a given association handle. */ function invalidate($assoc_handle, $dumb) { if ($dumb) { $key = $this->dumb_key; } else { $key = $this->normal_key; } $this->store->removeAssociation($key, $assoc_handle); } } /** * Encode an Auth_OpenID_Response to an Auth_OpenID_WebResponse. * * @package OpenID */ class Auth_OpenID_Encoder { var $responseFactory = 'Auth_OpenID_WebResponse'; /** * Encode an Auth_OpenID_Response and return an * Auth_OpenID_WebResponse. */ function encode(&$response) { global $_Auth_OpenID_Encode_Kvform, $_Auth_OpenID_Encode_Url; $cls = $this->responseFactory; $encode_as = $response->whichEncoding(); if ($encode_as == $_Auth_OpenID_Encode_Kvform) { $wr = new $cls(null, null, $response->encodeToKVForm()); if (is_a($response, 'Auth_OpenID_ServerError')) { $wr->code = AUTH_OPENID_HTTP_ERROR; } } else if ($encode_as == $_Auth_OpenID_Encode_Url) { $location = $response->encodeToURL(); $wr = new $cls(AUTH_OPENID_HTTP_REDIRECT, array('location' => $location)); } else { return new Auth_OpenID_EncodingError($response); } return $wr; } } /** * Returns true if the given response needs a signature. * * @access private */ function needsSigning($response) { return (in_array($response->request->mode, array('checkid_setup', 'checkid_immediate')) && $response->signed); } /** * An encoder which also takes care of signing fields when required. * * @package OpenID */ class Auth_OpenID_SigningEncoder extends Auth_OpenID_Encoder { function Auth_OpenID_SigningEncoder(&$signatory) { $this->signatory =& $signatory; } /** * Sign an Auth_OpenID_Response and return an * Auth_OpenID_WebResponse. */ function encode(&$response) { // the isinstance is a bit of a kludge... it means there isn't // really an adapter to make the interfaces quite match. if (!is_a($response, 'Auth_OpenID_ServerError') && needsSigning($response)) { if (!$this->signatory) { return new Auth_OpenID_ServerError(null, "Must have a store to sign request"); } if (array_key_exists('sig', $response->fields)) { return new Auth_OpenID_AlreadySigned($response); } $response = $this->signatory->sign($response); } return parent::encode($response); } } /** * Decode an incoming Auth_OpenID_WebResponse into an * Auth_OpenID_Request. * * @package OpenID */ class Auth_OpenID_Decoder { function Auth_OpenID_Decoder() { global $_Auth_OpenID_OpenID_Prefix; $this->prefix = $_Auth_OpenID_OpenID_Prefix; $this->handlers = array( 'checkid_setup' => 'Auth_OpenID_CheckIDRequest', 'checkid_immediate' => 'Auth_OpenID_CheckIDRequest', 'check_authentication' => 'Auth_OpenID_CheckAuthRequest', 'associate' => 'Auth_OpenID_AssociateRequest' ); } /** * Given an HTTP query in an array (key-value pairs), decode it * into an Auth_OpenID_Request object. */ function decode($query) { if (!$query) { return null; } $myquery = array(); foreach ($query as $k => $v) { if (strpos($k, $this->prefix) === 0) { $myquery[$k] = $v; } } if (!$myquery) { return null; } $mode = Auth_OpenID::arrayGet($myquery, $this->prefix . 'mode'); if (!$mode) { return new Auth_OpenID_ServerError($query, sprintf("No %s mode found in query", $this->prefix)); } $handlerCls = Auth_OpenID::arrayGet($this->handlers, $mode, $this->defaultDecoder($query)); if (!is_a($handlerCls, 'Auth_OpenID_ServerError')) { return call_user_func_array(array($handlerCls, 'fromQuery'), array($query)); } else { return $handlerCls; } } fun