/branches/v1.5-belier/composants/openid/Auth/OpenID.php |
---|
New file |
0,0 → 1,412 |
<?php |
/** |
* This is the PHP OpenID library by JanRain, Inc. |
* |
* This module contains core utility functionality used by the |
* library. See Consumer.php and Server.php for the consumer and |
* server implementations. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Require the fetcher code. |
*/ |
require_once "Services/Yadis/PlainHTTPFetcher.php"; |
require_once "Services/Yadis/ParanoidHTTPFetcher.php"; |
require_once "Auth/OpenID/BigMath.php"; |
/** |
* Status code returned by the server when the only option is to show |
* an error page, since we do not have enough information to redirect |
* back to the consumer. The associated value is an error message that |
* should be displayed on an HTML error page. |
* |
* @see Auth_OpenID_Server |
*/ |
define('Auth_OpenID_LOCAL_ERROR', 'local_error'); |
/** |
* Status code returned when there is an error to return in key-value |
* form to the consumer. The caller should return a 400 Bad Request |
* response with content-type text/plain and the value as the body. |
* |
* @see Auth_OpenID_Server |
*/ |
define('Auth_OpenID_REMOTE_ERROR', 'remote_error'); |
/** |
* Status code returned when there is a key-value form OK response to |
* the consumer. The value associated with this code is the |
* response. The caller should return a 200 OK response with |
* content-type text/plain and the value as the body. |
* |
* @see Auth_OpenID_Server |
*/ |
define('Auth_OpenID_REMOTE_OK', 'remote_ok'); |
/** |
* Status code returned when there is a redirect back to the |
* consumer. The value is the URL to redirect back to. The caller |
* should return a 302 Found redirect with a Location: header |
* containing the URL. |
* |
* @see Auth_OpenID_Server |
*/ |
define('Auth_OpenID_REDIRECT', 'redirect'); |
/** |
* Status code returned when the caller needs to authenticate the |
* user. The associated value is a {@link Auth_OpenID_ServerRequest} |
* object that can be used to complete the authentication. If the user |
* has taken some authentication action, use the retry() method of the |
* {@link Auth_OpenID_ServerRequest} object to complete the request. |
* |
* @see Auth_OpenID_Server |
*/ |
define('Auth_OpenID_DO_AUTH', 'do_auth'); |
/** |
* Status code returned when there were no OpenID arguments |
* passed. This code indicates that the caller should return a 200 OK |
* response and display an HTML page that says that this is an OpenID |
* server endpoint. |
* |
* @see Auth_OpenID_Server |
*/ |
define('Auth_OpenID_DO_ABOUT', 'do_about'); |
/** |
* Defines for regexes and format checking. |
*/ |
define('Auth_OpenID_letters', |
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); |
define('Auth_OpenID_digits', |
"0123456789"); |
define('Auth_OpenID_punct', |
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"); |
if (Auth_OpenID_getMathLib() === null) { |
define('Auth_OpenID_NO_MATH_SUPPORT', true); |
} |
/** |
* The OpenID utility function class. |
* |
* @package OpenID |
* @access private |
*/ |
class Auth_OpenID { |
/** |
* These namespaces are automatically fixed in query arguments by |
* Auth_OpenID::fixArgs. |
*/ |
function getOpenIDNamespaces() |
{ |
return array('openid', |
'sreg'); |
} |
/** |
* Rename query arguments back to 'openid.' from 'openid_' |
* |
* @access private |
* @param array $args An associative array of URL query arguments |
*/ |
function fixArgs($args) |
{ |
foreach (array_keys($args) as $key) { |
$fixed = $key; |
if (preg_match('/^openid/', $key)) { |
foreach (Auth_OpenID::getOpenIDNamespaces() as $ns) { |
if (preg_match('/'.$ns.'_/', $key)) { |
$fixed = preg_replace('/'.$ns.'_/', $ns.'.', $fixed); |
} |
} |
if ($fixed != $key) { |
$val = $args[$key]; |
unset($args[$key]); |
$args[$fixed] = $val; |
} |
} |
} |
return $args; |
} |
/** |
* Create dir_name as a directory if it does not exist. If it |
* exists, make sure that it is, in fact, a directory. Returns |
* true if the operation succeeded; false if not. |
* |
* @access private |
*/ |
function ensureDir($dir_name) |
{ |
if (is_dir($dir_name) || @mkdir($dir_name)) { |
return true; |
} else { |
if (Auth_OpenID::ensureDir(dirname($dir_name))) { |
return is_dir($dir_name) || @mkdir($dir_name); |
} else { |
return false; |
} |
} |
} |
/** |
* Convenience function for getting array values. |
* |
* @access private |
*/ |
function arrayGet($arr, $key, $fallback = null) |
{ |
if (is_array($arr)) { |
if (array_key_exists($key, $arr)) { |
return $arr[$key]; |
} else { |
return $fallback; |
} |
} else { |
trigger_error("Auth_OpenID::arrayGet expected " . |
"array as first parameter", E_USER_WARNING); |
return false; |
} |
} |
/** |
* Implements the PHP 5 'http_build_query' functionality. |
* |
* @access private |
* @param array $data Either an array key/value pairs or an array |
* of arrays, each of which holding two values: a key and a value, |
* sequentially. |
* @return string $result The result of url-encoding the key/value |
* pairs from $data into a URL query string |
* (e.g. "username=bob&id=56"). |
*/ |
function httpBuildQuery($data) |
{ |
$pairs = array(); |
foreach ($data as $key => $value) { |
if (is_array($value)) { |
$pairs[] = urlencode($value[0])."=".urlencode($value[1]); |
} else { |
$pairs[] = urlencode($key)."=".urlencode($value); |
} |
} |
return implode("&", $pairs); |
} |
/** |
* "Appends" query arguments onto a URL. The URL may or may not |
* already have arguments (following a question mark). |
* |
* @param string $url A URL, which may or may not already have |
* arguments. |
* @param array $args Either an array key/value pairs or an array of |
* arrays, each of which holding two values: a key and a value, |
* sequentially. If $args is an ordinary key/value array, the |
* parameters will be added to the URL in sorted alphabetical order; |
* if $args is an array of arrays, their order will be preserved. |
* @return string $url The original URL with the new parameters added. |
* |
*/ |
function appendArgs($url, $args) |
{ |
if (count($args) == 0) { |
return $url; |
} |
// Non-empty array; if it is an array of arrays, use |
// multisort; otherwise use sort. |
if (array_key_exists(0, $args) && |
is_array($args[0])) { |
// Do nothing here. |
} else { |
$keys = array_keys($args); |
sort($keys); |
$new_args = array(); |
foreach ($keys as $key) { |
$new_args[] = array($key, $args[$key]); |
} |
$args = $new_args; |
} |
$sep = '?'; |
if (strpos($url, '?') !== false) { |
$sep = '&'; |
} |
return $url . $sep . Auth_OpenID::httpBuildQuery($args); |
} |
/** |
* Turn a string into an ASCII string. |
* |
* Replace non-ascii characters with a %-encoded, UTF-8 |
* encoding. This function will fail if the input is a string and |
* there are non-7-bit-safe characters. It is assumed that the |
* caller will have already translated the input into a Unicode |
* character sequence, according to the encoding of the HTTP POST |
* or GET. |
* |
* Do not escape anything that is already 7-bit safe, so we do the |
* minimal transform on the identity URL |
* |
* @access private |
*/ |
function quoteMinimal($s) |
{ |
$res = array(); |
for ($i = 0; $i < strlen($s); $i++) { |
$c = $s[$i]; |
if ($c >= "\x80") { |
for ($j = 0; $j < count(utf8_encode($c)); $j++) { |
array_push($res, sprintf("%02X", ord($c[$j]))); |
} |
} else { |
array_push($res, $c); |
} |
} |
return implode('', $res); |
} |
/** |
* Implements python's urlunparse, which is not available in PHP. |
* Given the specified components of a URL, this function rebuilds |
* and returns the URL. |
* |
* @access private |
* @param string $scheme The scheme (e.g. 'http'). Defaults to 'http'. |
* @param string $host The host. Required. |
* @param string $port The port. |
* @param string $path The path. |
* @param string $query The query. |
* @param string $fragment The fragment. |
* @return string $url The URL resulting from assembling the |
* specified components. |
*/ |
function urlunparse($scheme, $host, $port = null, $path = '/', |
$query = '', $fragment = '') |
{ |
if (!$scheme) { |
$scheme = 'http'; |
} |
if (!$host) { |
return false; |
} |
if (!$path) { |
$path = '/'; |
} |
$result = $scheme . "://" . $host; |
if ($port) { |
$result .= ":" . $port; |
} |
$result .= $path; |
if ($query) { |
$result .= "?" . $query; |
} |
if ($fragment) { |
$result .= "#" . $fragment; |
} |
return $result; |
} |
/** |
* Given a URL, this "normalizes" it by adding a trailing slash |
* and / or a leading http:// scheme where necessary. Returns |
* null if the original URL is malformed and cannot be normalized. |
* |
* @access private |
* @param string $url The URL to be normalized. |
* @return mixed $new_url The URL after normalization, or null if |
* $url was malformed. |
*/ |
function normalizeUrl($url) |
{ |
if ($url === null) { |
return null; |
} |
assert(is_string($url)); |
$old_url = $url; |
$url = trim($url); |
if (strpos($url, "://") === false) { |
$url = "http://" . $url; |
} |
$parsed = @parse_url($url); |
if ($parsed === false) { |
return null; |
} |
$defaults = array( |
'scheme' => '', |
'host' => '', |
'path' => '', |
'query' => '', |
'fragment' => '', |
'port' => '' |
); |
$parsed = array_merge($defaults, $parsed); |
if (($parsed['scheme'] == '') || |
($parsed['host'] == '')) { |
if ($parsed['path'] == '' && |
$parsed['query'] == '' && |
$parsed['fragment'] == '') { |
return null; |
} |
$url = 'http://' + $url; |
$parsed = parse_url($url); |
$parsed = array_merge($defaults, $parsed); |
} |
$tail = array_map(array('Auth_OpenID', 'quoteMinimal'), |
array($parsed['path'], |
$parsed['query'], |
$parsed['fragment'])); |
if ($tail[0] == '') { |
$tail[0] = '/'; |
} |
$url = Auth_OpenID::urlunparse($parsed['scheme'], $parsed['host'], |
$parsed['port'], $tail[0], $tail[1], |
$tail[2]); |
assert(is_string($url)); |
return $url; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/KVForm.php |
---|
New file |
0,0 → 1,112 |
<?php |
/** |
* OpenID protocol key-value/comma-newline format parsing and |
* serialization |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @access private |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Container for key-value/comma-newline OpenID format and parsing |
*/ |
class Auth_OpenID_KVForm { |
/** |
* Convert an OpenID colon/newline separated string into an |
* associative array |
* |
* @static |
* @access private |
*/ |
function toArray($kvs, $strict=false) |
{ |
$lines = explode("\n", $kvs); |
$last = array_pop($lines); |
if ($last !== '') { |
array_push($lines, $last); |
if ($strict) { |
return false; |
} |
} |
$values = array(); |
for ($lineno = 0; $lineno < count($lines); $lineno++) { |
$line = $lines[$lineno]; |
$kv = explode(':', $line, 2); |
if (count($kv) != 2) { |
if ($strict) { |
return false; |
} |
continue; |
} |
$key = $kv[0]; |
$tkey = trim($key); |
if ($tkey != $key) { |
if ($strict) { |
return false; |
} |
} |
$value = $kv[1]; |
$tval = trim($value); |
if ($tval != $value) { |
if ($strict) { |
return false; |
} |
} |
$values[$tkey] = $tval; |
} |
return $values; |
} |
/** |
* Convert an array into an OpenID colon/newline separated string |
* |
* @static |
* @access private |
*/ |
function fromArray($values) |
{ |
if ($values === null) { |
return null; |
} |
ksort($values); |
$serialized = ''; |
foreach ($values as $key => $value) { |
if (is_array($value)) { |
list($key, $value) = array($value[0], $value[1]); |
} |
if (strpos($key, ':') !== false) { |
return null; |
} |
if (strpos($key, "\n") !== false) { |
return null; |
} |
if (strpos($value, "\n") !== false) { |
return null; |
} |
$serialized .= "$key:$value\n"; |
} |
return $serialized; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/DumbStore.php |
---|
New file |
0,0 → 1,116 |
<?php |
/** |
* This file supplies a dumb store backend for OpenID servers and |
* consumers. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Import the interface for creating a new store class. |
*/ |
require_once 'Auth/OpenID/Interface.php'; |
require_once 'Auth/OpenID/HMACSHA1.php'; |
/** |
* This is a store for use in the worst case, when you have no way of |
* saving state on the consumer site. Using this store makes the |
* consumer vulnerable to replay attacks, as it's unable to use |
* nonces. Avoid using this store if it is at all possible. |
* |
* Most of the methods of this class are implementation details. |
* Users of this class need to worry only about the constructor. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore { |
/** |
* Creates a new {@link Auth_OpenID_DumbStore} instance. For the security |
* of the tokens generated by the library, this class attempts to |
* at least have a secure implementation of getAuthKey. |
* |
* When you create an instance of this class, pass in a secret |
* phrase. The phrase is hashed with sha1 to make it the correct |
* length and form for an auth key. That allows you to use a long |
* string as the secret phrase, which means you can make it very |
* difficult to guess. |
* |
* Each {@link Auth_OpenID_DumbStore} instance that is created for use by |
* your consumer site needs to use the same $secret_phrase. |
* |
* @param string secret_phrase The phrase used to create the auth |
* key returned by getAuthKey |
*/ |
function Auth_OpenID_DumbStore($secret_phrase) |
{ |
$this->auth_key = Auth_OpenID_SHA1($secret_phrase); |
} |
/** |
* This implementation does nothing. |
*/ |
function storeAssociation($server_url, $association) |
{ |
} |
/** |
* This implementation always returns null. |
*/ |
function getAssociation($server_url, $handle = null) |
{ |
return null; |
} |
/** |
* This implementation always returns false. |
*/ |
function removeAssociation($server_url, $handle) |
{ |
return false; |
} |
/** |
* This implementation does nothing. |
*/ |
function storeNonce($nonce) |
{ |
} |
/** |
* In a system truly limited to dumb mode, nonces must all be |
* accepted. This therefore always returns true, which makes |
* replay attacks feasible. |
*/ |
function useNonce($nonce) |
{ |
return true; |
} |
/** |
* This method returns the auth key generated by the constructor. |
*/ |
function getAuthKey() |
{ |
return $this->auth_key; |
} |
/** |
* This store is a dumb mode store, so this method is overridden |
* to return true. |
*/ |
function isDumb() |
{ |
return true; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/Server.php |
---|
New file |
0,0 → 1,1307 |
<?php |
/** |
* OpenID server protocol and logic. |
* |
* Overview |
* |
* An OpenID server must perform three tasks: |
* |
* 1. Examine the incoming request to determine its nature and validity. |
* 2. Make a decision about how to respond to this request. |
* 3. Format the response according to the protocol. |
* |
* The first and last of these tasks may performed by the |
* 'decodeRequest' and 'encodeResponse' methods of the |
* Auth_OpenID_Server object. Who gets to do the intermediate task -- |
* deciding how to respond to the request -- will depend on what type |
* of request it is. |
* |
* If it's a request to authenticate a user (a 'checkid_setup' or |
* 'checkid_immediate' request), you need to decide if you will assert |
* that this user may claim the identity in question. Exactly how you |
* do that is a matter of application policy, but it generally |
* involves making sure the user has an account with your system and |
* is logged in, checking to see if that identity is hers to claim, |
* and verifying with the user that she does consent to releasing that |
* information to the party making the request. |
* |
* Examine the properties of the Auth_OpenID_CheckIDRequest object, |
* and if and when you've come to a decision, form a response by |
* calling Auth_OpenID_CheckIDRequest::answer. |
* |
* Other types of requests relate to establishing associations between |
* client and server and verifing the authenticity of previous |
* communications. Auth_OpenID_Server contains all the logic and data |
* necessary to respond to such requests; just pass it to |
* Auth_OpenID_Server::handleRequest. |
* |
* OpenID Extensions |
* |
* Do you want to provide other information for your users in addition |
* to authentication? Version 1.2 of the OpenID protocol allows |
* consumers to add extensions to their requests. For example, with |
* sites using the Simple Registration |
* Extension |
* (http://www.openidenabled.com/openid/simple-registration-extension/), |
* a user can agree to have their nickname and e-mail address sent to |
* a site when they sign up. |
* |
* Since extensions do not change the way OpenID authentication works, |
* code to handle extension requests may be completely separate from |
* the Auth_OpenID_Request class here. But you'll likely want data |
* sent back by your extension to be signed. Auth_OpenID_Response |
* provides methods with which you can add data to it which can be |
* signed with the other data in the OpenID signature. |
* |
* For example: |
* |
* // when request is a checkid_* request |
* response = request.answer(True) |
* // this will a signed 'openid.sreg.timezone' parameter to the response |
* response.addField('sreg', 'timezone', 'America/Los_Angeles') |
* |
* Stores |
* |
* The OpenID server needs to maintain state between requests in order |
* to function. Its mechanism for doing this is called a store. The |
* store interface is defined in Interface.php. Additionally, several |
* concrete store implementations are provided, so that most sites |
* won't need to implement a custom store. For a store backed by flat |
* files on disk, see Auth_OpenID_FileStore. For stores based on |
* MySQL, SQLite, or PostgreSQL, see the Auth_OpenID_SQLStore |
* subclasses. |
* |
* Upgrading |
* |
* The keys by which a server looks up associations in its store have |
* changed in version 1.2 of this library. If your store has entries |
* created from version 1.0 code, you should empty it. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Required imports |
*/ |
require_once "Auth/OpenID.php"; |
require_once "Auth/OpenID/Association.php"; |
require_once "Auth/OpenID/CryptUtil.php"; |
require_once "Auth/OpenID/BigMath.php"; |
require_once "Auth/OpenID/DiffieHellman.php"; |
require_once "Auth/OpenID/KVForm.php"; |
require_once "Auth/OpenID/TrustRoot.php"; |
require_once "Auth/OpenID/ServerRequest.php"; |
define('AUTH_OPENID_HTTP_OK', 200); |
define('AUTH_OPENID_HTTP_REDIRECT', 302); |
define('AUTH_OPENID_HTTP_ERROR', 400); |
global $_Auth_OpenID_Request_Modes, |
$_Auth_OpenID_OpenID_Prefix, |
$_Auth_OpenID_Encode_Kvform, |
$_Auth_OpenID_Encode_Url; |
/** |
* @access private |
*/ |
$_Auth_OpenID_Request_Modes = array('checkid_setup', |
'checkid_immediate'); |
/** |
* @access private |
*/ |
$_Auth_OpenID_OpenID_Prefix = "openid."; |
/** |
* @access private |
*/ |
$_Auth_OpenID_Encode_Kvform = array('kfvorm'); |
/** |
* @access private |
*/ |
$_Auth_OpenID_Encode_Url = array('URL/redirect'); |
/** |
* @access private |
*/ |
function _isError($obj, $cls = 'Auth_OpenID_ServerError') |
{ |
return is_a($obj, $cls); |
} |
/** |
* An error class which gets instantiated and returned whenever an |
* OpenID protocol error occurs. Be prepared to use this in place of |
* an ordinary server response. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_ServerError { |
/** |
* @access private |
*/ |
function Auth_OpenID_ServerError($query = null, $message = null) |
{ |
$this->message = $message; |
$this->query = $query; |
} |
/** |
* Returns the return_to URL for the request which caused this |
* error. |
*/ |
function hasReturnTo() |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
if ($this->query) { |
return array_key_exists($_Auth_OpenID_OpenID_Prefix . |
'return_to', $this->query); |
} else { |
return false; |
} |
} |
/** |
* Encodes this error's response as a URL suitable for |
* redirection. If the response has no return_to, another |
* Auth_OpenID_ServerError is returned. |
*/ |
function encodeToURL() |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$return_to = Auth_OpenID::arrayGet($this->query, |
$_Auth_OpenID_OpenID_Prefix . |
'return_to'); |
if (!$return_to) { |
return new Auth_OpenID_ServerError(null, "no return_to URL"); |
} |
return Auth_OpenID::appendArgs($return_to, |
array('openid.mode' => 'error', |
'openid.error' => $this->toString())); |
} |
/** |
* Encodes the response to key-value form. This is a |
* machine-readable format used to respond to messages which came |
* directly from the consumer and not through the user-agent. See |
* the OpenID specification. |
*/ |
function encodeToKVForm() |
{ |
return Auth_OpenID_KVForm::fromArray( |
array('mode' => 'error', |
'error' => $this->toString())); |
} |
/** |
* Returns one of $_Auth_OpenID_Encode_Url, |
* $_Auth_OpenID_Encode_Kvform, or null, depending on the type of |
* encoding expected for this error's payload. |
*/ |
function whichEncoding() |
{ |
global $_Auth_OpenID_Encode_Url, |
$_Auth_OpenID_Encode_Kvform, |
$_Auth_OpenID_Request_Modes; |
if ($this->hasReturnTo()) { |
return $_Auth_OpenID_Encode_Url; |
} |
$mode = Auth_OpenID::arrayGet($this->query, 'openid.mode'); |
if ($mode) { |
if (!in_array($mode, $_Auth_OpenID_Request_Modes)) { |
return $_Auth_OpenID_Encode_Kvform; |
} |
} |
return null; |
} |
/** |
* Returns this error message. |
*/ |
function toString() |
{ |
if ($this->message) { |
return $this->message; |
} else { |
return get_class($this) . " error"; |
} |
} |
} |
/** |
* An error indicating that the return_to URL is malformed. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_MalformedReturnURL extends Auth_OpenID_ServerError { |
function Auth_OpenID_MalformedReturnURL($query, $return_to) |
{ |
$this->return_to = $return_to; |
parent::Auth_OpenID_ServerError($query, "malformed return_to URL"); |
} |
} |
/** |
* This error is returned when the trust_root value is malformed. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_MalformedTrustRoot extends Auth_OpenID_ServerError { |
function toString() |
{ |
return "Malformed trust root"; |
} |
} |
/** |
* The base class for all server request classes. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_Request { |
var $mode = null; |
} |
/** |
* A request to verify the validity of a previous response. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_CheckAuthRequest extends Auth_OpenID_Request { |
var $mode = "check_authentication"; |
var $invalidate_handle = null; |
function Auth_OpenID_CheckAuthRequest($assoc_handle, $sig, $signed, |
$invalidate_handle = null) |
{ |
$this->assoc_handle = $assoc_handle; |
$this->sig = $sig; |
$this->signed = $signed; |
if ($invalidate_handle !== null) { |
$this->invalidate_handle = $invalidate_handle; |
} |
} |
function fromQuery($query) |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$required_keys = array('assoc_handle', 'sig', 'signed'); |
foreach ($required_keys as $k) { |
if (!array_key_exists($_Auth_OpenID_OpenID_Prefix . $k, |
$query)) { |
return new Auth_OpenID_ServerError($query, |
sprintf("%s request missing required parameter %s from \ |
query", "check_authentication", $k)); |
} |
} |
$assoc_handle = $query[$_Auth_OpenID_OpenID_Prefix . 'assoc_handle']; |
$sig = $query[$_Auth_OpenID_OpenID_Prefix . 'sig']; |
$signed_list = $query[$_Auth_OpenID_OpenID_Prefix . 'signed']; |
$signed_list = explode(",", $signed_list); |
$signed_pairs = array(); |
foreach ($signed_list as $field) { |
if ($field == 'mode') { |
// XXX KLUDGE HAX WEB PROTOCoL BR0KENNN |
// |
// openid.mode is currently check_authentication |
// because that's the mode of this request. But the |
// signature was made on something with a different |
// openid.mode. |
$value = "id_res"; |
} else { |
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . $field, |
$query)) { |
$value = $query[$_Auth_OpenID_OpenID_Prefix . $field]; |
} else { |
return new Auth_OpenID_ServerError($query, |
sprintf("Couldn't find signed field %r in query %s", |
$field, var_export($query, true))); |
} |
} |
$signed_pairs[] = array($field, $value); |
} |
$result = new Auth_OpenID_CheckAuthRequest($assoc_handle, $sig, |
$signed_pairs); |
$result->invalidate_handle = Auth_OpenID::arrayGet($query, |
$_Auth_OpenID_OpenID_Prefix . 'invalidate_handle'); |
return $result; |
} |
function answer(&$signatory) |
{ |
$is_valid = $signatory->verify($this->assoc_handle, $this->sig, |
$this->signed); |
// Now invalidate that assoc_handle so it this checkAuth |
// message cannot be replayed. |
$signatory->invalidate($this->assoc_handle, true); |
$response = new Auth_OpenID_ServerResponse($this); |
$response->fields['is_valid'] = $is_valid ? "true" : "false"; |
if ($this->invalidate_handle) { |
$assoc = $signatory->getAssociation($this->invalidate_handle, |
false); |
if (!$assoc) { |
$response->fields['invalidate_handle'] = |
$this->invalidate_handle; |
} |
} |
return $response; |
} |
} |
class Auth_OpenID_PlainTextServerSession { |
/** |
* An object that knows how to handle association requests with no |
* session type. |
*/ |
var $session_type = 'plaintext'; |
function fromQuery($unused_request) |
{ |
return new Auth_OpenID_PlainTextServerSession(); |
} |
function answer($secret) |
{ |
return array('mac_key' => base64_encode($secret)); |
} |
} |
class Auth_OpenID_DiffieHellmanServerSession { |
/** |
* An object that knows how to handle association requests with |
* the Diffie-Hellman session type. |
*/ |
var $session_type = 'DH-SHA1'; |
function Auth_OpenID_DiffieHellmanServerSession($dh, $consumer_pubkey) |
{ |
$this->dh = $dh; |
$this->consumer_pubkey = $consumer_pubkey; |
} |
function fromQuery($query) |
{ |
$dh_modulus = Auth_OpenID::arrayGet($query, 'openid.dh_modulus'); |
$dh_gen = Auth_OpenID::arrayGet($query, 'openid.dh_gen'); |
if ((($dh_modulus === null) && ($dh_gen !== null)) || |
(($dh_gen === null) && ($dh_modulus !== null))) { |
if ($dh_modulus === null) { |
$missing = 'modulus'; |
} else { |
$missing = 'generator'; |
} |
return new Auth_OpenID_ServerError( |
'If non-default modulus or generator is '. |
'supplied, both must be supplied. Missing '. |
$missing); |
} |
$lib =& Auth_OpenID_getMathLib(); |
if ($dh_modulus || $dh_gen) { |
$dh_modulus = $lib->base64ToLong($dh_modulus); |
$dh_gen = $lib->base64ToLong($dh_gen); |
if ($lib->cmp($dh_modulus, 0) == 0 || |
$lib->cmp($dh_gen, 0) == 0) { |
return new Auth_OpenID_ServerError( |
$query, "Failed to parse dh_mod or dh_gen"); |
} |
$dh = new Auth_OpenID_DiffieHellman($dh_modulus, $dh_gen); |
} else { |
$dh = new Auth_OpenID_DiffieHellman(); |
} |
$consumer_pubkey = Auth_OpenID::arrayGet($query, |
'openid.dh_consumer_public'); |
if ($consumer_pubkey === null) { |
return new Auth_OpenID_ServerError( |
'Public key for DH-SHA1 session '. |
'not found in query'); |
} |
$consumer_pubkey = |
$lib->base64ToLong($consumer_pubkey); |
if ($consumer_pubkey === false) { |
return new Auth_OpenID_ServerError($query, |
"dh_consumer_public is not base64"); |
} |
return new Auth_OpenID_DiffieHellmanServerSession($dh, |
$consumer_pubkey); |
} |
function answer($secret) |
{ |
$lib =& Auth_OpenID_getMathLib(); |
$mac_key = $this->dh->xorSecret($this->consumer_pubkey, $secret); |
return array( |
'dh_server_public' => |
$lib->longToBase64($this->dh->public), |
'enc_mac_key' => base64_encode($mac_key)); |
} |
} |
/** |
* A request to associate with the server. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request { |
var $mode = "associate"; |
var $assoc_type = 'HMAC-SHA1'; |
function Auth_OpenID_AssociateRequest(&$session) |
{ |
$this->session =& $session; |
} |
function fromQuery($query) |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$session_classes = array( |
'DH-SHA1' => 'Auth_OpenID_DiffieHellmanServerSession', |
null => 'Auth_OpenID_PlainTextServerSession'); |
$session_type = null; |
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . 'session_type', |
$query)) { |
$session_type = $query[$_Auth_OpenID_OpenID_Prefix . |
'session_type']; |
} |
if (!array_key_exists($session_type, $session_classes)) { |
return new Auth_OpenID_ServerError($query, |
"Unknown session type $session_type"); |
} |
$session_cls = $session_classes[$session_type]; |
$session = call_user_func_array(array($session_cls, 'fromQuery'), |
array($query)); |
if (($session === null) || (_isError($session))) { |
return new Auth_OpenID_ServerError($query, |
"Error parsing $session_type session"); |
} |
return new Auth_OpenID_AssociateRequest($session); |
} |
function answer($assoc) |
{ |
$ml =& Auth_OpenID_getMathLib(); |
$response = new Auth_OpenID_ServerResponse($this); |
$response->fields = array('expires_in' => $assoc->getExpiresIn(), |
'assoc_type' => 'HMAC-SHA1', |
'assoc_handle' => $assoc->handle); |
$r = $this->session->answer($assoc->secret); |
foreach ($r as $k => $v) { |
$response->fields[$k] = $v; |
} |
if ($this->session->session_type != 'plaintext') { |
$response->fields['session_type'] = $this->session->session_type; |
} |
return $response; |
} |
} |
/** |
* A request to confirm the identity of a user. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request { |
var $mode = "checkid_setup"; // or "checkid_immediate" |
var $immediate = false; |
var $trust_root = null; |
function make($query, $identity, $return_to, $trust_root = null, |
$immediate = false, $assoc_handle = null) |
{ |
if (!Auth_OpenID_TrustRoot::_parse($return_to)) { |
return new Auth_OpenID_MalformedReturnURL($query, $return_to); |
} |
$r = new Auth_OpenID_CheckIDRequest($identity, $return_to, |
$trust_root, $immediate, |
$assoc_handle); |
if (!$r->trustRootValid()) { |
return new Auth_OpenID_UntrustedReturnURL($return_to, |
$trust_root); |
} else { |
return $r; |
} |
} |
function Auth_OpenID_CheckIDRequest($identity, $return_to, |
$trust_root = null, $immediate = false, |
$assoc_handle = null) |
{ |
$this->identity = $identity; |
$this->return_to = $return_to; |
$this->trust_root = $trust_root; |
$this->assoc_handle = $assoc_handle; |
if ($immediate) { |
$this->immediate = true; |
$this->mode = "checkid_immediate"; |
} else { |
$this->immediate = false; |
$this->mode = "checkid_setup"; |
} |
} |
function fromQuery($query) |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$mode = $query[$_Auth_OpenID_OpenID_Prefix . 'mode']; |
$immediate = null; |
if ($mode == "checkid_immediate") { |
$immediate = true; |
$mode = "checkid_immediate"; |
} else { |
$immediate = false; |
$mode = "checkid_setup"; |
} |
$required = array('identity', |
'return_to'); |
$optional = array('trust_root', |
'assoc_handle'); |
$values = array(); |
foreach ($required as $field) { |
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . $field, |
$query)) { |
$value = $query[$_Auth_OpenID_OpenID_Prefix . $field]; |
} else { |
return new Auth_OpenID_ServerError($query, |
sprintf("Missing required field %s from request", |
$field)); |
} |
$values[$field] = $value; |
} |
foreach ($optional as $field) { |
$value = null; |
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . $field, |
$query)) { |
$value = $query[$_Auth_OpenID_OpenID_Prefix. $field]; |
} |
if ($value) { |
$values[$field] = $value; |
} |
} |
if (!Auth_OpenID_TrustRoot::_parse($values['return_to'])) { |
return new Auth_OpenID_MalformedReturnURL($query, |
$values['return_to']); |
} |
$obj = Auth_OpenID_CheckIDRequest::make($query, |
$values['identity'], |
$values['return_to'], |
Auth_OpenID::arrayGet($values, |
'trust_root', null), |
$immediate); |
if (is_a($obj, 'Auth_OpenID_ServerError')) { |
return $obj; |
} |
if (Auth_OpenID::arrayGet($values, 'assoc_handle')) { |
$obj->assoc_handle = $values['assoc_handle']; |
} |
return $obj; |
} |
function trustRootValid() |
{ |
if (!$this->trust_root) { |
return true; |
} |
$tr = Auth_OpenID_TrustRoot::_parse($this->trust_root); |
if ($tr === false) { |
return new Auth_OpenID_MalformedTrustRoot(null, $this->trust_root); |
} |
return Auth_OpenID_TrustRoot::match($this->trust_root, |
$this->return_to); |
} |
function answer($allow, $server_url = null) |
{ |
if ($allow || $this->immediate) { |
$mode = 'id_res'; |
} else { |
$mode = 'cancel'; |
} |
$response = new Auth_OpenID_CheckIDResponse($this, $mode); |
if ($allow) { |
$response->fields['identity'] = $this->identity; |
$response->fields['return_to'] = $this->return_to; |
if (!$this->trustRootValid()) { |
return new Auth_OpenID_UntrustedReturnURL($this->return_to, |
$this->trust_root); |
} |
} else { |
$response->signed = array(); |
if ($this->immediate) { |
if (!$server_url) { |
return new Auth_OpenID_ServerError(null, |
'setup_url is required for $allow=false \ |
in immediate mode.'); |
} |
$setup_request =& new Auth_OpenID_CheckIDRequest( |
$this->identity, |
$this->return_to, |
$this->trust_root, |
false, |
$this->assoc_handle); |
$setup_url = $setup_request->encodeToURL($server_url); |
$response->fields['user_setup_url'] = $setup_url; |
} |
} |
return $response; |
} |
function encodeToURL($server_url) |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
// Imported from the alternate reality where these classes are |
// used in both the client and server code, so Requests are |
// Encodable too. That's right, code imported from alternate |
// realities all for the love of you, id_res/user_setup_url. |
$q = array('mode' => $this->mode, |
'identity' => $this->identity, |
'return_to' => $this->return_to); |
if ($this->trust_root) { |
$q['trust_root'] = $this->trust_root; |
} |
if ($this->assoc_handle) { |
$q['assoc_handle'] = $this->assoc_handle; |
} |
$_q = array(); |
foreach ($q as $k => $v) { |
$_q[$_Auth_OpenID_OpenID_Prefix . $k] = $v; |
} |
return Auth_OpenID::appendArgs($server_url, $_q); |
} |
function getCancelURL() |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
if ($this->immediate) { |
return new Auth_OpenID_ServerError(null, |
"Cancel is not an appropriate \ |
response to immediate mode \ |
requests."); |
} |
return Auth_OpenID::appendArgs($this->return_to, |
array($_Auth_OpenID_OpenID_Prefix . 'mode' => |
'cancel')); |
} |
} |
/** |
* This class encapsulates the response to an OpenID server request. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_ServerResponse { |
function Auth_OpenID_ServerResponse($request) |
{ |
$this->request = $request; |
$this->fields = array(); |
} |
function whichEncoding() |
{ |
global $_Auth_OpenID_Encode_Kvform, |
$_Auth_OpenID_Request_Modes, |
$_Auth_OpenID_Encode_Url; |
if (in_array($this->request->mode, $_Auth_OpenID_Request_Modes)) { |
return $_Auth_OpenID_Encode_Url; |
} else { |
return $_Auth_OpenID_Encode_Kvform; |
} |
} |
function encodeToURL() |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$fields = array(); |
foreach ($this->fields as $k => $v) { |
$fields[$_Auth_OpenID_OpenID_Prefix . $k] = $v; |
} |
return Auth_OpenID::appendArgs($this->request->return_to, $fields); |
} |
function encodeToKVForm() |
{ |
return Auth_OpenID_KVForm::fromArray($this->fields); |
} |
} |
/** |
* A response to a checkid request. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_CheckIDResponse extends Auth_OpenID_ServerResponse { |
function Auth_OpenID_CheckIDResponse(&$request, $mode = 'id_res') |
{ |
parent::Auth_OpenID_ServerResponse($request); |
$this->fields['mode'] = $mode; |
$this->signed = array(); |
if ($mode == 'id_res') { |
array_push($this->signed, 'mode', 'identity', 'return_to'); |
} |
} |
function addField($namespace, $key, $value, $signed = true) |
{ |
if ($namespace) { |
$key = sprintf('%s.%s', $namespace, $key); |
} |
$this->fields[$key] = $value; |
if ($signed && !in_array($key, $this->signed)) { |
$this->signed[] = $key; |
} |
} |
function addFields($namespace, $fields, $signed = true) |
{ |
foreach ($fields as $k => $v) { |
$this->addField($namespace, $k, $v, $signed); |
} |
} |
function update($namespace, $other) |
{ |
$namespaced_fields = array(); |
foreach ($other->fields as $k => $v) { |
$name = sprintf('%s.%s', $namespace, $k); |
$namespaced_fields[$name] = $v; |
} |
$this->fields = array_merge($this->fields, $namespaced_fields); |
$this->signed = array_merge($this->signed, $other->signed); |
} |
} |
/** |
* A web-capable response object which you can use to generate a |
* user-agent response. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_WebResponse { |
var $code = AUTH_OPENID_HTTP_OK; |
var $body = ""; |
function Auth_OpenID_WebResponse($code = null, $headers = null, |
$body = null) |
{ |
if ($code) { |
$this->code = $code; |
} |
if ($headers !== null) { |
$this->headers = $headers; |
} else { |
$this->headers = array(); |
} |
if ($body !== null) { |
$this->body = $body; |
} |
} |
} |
/** |
* Responsible for the signature of query data and the verification of |
* OpenID signature values. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_Signatory { |
// = 14 * 24 * 60 * 60; # 14 days, in seconds |
var $SECRET_LIFETIME = 1209600; |
// keys have a bogus server URL in them because the filestore |
// really does expect that key to be a URL. This seems a little |
// silly for the server store, since I expect there to be only one |
// server URL. |
var $normal_key = 'http://localhost/|normal'; |
var $dumb_key = 'http://localhost/|dumb'; |
/** |
* Create a new signatory using a given store. |
*/ |
function Auth_OpenID_Signatory(&$store) |
{ |
// assert store is not None |
$this->store =& $store; |
} |
/** |
* Verify, using a given association handle, a signature with |
* signed key-value pairs from an HTTP request. |
*/ |
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; |
} |
} |
function defaultDecoder($query) |
{ |
$mode = $query[$this->prefix . 'mode']; |
return new Auth_OpenID_ServerError($query, |
sprintf("No decoder for mode %s", $mode)); |
} |
} |
/** |
* An error that indicates an encoding problem occurred. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_EncodingError { |
function Auth_OpenID_EncodingError(&$response) |
{ |
$this->response =& $response; |
} |
} |
/** |
* An error that indicates that a response was already signed. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_AlreadySigned extends Auth_OpenID_EncodingError { |
// This response is already signed. |
} |
/** |
* An error that indicates that the given return_to is not under the |
* given trust_root. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_UntrustedReturnURL extends Auth_OpenID_ServerError { |
function Auth_OpenID_UntrustedReturnURL($return_to, $trust_root) |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$query = array( |
$_Auth_OpenID_OpenID_Prefix . 'return_to' => $return_to, |
$_Auth_OpenID_OpenID_Prefix . 'trust_root' => $trust_root); |
parent::Auth_OpenID_ServerError($query); |
} |
function toString() |
{ |
global $_Auth_OpenID_OpenID_Prefix; |
$return_to = $this->query[$_Auth_OpenID_OpenID_Prefix . 'return_to']; |
$trust_root = $this->query[$_Auth_OpenID_OpenID_Prefix . 'trust_root']; |
return sprintf("return_to %s not under trust_root %s", |
$return_to, $trust_root); |
} |
} |
/** |
* An object that implements the OpenID protocol for a single URL. |
* |
* Use this object by calling getOpenIDResponse when you get any |
* request for the server URL. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_Server { |
function Auth_OpenID_Server(&$store) |
{ |
$this->store =& $store; |
$this->signatory =& new Auth_OpenID_Signatory($this->store); |
$this->encoder =& new Auth_OpenID_SigningEncoder($this->signatory); |
$this->decoder =& new Auth_OpenID_Decoder(); |
} |
/** |
* Handle a request. Given an Auth_OpenID_Request object, call |
* the appropriate Auth_OpenID_Server method to process the |
* request and generate a response. |
* |
* @param Auth_OpenID_Request $request An Auth_OpenID_Request |
* returned by Auth_OpenID_Server::decodeRequest. |
* |
* @return Auth_OpenID_Response $response A response object |
* capable of generating a user-agent reply. |
*/ |
function handleRequest($request) |
{ |
if (method_exists($this, "openid_" . $request->mode)) { |
$handler = array($this, "openid_" . $request->mode); |
return call_user_func($handler, $request); |
} |
return null; |
} |
/** |
* The callback for 'check_authentication' messages. |
* |
* @access private |
*/ |
function openid_check_authentication(&$request) |
{ |
return $request->answer($this->signatory); |
} |
/** |
* The callback for 'associate' messages. |
* |
* @access private |
*/ |
function openid_associate(&$request) |
{ |
$assoc = $this->signatory->createAssociation(false); |
return $request->answer($assoc); |
} |
/** |
* Encodes as response in the appropriate format suitable for |
* sending to the user agent. |
*/ |
function encodeResponse(&$response) |
{ |
return $this->encoder->encode($response); |
} |
/** |
* Decodes a query args array into the appropriate |
* Auth_OpenID_Request object. |
*/ |
function decodeRequest(&$query) |
{ |
return $this->decoder->decode($query); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/Parse.php |
---|
New file |
0,0 → 1,308 |
<?php |
/** |
* This module implements a VERY limited parser that finds <link> tags |
* in the head of HTML or XHTML documents and parses out their |
* attributes according to the OpenID spec. It is a liberal parser, |
* but it requires these things from the data in order to work: |
* |
* - There must be an open <html> tag |
* |
* - There must be an open <head> tag inside of the <html> tag |
* |
* - Only <link>s that are found inside of the <head> tag are parsed |
* (this is by design) |
* |
* - The parser follows the OpenID specification in resolving the |
* attributes of the link tags. This means that the attributes DO |
* NOT get resolved as they would by an XML or HTML parser. In |
* particular, only certain entities get replaced, and href |
* attributes do not get resolved relative to a base URL. |
* |
* From http://openid.net/specs.bml: |
* |
* - The openid.server URL MUST be an absolute URL. OpenID consumers |
* MUST NOT attempt to resolve relative URLs. |
* |
* - The openid.server URL MUST NOT include entities other than &, |
* <, >, and ". |
* |
* The parser ignores SGML comments and <![CDATA[blocks]]>. Both kinds |
* of quoting are allowed for attributes. |
* |
* The parser deals with invalid markup in these ways: |
* |
* - Tag names are not case-sensitive |
* |
* - The <html> tag is accepted even when it is not at the top level |
* |
* - The <head> tag is accepted even when it is not a direct child of |
* the <html> tag, but a <html> tag must be an ancestor of the |
* <head> tag |
* |
* - <link> tags are accepted even when they are not direct children |
* of the <head> tag, but a <head> tag must be an ancestor of the |
* <link> tag |
* |
* - If there is no closing tag for an open <html> or <head> tag, the |
* remainder of the document is viewed as being inside of the |
* tag. If there is no closing tag for a <link> tag, the link tag is |
* treated as a short tag. Exceptions to this rule are that <html> |
* closes <html> and <body> or <head> closes <head> |
* |
* - Attributes of the <link> tag are not required to be quoted. |
* |
* - In the case of duplicated attribute names, the attribute coming |
* last in the tag will be the value returned. |
* |
* - Any text that does not parse as an attribute within a link tag |
* will be ignored. (e.g. <link pumpkin rel='openid.server' /> will |
* ignore pumpkin) |
* |
* - If there are more than one <html> or <head> tag, the parser only |
* looks inside of the first one. |
* |
* - The contents of <script> tags are ignored entirely, except |
* unclosed <script> tags. Unclosed <script> tags are ignored. |
* |
* - Any other invalid markup is ignored, including unclosed SGML |
* comments and unclosed <![CDATA[blocks. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @access private |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Require Auth_OpenID::arrayGet(). |
*/ |
require_once "Auth/OpenID.php"; |
class Auth_OpenID_Parse { |
/** |
* Specify some flags for use with regex matching. |
*/ |
var $_re_flags = "si"; |
/** |
* Stuff to remove before we start looking for tags |
*/ |
var $_removed_re = |
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>"; |
/** |
* Starts with the tag name at a word boundary, where the tag name |
* is not a namespace |
*/ |
var $_tag_expr = "<%s\b(?!:)([^>]*?)(?:\/>|>(.*?)(?:<\/?%s\s*>|\Z))"; |
var $_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)'; |
function Auth_OpenID_Parse() |
{ |
$this->_link_find = sprintf("/<link\b(?!:)([^>]*)(?!<)>/%s", |
$this->_re_flags); |
$this->_entity_replacements = array( |
'amp' => '&', |
'lt' => '<', |
'gt' => '>', |
'quot' => '"' |
); |
$this->_attr_find = sprintf("/%s/%s", |
$this->_attr_find, |
$this->_re_flags); |
$this->_removed_re = sprintf("/%s/%s", |
$this->_removed_re, |
$this->_re_flags); |
$this->_ent_replace = |
sprintf("&(%s);", implode("|", |
$this->_entity_replacements)); |
} |
/** |
* Returns a regular expression that will match a given tag in an |
* SGML string. |
*/ |
function tagMatcher($tag_name, $close_tags = null) |
{ |
if ($close_tags) { |
$options = implode("|", array_merge(array($tag_name), $close_tags)); |
$closer = sprintf("(?:%s)", $options); |
} else { |
$closer = $tag_name; |
} |
$expr = sprintf($this->_tag_expr, $tag_name, $closer); |
return sprintf("/%s/%s", $expr, $this->_re_flags); |
} |
function htmlFind() |
{ |
return $this->tagMatcher('html'); |
} |
function headFind() |
{ |
return $this->tagMatcher('head', array('body')); |
} |
function replaceEntities($str) |
{ |
foreach ($this->_entity_replacements as $old => $new) { |
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str); |
} |
return $str; |
} |
function removeQuotes($str) |
{ |
$matches = array(); |
$double = '/^"(.*)"$/'; |
$single = "/^\'(.*)\'$/"; |
if (preg_match($double, $str, $matches)) { |
return $matches[1]; |
} else if (preg_match($single, $str, $matches)) { |
return $matches[1]; |
} else { |
return $str; |
} |
} |
/** |
* Find all link tags in a string representing a HTML document and |
* return a list of their attributes. |
* |
* @param string $html The text to parse |
* @return array $list An array of arrays of attributes, one for each |
* link tag |
*/ |
function parseLinkAttrs($html) |
{ |
$stripped = preg_replace($this->_removed_re, |
"", |
$html); |
// Try to find the <HTML> tag. |
$html_re = $this->htmlFind(); |
$html_matches = array(); |
if (!preg_match($html_re, $stripped, $html_matches)) { |
return array(); |
} |
// Try to find the <HEAD> tag. |
$head_re = $this->headFind(); |
$head_matches = array(); |
if (!preg_match($head_re, $html_matches[0], $head_matches)) { |
return array(); |
} |
$link_data = array(); |
$link_matches = array(); |
if (!preg_match_all($this->_link_find, $head_matches[0], |
$link_matches)) { |
return array(); |
} |
foreach ($link_matches[0] as $link) { |
$attr_matches = array(); |
preg_match_all($this->_attr_find, $link, $attr_matches); |
$link_attrs = array(); |
foreach ($attr_matches[0] as $index => $full_match) { |
$name = $attr_matches[1][$index]; |
$value = $this->replaceEntities( |
$this->removeQuotes($attr_matches[2][$index])); |
$link_attrs[strtolower($name)] = $value; |
} |
$link_data[] = $link_attrs; |
} |
return $link_data; |
} |
function relMatches($rel_attr, $target_rel) |
{ |
// Does this target_rel appear in the rel_str? |
// XXX: TESTME |
$rels = preg_split("/\s+/", trim($rel_attr)); |
foreach ($rels as $rel) { |
$rel = strtolower($rel); |
if ($rel == $target_rel) { |
return 1; |
} |
} |
return 0; |
} |
function linkHasRel($link_attrs, $target_rel) |
{ |
// Does this link have target_rel as a relationship? |
// XXX: TESTME |
$rel_attr = Auth_OpeniD::arrayGet($link_attrs, 'rel', null); |
return ($rel_attr && $this->relMatches($rel_attr, |
$target_rel)); |
} |
function findLinksRel($link_attrs_list, $target_rel) |
{ |
// Filter the list of link attributes on whether it has |
// target_rel as a relationship. |
// XXX: TESTME |
$result = array(); |
foreach ($link_attrs_list as $attr) { |
if ($this->linkHasRel($attr, $target_rel)) { |
$result[] = $attr; |
} |
} |
return $result; |
} |
function findFirstHref($link_attrs_list, $target_rel) |
{ |
// Return the value of the href attribute for the first link |
// tag in the list that has target_rel as a relationship. |
// XXX: TESTME |
$matches = $this->findLinksRel($link_attrs_list, |
$target_rel); |
if (!$matches) { |
return null; |
} |
$first = $matches[0]; |
return Auth_OpenID::arrayGet($first, 'href', null); |
} |
} |
function Auth_OpenID_legacy_discover($html_text) |
{ |
$p = new Auth_OpenID_Parse(); |
$link_attrs = $p->parseLinkAttrs($html_text); |
$server_url = $p->findFirstHref($link_attrs, |
'openid.server'); |
if ($server_url === null) { |
return false; |
} else { |
$delegate_url = $p->findFirstHref($link_attrs, |
'openid.delegate'); |
return array($delegate_url, $server_url); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/BigMath.php |
---|
New file |
0,0 → 1,444 |
<?php |
/** |
* BigMath: A math library wrapper that abstracts out the underlying |
* long integer library. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @access private |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Needed for random number generation |
*/ |
require_once 'Auth/OpenID/CryptUtil.php'; |
/** |
* The superclass of all big-integer math implementations |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_MathLibrary { |
/** |
* Given a long integer, returns the number converted to a binary |
* string. This function accepts long integer values of arbitrary |
* magnitude and uses the local large-number math library when |
* available. |
* |
* @param integer $long The long number (can be a normal PHP |
* integer or a number created by one of the available long number |
* libraries) |
* @return string $binary The binary version of $long |
*/ |
function longToBinary($long) |
{ |
$cmp = $this->cmp($long, 0); |
if ($cmp < 0) { |
$msg = __FUNCTION__ . " takes only positive integers."; |
trigger_error($msg, E_USER_ERROR); |
return null; |
} |
if ($cmp == 0) { |
return "\x00"; |
} |
$bytes = array(); |
while ($this->cmp($long, 0) > 0) { |
array_unshift($bytes, $this->mod($long, 256)); |
$long = $this->div($long, pow(2, 8)); |
} |
if ($bytes && ($bytes[0] > 127)) { |
array_unshift($bytes, 0); |
} |
$string = ''; |
foreach ($bytes as $byte) { |
$string .= pack('C', $byte); |
} |
return $string; |
} |
/** |
* Given a binary string, returns the binary string converted to a |
* long number. |
* |
* @param string $binary The binary version of a long number, |
* probably as a result of calling longToBinary |
* @return integer $long The long number equivalent of the binary |
* string $str |
*/ |
function binaryToLong($str) |
{ |
if ($str === null) { |
return null; |
} |
// Use array_merge to return a zero-indexed array instead of a |
// one-indexed array. |
$bytes = array_merge(unpack('C*', $str)); |
$n = $this->init(0); |
if ($bytes && ($bytes[0] > 127)) { |
trigger_error("bytesToNum works only for positive integers.", |
E_USER_WARNING); |
return null; |
} |
foreach ($bytes as $byte) { |
$n = $this->mul($n, pow(2, 8)); |
$n = $this->add($n, $byte); |
} |
return $n; |
} |
function base64ToLong($str) |
{ |
$b64 = base64_decode($str); |
if ($b64 === false) { |
return false; |
} |
return $this->binaryToLong($b64); |
} |
function longToBase64($str) |
{ |
return base64_encode($this->longToBinary($str)); |
} |
/** |
* Returns a random number in the specified range. This function |
* accepts $start, $stop, and $step values of arbitrary magnitude |
* and will utilize the local large-number math library when |
* available. |
* |
* @param integer $start The start of the range, or the minimum |
* random number to return |
* @param integer $stop The end of the range, or the maximum |
* random number to return |
* @param integer $step The step size, such that $result - ($step |
* * N) = $start for some N |
* @return integer $result The resulting randomly-generated number |
*/ |
function rand($stop) |
{ |
static $duplicate_cache = array(); |
// Used as the key for the duplicate cache |
$rbytes = $this->longToBinary($stop); |
if (array_key_exists($rbytes, $duplicate_cache)) { |
list($duplicate, $nbytes) = $duplicate_cache[$rbytes]; |
} else { |
if ($rbytes[0] == "\x00") { |
$nbytes = strlen($rbytes) - 1; |
} else { |
$nbytes = strlen($rbytes); |
} |
$mxrand = $this->pow(256, $nbytes); |
// If we get a number less than this, then it is in the |
// duplicated range. |
$duplicate = $this->mod($mxrand, $stop); |
if (count($duplicate_cache) > 10) { |
$duplicate_cache = array(); |
} |
$duplicate_cache[$rbytes] = array($duplicate, $nbytes); |
} |
do { |
$bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes); |
$n = $this->binaryToLong($bytes); |
// Keep looping if this value is in the low duplicated range |
} while ($this->cmp($n, $duplicate) < 0); |
return $this->mod($n, $stop); |
} |
} |
/** |
* Exposes BCmath math library functionality. |
* |
* {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided |
* by the BCMath extension. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{ |
var $type = 'bcmath'; |
function add($x, $y) |
{ |
return bcadd($x, $y); |
} |
function sub($x, $y) |
{ |
return bcsub($x, $y); |
} |
function pow($base, $exponent) |
{ |
return bcpow($base, $exponent); |
} |
function cmp($x, $y) |
{ |
return bccomp($x, $y); |
} |
function init($number, $base = 10) |
{ |
return $number; |
} |
function mod($base, $modulus) |
{ |
return bcmod($base, $modulus); |
} |
function mul($x, $y) |
{ |
return bcmul($x, $y); |
} |
function div($x, $y) |
{ |
return bcdiv($x, $y); |
} |
/** |
* Same as bcpowmod when bcpowmod is missing |
* |
* @access private |
*/ |
function _powmod($base, $exponent, $modulus) |
{ |
$square = $this->mod($base, $modulus); |
$result = 1; |
while($this->cmp($exponent, 0) > 0) { |
if ($this->mod($exponent, 2)) { |
$result = $this->mod($this->mul($result, $square), $modulus); |
} |
$square = $this->mod($this->mul($square, $square), $modulus); |
$exponent = $this->div($exponent, 2); |
} |
return $result; |
} |
function powmod($base, $exponent, $modulus) |
{ |
if (function_exists('bcpowmod')) { |
return bcpowmod($base, $exponent, $modulus); |
} else { |
return $this->_powmod($base, $exponent, $modulus); |
} |
} |
function toString($num) |
{ |
return $num; |
} |
} |
/** |
* Exposes GMP math library functionality. |
* |
* {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided |
* by the GMP extension. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{ |
var $type = 'gmp'; |
function add($x, $y) |
{ |
return gmp_add($x, $y); |
} |
function sub($x, $y) |
{ |
return gmp_sub($x, $y); |
} |
function pow($base, $exponent) |
{ |
return gmp_pow($base, $exponent); |
} |
function cmp($x, $y) |
{ |
return gmp_cmp($x, $y); |
} |
function init($number, $base = 10) |
{ |
return gmp_init($number, $base); |
} |
function mod($base, $modulus) |
{ |
return gmp_mod($base, $modulus); |
} |
function mul($x, $y) |
{ |
return gmp_mul($x, $y); |
} |
function div($x, $y) |
{ |
return gmp_div_q($x, $y); |
} |
function powmod($base, $exponent, $modulus) |
{ |
return gmp_powm($base, $exponent, $modulus); |
} |
function toString($num) |
{ |
return gmp_strval($num); |
} |
} |
/** |
* Define the supported extensions. An extension array has keys |
* 'modules', 'extension', and 'class'. 'modules' is an array of PHP |
* module names which the loading code will attempt to load. These |
* values will be suffixed with a library file extension (e.g. ".so"). |
* 'extension' is the name of a PHP extension which will be tested |
* before 'modules' are loaded. 'class' is the string name of a |
* {@link Auth_OpenID_MathWrapper} subclass which should be |
* instantiated if a given extension is present. |
* |
* You can define new math library implementations and add them to |
* this array. |
*/ |
global $_Auth_OpenID_math_extensions; |
$_Auth_OpenID_math_extensions = array( |
array('modules' => array('gmp', 'php_gmp'), |
'extension' => 'gmp', |
'class' => 'Auth_OpenID_GmpMathWrapper'), |
array('modules' => array('bcmath', 'php_bcmath'), |
'extension' => 'bcmath', |
'class' => 'Auth_OpenID_BcMathWrapper') |
); |
/** |
* Detect which (if any) math library is available |
*/ |
function Auth_OpenID_detectMathLibrary($exts) |
{ |
$loaded = false; |
foreach ($exts as $extension) { |
// See if the extension specified is already loaded. |
if ($extension['extension'] && |
extension_loaded($extension['extension'])) { |
$loaded = true; |
} |
// Try to load dynamic modules. |
if (!$loaded) { |
foreach ($extension['modules'] as $module) { |
if (@dl($module . "." . PHP_SHLIB_SUFFIX)) { |
$loaded = true; |
break; |
} |
} |
} |
// If the load succeeded, supply an instance of |
// Auth_OpenID_MathWrapper which wraps the specified |
// module's functionality. |
if ($loaded) { |
return $extension; |
} |
} |
return false; |
} |
/** |
* {@link Auth_OpenID_getMathLib} checks for the presence of long |
* number extension modules and returns an instance of |
* {@link Auth_OpenID_MathWrapper} which exposes the module's |
* functionality. |
* |
* Checks for the existence of an extension module described by the |
* local {@link Auth_OpenID_math_extensions} array and returns an |
* instance of a wrapper for that extension module. If no extension |
* module is found, an instance of {@link Auth_OpenID_MathWrapper} is |
* returned, which wraps the native PHP integer implementation. The |
* proper calling convention for this method is $lib =& |
* Auth_OpenID_getMathLib(). |
* |
* This function checks for the existence of specific long number |
* implementations in the following order: GMP followed by BCmath. |
* |
* @return Auth_OpenID_MathWrapper $instance An instance of |
* {@link Auth_OpenID_MathWrapper} or one of its subclasses |
* |
* @package OpenID |
*/ |
function &Auth_OpenID_getMathLib() |
{ |
// The instance of Auth_OpenID_MathWrapper that we choose to |
// supply will be stored here, so that subseqent calls to this |
// method will return a reference to the same object. |
static $lib = null; |
if (isset($lib)) { |
return $lib; |
} |
if (defined('Auth_OpenID_NO_MATH_SUPPORT')) { |
$null = null; |
return $null; |
} |
// If this method has not been called before, look at |
// $Auth_OpenID_math_extensions and try to find an extension that |
// works. |
global $_Auth_OpenID_math_extensions; |
$ext = Auth_OpenID_detectMathLibrary($_Auth_OpenID_math_extensions); |
if ($ext === false) { |
$tried = array(); |
foreach ($_Auth_OpenID_math_extensions as $extinfo) { |
$tried[] = $extinfo['extension']; |
} |
$triedstr = implode(", ", $tried); |
define('Auth_OpenID_NO_MATH_SUPPORT', true); |
return null; |
} |
// Instantiate a new wrapper |
$class = $ext['class']; |
$lib = new $class(); |
return $lib; |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/Association.php |
---|
New file |
0,0 → 1,308 |
<?php |
/** |
* This module contains code for dealing with associations between |
* consumers and servers. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* @access private |
*/ |
require_once 'Auth/OpenID/CryptUtil.php'; |
/** |
* @access private |
*/ |
require_once 'Auth/OpenID/KVForm.php'; |
/** |
* This class represents an association between a server and a |
* consumer. In general, users of this library will never see |
* instances of this object. The only exception is if you implement a |
* custom {@link Auth_OpenID_OpenIDStore}. |
* |
* If you do implement such a store, it will need to store the values |
* of the handle, secret, issued, lifetime, and assoc_type instance |
* variables. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_Association { |
/** |
* This is a HMAC-SHA1 specific value. |
* |
* @access private |
*/ |
var $SIG_LENGTH = 20; |
/** |
* The ordering and name of keys as stored by serialize. |
* |
* @access private |
*/ |
var $assoc_keys = array( |
'version', |
'handle', |
'secret', |
'issued', |
'lifetime', |
'assoc_type' |
); |
/** |
* This is an alternate constructor (factory method) used by the |
* OpenID consumer library to create associations. OpenID store |
* implementations shouldn't use this constructor. |
* |
* @access private |
* |
* @param integer $expires_in This is the amount of time this |
* association is good for, measured in seconds since the |
* association was issued. |
* |
* @param string $handle This is the handle the server gave this |
* association. |
* |
* @param string secret This is the shared secret the server |
* generated for this association. |
* |
* @param assoc_type This is the type of association this |
* instance represents. The only valid value of this field at |
* this time is 'HMAC-SHA1', but new types may be defined in the |
* future. |
* |
* @return association An {@link Auth_OpenID_Association} |
* instance. |
*/ |
function fromExpiresIn($expires_in, $handle, $secret, $assoc_type) |
{ |
$issued = time(); |
$lifetime = $expires_in; |
return new Auth_OpenID_Association($handle, $secret, |
$issued, $lifetime, $assoc_type); |
} |
/** |
* This is the standard constructor for creating an association. |
* The library should create all of the necessary associations, so |
* this constructor is not part of the external API. |
* |
* @access private |
* |
* @param string $handle This is the handle the server gave this |
* association. |
* |
* @param string $secret This is the shared secret the server |
* generated for this association. |
* |
* @param integer $issued This is the time this association was |
* issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a |
* unix timestamp) |
* |
* @param integer $lifetime This is the amount of time this |
* association is good for, measured in seconds since the |
* association was issued. |
* |
* @param string $assoc_type This is the type of association this |
* instance represents. The only valid value of this field at |
* this time is 'HMAC-SHA1', but new types may be defined in the |
* future. |
*/ |
function Auth_OpenID_Association( |
$handle, $secret, $issued, $lifetime, $assoc_type) |
{ |
if ($assoc_type != 'HMAC-SHA1') { |
$fmt = 'HMAC-SHA1 is the only supported association type (got %s)'; |
trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR); |
} |
$this->handle = $handle; |
$this->secret = $secret; |
$this->issued = $issued; |
$this->lifetime = $lifetime; |
$this->assoc_type = $assoc_type; |
} |
/** |
* This returns the number of seconds this association is still |
* valid for, or 0 if the association is no longer valid. |
* |
* @return integer $seconds The number of seconds this association |
* is still valid for, or 0 if the association is no longer valid. |
*/ |
function getExpiresIn($now = null) |
{ |
if ($now == null) { |
$now = time(); |
} |
return max(0, $this->issued + $this->lifetime - $now); |
} |
/** |
* This checks to see if two {@link Auth_OpenID_Association} |
* instances represent the same association. |
* |
* @return bool $result true if the two instances represent the |
* same association, false otherwise. |
*/ |
function equal($other) |
{ |
return ((gettype($this) == gettype($other)) |
&& ($this->handle == $other->handle) |
&& ($this->secret == $other->secret) |
&& ($this->issued == $other->issued) |
&& ($this->lifetime == $other->lifetime) |
&& ($this->assoc_type == $other->assoc_type)); |
} |
/** |
* Convert an association to KV form. |
* |
* @return string $result String in KV form suitable for |
* deserialization by deserialize. |
*/ |
function serialize() |
{ |
$data = array( |
'version' => '2', |
'handle' => $this->handle, |
'secret' => base64_encode($this->secret), |
'issued' => strval(intval($this->issued)), |
'lifetime' => strval(intval($this->lifetime)), |
'assoc_type' => $this->assoc_type |
); |
assert(array_keys($data) == $this->assoc_keys); |
return Auth_OpenID_KVForm::fromArray($data, $strict = true); |
} |
/** |
* Parse an association as stored by serialize(). This is the |
* inverse of serialize. |
* |
* @param string $assoc_s Association as serialized by serialize() |
* @return Auth_OpenID_Association $result instance of this class |
*/ |
function deserialize($class_name, $assoc_s) |
{ |
$pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true); |
$keys = array(); |
$values = array(); |
foreach ($pairs as $key => $value) { |
if (is_array($value)) { |
list($key, $value) = $value; |
} |
$keys[] = $key; |
$values[] = $value; |
} |
$class_vars = get_class_vars($class_name); |
$class_assoc_keys = $class_vars['assoc_keys']; |
sort($keys); |
sort($class_assoc_keys); |
if ($keys != $class_assoc_keys) { |
trigger_error('Unexpected key values: ' . strval($keys), |
E_USER_WARNING); |
return null; |
} |
$version = $pairs['version']; |
$handle = $pairs['handle']; |
$secret = $pairs['secret']; |
$issued = $pairs['issued']; |
$lifetime = $pairs['lifetime']; |
$assoc_type = $pairs['assoc_type']; |
if ($version != '2') { |
trigger_error('Unknown version: ' . $version, E_USER_WARNING); |
return null; |
} |
$issued = intval($issued); |
$lifetime = intval($lifetime); |
$secret = base64_decode($secret); |
return new $class_name( |
$handle, $secret, $issued, $lifetime, $assoc_type); |
} |
/** |
* Generate a signature for a sequence of (key, value) pairs |
* |
* @access private |
* @param array $pairs The pairs to sign, in order. This is an |
* array of two-tuples. |
* @return string $signature The binary signature of this sequence |
* of pairs |
*/ |
function sign($pairs) |
{ |
$kv = Auth_OpenID_KVForm::fromArray($pairs); |
return Auth_OpenID_HMACSHA1($this->secret, $kv); |
} |
/** |
* Generate a signature for some fields in a dictionary |
* |
* @access private |
* @param array $fields The fields to sign, in order; this is an |
* array of strings. |
* @param array $data Dictionary of values to sign (an array of |
* string => string pairs). |
* @return string $signature The signature, base64 encoded |
*/ |
function signDict($fields, $data, $prefix = 'openid.') |
{ |
$pairs = array(); |
foreach ($fields as $field) { |
$pairs[] = array($field, $data[$prefix . $field]); |
} |
return base64_encode($this->sign($pairs)); |
} |
/** |
* Add a signature to an array of fields |
* |
* @access private |
*/ |
function addSignature($fields, &$data, $prefix = 'openid.') |
{ |
$sig = $this->signDict($fields, $data, $prefix); |
$signed = implode(",", $fields); |
$data[$prefix . 'sig'] = $sig; |
$data[$prefix . 'signed'] = $signed; |
} |
/** |
* Confirm that the signature of these fields matches the |
* signature contained in the data |
* |
* @access private |
*/ |
function checkSignature($data, $prefix = 'openid.') |
{ |
$signed = $data[$prefix . 'signed']; |
$fields = explode(",", $signed); |
$expected_sig = $this->signDict($fields, $data, $prefix); |
$request_sig = $data[$prefix . 'sig']; |
return ($request_sig == $expected_sig); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/SQLStore.php |
---|
New file |
0,0 → 1,658 |
<?php |
/** |
* SQL-backed OpenID stores. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Require the PEAR DB module because we'll need it for the SQL-based |
* stores implemented here. We silence any errors from the inclusion |
* because it might not be present, and a user of the SQL stores may |
* supply an Auth_OpenID_DatabaseConnection instance that implements |
* its own storage. |
*/ |
global $__Auth_OpenID_PEAR_AVAILABLE; |
$__Auth_OpenID_PEAR_AVAILABLE = @include_once 'DB.php'; |
/** |
* @access private |
*/ |
require_once 'Auth/OpenID/Interface.php'; |
/** |
* This is the parent class for the SQL stores, which contains the |
* logic common to all of the SQL stores. |
* |
* The table names used are determined by the class variables |
* settings_table_name, associations_table_name, and |
* nonces_table_name. To change the name of the tables used, pass new |
* table names into the constructor. |
* |
* To create the tables with the proper schema, see the createTables |
* method. |
* |
* This class shouldn't be used directly. Use one of its subclasses |
* instead, as those contain the code necessary to use a specific |
* database. If you're an OpenID integrator and you'd like to create |
* an SQL-driven store that wraps an application's database |
* abstraction, be sure to create a subclass of |
* {@link Auth_OpenID_DatabaseConnection} that calls the application's |
* database abstraction calls. Then, pass an instance of your new |
* database connection class to your SQLStore subclass constructor. |
* |
* All methods other than the constructor and createTables should be |
* considered implementation details. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore { |
/** |
* This creates a new SQLStore instance. It requires an |
* established database connection be given to it, and it allows |
* overriding the default table names. |
* |
* @param connection $connection This must be an established |
* connection to a database of the correct type for the SQLStore |
* subclass you're using. This must either be an PEAR DB |
* connection handle or an instance of a subclass of |
* Auth_OpenID_DatabaseConnection. |
* |
* @param string $settings_table This is an optional parameter to |
* specify the name of the table used for this store's settings. |
* The default value is 'oid_settings'. |
* |
* @param associations_table: This is an optional parameter to |
* specify the name of the table used for storing associations. |
* The default value is 'oid_associations'. |
* |
* @param nonces_table: This is an optional parameter to specify |
* the name of the table used for storing nonces. The default |
* value is 'oid_nonces'. |
*/ |
function Auth_OpenID_SQLStore($connection, $settings_table = null, |
$associations_table = null, |
$nonces_table = null) |
{ |
global $__Auth_OpenID_PEAR_AVAILABLE; |
$this->settings_table_name = "oid_settings"; |
$this->associations_table_name = "oid_associations"; |
$this->nonces_table_name = "oid_nonces"; |
// Check the connection object type to be sure it's a PEAR |
// database connection. |
if (!(is_object($connection) && |
(is_subclass_of($connection, 'db_common') || |
is_subclass_of($connection, |
'auth_openid_databaseconnection')))) { |
trigger_error("Auth_OpenID_SQLStore expected PEAR connection " . |
"object (got ".get_class($connection).")", |
E_USER_ERROR); |
return; |
} |
$this->connection = $connection; |
// Be sure to set the fetch mode so the results are keyed on |
// column name instead of column index. This is a PEAR |
// constant, so only try to use it if PEAR is present. Note |
// that Auth_Openid_Databaseconnection instances need not |
// implement ::setFetchMode for this reason. |
if ($__Auth_OpenID_PEAR_AVAILABLE) { |
$this->connection->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
if ($settings_table) { |
$this->settings_table_name = $settings_table; |
} |
if ($associations_table) { |
$this->associations_table_name = $associations_table; |
} |
if ($nonces_table) { |
$this->nonces_table_name = $nonces_table; |
} |
$this->max_nonce_age = 6 * 60 * 60; |
// Be sure to run the database queries with auto-commit mode |
// turned OFF, because we want every function to run in a |
// transaction, implicitly. As a rule, methods named with a |
// leading underscore will NOT control transaction behavior. |
// Callers of these methods will worry about transactions. |
$this->connection->autoCommit(false); |
// Create an empty SQL strings array. |
$this->sql = array(); |
// Call this method (which should be overridden by subclasses) |
// to populate the $this->sql array with SQL strings. |
$this->setSQL(); |
// Verify that all required SQL statements have been set, and |
// raise an error if any expected SQL strings were either |
// absent or empty. |
list($missing, $empty) = $this->_verifySQL(); |
if ($missing) { |
trigger_error("Expected keys in SQL query list: " . |
implode(", ", $missing), |
E_USER_ERROR); |
return; |
} |
if ($empty) { |
trigger_error("SQL list keys have no SQL strings: " . |
implode(", ", $empty), |
E_USER_ERROR); |
return; |
} |
// Add table names to queries. |
$this->_fixSQL(); |
} |
function tableExists($table_name) |
{ |
return !$this->isError( |
$this->connection->query("SELECT * FROM %s LIMIT 0", |
$table_name)); |
} |
/** |
* Returns true if $value constitutes a database error; returns |
* false otherwise. |
*/ |
function isError($value) |
{ |
return PEAR::isError($value); |
} |
/** |
* Converts a query result to a boolean. If the result is a |
* database error according to $this->isError(), this returns |
* false; otherwise, this returns true. |
*/ |
function resultToBool($obj) |
{ |
if ($this->isError($obj)) { |
return false; |
} else { |
return true; |
} |
} |
/** |
* This method should be overridden by subclasses. This method is |
* called by the constructor to set values in $this->sql, which is |
* an array keyed on sql name. |
*/ |
function setSQL() |
{ |
} |
/** |
* Resets the store by removing all records from the store's |
* tables. |
*/ |
function reset() |
{ |
$this->connection->query(sprintf("DELETE FROM %s", |
$this->associations_table_name)); |
$this->connection->query(sprintf("DELETE FROM %s", |
$this->nonces_table_name)); |
$this->connection->query(sprintf("DELETE FROM %s", |
$this->settings_table_name)); |
} |
/** |
* @access private |
*/ |
function _verifySQL() |
{ |
$missing = array(); |
$empty = array(); |
$required_sql_keys = array( |
'nonce_table', |
'assoc_table', |
'settings_table', |
'get_auth', |
'create_auth', |
'set_assoc', |
'get_assoc', |
'get_assocs', |
'remove_assoc', |
'add_nonce', |
'get_nonce', |
'remove_nonce' |
); |
foreach ($required_sql_keys as $key) { |
if (!array_key_exists($key, $this->sql)) { |
$missing[] = $key; |
} else if (!$this->sql[$key]) { |
$empty[] = $key; |
} |
} |
return array($missing, $empty); |
} |
/** |
* @access private |
*/ |
function _fixSQL() |
{ |
$replacements = array( |
array( |
'value' => $this->nonces_table_name, |
'keys' => array('nonce_table', |
'add_nonce', |
'get_nonce', |
'remove_nonce') |
), |
array( |
'value' => $this->associations_table_name, |
'keys' => array('assoc_table', |
'set_assoc', |
'get_assoc', |
'get_assocs', |
'remove_assoc') |
), |
array( |
'value' => $this->settings_table_name, |
'keys' => array('settings_table', |
'get_auth', |
'create_auth') |
) |
); |
foreach ($replacements as $item) { |
$value = $item['value']; |
$keys = $item['keys']; |
foreach ($keys as $k) { |
if (is_array($this->sql[$k])) { |
foreach ($this->sql[$k] as $part_key => $part_value) { |
$this->sql[$k][$part_key] = sprintf($part_value, |
$value); |
} |
} else { |
$this->sql[$k] = sprintf($this->sql[$k], $value); |
} |
} |
} |
} |
function blobDecode($blob) |
{ |
return $blob; |
} |
function blobEncode($str) |
{ |
return $str; |
} |
function createTables() |
{ |
$this->connection->autoCommit(true); |
$n = $this->create_nonce_table(); |
$a = $this->create_assoc_table(); |
$s = $this->create_settings_table(); |
$this->connection->autoCommit(false); |
if ($n && $a && $s) { |
return true; |
} else { |
return false; |
} |
} |
function create_nonce_table() |
{ |
if (!$this->tableExists($this->nonces_table_name)) { |
$r = $this->connection->query($this->sql['nonce_table']); |
return $this->resultToBool($r); |
} |
return true; |
} |
function create_assoc_table() |
{ |
if (!$this->tableExists($this->associations_table_name)) { |
$r = $this->connection->query($this->sql['assoc_table']); |
return $this->resultToBool($r); |
} |
return true; |
} |
function create_settings_table() |
{ |
if (!$this->tableExists($this->settings_table_name)) { |
$r = $this->connection->query($this->sql['settings_table']); |
return $this->resultToBool($r); |
} |
return true; |
} |
/** |
* @access private |
*/ |
function _get_auth() |
{ |
return $this->connection->getOne($this->sql['get_auth']); |
} |
/** |
* @access private |
*/ |
function _create_auth($str) |
{ |
return $this->connection->query($this->sql['create_auth'], |
array($str)); |
} |
function getAuthKey() |
{ |
$value = $this->_get_auth(); |
if (!$value) { |
$auth_key = |
Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN); |
$auth_key_s = $this->blobEncode($auth_key); |
$this->_create_auth($auth_key_s); |
} else { |
$auth_key_s = $value; |
$auth_key = $this->blobDecode($auth_key_s); |
} |
$this->connection->commit(); |
if (strlen($auth_key) != $this->AUTH_KEY_LEN) { |
$fmt = "Expected %d-byte string for auth key. Got key of length %d"; |
trigger_error(sprintf($fmt, $this->AUTH_KEY_LEN, strlen($auth_key)), |
E_USER_WARNING); |
return null; |
} |
return $auth_key; |
} |
/** |
* @access private |
*/ |
function _set_assoc($server_url, $handle, $secret, $issued, |
$lifetime, $assoc_type) |
{ |
return $this->connection->query($this->sql['set_assoc'], |
array( |
$server_url, |
$handle, |
$secret, |
$issued, |
$lifetime, |
$assoc_type)); |
} |
function storeAssociation($server_url, $association) |
{ |
if ($this->resultToBool($this->_set_assoc( |
$server_url, |
$association->handle, |
$this->blobEncode( |
$association->secret), |
$association->issued, |
$association->lifetime, |
$association->assoc_type |
))) { |
$this->connection->commit(); |
} else { |
$this->connection->rollback(); |
} |
} |
/** |
* @access private |
*/ |
function _get_assoc($server_url, $handle) |
{ |
$result = $this->connection->getRow($this->sql['get_assoc'], |
array($server_url, $handle)); |
if ($this->isError($result)) { |
return null; |
} else { |
return $result; |
} |
} |
/** |
* @access private |
*/ |
function _get_assocs($server_url) |
{ |
$result = $this->connection->getAll($this->sql['get_assocs'], |
array($server_url)); |
if ($this->isError($result)) { |
return array(); |
} else { |
return $result; |
} |
} |
function removeAssociation($server_url, $handle) |
{ |
if ($this->_get_assoc($server_url, $handle) == null) { |
return false; |
} |
if ($this->resultToBool($this->connection->query( |
$this->sql['remove_assoc'], |
array($server_url, $handle)))) { |
$this->connection->commit(); |
} else { |
$this->connection->rollback(); |
} |
return true; |
} |
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; |
} |
} |
} |
/** |
* @access private |
*/ |
function _add_nonce($nonce, $expires) |
{ |
$sql = $this->sql['add_nonce']; |
$result = $this->connection->query($sql, array($nonce, $expires)); |
return $this->resultToBool($result); |
} |
/** |
* @access private |
*/ |
function storeNonce($nonce) |
{ |
if ($this->_add_nonce($nonce, time())) { |
$this->connection->commit(); |
} else { |
$this->connection->rollback(); |
} |
} |
/** |
* @access private |
*/ |
function _get_nonce($nonce) |
{ |
$result = $this->connection->getRow($this->sql['get_nonce'], |
array($nonce)); |
if ($this->isError($result)) { |
return null; |
} else { |
return $result; |
} |
} |
/** |
* @access private |
*/ |
function _remove_nonce($nonce) |
{ |
$this->connection->query($this->sql['remove_nonce'], |
array($nonce)); |
} |
function useNonce($nonce) |
{ |
$row = $this->_get_nonce($nonce); |
if ($row !== null) { |
$nonce = $row['nonce']; |
$timestamp = $row['expires']; |
$nonce_age = time() - $timestamp; |
if ($nonce_age > $this->max_nonce_age) { |
$present = 0; |
} else { |
$present = 1; |
} |
$this->_remove_nonce($nonce); |
} else { |
$present = 0; |
} |
$this->connection->commit(); |
return $present; |
} |
/** |
* "Octifies" a binary string by returning a string with escaped |
* octal bytes. This is used for preparing binary data for |
* PostgreSQL BYTEA fields. |
* |
* @access private |
*/ |
function _octify($str) |
{ |
$result = ""; |
for ($i = 0; $i < strlen($str); $i++) { |
$ch = substr($str, $i, 1); |
if ($ch == "\\") { |
$result .= "\\\\\\\\"; |
} else if (ord($ch) == 0) { |
$result .= "\\\\000"; |
} else { |
$result .= "\\" . strval(decoct(ord($ch))); |
} |
} |
return $result; |
} |
/** |
* "Unoctifies" octal-escaped data from PostgreSQL and returns the |
* resulting ASCII (possibly binary) string. |
* |
* @access private |
*/ |
function _unoctify($str) |
{ |
$result = ""; |
$i = 0; |
while ($i < strlen($str)) { |
$char = $str[$i]; |
if ($char == "\\") { |
// Look to see if the next char is a backslash and |
// append it. |
if ($str[$i + 1] != "\\") { |
$octal_digits = substr($str, $i + 1, 3); |
$dec = octdec($octal_digits); |
$char = chr($dec); |
$i += 4; |
} else { |
$char = "\\"; |
$i += 2; |
} |
} else { |
$i += 1; |
} |
$result .= $char; |
} |
return $result; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/SQLiteStore.php |
---|
New file |
0,0 → 1,66 |
<?php |
/** |
* An SQLite store. |
* |
* @package OpenID |
*/ |
/** |
* Require the base class file. |
*/ |
require_once "Auth/OpenID/SQLStore.php"; |
/** |
* An SQL store that uses SQLite as its backend. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_SQLiteStore extends Auth_OpenID_SQLStore { |
function setSQL() |
{ |
$this->sql['nonce_table'] = |
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ". |
"expires INTEGER)"; |
$this->sql['assoc_table'] = |
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ". |
"secret BLOB(128), issued INTEGER, lifetime INTEGER, ". |
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle))"; |
$this->sql['settings_table'] = |
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ". |
"value BLOB(20))"; |
$this->sql['create_auth'] = |
"INSERT INTO %s VALUES ('auth_key', ?)"; |
$this->sql['get_auth'] = |
"SELECT value FROM %s WHERE setting = 'auth_key'"; |
$this->sql['set_assoc'] = |
"INSERT OR REPLACE INTO %s VALUES (?, ?, ?, ?, ?, ?)"; |
$this->sql['get_assocs'] = |
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". |
"WHERE server_url = ?"; |
$this->sql['get_assoc'] = |
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". |
"WHERE server_url = ? AND handle = ?"; |
$this->sql['remove_assoc'] = |
"DELETE FROM %s WHERE server_url = ? AND handle = ?"; |
$this->sql['add_nonce'] = |
"INSERT OR REPLACE INTO %s (nonce, expires) VALUES (?, ?)"; |
$this->sql['get_nonce'] = |
"SELECT * FROM %s WHERE nonce = ?"; |
$this->sql['remove_nonce'] = |
"DELETE FROM %s WHERE nonce = ?"; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/Discover.php |
---|
New file |
0,0 → 1,258 |
<?php |
/** |
* The OpenID and Yadis discovery implementation for OpenID 1.2. |
*/ |
require_once "Auth/OpenID.php"; |
require_once "Auth/OpenID/Parse.php"; |
require_once "Services/Yadis/XRIRes.php"; |
require_once "Services/Yadis/Yadis.php"; |
define('_OPENID_1_0_NS', 'http://openid.net/xmlns/1.0'); |
define('_OPENID_1_2_TYPE', 'http://openid.net/signon/1.2'); |
define('_OPENID_1_1_TYPE', 'http://openid.net/signon/1.1'); |
define('_OPENID_1_0_TYPE', 'http://openid.net/signon/1.0'); |
/** |
* Object representing an OpenID service endpoint. |
*/ |
class Auth_OpenID_ServiceEndpoint { |
function Auth_OpenID_ServiceEndpoint() |
{ |
$this->identity_url = null; |
$this->server_url = null; |
$this->type_uris = array(); |
$this->delegate = null; |
$this->canonicalID = null; |
$this->used_yadis = false; // whether this came from an XRDS |
} |
function usesExtension($extension_uri) |
{ |
return in_array($extension_uri, $this->type_uris); |
} |
function parseService($yadis_url, $uri, $type_uris, $service_element) |
{ |
// Set the state of this object based on the contents of the |
// service element. |
$this->type_uris = $type_uris; |
$this->identity_url = $yadis_url; |
$this->server_url = $uri; |
$this->delegate = Auth_OpenID_ServiceEndpoint::findDelegate( |
$service_element); |
$this->used_yadis = true; |
} |
function findDelegate($service) |
{ |
// Extract a openid:Delegate value from a Yadis Service |
// element. If no delegate is found, returns null. |
// Try to register new namespace. |
$service->parser->registerNamespace('openid', |
'http://openid.net/xmlns/1.0'); |
// XXX: should this die if there is more than one delegate |
// element? |
$delegates = $service->getElements("openid:Delegate"); |
if ($delegates) { |
return $service->parser->content($delegates[0]); |
} else { |
return null; |
} |
} |
function getServerID() |
{ |
// Return the identifier that should be sent as the |
// openid.identity_url parameter to the server. |
if ($this->delegate === null) { |
if ($this->canonicalID) { |
return $this->canonicalID; |
} else { |
return $this->identity_url; |
} |
} else { |
return $this->delegate; |
} |
} |
function fromHTML($uri, $html) |
{ |
// Parse the given document as HTML looking for an OpenID <link |
// rel=...> |
$urls = Auth_OpenID_legacy_discover($html); |
if ($urls === false) { |
return null; |
} |
list($delegate_url, $server_url) = $urls; |
$service = new Auth_OpenID_ServiceEndpoint(); |
$service->identity_url = $uri; |
$service->delegate = $delegate_url; |
$service->server_url = $server_url; |
$service->type_uris = array(_OPENID_1_0_TYPE); |
return $service; |
} |
} |
function filter_MatchesAnyOpenIDType(&$service) |
{ |
$uris = $service->getTypes(); |
foreach ($uris as $uri) { |
if (in_array($uri, |
array(_OPENID_1_0_TYPE, |
_OPENID_1_1_TYPE, |
_OPENID_1_2_TYPE))) { |
return true; |
} |
} |
return false; |
} |
function Auth_OpenID_makeOpenIDEndpoints($uri, $endpoints) |
{ |
$s = array(); |
if (!$endpoints) { |
return $s; |
} |
foreach ($endpoints as $service) { |
$type_uris = $service->getTypes(); |
$uris = $service->getURIs(); |
// If any Type URIs match and there is an endpoint URI |
// specified, then this is an OpenID endpoint |
if ($type_uris && |
$uris) { |
foreach ($uris as $service_uri) { |
$openid_endpoint = new Auth_OpenID_ServiceEndpoint(); |
$openid_endpoint->parseService($uri, |
$service_uri, |
$type_uris, |
$service); |
$s[] = $openid_endpoint; |
} |
} |
} |
return $s; |
} |
function Auth_OpenID_discoverWithYadis($uri, &$fetcher) |
{ |
// Discover OpenID services for a URI. Tries Yadis and falls back |
// on old-style <link rel='...'> discovery if Yadis fails. |
// Might raise a yadis.discover.DiscoveryFailure if no document |
// came back for that URI at all. I don't think falling back to |
// OpenID 1.0 discovery on the same URL will help, so don't bother |
// to catch it. |
$openid_services = array(); |
$http_response = null; |
$response = Services_Yadis_Yadis::discover($uri, $http_response, |
$fetcher); |
if ($response) { |
$identity_url = $response->uri; |
$openid_services = |
$response->xrds->services(array('filter_MatchesAnyOpenIDType')); |
} |
if (!$openid_services) { |
return @Auth_OpenID_discoverWithoutYadis($uri, |
$fetcher); |
} |
if (!$openid_services) { |
$body = $response->body; |
// Try to parse the response as HTML to get OpenID 1.0/1.1 |
// <link rel="..."> |
$service = Auth_OpenID_ServiceEndpoint::fromHTML($identity_url, |
$body); |
if ($service !== null) { |
$openid_services = array($service); |
} |
} else { |
$openid_services = Auth_OpenID_makeOpenIDEndpoints($response->uri, |
$openid_services); |
} |
return array($identity_url, $openid_services, $http_response); |
} |
function _Auth_OpenID_discoverServiceList($uri, &$fetcher) |
{ |
list($url, $services, $resp) = Auth_OpenID_discoverWithYadis($uri, |
$fetcher); |
return $services; |
} |
function _Auth_OpenID_discoverXRIServiceList($uri, &$fetcher) |
{ |
list($url, $services, $resp) = _Auth_OpenID_discoverXRI($uri, |
$fetcher); |
return $services; |
} |
function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher) |
{ |
$http_resp = @$fetcher->get($uri); |
if ($http_resp->status != 200) { |
return array(null, array(), $http_resp); |
} |
$identity_url = $http_resp->final_url; |
// Try to parse the response as HTML to get OpenID 1.0/1.1 <link |
// rel="..."> |
$endpoint =& new Auth_OpenID_ServiceEndpoint(); |
$service = $endpoint->fromHTML($identity_url, $http_resp->body); |
if ($service === null) { |
$openid_services = array(); |
} else { |
$openid_services = array($service); |
} |
return array($identity_url, $openid_services, $http_resp); |
} |
function _Auth_OpenID_discoverXRI($iname, &$fetcher) |
{ |
$services = new Services_Yadis_ProxyResolver($fetcher); |
list($canonicalID, $service_list) = $services->query($iname, |
array(_OPENID_1_0_TYPE, |
_OPENID_1_1_TYPE, |
_OPENID_1_2_TYPE), |
array('filter_MatchesAnyOpenIDType')); |
$endpoints = Auth_OpenID_makeOpenIDEndpoints($iname, $service_list); |
for ($i = 0; $i < count($endpoints); $i++) { |
$endpoints[$i]->canonicalID = $canonicalID; |
} |
// FIXME: returned xri should probably be in some normal form |
return array($iname, $endpoints, null); |
} |
function Auth_OpenID_discover($uri, &$fetcher) |
{ |
return @Auth_OpenID_discoverWithYadis($uri, $fetcher); |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/ServerRequest.php |
---|
New file |
0,0 → 1,37 |
<?php |
/** |
* OpenID Server Request |
* |
* @see Auth_OpenID_Server |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Imports |
*/ |
require_once "Auth/OpenID.php"; |
/** |
* Object that holds the state of a request to the OpenID server |
* |
* With accessor functions to get at the internal request data. |
* |
* @see Auth_OpenID_Server |
* @package OpenID |
*/ |
class Auth_OpenID_ServerRequest { |
function Auth_OpenID_ServerRequest() |
{ |
$this->mode = null; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/PostgreSQLStore.php |
---|
New file |
0,0 → 1,136 |
<?php |
/** |
* A PostgreSQL store. |
* |
* @package OpenID |
*/ |
/** |
* Require the base class file. |
*/ |
require_once "Auth/OpenID/SQLStore.php"; |
/** |
* An SQL store that uses PostgreSQL as its backend. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_PostgreSQLStore extends Auth_OpenID_SQLStore { |
/** |
* @access private |
*/ |
function setSQL() |
{ |
$this->sql['nonce_table'] = |
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ". |
"expires INTEGER)"; |
$this->sql['assoc_table'] = |
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ". |
"secret BYTEA, issued INTEGER, lifetime INTEGER, ". |
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle), ". |
"CONSTRAINT secret_length_constraint CHECK ". |
"(LENGTH(secret) <= 128))"; |
$this->sql['settings_table'] = |
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ". |
"value BYTEA, ". |
"CONSTRAINT value_length_constraint CHECK (LENGTH(value) <= 20))"; |
$this->sql['create_auth'] = |
"INSERT INTO %s VALUES ('auth_key', '!')"; |
$this->sql['get_auth'] = |
"SELECT value FROM %s WHERE setting = 'auth_key'"; |
$this->sql['set_assoc'] = |
array( |
'insert_assoc' => "INSERT INTO %s (server_url, handle, ". |
"secret, issued, lifetime, assoc_type) VALUES ". |
"(?, ?, '!', ?, ?, ?)", |
'update_assoc' => "UPDATE %s SET secret = '!', issued = ?, ". |
"lifetime = ?, assoc_type = ? WHERE server_url = ? AND ". |
"handle = ?" |
); |
$this->sql['get_assocs'] = |
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". |
"WHERE server_url = ?"; |
$this->sql['get_assoc'] = |
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". |
"WHERE server_url = ? AND handle = ?"; |
$this->sql['remove_assoc'] = |
"DELETE FROM %s WHERE server_url = ? AND handle = ?"; |
$this->sql['add_nonce'] = |
array( |
'insert_nonce' => "INSERT INTO %s (nonce, expires) VALUES ". |
"(?, ?)", |
'update_nonce' => "UPDATE %s SET expires = ? WHERE nonce = ?" |
); |
$this->sql['get_nonce'] = |
"SELECT * FROM %s WHERE nonce = ?"; |
$this->sql['remove_nonce'] = |
"DELETE FROM %s WHERE nonce = ?"; |
} |
/** |
* @access private |
*/ |
function _set_assoc($server_url, $handle, $secret, $issued, $lifetime, |
$assoc_type) |
{ |
$result = $this->_get_assoc($server_url, $handle); |
if ($result) { |
// Update the table since this associations already exists. |
$this->connection->query($this->sql['set_assoc']['update_assoc'], |
array($secret, $issued, $lifetime, |
$assoc_type, $server_url, $handle)); |
} else { |
// Insert a new record because this association wasn't |
// found. |
$this->connection->query($this->sql['set_assoc']['insert_assoc'], |
array($server_url, $handle, $secret, |
$issued, $lifetime, $assoc_type)); |
} |
} |
/** |
* @access private |
*/ |
function _add_nonce($nonce, $expires) |
{ |
if ($this->_get_nonce($nonce)) { |
return $this->resultToBool($this->connection->query( |
$this->sql['add_nonce']['update_nonce'], |
array($expires, $nonce))); |
} else { |
return $this->resultToBool($this->connection->query( |
$this->sql['add_nonce']['insert_nonce'], |
array($nonce, $expires))); |
} |
} |
/** |
* @access private |
*/ |
function blobEncode($blob) |
{ |
return $this->_octify($blob); |
} |
/** |
* @access private |
*/ |
function blobDecode($blob) |
{ |
return $this->_unoctify($blob); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/MySQLStore.php |
---|
New file |
0,0 → 1,78 |
<?php |
/** |
* A MySQL store. |
* |
* @package OpenID |
*/ |
/** |
* Require the base class file. |
*/ |
require_once "Auth/OpenID/SQLStore.php"; |
/** |
* An SQL store that uses MySQL as its backend. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore { |
/** |
* @access private |
*/ |
function setSQL() |
{ |
$this->sql['nonce_table'] = |
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ". |
"expires INTEGER) TYPE=InnoDB"; |
$this->sql['assoc_table'] = |
"CREATE TABLE %s (server_url BLOB, handle VARCHAR(255), ". |
"secret BLOB, issued INTEGER, lifetime INTEGER, ". |
"assoc_type VARCHAR(64), PRIMARY KEY (server_url(255), handle)) ". |
"TYPE=InnoDB"; |
$this->sql['settings_table'] = |
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ". |
"value BLOB) TYPE=InnoDB"; |
$this->sql['create_auth'] = |
"INSERT INTO %s VALUES ('auth_key', !)"; |
$this->sql['get_auth'] = |
"SELECT value FROM %s WHERE setting = 'auth_key'"; |
$this->sql['set_assoc'] = |
"REPLACE INTO %s VALUES (?, ?, !, ?, ?, ?)"; |
$this->sql['get_assocs'] = |
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". |
"WHERE server_url = ?"; |
$this->sql['get_assoc'] = |
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". |
"WHERE server_url = ? AND handle = ?"; |
$this->sql['remove_assoc'] = |
"DELETE FROM %s WHERE server_url = ? AND handle = ?"; |
$this->sql['add_nonce'] = |
"REPLACE INTO %s (nonce, expires) VALUES (?, ?)"; |
$this->sql['get_nonce'] = |
"SELECT * FROM %s WHERE nonce = ?"; |
$this->sql['remove_nonce'] = |
"DELETE FROM %s WHERE nonce = ?"; |
} |
/** |
* @access private |
*/ |
function blobEncode($blob) |
{ |
return "0x" . bin2hex($blob); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/DatabaseConnection.php |
---|
New file |
0,0 → 1,131 |
<?php |
/** |
* The Auth_OpenID_DatabaseConnection class, which is used to emulate |
* a PEAR database connection. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* An empty base class intended to emulate PEAR connection |
* functionality in applications that supply their own database |
* abstraction mechanisms. See {@link Auth_OpenID_SQLStore} for more |
* information. You should subclass this class if you need to create |
* an SQL store that needs to access its database using an |
* application's database abstraction layer instead of a PEAR database |
* connection. Any subclass of Auth_OpenID_DatabaseConnection MUST |
* adhere to the interface specified here. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_DatabaseConnection { |
/** |
* Sets auto-commit mode on this database connection. |
* |
* @param bool $mode True if auto-commit is to be used; false if |
* not. |
*/ |
function autoCommit($mode) |
{ |
} |
/** |
* Run an SQL query with the specified parameters, if any. |
* |
* @param string $sql An SQL string with placeholders. The |
* placeholders are assumed to be specific to the database engine |
* for this connection. |
* |
* @param array $params An array of parameters to insert into the |
* SQL string using this connection's escaping mechanism. |
* |
* @return mixed $result The result of calling this connection's |
* internal query function. The type of result depends on the |
* underlying database engine. This method is usually used when |
* the result of a query is not important, like a DDL query. |
*/ |
function query($sql, $params = array()) |
{ |
} |
/** |
* Starts a transaction on this connection, if supported. |
*/ |
function begin() |
{ |
} |
/** |
* Commits a transaction on this connection, if supported. |
*/ |
function commit() |
{ |
} |
/** |
* Performs a rollback on this connection, if supported. |
*/ |
function rollback() |
{ |
} |
/** |
* Run an SQL query and return the first column of the first row |
* of the result set, if any. |
* |
* @param string $sql An SQL string with placeholders. The |
* placeholders are assumed to be specific to the database engine |
* for this connection. |
* |
* @param array $params An array of parameters to insert into the |
* SQL string using this connection's escaping mechanism. |
* |
* @return mixed $result The value of the first column of the |
* first row of the result set. False if no such result was |
* found. |
*/ |
function getOne($sql, $params = array()) |
{ |
} |
/** |
* Run an SQL query and return the first row of the result set, if |
* any. |
* |
* @param string $sql An SQL string with placeholders. The |
* placeholders are assumed to be specific to the database engine |
* for this connection. |
* |
* @param array $params An array of parameters to insert into the |
* SQL string using this connection's escaping mechanism. |
* |
* @return array $result The first row of the result set, if any, |
* keyed on column name. False if no such result was found. |
*/ |
function getRow($sql, $params = array()) |
{ |
} |
/** |
* Run an SQL query with the specified parameters, if any. |
* |
* @param string $sql An SQL string with placeholders. The |
* placeholders are assumed to be specific to the database engine |
* for this connection. |
* |
* @param array $params An array of parameters to insert into the |
* SQL string using this connection's escaping mechanism. |
* |
* @return array $result An array of arrays representing the |
* result of the query; each array is keyed on column name. |
*/ |
function getAll($sql, $params = array()) |
{ |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/TrustRoot.php |
---|
New file |
0,0 → 1,243 |
<?php |
/** |
* Functions for dealing with OpenID trust roots |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* A regular expression that matches a domain ending in a top-level domains. |
* Used in checking trust roots for sanity. |
* |
* @access private |
*/ |
define('Auth_OpenID___TLDs', |
'/\.(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|' . |
'ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|' . |
'bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|' . |
'cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|' . |
'fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|' . |
'gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|' . |
'ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|' . |
'ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|' . |
'nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|' . |
'ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|' . |
'so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|' . |
'ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$/'); |
/** |
* A wrapper for trust-root related functions |
*/ |
class Auth_OpenID_TrustRoot { |
/** |
* Parse a URL into its trust_root parts. |
* |
* @static |
* |
* @access private |
* |
* @param string $trust_root The url to parse |
* |
* @return mixed $parsed Either an associative array of trust root |
* parts or false if parsing failed. |
*/ |
function _parse($trust_root) |
{ |
$parts = @parse_url($trust_root); |
if ($parts === false) { |
return false; |
} |
$required_parts = array('scheme', 'host'); |
$forbidden_parts = array('user', 'pass', 'fragment'); |
$keys = array_keys($parts); |
if (array_intersect($keys, $required_parts) != $required_parts) { |
return false; |
} |
if (array_intersect($keys, $forbidden_parts) != array()) { |
return false; |
} |
// Return false if the original trust root value has more than |
// one port specification. |
if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) { |
return false; |
} |
$scheme = strtolower($parts['scheme']); |
$allowed_schemes = array('http', 'https'); |
if (!in_array($scheme, $allowed_schemes)) { |
return false; |
} |
$parts['scheme'] = $scheme; |
$host = strtolower($parts['host']); |
$hostparts = explode('*', $host); |
switch (count($hostparts)) { |
case 1: |
$parts['wildcard'] = false; |
break; |
case 2: |
if ($hostparts[0] || |
($hostparts[1] && substr($hostparts[1], 0, 1) != '.')) { |
return false; |
} |
$host = $hostparts[1]; |
$parts['wildcard'] = true; |
break; |
default: |
return false; |
} |
if (strpos($host, ':') !== false) { |
return false; |
} |
$parts['host'] = $host; |
if (isset($parts['path'])) { |
$path = strtolower($parts['path']); |
if (substr($path, -1) != '/') { |
$path .= '/'; |
} |
} else { |
$path = '/'; |
} |
$parts['path'] = $path; |
if (!isset($parts['port'])) { |
$parts['port'] = false; |
} |
return $parts; |
} |
/** |
* Is this trust root sane? |
* |
* A trust root is sane if it is syntactically valid and it has a |
* reasonable domain name. Specifically, the domain name must be |
* more than one level below a standard TLD or more than two |
* levels below a two-letter tld. |
* |
* For example, '*.com' is not a sane trust root, but '*.foo.com' |
* is. '*.co.uk' is not sane, but '*.bbc.co.uk' is. |
* |
* This check is not always correct, but it attempts to err on the |
* side of marking sane trust roots insane instead of marking |
* insane trust roots sane. For example, 'kink.fm' is marked as |
* insane even though it "should" (for some meaning of should) be |
* marked sane. |
* |
* This function should be used when creating OpenID servers to |
* alert the users of the server when a consumer attempts to get |
* the user to accept a suspicious trust root. |
* |
* @static |
* @param string $trust_root The trust root to check |
* @return bool $sanity Whether the trust root looks OK |
*/ |
function isSane($trust_root) |
{ |
$parts = Auth_OpenID_TrustRoot::_parse($trust_root); |
if ($parts === false) { |
return false; |
} |
// Localhost is a special case |
if ($parts['host'] == 'localhost') { |
return true; |
} |
// Get the top-level domain of the host. If it is not a valid TLD, |
// it's not sane. |
preg_match(Auth_OpenID___TLDs, $parts['host'], $matches); |
if (!$matches) { |
return false; |
} |
$tld = $matches[1]; |
// Require at least two levels of specificity for non-country |
// tlds and three levels for country tlds. |
$elements = explode('.', $parts['host']); |
$n = count($elements); |
if ($parts['wildcard']) { |
$n -= 1; |
} |
if (strlen($tld) == 2) { |
$n -= 1; |
} |
if ($n <= 1) { |
return false; |
} |
return true; |
} |
/** |
* Does this URL match the given trust root? |
* |
* Return whether the URL falls under the given trust root. This |
* does not check whether the trust root is sane. If the URL or |
* trust root do not parse, this function will return false. |
* |
* @param string $trust_root The trust root to match against |
* |
* @param string $url The URL to check |
* |
* @return bool $matches Whether the URL matches against the |
* trust root |
*/ |
function match($trust_root, $url) |
{ |
$trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root); |
$url_parsed = Auth_OpenID_TrustRoot::_parse($url); |
if (!$trust_root_parsed || !$url_parsed) { |
return false; |
} |
// Check hosts matching |
if ($url_parsed['wildcard']) { |
return false; |
} |
if ($trust_root_parsed['wildcard']) { |
$host_tail = $trust_root_parsed['host']; |
$host = $url_parsed['host']; |
if ($host_tail && |
substr($host, -(strlen($host_tail))) != $host_tail && |
substr($host_tail, 1) != $host) { |
return false; |
} |
} else { |
if ($trust_root_parsed['host'] != $url_parsed['host']) { |
return false; |
} |
} |
// Check path and query matching |
$base_path = $trust_root_parsed['path']; |
$path = $url_parsed['path']; |
if (!isset($trust_root_parsed['query'])) { |
if (substr($path, 0, strlen($base_path)) != $base_path) { |
return false; |
} |
} else { |
$base_query = $trust_root_parsed['query']; |
$query = @$url_parsed['query']; |
$qplus = substr($query, 0, strlen($base_query) + 1); |
$bqplus = $base_query . '&'; |
if ($base_path != $path || |
($base_query != $query && $qplus != $bqplus)) { |
return false; |
} |
} |
// The port and scheme need to match exactly |
return ($trust_root_parsed['scheme'] == $url_parsed['scheme'] && |
$url_parsed['port'] === $trust_root_parsed['port']); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/HMACSHA1.php |
---|
New file |
0,0 → 1,72 |
<?php |
/** |
* This is the HMACSHA1 implementation for the OpenID library. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @access private |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback |
* implementation. |
*/ |
define('Auth_OpenID_SHA1_BLOCKSIZE', 64); |
if (!function_exists('sha1')) { |
/** |
* Return a raw SHA1 hash of the given string |
* |
* XXX: include the SHA1 code from Dan Libby's OpenID library |
*/ |
function Auth_OpenID_SHA1($text) |
{ |
trigger_error('No SHA1 function found', E_USER_ERROR); |
} |
} else { |
/** |
* @ignore |
*/ |
function Auth_OpenID_SHA1($text) |
{ |
$hex = sha1($text); |
$raw = ''; |
for ($i = 0; $i < 40; $i += 2) { |
$hexcode = substr($hex, $i, 2); |
$charcode = (int)base_convert($hexcode, 16, 10); |
$raw .= chr($charcode); |
} |
return $raw; |
} |
} |
/** |
* Compute an HMAC/SHA1 hash. |
* |
* @access private |
* @param string $key The HMAC key |
* @param string $text The message text to hash |
* @return string $mac The MAC |
*/ |
function Auth_OpenID_HMACSHA1($key, $text) |
{ |
if (strlen($key) > Auth_OpenID_SHA1_BLOCKSIZE) { |
$key = Auth_OpenID_SHA1($key, true); |
} |
$key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00)); |
$ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE); |
$opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE); |
$hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true); |
$hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true); |
return $hmac; |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/DiffieHellman.php |
---|
New file |
0,0 → 1,181 |
<?php |
/** |
* The OpenID library's Diffie-Hellman implementation. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @access private |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
require_once 'Auth/OpenID/BigMath.php'; |
require_once 'Auth/OpenID/HMACSHA1.php'; |
function Auth_OpenID_getDefaultMod() |
{ |
return '155172898181473697471232257763715539915724801'. |
'966915404479707795314057629378541917580651227423'. |
'698188993727816152646631438561595825688188889951'. |
'272158842675419950341258706556549803580104870537'. |
'681476726513255747040765857479291291572334510643'. |
'245094715007229621094194349783925984760375594985'. |
'848253359305585439638443'; |
} |
function Auth_OpenID_getDefaultGen() |
{ |
return '2'; |
} |
/** |
* The Diffie-Hellman key exchange class. This class relies on |
* {@link Auth_OpenID_MathLibrary} to perform large number operations. |
* |
* @access private |
* @package OpenID |
*/ |
class Auth_OpenID_DiffieHellman { |
var $mod; |
var $gen; |
var $private; |
var $lib = null; |
function Auth_OpenID_DiffieHellman($mod = null, $gen = null, |
$private = null, $lib = null) |
{ |
if ($lib === null) { |
$this->lib =& Auth_OpenID_getMathLib(); |
} else { |
$this->lib =& $lib; |
} |
if ($mod === null) { |
$this->mod = $this->lib->init(Auth_OpenID_getDefaultMod()); |
} else { |
$this->mod = $mod; |
} |
if ($gen === null) { |
$this->gen = $this->lib->init(Auth_OpenID_getDefaultGen()); |
} else { |
$this->gen = $gen; |
} |
if ($private === null) { |
$r = $this->lib->rand($this->mod); |
$this->private = $this->lib->add($r, 1); |
} else { |
$this->private = $private; |
} |
$this->public = $this->lib->powmod($this->gen, $this->private, |
$this->mod); |
} |
function getSharedSecret($composite) |
{ |
return $this->lib->powmod($composite, $this->private, $this->mod); |
} |
function getPublicKey() |
{ |
return $this->public; |
} |
/** |
* Generate the arguments for an OpenID Diffie-Hellman association |
* request |
*/ |
function getAssocArgs() |
{ |
$cpub = $this->lib->longToBase64($this->getPublicKey()); |
$args = array( |
'openid.dh_consumer_public' => $cpub, |
'openid.session_type' => 'DH-SHA1' |
); |
if ($this->lib->cmp($this->mod, Auth_OpenID_getDefaultMod()) || |
$this->lib->cmp($this->gen, Auth_OpenID_getDefaultGen())) { |
$args['openid.dh_modulus'] = $this->lib->longToBase64($this->mod); |
$args['openid.dh_gen'] = $this->lib->longToBase64($this->gen); |
} |
return $args; |
} |
function usingDefaultValues() |
{ |
return ($this->mod == Auth_OpenID_getDefaultMod() && |
$this->gen == Auth_OpenID_getDefaultGen()); |
} |
/** |
* Perform the server side of the OpenID Diffie-Hellman association |
*/ |
function serverAssociate($consumer_args, $assoc_secret) |
{ |
$lib =& Auth_OpenID_getMathLib(); |
if (isset($consumer_args['openid.dh_modulus'])) { |
$mod = $lib->base64ToLong($consumer_args['openid.dh_modulus']); |
} else { |
$mod = null; |
} |
if (isset($consumer_args['openid.dh_gen'])) { |
$gen = $lib->base64ToLong($consumer_args['openid.dh_gen']); |
} else { |
$gen = null; |
} |
$cpub64 = @$consumer_args['openid.dh_consumer_public']; |
if (!isset($cpub64)) { |
return false; |
} |
$dh = new Auth_OpenID_DiffieHellman($mod, $gen); |
$cpub = $lib->base64ToLong($cpub64); |
$mac_key = $dh->xorSecret($cpub, $assoc_secret); |
$enc_mac_key = base64_encode($mac_key); |
$spub64 = $lib->longToBase64($dh->getPublicKey()); |
$server_args = array( |
'session_type' => 'DH-SHA1', |
'dh_server_public' => $spub64, |
'enc_mac_key' => $enc_mac_key |
); |
return $server_args; |
} |
function consumerFinish($reply) |
{ |
$spub = $this->lib->base64ToLong($reply['dh_server_public']); |
if ($this->lib->cmp($spub, 0) <= 0) { |
return false; |
} |
$enc_mac_key = base64_decode($reply['enc_mac_key']); |
return $this->xorSecret($spub, $enc_mac_key); |
} |
function xorSecret($composite, $secret) |
{ |
$dh_shared = $this->getSharedSecret($composite); |
$dh_shared_str = $this->lib->longToBinary($dh_shared); |
$sha1_dh_shared = Auth_OpenID_SHA1($dh_shared_str); |
$xsecret = ""; |
for ($i = 0; $i < strlen($secret); $i++) { |
$xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i])); |
} |
return $xsecret; |
} |
} |
/branches/v1.5-belier/composants/openid/Auth/OpenID/URINorm.php |
---|
New file |
0,0 → 1,231 |
<?php |
/** |
* URI normalization routines. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
require_once 'Services/Yadis/Misc.php'; |
// from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt) |
function Auth_OpenID_getURIPattern() |
{ |
return '&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&'; |
} |
function Auth_OpenID_getAuthorityPattern() |
{ |
return '/^([^@]*@)?([^:]*)(:.*)?/'; |
} |
function Auth_OpenID_getEncodedPattern() |
{ |
return '/%([0-9A-Fa-f]{2})/'; |
} |
function Auth_OpenID_getUnreserved() |
{ |
$_unreserved = array(); |
for ($i = 0; $i < 256; $i++) { |
$_unreserved[$i] = false; |
} |
for ($i = ord('A'); $i <= ord('Z'); $i++) { |
$_unreserved[$i] = true; |
} |
for ($i = ord('0'); $i <= ord('9'); $i++) { |
$_unreserved[$i] = true; |
} |
for ($i = ord('a'); $i <= ord('z'); $i++) { |
$_unreserved[$i] = true; |
} |
$_unreserved[ord('-')] = true; |
$_unreserved[ord('.')] = true; |
$_unreserved[ord('_')] = true; |
$_unreserved[ord('~')] = true; |
return $_unreserved; |
} |
function Auth_OpenID_getEscapeRE() |
{ |
$parts = array(); |
foreach (array_merge(Services_Yadis_getUCSChars(), |
Services_Yadis_getIPrivateChars()) as $pair) { |
list($m, $n) = $pair; |
$parts[] = sprintf("%s-%s", chr($m), chr($n)); |
} |
return sprintf('[%s]', implode('', $parts)); |
} |
function Auth_OpenID_pct_encoded_replace_unreserved($mo) |
{ |
$_unreserved = Auth_OpenID_getUnreserved(); |
$i = intval($mo[1], 16); |
if ($_unreserved[$i]) { |
return chr($i); |
} else { |
return strtoupper($mo[0]); |
} |
return $mo[0]; |
} |
function Auth_OpenID_pct_encoded_replace($mo) |
{ |
return chr(intval($mo[1], 16)); |
} |
function Auth_OpenID_remove_dot_segments($path) |
{ |
$result_segments = array(); |
while ($path) { |
if (Services_Yadis_startswith($path, '../')) { |
$path = substr($path, 3); |
} else if (Services_Yadis_startswith($path, './')) { |
$path = substr($path, 2); |
} else if (Services_Yadis_startswith($path, '/./')) { |
$path = substr($path, 2); |
} else if ($path == '/.') { |
$path = '/'; |
} else if (Services_Yadis_startswith($path, '/../')) { |
$path = substr($path, 3); |
if ($result_segments) { |
array_pop($result_segments); |
} |
} else if ($path == '/..') { |
$path = '/'; |
if ($result_segments) { |
array_pop($result_segments); |
} |
} else if (($path == '..') || |
($path == '.')) { |
$path = ''; |
} else { |
$i = 0; |
if ($path[0] == '/') { |
$i = 1; |
} |
$i = strpos($path, '/', $i); |
if ($i === false) { |
$i = strlen($path); |
} |
$result_segments[] = substr($path, 0, $i); |
$path = substr($path, $i); |
} |
} |
return implode('', $result_segments); |
} |
function Auth_OpenID_urinorm($uri) |
{ |
$uri_matches = array(); |
preg_match(Auth_OpenID_getURIPattern(), $uri, $uri_matches); |
if (count($uri_matches) < 9) { |
for ($i = count($uri_matches); $i <= 9; $i++) { |
$uri_matches[] = ''; |
} |
} |
$scheme = $uri_matches[2]; |
if ($scheme) { |
$scheme = strtolower($scheme); |
} |
$scheme = $uri_matches[2]; |
if ($scheme === '') { |
// No scheme specified |
return null; |
} |
$scheme = strtolower($scheme); |
if (!in_array($scheme, array('http', 'https'))) { |
// Not an absolute HTTP or HTTPS URI |
return null; |
} |
$authority = $uri_matches[4]; |
if ($authority === '') { |
// Not an absolute URI |
return null; |
} |
$authority_matches = array(); |
preg_match(Auth_OpenID_getAuthorityPattern(), |
$authority, $authority_matches); |
if (count($authority_matches) === 0) { |
// URI does not have a valid authority |
return null; |
} |
if (count($authority_matches) < 4) { |
for ($i = count($authority_matches); $i <= 4; $i++) { |
$authority_matches[] = ''; |
} |
} |
list($_whole, $userinfo, $host, $port) = $authority_matches; |
if ($userinfo === null) { |
$userinfo = ''; |
} |
if (strpos($host, '%') !== -1) { |
$host = strtolower($host); |
$host = preg_replace_callback( |
Auth_OpenID_getEncodedPattern(), |
'Auth_OpenID_pct_encoded_replace', $host); |
// NO IDNA. |
// $host = unicode($host, 'utf-8').encode('idna'); |
} else { |
$host = strtolower($host); |
} |
if ($port) { |
if (($port == ':') || |
($scheme == 'http' && $port == ':80') || |
($scheme == 'https' && $port == ':443')) { |
$port = ''; |
} |
} else { |
$port = ''; |
} |
$authority = $userinfo . $host . $port; |
$path = $uri_matches[5]; |
$path = preg_replace_callback( |
Auth_OpenID_getEncodedPattern(), |
'Auth_OpenID_pct_encoded_replace_unreserved', $path); |
$path = Auth_OpenID_remove_dot_segments($path); |
if (!$path) { |
$path = '/'; |
} |
$query = $uri_matches[6]; |
if ($query === null) { |
$query = ''; |
} |
$fragment = $uri_matches[8]; |
if ($fragment === null) { |
$fragment = ''; |
} |
return $scheme . '://' . $authority . $path . $query . $fragment; |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/Consumer.php |
---|
New file |
0,0 → 1,1186 |
<?php |
/** |
* This module documents the main interface with the OpenID consumer |
* library. The only part of the library which has to be used and |
* isn't documented in full here is the store required to create an |
* Auth_OpenID_Consumer instance. More on the abstract store type and |
* concrete implementations of it that are provided in the |
* documentation for the Auth_OpenID_Consumer constructor. |
* |
* OVERVIEW |
* |
* The OpenID identity verification process most commonly uses the |
* following steps, as visible to the user of this library: |
* |
* 1. The user enters their OpenID into a field on the consumer's |
* site, and hits a login button. |
* 2. The consumer site discovers the user's OpenID server using the |
* YADIS protocol. |
* 3. The consumer site sends the browser a redirect to the identity |
* server. This is the authentication request as described in |
* the OpenID specification. |
* 4. The identity server's site sends the browser a redirect back |
* to the consumer site. This redirect contains the server's |
* response to the authentication request. |
* |
* The most important part of the flow to note is the consumer's site |
* must handle two separate HTTP requests in order to perform the full |
* identity check. |
* |
* LIBRARY DESIGN |
* |
* This consumer library is designed with that flow in mind. The goal |
* is to make it as easy as possible to perform the above steps |
* securely. |
* |
* At a high level, there are two important parts in the consumer |
* library. The first important part is this module, which contains |
* the interface to actually use this library. The second is the |
* Auth_OpenID_Interface class, which describes the interface to use |
* if you need to create a custom method for storing the state this |
* library needs to maintain between requests. |
* |
* In general, the second part is less important for users of the |
* library to know about, as several implementations are provided |
* which cover a wide variety of situations in which consumers may use |
* the library. |
* |
* This module contains a class, Auth_OpenID_Consumer, with methods |
* corresponding to the actions necessary in each of steps 2, 3, and 4 |
* described in the overview. Use of this library should be as easy |
* as creating an Auth_OpenID_Consumer instance and calling the |
* methods appropriate for the action the site wants to take. |
* |
* STORES AND DUMB MODE |
* |
* OpenID is a protocol that works best when the consumer site is able |
* to store some state. This is the normal mode of operation for the |
* protocol, and is sometimes referred to as smart mode. There is |
* also a fallback mode, known as dumb mode, which is available when |
* the consumer site is not able to store state. This mode should be |
* avoided when possible, as it leaves the implementation more |
* vulnerable to replay attacks. |
* |
* The mode the library works in for normal operation is determined by |
* the store that it is given. The store is an abstraction that |
* handles the data that the consumer needs to manage between http |
* requests in order to operate efficiently and securely. |
* |
* Several store implementation are provided, and the interface is |
* fully documented so that custom stores can be used as well. See |
* the documentation for the Auth_OpenID_Consumer class for more |
* information on the interface for stores. The implementations that |
* are provided allow the consumer site to store the necessary data in |
* several different ways, including several SQL databases and normal |
* files on disk. |
* |
* There is an additional concrete store provided that puts the system |
* in dumb mode. This is not recommended, as it removes the library's |
* ability to stop replay attacks reliably. It still uses time-based |
* checking to make replay attacks only possible within a small |
* window, but they remain possible within that window. This store |
* should only be used if the consumer site has no way to retain data |
* between requests at all. |
* |
* IMMEDIATE MODE |
* |
* In the flow described above, the user may need to confirm to the |
* lidentity server that it's ok to authorize his or her identity. |
* The server may draw pages asking for information from the user |
* before it redirects the browser back to the consumer's site. This |
* is generally transparent to the consumer site, so it is typically |
* ignored as an implementation detail. |
* |
* There can be times, however, where the consumer site wants to get a |
* response immediately. When this is the case, the consumer can put |
* the library in immediate mode. In immediate mode, there is an |
* extra response possible from the server, which is essentially the |
* server reporting that it doesn't have enough information to answer |
* the question yet. In addition to saying that, the identity server |
* provides a URL to which the user can be sent to provide the needed |
* information and let the server finish handling the original |
* request. |
* |
* USING THIS LIBRARY |
* |
* Integrating this library into an application is usually a |
* relatively straightforward process. The process should basically |
* follow this plan: |
* |
* Add an OpenID login field somewhere on your site. When an OpenID |
* is entered in that field and the form is submitted, it should make |
* a request to the your site which includes that OpenID URL. |
* |
* First, the application should instantiate the Auth_OpenID_Consumer |
* class using the store of choice (Auth_OpenID_FileStore or one of |
* the SQL-based stores). If the application has any sort of session |
* framework that provides per-client state management, a dict-like |
* object to access the session should be passed as the optional |
* second parameter. (The default behavior is to use PHP's standard |
* session machinery.) |
* |
* Next, the application should call the Auth_OpenID_Consumer object's |
* 'begin' method. This method takes the OpenID URL. The 'begin' |
* method returns an Auth_OpenID_AuthRequest object. |
* |
* Next, the application should call the 'redirectURL' method of the |
* Auth_OpenID_AuthRequest object. The 'return_to' URL parameter is |
* the URL that the OpenID server will send the user back to after |
* attempting to verify his or her identity. The 'trust_root' is the |
* URL (or URL pattern) that identifies your web site to the user when |
* he or she is authorizing it. Send a redirect to the resulting URL |
* to the user's browser. |
* |
* That's the first half of the authentication process. The second |
* half of the process is done after the user's ID server sends the |
* user's browser a redirect back to your site to complete their |
* login. |
* |
* When that happens, the user will contact your site at the URL given |
* as the 'return_to' URL to the Auth_OpenID_AuthRequest::redirectURL |
* call made above. The request will have several query parameters |
* added to the URL by the identity server as the information |
* necessary to finish the request. |
* |
* Lastly, instantiate an Auth_OpenID_Consumer instance as above and |
* call its 'complete' method, passing in all the received query |
* arguments. |
* |
* There are multiple possible return types possible from that |
* method. These indicate the whether or not the login was successful, |
* and include any additional information appropriate for their type. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* Require utility classes and functions for the consumer. |
*/ |
require_once "Auth/OpenID.php"; |
require_once "Auth/OpenID/HMACSHA1.php"; |
require_once "Auth/OpenID/Association.php"; |
require_once "Auth/OpenID/CryptUtil.php"; |
require_once "Auth/OpenID/DiffieHellman.php"; |
require_once "Auth/OpenID/KVForm.php"; |
require_once "Auth/OpenID/Discover.php"; |
require_once "Services/Yadis/Manager.php"; |
require_once "Services/Yadis/XRI.php"; |
/** |
* This is the status code returned when the complete method returns |
* successfully. |
*/ |
define('Auth_OpenID_SUCCESS', 'success'); |
/** |
* Status to indicate cancellation of OpenID authentication. |
*/ |
define('Auth_OpenID_CANCEL', 'cancel'); |
/** |
* This is the status code completeAuth returns when the value it |
* received indicated an invalid login. |
*/ |
define('Auth_OpenID_FAILURE', 'failure'); |
/** |
* This is the status code completeAuth returns when the |
* {@link Auth_OpenID_Consumer} instance is in immediate mode, and the |
* identity server sends back a URL to send the user to to complete his |
* or her login. |
*/ |
define('Auth_OpenID_SETUP_NEEDED', 'setup needed'); |
/** |
* This is the status code beginAuth returns when the page fetched |
* from the entered OpenID URL doesn't contain the necessary link tags |
* to function as an identity page. |
*/ |
define('Auth_OpenID_PARSE_ERROR', 'parse error'); |
/** |
* This is the characters that the nonces are made from. |
*/ |
define('Auth_OpenID_DEFAULT_NONCE_CHRS',"abcdefghijklmnopqrstuvwxyz" . |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); |
/** |
* An OpenID consumer implementation that performs discovery and does |
* session management. See the Consumer.php file documentation for |
* more information. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_Consumer { |
/** |
* @access private |
*/ |
var $session_key_prefix = "_openid_consumer_"; |
/** |
* @access private |
*/ |
var $_token_suffix = "last_token"; |
/** |
* Initialize a Consumer instance. |
* |
* You should create a new instance of the Consumer object with |
* every HTTP request that handles OpenID transactions. |
* |
* @param Auth_OpenID_OpenIDStore $store This must be an object |
* that implements the interface in {@link |
* Auth_OpenID_OpenIDStore}. Several concrete implementations are |
* provided, to cover most common use cases. For stores backed by |
* MySQL, PostgreSQL, or SQLite, see the {@link |
* Auth_OpenID_SQLStore} class and its sublcasses. For a |
* filesystem-backed store, see the {@link Auth_OpenID_FileStore} |
* module. As a last resort, if it isn't possible for the server |
* to store state at all, an instance of {@link |
* Auth_OpenID_DumbStore} can be used. |
* |
* @param mixed session An object which implements the interface |
* of the Services_Yadis_Session class. Particularly, this object |
* is expected to have these methods: get($key), set($key, |
* $value), and del($key). This defaults to a session object |
* which wraps PHP's native session machinery. You should only |
* need to pass something here if you have your own sessioning |
* implementation. |
*/ |
function Auth_OpenID_Consumer(&$store, $session = null) |
{ |
if ($session === null) { |
$session = new Services_Yadis_PHPSession(); |
} |
$this->session =& $session; |
$this->consumer =& new Auth_OpenID_GenericConsumer($store); |
$this->_token_key = $this->session_key_prefix . $this->_token_suffix; |
} |
/** |
* Start the OpenID authentication process. See steps 1-2 in the |
* overview at the top of this file. |
* |
* @param User_url: Identity URL given by the user. This method |
* performs a textual transformation of the URL to try and make |
* sure it is normalized. For example, a user_url of example.com |
* will be normalized to http://example.com/ normalizing and |
* resolving any redirects the server might issue. |
* |
* @return Auth_OpenID_AuthRequest $auth_request An object |
* containing the discovered information will be returned, with a |
* method for building a redirect URL to the server, as described |
* in step 3 of the overview. This object may also be used to add |
* extension arguments to the request, using its 'addExtensionArg' |
* method. |
*/ |
function begin($user_url) |
{ |
$discoverMethod = '_Auth_OpenID_discoverServiceList'; |
$openid_url = $user_url; |
if (Services_Yadis_identifierScheme($user_url) == 'XRI') { |
$discoverMethod = '_Auth_OpenID_discoverXRIServiceList'; |
} else { |
$openid_url = Auth_OpenID::normalizeUrl($user_url); |
} |
$disco =& new Services_Yadis_Discovery($this->session, |
$openid_url, |
$this->session_key_prefix); |
// Set the 'stale' attribute of the manager. If discovery |
// fails in a fatal way, the stale flag will cause the manager |
// to be cleaned up next time discovery is attempted. |
$m = $disco->getManager(); |
$loader = new Services_Yadis_ManagerLoader(); |
if ($m) { |
if ($m->stale) { |
$disco->destroyManager(); |
} else { |
$m->stale = true; |
$disco->session->set($disco->session_key, |
serialize($loader->toSession($m))); |
} |
} |
$endpoint = $disco->getNextService($discoverMethod, |
$this->consumer->fetcher); |
// Reset the 'stale' attribute of the manager. |
$m =& $disco->getManager(); |
if ($m) { |
$m->stale = false; |
$disco->session->set($disco->session_key, |
serialize($loader->toSession($m))); |
} |
if ($endpoint === null) { |
return null; |
} else { |
return $this->beginWithoutDiscovery($endpoint); |
} |
} |
/** |
* Start OpenID verification without doing OpenID server |
* discovery. This method is used internally by Consumer.begin |
* after discovery is performed, and exists to provide an |
* interface for library users needing to perform their own |
* discovery. |
* |
* @param Auth_OpenID_ServiceEndpoint $endpoint an OpenID service |
* endpoint descriptor. |
* |
* @return Auth_OpenID_AuthRequest $auth_request An OpenID |
* authentication request object. |
*/ |
function &beginWithoutDiscovery($endpoint) |
{ |
$loader = new Auth_OpenID_ServiceEndpointLoader(); |
$auth_req = $this->consumer->begin($endpoint); |
$this->session->set($this->_token_key, |
$loader->toSession($auth_req->endpoint)); |
return $auth_req; |
} |
/** |
* Called to interpret the server's response to an OpenID |
* request. It is called in step 4 of the flow described in the |
* consumer overview. |
* |
* @param array $query An array of the query parameters (key => |
* value pairs) for this HTTP request. |
* |
* @return Auth_OpenID_ConsumerResponse $response A instance of an |
* Auth_OpenID_ConsumerResponse subclass. The type of response is |
* indicated by the status attribute, which will be one of |
* SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED. |
*/ |
function complete($query) |
{ |
$query = Auth_OpenID::fixArgs($query); |
$loader = new Auth_OpenID_ServiceEndpointLoader(); |
$endpoint_data = $this->session->get($this->_token_key); |
$endpoint = |
$loader->fromSession($endpoint_data); |
if ($endpoint === null) { |
$response = new Auth_OpenID_FailureResponse(null, |
'No session state found'); |
} else { |
$response = $this->consumer->complete($query, $endpoint); |
$this->session->del($this->_token_key); |
} |
if (in_array($response->status, array(Auth_OpenID_SUCCESS, |
Auth_OpenID_CANCEL))) { |
if ($response->identity_url !== null) { |
$disco = new Services_Yadis_Discovery($this->session, |
$response->identity_url, |
$this->session_key_prefix); |
$disco->cleanup(); |
} |
} |
return $response; |
} |
} |
class Auth_OpenID_DiffieHellmanConsumerSession { |
var $session_type = 'DH-SHA1'; |
function Auth_OpenID_DiffieHellmanConsumerSession($dh = null) |
{ |
if ($dh === null) { |
$dh = new Auth_OpenID_DiffieHellman(); |
} |
$this->dh = $dh; |
} |
function getRequest() |
{ |
$math =& Auth_OpenID_getMathLib(); |
$cpub = $math->longToBase64($this->dh->public); |
$args = array('openid.dh_consumer_public' => $cpub); |
if (!$this->dh->usingDefaultValues()) { |
$args = array_merge($args, array( |
'openid.dh_modulus' => |
$math->longToBase64($this->dh->mod), |
'openid.dh_gen' => |
$math->longToBase64($this->dh->gen))); |
} |
return $args; |
} |
function extractSecret($response) |
{ |
if (!array_key_exists('dh_server_public', $response)) { |
return null; |
} |
if (!array_key_exists('enc_mac_key', $response)) { |
return null; |
} |
$math =& Auth_OpenID_getMathLib(); |
$spub = $math->base64ToLong($response['dh_server_public']); |
$enc_mac_key = base64_decode($response['enc_mac_key']); |
return $this->dh->xorSecret($spub, $enc_mac_key); |
} |
} |
class Auth_OpenID_PlainTextConsumerSession { |
var $session_type = null; |
function getRequest() |
{ |
return array(); |
} |
function extractSecret($response) |
{ |
if (!array_key_exists('mac_key', $response)) { |
return null; |
} |
return base64_decode($response['mac_key']); |
} |
} |
/** |
* This class is the interface to the OpenID consumer logic. |
* Instances of it maintain no per-request state, so they can be |
* reused (or even used by multiple threads concurrently) as needed. |
* |
* @package OpenID |
* @access private |
*/ |
class Auth_OpenID_GenericConsumer { |
/** |
* This consumer's store object. |
*/ |
var $store; |
/** |
* @access private |
*/ |
var $_use_assocs; |
/** |
* This is the number of characters in the generated nonce for |
* each transaction. |
*/ |
var $nonce_len = 8; |
/** |
* What characters are allowed in nonces |
*/ |
var $nonce_chrs = Auth_OpenID_DEFAULT_NONCE_CHRS; |
/** |
* This method initializes a new {@link Auth_OpenID_Consumer} |
* instance to access the library. |
* |
* @param Auth_OpenID_OpenIDStore $store This must be an object |
* that implements the interface in {@link Auth_OpenID_OpenIDStore}. |
* Several concrete implementations are provided, to cover most common use |
* cases. For stores backed by MySQL, PostgreSQL, or SQLite, see |
* the {@link Auth_OpenID_SQLStore} class and its sublcasses. For a |
* filesystem-backed store, see the {@link Auth_OpenID_FileStore} module. |
* As a last resort, if it isn't possible for the server to store |
* state at all, an instance of {@link Auth_OpenID_DumbStore} can be used. |
* |
* @param bool $immediate This is an optional boolean value. It |
* controls whether the library uses immediate mode, as explained |
* in the module description. The default value is False, which |
* disables immediate mode. |
*/ |
function Auth_OpenID_GenericConsumer(&$store) |
{ |
$this->store =& $store; |
$this->_use_assocs = |
!(defined('Auth_OpenID_NO_MATH_SUPPORT') || |
($this->store && $this->store->isDumb())); |
$this->fetcher = Services_Yadis_Yadis::getHTTPFetcher(); |
} |
function begin($service_endpoint) |
{ |
$nonce = $this->_createNonce(); |
$assoc = $this->_getAssociation($service_endpoint->server_url); |
$r = new Auth_OpenID_AuthRequest($assoc, $service_endpoint); |
$r->return_to_args['nonce'] = $nonce; |
return $r; |
} |
function complete($query, $endpoint) |
{ |
$mode = Auth_OpenID::arrayGet($query, 'openid.mode', |
'<no mode specified>'); |
if ($mode == Auth_OpenID_CANCEL) { |
return new Auth_OpenID_CancelResponse($endpoint); |
} else if ($mode == 'error') { |
$error = Auth_OpenID::arrayGet($query, 'openid.error'); |
return new Auth_OpenID_FailureResponse($endpoint, $error); |
} else if ($mode == 'id_res') { |
if ($endpoint->identity_url === null) { |
return new Auth_OpenID_FailureResponse($identity_url, |
"No session state found"); |
} |
$response = $this->_doIdRes($query, $endpoint); |
if ($response === null) { |
return new Auth_OpenID_FailureResponse($endpoint, |
"HTTP request failed"); |
} |
if ($response->status == Auth_OpenID_SUCCESS) { |
return $this->_checkNonce($response, |
Auth_OpenID::arrayGet($query, |
'nonce')); |
} else { |
return $response; |
} |
} else { |
return new Auth_OpenID_FailureResponse($endpoint, |
sprintf("Invalid openid.mode '%s'", |
$mode)); |
} |
} |
/** |
* @access private |
*/ |
function _doIdRes($query, $endpoint) |
{ |
$user_setup_url = Auth_OpenID::arrayGet($query, |
'openid.user_setup_url'); |
if ($user_setup_url !== null) { |
return new Auth_OpenID_SetupNeededResponse($endpoint, |
$user_setup_url); |
} |
$return_to = Auth_OpenID::arrayGet($query, 'openid.return_to', null); |
$server_id2 = Auth_OpenID::arrayGet($query, 'openid.identity', null); |
$assoc_handle = Auth_OpenID::arrayGet($query, |
'openid.assoc_handle', null); |
if (($return_to === null) || |
($server_id2 === null) || |
($assoc_handle === null)) { |
return new Auth_OpenID_FailureResponse($endpoint, |
"Missing required field"); |
} |
if ($endpoint->getServerID() != $server_id2) { |
return new Auth_OpenID_FailureResponse($endpoint, |
"Server ID (delegate) mismatch"); |
} |
$signed = Auth_OpenID::arrayGet($query, 'openid.signed'); |
$assoc = $this->store->getAssociation($endpoint->server_url, |
$assoc_handle); |
if ($assoc === null) { |
// It's not an association we know about. Dumb mode is |
// our only possible path for recovery. |
if ($this->_checkAuth($query, $endpoint->server_url)) { |
return new Auth_OpenID_SuccessResponse($endpoint, $query, |
$signed); |
} else { |
return new Auth_OpenID_FailureResponse($endpoint, |
"Server denied check_authentication"); |
} |
} |
if ($assoc->getExpiresIn() <= 0) { |
$msg = sprintf("Association with %s expired", |
$endpoint->server_url); |
return new Auth_OpenID_FailureResponse($endpoint, $msg); |
} |
// Check the signature |
$sig = Auth_OpenID::arrayGet($query, 'openid.sig', null); |
if (($sig === null) || |
($signed === null)) { |
return new Auth_OpenID_FailureResponse($endpoint, |
"Missing argument signature"); |
} |
$signed_list = explode(",", $signed); |
//Fail if the identity field is present but not signed |
if (($endpoint->identity_url !== null) && |
(!in_array('identity', $signed_list))) { |
$msg = '"openid.identity" not signed'; |
return new Auth_OpenID_FailureResponse($endpoint, $msg); |
} |
$v_sig = $assoc->signDict($signed_list, $query); |
if ($v_sig != $sig) { |
return new Auth_OpenID_FailureResponse($endpoint, |
"Bad signature"); |
} |
return Auth_OpenID_SuccessResponse::fromQuery($endpoint, |
$query, $signed); |
} |
/** |
* @access private |
*/ |
function _checkAuth($query, $server_url) |
{ |
$request = $this->_createCheckAuthRequest($query); |
if ($request === null) { |
return false; |
} |
$response = $this->_makeKVPost($request, $server_url); |
if ($response == null) { |
return false; |
} |
return $this->_processCheckAuthResponse($response, $server_url); |
} |
/** |
* @access private |
*/ |
function _createCheckAuthRequest($query) |
{ |
$signed = Auth_OpenID::arrayGet($query, 'openid.signed', null); |
if ($signed === null) { |
return null; |
} |
$whitelist = array('assoc_handle', 'sig', |
'signed', 'invalidate_handle'); |
$signed = array_merge(explode(",", $signed), $whitelist); |
$check_args = array(); |
foreach ($query as $key => $value) { |
if (in_array(substr($key, 7), $signed)) { |
$check_args[$key] = $value; |
} |
} |
$check_args['openid.mode'] = 'check_authentication'; |
return $check_args; |
} |
/** |
* @access private |
*/ |
function _processCheckAuthResponse($response, $server_url) |
{ |
$is_valid = Auth_OpenID::arrayGet($response, 'is_valid', 'false'); |
$invalidate_handle = Auth_OpenID::arrayGet($response, |
'invalidate_handle'); |
if ($invalidate_handle !== null) { |
$this->store->removeAssociation($server_url, |
$invalidate_handle); |
} |
if ($is_valid == 'true') { |
return true; |
} |
return false; |
} |
/** |
* @access private |
*/ |
function _makeKVPost($args, $server_url) |
{ |
$mode = $args['openid.mode']; |
$pairs = array(); |
foreach ($args as $k => $v) { |
$v = urlencode($v); |
$pairs[] = "$k=$v"; |
} |
$body = implode("&", $pairs); |
$resp = $this->fetcher->post($server_url, $body); |
if ($resp === null) { |
return null; |
} |
$response = Auth_OpenID_KVForm::toArray($resp->body); |
if ($resp->status == 400) { |
return null; |
} else if ($resp->status != 200) { |
return null; |
} |
return $response; |
} |
/** |
* @access private |
*/ |
function _checkNonce($response, $nonce) |
{ |
$parsed_url = parse_url($response->getReturnTo()); |
$query_str = @$parsed_url['query']; |
$query = array(); |
parse_str($query_str, $query); |
$found = false; |
foreach ($query as $k => $v) { |
if ($k == 'nonce') { |
if ($v != $nonce) { |
return new Auth_OpenID_FailureResponse($response, |
"Nonce mismatch"); |
} else { |
$found = true; |
break; |
} |
} |
} |
if (!$found) { |
return new Auth_OpenID_FailureResponse($response, |
sprintf("Nonce missing from return_to: %s", |
$response->getReturnTo())); |
} |
if (!$this->store->useNonce($nonce)) { |
return new Auth_OpenID_FailureResponse($response, |
"Nonce missing from store"); |
} |
return $response; |
} |
/** |
* @access private |
*/ |
function _createNonce() |
{ |
$nonce = Auth_OpenID_CryptUtil::randomString($this->nonce_len, |
$this->nonce_chrs); |
$this->store->storeNonce($nonce); |
return $nonce; |
} |
/** |
* @access protected |
*/ |
function _createDiffieHellman() |
{ |
return new Auth_OpenID_DiffieHellman(); |
} |
/** |
* @access private |
*/ |
function _getAssociation($server_url) |
{ |
if (!$this->_use_assocs) { |
return null; |
} |
$assoc = $this->store->getAssociation($server_url); |
if (($assoc === null) || |
($assoc->getExpiresIn() <= 0)) { |
$parts = $this->_createAssociateRequest($server_url); |
if ($parts === null) { |
return null; |
} |
list($assoc_session, $args) = $parts; |
$response = $this->_makeKVPost($args, $server_url); |
if ($response === null) { |
$assoc = null; |
} else { |
$assoc = $this->_parseAssociation($response, $assoc_session, |
$server_url); |
} |
} |
return $assoc; |
} |
function _createAssociateRequest($server_url) |
{ |
$parts = parse_url($server_url); |
if ($parts === false) { |
return null; |
} |
if (array_key_exists('scheme', $parts)) { |
$proto = $parts['scheme']; |
} else { |
$proto = 'http'; |
} |
if ($proto == 'https') { |
$assoc_session = new Auth_OpenID_PlainTextConsumerSession(); |
} else { |
$assoc_session = new Auth_OpenID_DiffieHellmanConsumerSession(); |
} |
$args = array( |
'openid.mode' => 'associate', |
'openid.assoc_type' => 'HMAC-SHA1'); |
if ($assoc_session->session_type !== null) { |
$args['openid.session_type'] = $assoc_session->session_type; |
} |
$args = array_merge($args, $assoc_session->getRequest()); |
return array($assoc_session, $args); |
} |
/** |
* @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; |
} |
} |
/** |
* This class represents an authentication request from a consumer to |
* an OpenID server. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_AuthRequest { |
/** |
* Initialize an authentication request with the specified token, |
* association, and endpoint. |
* |
* Users of this library should not create instances of this |
* class. Instances of this class are created by the library when |
* needed. |
*/ |
function Auth_OpenID_AuthRequest($assoc, $endpoint) |
{ |
$this->assoc = $assoc; |
$this->endpoint = $endpoint; |
$this->extra_args = array(); |
$this->return_to_args = array(); |
} |
/** |
* Add an extension argument to this OpenID authentication |
* request. |
* |
* Use caution when adding arguments, because they will be |
* URL-escaped and appended to the redirect URL, which can easily |
* get quite long. |
* |
* @param string $namespace The namespace for the extension. For |
* example, the simple registration extension uses the namespace |
* 'sreg'. |
* |
* @param string $key The key within the extension namespace. For |
* example, the nickname field in the simple registration |
* extension's key is 'nickname'. |
* |
* @param string $value The value to provide to the server for |
* this argument. |
*/ |
function addExtensionArg($namespace, $key, $value) |
{ |
$arg_name = implode('.', array('openid', $namespace, $key)); |
$this->extra_args[$arg_name] = $value; |
} |
/** |
* Compute the appropriate redirection URL for this request based |
* on a specified trust root and return-to. |
* |
* @param string $trust_root The trust root URI for your |
* application. |
* |
* @param string$ $return_to The return-to URL to be used when the |
* OpenID server redirects the user back to your site. |
* |
* @return string $redirect_url The resulting redirect URL that |
* you should send to the user agent. |
*/ |
function redirectURL($trust_root, $return_to, $immediate=false) |
{ |
if ($immediate) { |
$mode = 'checkid_immediate'; |
} else { |
$mode = 'checkid_setup'; |
} |
$return_to = Auth_OpenID::appendArgs($return_to, $this->return_to_args); |
$redir_args = array( |
'openid.mode' => $mode, |
'openid.identity' => $this->endpoint->getServerID(), |
'openid.return_to' => $return_to, |
'openid.trust_root' => $trust_root); |
if ($this->assoc) { |
$redir_args['openid.assoc_handle'] = $this->assoc->handle; |
} |
$redir_args = array_merge($redir_args, $this->extra_args); |
return Auth_OpenID::appendArgs($this->endpoint->server_url, |
$redir_args); |
} |
} |
/** |
* The base class for responses from the Auth_OpenID_Consumer. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_ConsumerResponse { |
var $status = null; |
} |
/** |
* A response with a status of Auth_OpenID_SUCCESS. Indicates that |
* this request is a successful acknowledgement from the OpenID server |
* that the supplied URL is, indeed controlled by the requesting |
* agent. This has three relevant attributes: |
* |
* identity_url - The identity URL that has been authenticated |
* |
* signed_args - The arguments in the server's response that were |
* signed and verified. |
* |
* status - Auth_OpenID_SUCCESS. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse { |
var $status = Auth_OpenID_SUCCESS; |
/** |
* @access private |
*/ |
function Auth_OpenID_SuccessResponse($endpoint, $signed_args) |
{ |
$this->endpoint = $endpoint; |
$this->identity_url = $endpoint->identity_url; |
$this->signed_args = $signed_args; |
} |
/** |
* @access private |
*/ |
function fromQuery($endpoint, $query, $signed) |
{ |
$signed_args = array(); |
foreach (explode(",", $signed) as $field_name) { |
$field_name = 'openid.' . $field_name; |
$signed_args[$field_name] = Auth_OpenID::arrayGet($query, |
$field_name, ''); |
} |
return new Auth_OpenID_SuccessResponse($endpoint, $signed_args); |
} |
/** |
* Extract signed extension data from the server's response. |
* |
* @param string $prefix The extension namespace from which to |
* extract the extension data. |
*/ |
function extensionResponse($prefix) |
{ |
$response = array(); |
$prefix = sprintf('openid.%s.', $prefix); |
$prefix_len = strlen($prefix); |
foreach ($this->signed_args as $k => $v) { |
if (strpos($k, $prefix) === 0) { |
$response_key = substr($k, $prefix_len); |
$response[$response_key] = $v; |
} |
} |
return $response; |
} |
/** |
* Get the openid.return_to argument from this response. |
* |
* This is useful for verifying that this request was initiated by |
* this consumer. |
* |
* @return string $return_to The return_to URL supplied to the |
* server on the initial request, or null if the response did not |
* contain an 'openid.return_to' argument. |
*/ |
function getReturnTo() |
{ |
return Auth_OpenID::arrayGet($this->signed_args, 'openid.return_to'); |
} |
} |
/** |
* A response with a status of Auth_OpenID_FAILURE. Indicates that the |
* OpenID protocol has failed. This could be locally or remotely |
* triggered. This has three relevant attributes: |
* |
* identity_url - The identity URL for which authentication was |
* attempted, if it can be determined. Otherwise, null. |
* |
* message - A message indicating why the request failed, if one is |
* supplied. Otherwise, null. |
* |
* status - Auth_OpenID_FAILURE. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_FailureResponse extends Auth_OpenID_ConsumerResponse { |
var $status = Auth_OpenID_FAILURE; |
function Auth_OpenID_FailureResponse($endpoint, $message = null) |
{ |
$this->endpoint = $endpoint; |
if ($endpoint !== null) { |
$this->identity_url = $endpoint->identity_url; |
} else { |
$this->identity_url = null; |
} |
$this->message = $message; |
} |
} |
/** |
* A response with a status of Auth_OpenID_CANCEL. Indicates that the |
* user cancelled the OpenID authentication request. This has two |
* relevant attributes: |
* |
* identity_url - The identity URL for which authentication was |
* attempted, if it can be determined. Otherwise, null. |
* |
* status - Auth_OpenID_SUCCESS. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_CancelResponse extends Auth_OpenID_ConsumerResponse { |
var $status = Auth_OpenID_CANCEL; |
function Auth_OpenID_CancelResponse($endpoint) |
{ |
$this->endpoint = $endpoint; |
$this->identity_url = $endpoint->identity_url; |
} |
} |
/** |
* A response with a status of Auth_OpenID_SETUP_NEEDED. Indicates |
* that the request was in immediate mode, and the server is unable to |
* authenticate the user without further interaction. |
* |
* identity_url - The identity URL for which authentication was |
* attempted. |
* |
* setup_url - A URL that can be used to send the user to the server |
* to set up for authentication. The user should be redirected in to |
* the setup_url, either in the current window or in a new browser |
* window. |
* |
* status - Auth_OpenID_SETUP_NEEDED. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_SetupNeededResponse extends Auth_OpenID_ConsumerResponse { |
var $status = Auth_OpenID_SETUP_NEEDED; |
function Auth_OpenID_SetupNeededResponse($endpoint, |
$setup_url = null) |
{ |
$this->endpoint = $endpoint; |
$this->identity_url = $endpoint->identity_url; |
$this->setup_url = $setup_url; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/FileStore.php |
---|
New file |
0,0 → 1,674 |
<?php |
/** |
* This file supplies a Memcached store backend for OpenID servers and |
* consumers. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
* |
*/ |
/** |
* Require base class for creating a new interface. |
*/ |
require_once 'Auth/OpenID.php'; |
require_once 'Auth/OpenID/Interface.php'; |
require_once 'Auth/OpenID/HMACSHA1.php'; |
/** |
* This is a filesystem-based store for OpenID associations and |
* nonces. This store should be safe for use in concurrent systems on |
* both windows and unix (excluding NFS filesystems). There are a |
* couple race conditions in the system, but those failure cases have |
* been set up in such a way that the worst-case behavior is someone |
* having to try to log in a second time. |
* |
* Most of the methods of this class are implementation details. |
* People wishing to just use this store need only pay attention to |
* the constructor. |
* |
* @package OpenID |
*/ |
class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore { |
/** |
* Initializes a new {@link Auth_OpenID_FileStore}. This |
* initializes the nonce and association directories, which are |
* subdirectories of the directory passed in. |
* |
* @param string $directory This is the directory to put the store |
* directories in. |
*/ |
function Auth_OpenID_FileStore($directory) |
{ |
if (!Auth_OpenID::ensureDir($directory)) { |
trigger_error('Not a directory and failed to create: ' |
. $directory, E_USER_ERROR); |
} |
$directory = realpath($directory); |
$this->directory = $directory; |
$this->active = true; |
$this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces'; |
$this->association_dir = $directory . DIRECTORY_SEPARATOR . |
'associations'; |
// Temp dir must be on the same filesystem as the assciations |
// $directory and the $directory containing the auth key file. |
$this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp'; |
$this->auth_key_name = $directory . DIRECTORY_SEPARATOR . 'auth_key'; |
$this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds |
if (!$this->_setup()) { |
trigger_error('Failed to initialize OpenID file store in ' . |
$directory, E_USER_ERROR); |
} |
} |
function destroy() |
{ |
Auth_OpenID_FileStore::_rmtree($this->directory); |
$this->active = false; |
} |
/** |
* Make sure that the directories in which we store our data |
* exist. |
* |
* @access private |
*/ |
function _setup() |
{ |
return (Auth_OpenID::ensureDir(dirname($this->auth_key_name)) && |
Auth_OpenID::ensureDir($this->nonce_dir) && |
Auth_OpenID::ensureDir($this->association_dir) && |
Auth_OpenID::ensureDir($this->temp_dir)); |
} |
/** |
* Create a temporary file on the same filesystem as |
* $this->auth_key_name and $this->association_dir. |
* |
* The temporary directory should not be cleaned if there are any |
* processes using the store. If there is no active process using |
* the store, it is safe to remove all of the files in the |
* temporary directory. |
* |
* @return array ($fd, $filename) |
* @access private |
*/ |
function _mktemp() |
{ |
$name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir); |
$file_obj = @fopen($name, 'wb'); |
if ($file_obj !== false) { |
return array($file_obj, $name); |
} else { |
Auth_OpenID_FileStore::_removeIfPresent($name); |
} |
} |
/** |
* Read the auth key from the auth key file. Will return None if |
* there is currently no key. |
* |
* @return mixed |
*/ |
function readAuthKey() |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$auth_key_file = @fopen($this->auth_key_name, 'rb'); |
if ($auth_key_file === false) { |
return null; |
} |
$key = fread($auth_key_file, filesize($this->auth_key_name)); |
fclose($auth_key_file); |
return $key; |
} |
/** |
* Generate a new random auth key and safely store it in the |
* location specified by $this->auth_key_name. |
* |
* @return string $key |
*/ |
function createAuthKey() |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$auth_key = Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN); |
list($file_obj, $tmp) = $this->_mktemp(); |
fwrite($file_obj, $auth_key); |
fflush($file_obj); |
fclose($file_obj); |
if (function_exists('link')) { |
// Posix filesystem |
$saved = link($tmp, $this->auth_key_name); |
Auth_OpenID_FileStore::_removeIfPresent($tmp); |
} else { |
// Windows filesystem |
$saved = rename($tmp, $this->auth_key_name); |
} |
if (!$saved) { |
// The link failed, either because we lack the permission, |
// or because the file already exists; try to read the key |
// in case the file already existed. |
$auth_key = $this->readAuthKey(); |
} |
return $auth_key; |
} |
/** |
* Retrieve the auth key from the file specified by |
* $this->auth_key_name, creating it if it does not exist. |
* |
* @return string $key |
*/ |
function getAuthKey() |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$auth_key = $this->readAuthKey(); |
if ($auth_key === null) { |
$auth_key = $this->createAuthKey(); |
if (strlen($auth_key) != $this->AUTH_KEY_LEN) { |
$fmt = 'Got an invalid auth key from %s. Expected '. |
'%d-byte string. Got: %s'; |
$msg = sprintf($fmt, $this->auth_key_name, $this->AUTH_KEY_LEN, |
$auth_key); |
trigger_error($msg, E_USER_WARNING); |
return null; |
} |
} |
return $auth_key; |
} |
/** |
* Create a unique filename for a given server url and |
* handle. This implementation does not assume anything about the |
* format of the handle. The filename that is returned will |
* contain the domain name from the server URL for ease of human |
* inspection of the data directory. |
* |
* @return string $filename |
*/ |
function getAssociationFilename($server_url, $handle) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
if (strpos($server_url, '://') === false) { |
trigger_error(sprintf("Bad server URL: %s", $server_url), |
E_USER_WARNING); |
return null; |
} |
list($proto, $rest) = explode('://', $server_url, 2); |
$parts = explode('/', $rest); |
$domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]); |
$url_hash = Auth_OpenID_FileStore::_safe64($server_url); |
if ($handle) { |
$handle_hash = Auth_OpenID_FileStore::_safe64($handle); |
} else { |
$handle_hash = ''; |
} |
$filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash, |
$handle_hash); |
return $this->association_dir. DIRECTORY_SEPARATOR . $filename; |
} |
/** |
* Store an association in the association directory. |
*/ |
function storeAssociation($server_url, $association) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return false; |
} |
$association_s = $association->serialize(); |
$filename = $this->getAssociationFilename($server_url, |
$association->handle); |
list($tmp_file, $tmp) = $this->_mktemp(); |
if (!$tmp_file) { |
trigger_error("_mktemp didn't return a valid file descriptor", |
E_USER_WARNING); |
return false; |
} |
fwrite($tmp_file, $association_s); |
fflush($tmp_file); |
fclose($tmp_file); |
if (@rename($tmp, $filename)) { |
return true; |
} else { |
// In case we are running on Windows, try unlinking the |
// file in case it exists. |
@unlink($filename); |
// Now the target should not exist. Try renaming again, |
// giving up if it fails. |
if (@rename($tmp, $filename)) { |
return true; |
} |
} |
// If there was an error, don't leave the temporary file |
// around. |
Auth_OpenID_FileStore::_removeIfPresent($tmp); |
return false; |
} |
/** |
* Retrieve an association. If no handle is specified, return the |
* association with the most recent issue time. |
* |
* @return mixed $association |
*/ |
function getAssociation($server_url, $handle = null) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
if ($handle === null) { |
$handle = ''; |
} |
// The filename with the empty handle is a prefix of all other |
// associations for the given server URL. |
$filename = $this->getAssociationFilename($server_url, $handle); |
if ($handle) { |
return $this->_getAssociation($filename); |
} else { |
$association_files = |
Auth_OpenID_FileStore::_listdir($this->association_dir); |
$matching_files = array(); |
// strip off the path to do the comparison |
$name = basename($filename); |
foreach ($association_files as $association_file) { |
if (strpos($association_file, $name) === 0) { |
$matching_files[] = $association_file; |
} |
} |
$matching_associations = array(); |
// read the matching files and sort by time issued |
foreach ($matching_files as $name) { |
$full_name = $this->association_dir . DIRECTORY_SEPARATOR . |
$name; |
$association = $this->_getAssociation($full_name); |
if ($association !== null) { |
$matching_associations[] = array($association->issued, |
$association); |
} |
} |
$issued = array(); |
$assocs = array(); |
foreach ($matching_associations as $key => $assoc) { |
$issued[$key] = $assoc[0]; |
$assocs[$key] = $assoc[1]; |
} |
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC, |
$matching_associations); |
// return the most recently issued one. |
if ($matching_associations) { |
list($issued, $assoc) = $matching_associations[0]; |
return $assoc; |
} else { |
return null; |
} |
} |
} |
/** |
* @access private |
*/ |
function _getAssociation($filename) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$assoc_file = @fopen($filename, 'rb'); |
if ($assoc_file === false) { |
return null; |
} |
$assoc_s = fread($assoc_file, filesize($filename)); |
fclose($assoc_file); |
if (!$assoc_s) { |
return null; |
} |
$association = |
Auth_OpenID_Association::deserialize('Auth_OpenID_Association', |
$assoc_s); |
if (!$association) { |
Auth_OpenID_FileStore::_removeIfPresent($filename); |
return null; |
} |
if ($association->getExpiresIn() == 0) { |
Auth_OpenID_FileStore::_removeIfPresent($filename); |
return null; |
} else { |
return $association; |
} |
} |
/** |
* Remove an association if it exists. Do nothing if it does not. |
* |
* @return bool $success |
*/ |
function removeAssociation($server_url, $handle) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$assoc = $this->getAssociation($server_url, $handle); |
if ($assoc === null) { |
return false; |
} else { |
$filename = $this->getAssociationFilename($server_url, $handle); |
return Auth_OpenID_FileStore::_removeIfPresent($filename); |
} |
} |
/** |
* Mark this nonce as present. |
*/ |
function storeNonce($nonce) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce; |
$nonce_file = fopen($filename, 'w'); |
if ($nonce_file === false) { |
return false; |
} |
fclose($nonce_file); |
return true; |
} |
/** |
* Return whether this nonce is present. As a side effect, mark it |
* as no longer present. |
* |
* @return bool $present |
*/ |
function useNonce($nonce) |
{ |
if (!$this->active) { |
trigger_error("FileStore no longer active", E_USER_ERROR); |
return null; |
} |
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce; |
$st = @stat($filename); |
if ($st === false) { |
return false; |
} |
// Either it is too old or we are using it. Either way, we |
// must remove the file. |
if (!unlink($filename)) { |
return false; |
} |
$now = time(); |
$nonce_age = $now - $st[9]; |
// We can us it if the age of the file is less than the |
// expiration time. |
return $nonce_age <= $this->max_nonce_age; |
} |
/** |
* 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); |
} |
} |
} |
} |
} |
/** |
* @access private |
*/ |
function _rmtree($dir) |
{ |
if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) { |
$dir .= DIRECTORY_SEPARATOR; |
} |
if ($handle = opendir($dir)) { |
while ($item = readdir($handle)) { |
if (!in_array($item, array('.', '..'))) { |
if (is_dir($dir . $item)) { |
if (!Auth_OpenID_FileStore::_rmtree($dir . $item)) { |
return false; |
} |
} else if (is_file($dir . $item)) { |
if (!unlink($dir . $item)) { |
return false; |
} |
} |
} |
} |
closedir($handle); |
if (!@rmdir($dir)) { |
return false; |
} |
return true; |
} else { |
// Couldn't open directory. |
return false; |
} |
} |
/** |
* @access private |
*/ |
function _mkstemp($dir) |
{ |
foreach (range(0, 4) as $i) { |
$name = tempnam($dir, "php_openid_filestore_"); |
if ($name !== false) { |
return $name; |
} |
} |
return false; |
} |
/** |
* @access private |
*/ |
function _mkdtemp($dir) |
{ |
foreach (range(0, 4) as $i) { |
$name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) . |
"-" . strval(rand(1, time())); |
if (!mkdir($name, 0700)) { |
return false; |
} else { |
return $name; |
} |
} |
return false; |
} |
/** |
* @access private |
*/ |
function _listdir($dir) |
{ |
$handle = opendir($dir); |
$files = array(); |
while (false !== ($filename = readdir($handle))) { |
$files[] = $filename; |
} |
return $files; |
} |
/** |
* @access private |
*/ |
function _isFilenameSafe($char) |
{ |
$_Auth_OpenID_filename_allowed = Auth_OpenID_letters . |
Auth_OpenID_digits . "."; |
return (strpos($_Auth_OpenID_filename_allowed, $char) !== false); |
} |
/** |
* @access private |
*/ |
function _safe64($str) |
{ |
$h64 = base64_encode(Auth_OpenID_SHA1($str)); |
$h64 = str_replace('+', '_', $h64); |
$h64 = str_replace('/', '.', $h64); |
$h64 = str_replace('=', '', $h64); |
return $h64; |
} |
/** |
* @access private |
*/ |
function _filenameEscape($str) |
{ |
$filename = ""; |
for ($i = 0; $i < strlen($str); $i++) { |
$c = $str[$i]; |
if (Auth_OpenID_FileStore::_isFilenameSafe($c)) { |
$filename .= $c; |
} else { |
$filename .= sprintf("_%02X", ord($c)); |
} |
} |
return $filename; |
} |
/** |
* Attempt to remove a file, returning whether the file existed at |
* the time of the call. |
* |
* @access private |
* @return bool $result True if the file was present, false if not. |
*/ |
function _removeIfPresent($filename) |
{ |
return @unlink($filename); |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/CryptUtil.php |
---|
New file |
0,0 → 1,109 |
<?php |
/** |
* CryptUtil: A suite of wrapper utility functions for the OpenID |
* library. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @access private |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
if (!defined('Auth_OpenID_RAND_SOURCE')) { |
/** |
* The filename for a source of random bytes. Define this yourself |
* if you have a different source of randomness. |
*/ |
define('Auth_OpenID_RAND_SOURCE', '/dev/urandom'); |
} |
class Auth_OpenID_CryptUtil { |
/** |
* Get the specified number of random bytes. |
* |
* Attempts to use a cryptographically secure (not predictable) |
* source of randomness if available. If there is no high-entropy |
* randomness source available, it will fail. As a last resort, |
* for non-critical systems, define |
* <code>Auth_OpenID_RAND_SOURCE</code> as <code>null</code>, and |
* the code will fall back on a pseudo-random number generator. |
* |
* @param int $num_bytes The length of the return value |
* @return string $bytes random bytes |
*/ |
function getBytes($num_bytes) |
{ |
static $f = null; |
$bytes = ''; |
if ($f === null) { |
if (Auth_OpenID_RAND_SOURCE === null) { |
$f = false; |
} else { |
$f = @fopen(Auth_OpenID_RAND_SOURCE, "r"); |
if ($f === false) { |
$msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' . |
' continue with an insecure random number generator.'; |
trigger_error($msg, E_USER_ERROR); |
} |
} |
} |
if ($f === false) { |
// pseudorandom used |
$bytes = ''; |
for ($i = 0; $i < $num_bytes; $i += 4) { |
$bytes .= pack('L', mt_rand()); |
} |
$bytes = substr($bytes, 0, $num_bytes); |
} else { |
$bytes = fread($f, $num_bytes); |
} |
return $bytes; |
} |
/** |
* Produce a string of length random bytes, chosen from chrs. If |
* $chrs is null, the resulting string may contain any characters. |
* |
* @param integer $length The length of the resulting |
* randomly-generated string |
* @param string $chrs A string of characters from which to choose |
* to build the new string |
* @return string $result A string of randomly-chosen characters |
* from $chrs |
*/ |
function randomString($length, $population = null) |
{ |
if ($population === null) { |
return Auth_OpenID_CryptUtil::getBytes($length); |
} |
$popsize = strlen($population); |
if ($popsize > 256) { |
$msg = 'More than 256 characters supplied to ' . __FUNCTION__; |
trigger_error($msg, E_USER_ERROR); |
} |
$duplicate = 256 % $popsize; |
$str = ""; |
for ($i = 0; $i < $length; $i++) { |
do { |
$n = ord(Auth_OpenID_CryptUtil::getBytes(1)); |
} while ($n < $duplicate); |
$n %= $popsize; |
$str .= $population[$n]; |
} |
return $str; |
} |
} |
?> |
/branches/v1.5-belier/composants/openid/Auth/OpenID/Interface.php |
---|
New file |
0,0 → 1,188 |
<?php |
/** |
* This file specifies the interface for PHP OpenID store implementations. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: See the COPYING file included in this distribution. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
* @copyright 2005 Janrain, Inc. |
* @license http://www.gnu.org/copyleft/lesser.html LGPL |
*/ |
/** |
* This is the interface for the store objects the OpenID library |
* uses. It is a single class that provides all of the persistence |
* mechanisms that the OpenID library needs, for both servers and |
* consumers. If you want to create an SQL-driven store, please see |
* then {@link Auth_OpenID_SQLStore} class. |
* |
* @package OpenID |
* @author JanRain, Inc. <openid@janrain.com> |
*/ |
class Auth_OpenID_OpenIDStore { |
/** |
* @var integer The length of the auth key that should be returned |
* by the getAuthKey method. |
*/ |
var $AUTH_KEY_LEN = 20; |
/** |
* This method puts an Association object into storage, |
* retrievable by server URL and handle. |
* |
* @param string $server_url The URL of the identity server that |
* this association is with. Because of the way the server portion |
* of the library uses this interface, don't assume there are any |
* limitations on the character set of the input string. In |
* particular, expect to see unescaped non-url-safe characters in |
* the server_url field. |
* |
* @param Association $association The Association to store. |
*/ |
function storeAssociation($server_url, $association) |
{ |
trigger_error("Auth_OpenID_OpenIDStore::storeAssociation ". |
"not implemented", E_USER_ERROR); |
} |
/** |
* This method returns an Association object from storage that |
* matches the server URL and, if specified, handle. It returns |
* null if no such association is found or if the matching |
* association is expired. |
* |
* If no handle is specified, the store may return any association |
* which matches the server URL. If multiple associations are |
* valid, the recommended return value for this method is the one |
* that will remain valid for the longest duration. |
* |
* This method is allowed (and encouraged) to garbage collect |
* expired associations when found. This method must not return |
* expired associations. |
* |
* @param string $server_url The URL of the identity server to get |
* the association for. Because of the way the server portion of |
* the library uses this interface, don't assume there are any |
* limitations on the character set of the input string. In |
* particular, expect to see unescaped non-url-safe characters in |
* the server_url field. |
* |
* @param mixed $handle This optional parameter is the handle of |
* the specific association to get. If no specific handle is |
* provided, any valid association matching the server URL is |
* returned. |
* |
* @return Association The Association for the given identity |
* server. |
*/ |
function getAssociation($server_url, $handle = null) |
{ |
trigger_error("Auth_OpenID_OpenIDStore::getAssociation ". |
"not implemented", E_USER_ERROR); |
} |
/** |
* This method removes the matching association if it's found, and |
* returns whether the association was removed or not. |
* |
* @param string $server_url The URL of the identity server the |
* association to remove belongs to. Because of the way the server |
* portion of the library uses this interface, don't assume there |
* are any limitations on the character set of the input |
* string. In particular, expect to see unescaped non-url-safe |
* characters in the server_url field. |
* |
* @param string $handle This is the handle of the association to |
* remove. If there isn't an association found that matches both |
* the given URL and handle, then there was no matching handle |
* found. |
* |
* @return mixed Returns whether or not the given association existed. |
*/ |
function removeAssociation($server_url, $handle) |
{ |
trigger_error("Auth_OpenID_OpenIDStore::removeAssociation ". |
"not implemented", E_USER_ERROR); |
} |
/** |
* Stores a nonce. This is used by the consumer to prevent replay |
* attacks. |
* |
* @param string $nonce The nonce to store. |
* |
* @return null |
*/ |
function storeNonce($nonce) |
{ |
trigger_error("Auth_OpenID_OpenIDStore::storeNonce ". |
"not implemented", E_USER_ERROR); |
} |
/** |
* This method is called when the library is attempting to use a |
* nonce. If the nonce is in the store, this method removes it and |
* returns a value which evaluates as true. Otherwise it returns a |
* value which evaluates as false. |
* |
* This method is allowed and encouraged to treat nonces older |
* than some period (a very conservative window would be 6 hours, |
* for example) as no longer existing, and return False and remove |
* them. |
* |
* @param string $nonce The nonce to use. |
* |
* @return bool Whether or not the nonce was valid. |
*/ |
function useNonce($nonce) |
{ |
trigger_error("Auth_OpenID_OpenIDStore::useNonce ". |
"not implemented", E_USER_ERROR); |
} |
/** |
* This method returns a key used to sign the tokens, to ensure |
* that they haven't been tampered with in transit. It should |
* return the same key every time it is called. The key returned |
* should be {@link AUTH_KEY_LEN} bytes long. |
* |
* @return string The key. It should be {@link AUTH_KEY_LEN} bytes in |
* length, and use the full range of byte values. That is, it |
* should be treated as a lump of binary data stored in a string. |
*/ |
function getAuthKey() |
{ |
trigger_error("Auth_OpenID_OpenIDStore::getAuthKey ". |
"not implemented", E_USER_ERROR); |
} |
/** |
* This method must return true if the store is a dumb-mode-style |
* store. Unlike all other methods in this class, this one |
* provides a default implementation, which returns false. |
* |
* In general, any custom subclass of {@link Auth_OpenID_OpenIDStore} |
* won't override this method, as custom subclasses are only likely to |
* be created when the store is fully functional. |
* |
* @return bool true if the store works fully, false if the |
* consumer will have to use dumb mode to use this store. |
*/ |
function isDumb() |
{ |
return false; |
} |
/** |
* Removes all entries from the store; implementation is optional. |
*/ |
function reset() |
{ |
} |
} |
?> |