diff --git a/modules/member/member.controller.php b/modules/member/member.controller.php
index 22c0881e4..6b017974e 100644
--- a/modules/member/member.controller.php
+++ b/modules/member/member.controller.php
@@ -86,37 +86,112 @@
ob_clean();
}
+ function getLegacyUserIDsFromOpenID($openid_identity) {
+ // Issue 17515512:
+ // OpenID Provider가 openid.identity를
+ // http://araste.myid.net/ 으로 넘겨주든
+ // http://araste.myid.net 으로 넘겨주든,
+ // 동일한 제로보드 사용자 이름에 매핑되어야 한다.
+ // 가입되지 않은 경우엔 / 를 뗀 것이 우선이 된다.
+ // OpenID Provider의 정책의 일시적 변경 때문에
+ // / 가 붙은 꼴의 유저아이디로 (예: jangxyz.myid.net/ )
+ // 가입된 사례가 있다. 이 때는
+ // jangxyz.myid.net 과 jangxyz.myid.net/ 둘 모두로 시도해보아야 한다.
+ // 이를 위한 workaround이다.
+
+ $result = array();
+ $uri_matches = array();
+ preg_match(Auth_OpenID_getURIPattern(), $openid_identity, $uri_matches);
+
+ if (count($uri_matches) < 9) {
+ for ($i = count($uri_matches); $i <= 9; $i++) {
+ $uri_matches[] = '';
+ }
+ }
+
+ $scheme = $uri_matches[2];
+ $authority = $uri_matches[4];
+ $path = $uri_matches[5];
+ $query = $uri_matches[6];
+ $fragment = $uri_matches[8];
+
+ if ($scheme === null) $scheme = '';
+ if ($authority === null) $authority = '';
+ if ($path === null) $path = '';
+ if ($query === null) $query = '';
+ if ($fragment === null) $fragment = '';
+
+ if ($scheme == 'http' or $scheme == '')
+ $scheme_part = '';
+ else
+ $scheme_part = $scheme."://";
+
+
+ if ($path == '' || $path == '/') {
+ $result[] = $scheme_part.$authority.''.$query.$fragment;
+ $result[] = $scheme_part.$authority.'/'.$query.$fragment;
+ }
+ else {
+ $result[] = $scheme_part.$authority.$path.$query.$fragment;
+ }
+
+ return $result;
+ }
+
/**
* @brief openid 인증 체크
**/
function procMemberOpenIDValidate() {
+ // use the JanRain php-openid library
+ ini_set('include_path', ini_get('include_path').':./modules/member/php-openid-1.2.3');
+ require_once('Auth/OpenID/URINorm.php');
+
$oModuleModel = &getModel('module');
$config = $oModuleModel->getModuleConfig('member');
if($config->enable_openid != 'Y') $this->stop('msg_invalid_request');
+ $openid_identity = Auth_OpenID_urinorm($_GET['openid_identity']);
+
ob_start();
require('./modules/member/openid_lib/class.openid.php');
require_once('./modules/member/openid_lib/libcurlemu.inc.php');
$openid = new SimpleOpenID;
- $openid->SetIdentity($_GET['openid_identity']);
+ $openid->SetIdentity($openid_identity);
$openid_validation_result = $openid->ValidateWithServer();
+
ob_clean();
// 인증 성공
if ($openid_validation_result == true) {
- // 기본 정보들을 받음
- $args->user_id = $args->nick_name = preg_replace('/^http:\/\//i','',Context::get('openid_identity'));
- $args->email_address = Context::get('openid_sreg_email');
- $args->user_name = Context::get('openid_sreg_fullname');
- if(!$args->user_name) list($args->user_name) = explode('@', $args->email_address);
- $args->birthday = str_replace('-','',Context::get('openid_sreg_dob'));
- // 자체 인증 시도
- $output = $this->doLogin($args->user_id);
+ // 이 오픈아이디와 연결된 (또는 연결되어 있을 가능성이 있는) 제로보드 아이디들을 받아온다.
+ $login_success = false;
+ $user_id_candidates = $this->getLegacyUserIDsFromOpenID($openid_identity);
+
+ $default_user_id = $user_id_candidates[0];
+
+ foreach($user_id_candidates as $user_id) {
+ $args->user_id = $args->nick_name = $user_id;
+ // 기본 정보들을 받음
+ $args->email_address = Context::get('openid_sreg_email');
+ $args->user_name = Context::get('openid_sreg_fullname');
+ if(!$args->user_name) list($args->user_name) = explode('@', $args->email_address);
+ $args->birthday = str_replace('-','',Context::get('openid_sreg_dob'));
+
+ // 자체 인증 시도
+ $output = $this->doLogin($args->user_id);
+
+
+ if ($output->toBool()) {
+ $login_success = true;
+ break;
+ }
+ }
// 자체 인증 실패시 회원 가입시킴
- if(!$output->toBool()) {
+ if(!$login_success) {
+ $args->user_id = $args->nick_name = $default_user_id;
$args->password = md5(getmicrotime());
$output = $this->insertMember($args);
if(!$output->toBool()) return $this->stop($output->getMessage());
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID.php b/modules/member/php-openid-1.2.3/Auth/OpenID.php
new file mode 100644
index 000000000..86278b9f1
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID.php
@@ -0,0 +1,412 @@
+
+ * @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;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/Association.php b/modules/member/php-openid-1.2.3/Auth/OpenID/Association.php
new file mode 100644
index 000000000..109a97080
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/Association.php
@@ -0,0 +1,308 @@
+
+ * @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);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/BigMath.php b/modules/member/php-openid-1.2.3/Auth/OpenID/BigMath.php
new file mode 100644
index 000000000..3113104ba
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/BigMath.php
@@ -0,0 +1,444 @@
+
+ * @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;
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/Consumer.php b/modules/member/php-openid-1.2.3/Auth/OpenID/Consumer.php
new file mode 100644
index 000000000..7ea75c75a
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/Consumer.php
@@ -0,0 +1,1186 @@
+
+ * @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',
+ 'Auth_OpenID_RAND_SOURCE as null, 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;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/DatabaseConnection.php b/modules/member/php-openid-1.2.3/Auth/OpenID/DatabaseConnection.php
new file mode 100644
index 000000000..3f4515fa5
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/DatabaseConnection.php
@@ -0,0 +1,131 @@
+
+ * @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())
+ {
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/DiffieHellman.php b/modules/member/php-openid-1.2.3/Auth/OpenID/DiffieHellman.php
new file mode 100644
index 000000000..2b845b78b
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/DiffieHellman.php
@@ -0,0 +1,181 @@
+
+ * @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;
+ }
+}
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/Discover.php b/modules/member/php-openid-1.2.3/Auth/OpenID/Discover.php
new file mode 100644
index 000000000..d87d47d16
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/Discover.php
@@ -0,0 +1,258 @@
+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
+ $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 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
+ //
+ $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
+ $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);
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/DumbStore.php b/modules/member/php-openid-1.2.3/Auth/OpenID/DumbStore.php
new file mode 100644
index 000000000..d4d8a8b42
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/DumbStore.php
@@ -0,0 +1,116 @@
+
+ * @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;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/FileStore.php b/modules/member/php-openid-1.2.3/Auth/OpenID/FileStore.php
new file mode 100644
index 000000000..6ce88568e
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/FileStore.php
@@ -0,0 +1,674 @@
+
+ * @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);
+ }
+}
+
+?>
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/HMACSHA1.php b/modules/member/php-openid-1.2.3/Auth/OpenID/HMACSHA1.php
new file mode 100644
index 000000000..6daadb5f8
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/HMACSHA1.php
@@ -0,0 +1,72 @@
+
+ * @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;
+}
+
+?>
\ No newline at end of file
diff --git a/modules/member/php-openid-1.2.3/Auth/OpenID/Interface.php b/modules/member/php-openid-1.2.3/Auth/OpenID/Interface.php
new file mode 100644
index 000000000..ce9fa1feb
--- /dev/null
+++ b/modules/member/php-openid-1.2.3/Auth/OpenID/Interface.php
@@ -0,0 +1,188 @@
+
+ * @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.