webmaster@1: $val) { webmaster@1: $query[] = $key .'='. urlencode($val); webmaster@1: } webmaster@1: webmaster@1: $sep = (strpos($url, '?') === FALSE) ? '?' : '&'; webmaster@1: header('Location: '. $url . $sep . implode('&', $query), TRUE, 302); webmaster@1: exit; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Creates a js auto-submit redirect for (for the 2.x protocol) webmaster@1: */ webmaster@1: function openid_redirect($url, $message) { webmaster@1: $output = ''. t('OpenID redirect') ."\n"; webmaster@1: $output .= drupal_get_form('openid_redirect_form', $url, $message); webmaster@1: $output .= ''; webmaster@1: $output .= "\n"; webmaster@1: print $output; webmaster@1: exit; webmaster@1: } webmaster@1: webmaster@1: function openid_redirect_form(&$form_state, $url, $message) { webmaster@1: $form = array(); webmaster@1: $form['#action'] = $url; webmaster@1: $form['#method'] = "post"; webmaster@1: foreach ($message as $key => $value) { webmaster@1: $form[$key] = array( webmaster@1: '#type' => 'hidden', webmaster@1: '#name' => $key, webmaster@1: '#value' => $value, webmaster@1: ); webmaster@1: } webmaster@1: $form['submit'] = array( webmaster@1: '#type' => 'submit', webmaster@1: '#prefix' => '', webmaster@1: '#value' => t('Send'), webmaster@1: ); webmaster@1: webmaster@1: return $form; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Determine if the given identifier is an XRI ID. webmaster@1: */ webmaster@1: function _openid_is_xri($identifier) { webmaster@1: $firstchar = substr($identifier, 0, 1); webmaster@1: if ($firstchar == "@" || $firstchar == "=") webmaster@1: return TRUE; webmaster@1: webmaster@1: if (stristr($identifier, 'xri://') !== FALSE) { webmaster@1: return TRUE; webmaster@1: } webmaster@1: webmaster@1: return FALSE; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Normalize the given identifier as per spec. webmaster@1: */ webmaster@1: function _openid_normalize($identifier) { webmaster@1: if (_openid_is_xri($identifier)) { webmaster@1: return _openid_normalize_xri($identifier); webmaster@1: } webmaster@1: else { webmaster@1: return _openid_normalize_url($identifier); webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: function _openid_normalize_xri($xri) { webmaster@1: $normalized_xri = $xri; webmaster@1: if (stristr($xri, 'xri://') !== FALSE) { webmaster@1: $normalized_xri = substr($xri, 6); webmaster@1: } webmaster@1: return $normalized_xri; webmaster@1: } webmaster@1: webmaster@1: function _openid_normalize_url($url) { webmaster@1: $normalized_url = $url; webmaster@1: webmaster@1: if (stristr($url, '://') === FALSE) { webmaster@1: $normalized_url = 'http://'. $url; webmaster@1: } webmaster@1: webmaster@1: if (substr_count($normalized_url, '/') < 3) { webmaster@1: $normalized_url .= '/'; webmaster@1: } webmaster@1: webmaster@1: return $normalized_url; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Create a serialized message packet as per spec: $key:$value\n . webmaster@1: */ webmaster@1: function _openid_create_message($data) { webmaster@1: $serialized = ''; webmaster@1: webmaster@1: foreach ($data as $key => $value) { webmaster@1: if ((strpos($key, ':') !== FALSE) || (strpos($key, "\n") !== FALSE) || (strpos($value, "\n") !== FALSE)) { webmaster@1: return null; webmaster@1: } webmaster@1: $serialized .= "$key:$value\n"; webmaster@1: } webmaster@1: return $serialized; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Encode a message from _openid_create_message for HTTP Post webmaster@1: */ webmaster@1: function _openid_encode_message($message) { webmaster@1: $encoded_message = ''; webmaster@1: webmaster@1: $items = explode("\n", $message); webmaster@1: foreach ($items as $item) { webmaster@1: $parts = explode(':', $item, 2); webmaster@1: webmaster@1: if (count($parts) == 2) { webmaster@1: if ($encoded_message != '') { webmaster@1: $encoded_message .= '&'; webmaster@1: } webmaster@1: $encoded_message .= rawurlencode(trim($parts[0])) .'='. rawurlencode(trim($parts[1])); webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: return $encoded_message; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Convert a direct communication message webmaster@1: * into an associative array. webmaster@1: */ webmaster@1: function _openid_parse_message($message) { webmaster@1: $parsed_message = array(); webmaster@1: webmaster@1: $items = explode("\n", $message); webmaster@1: foreach ($items as $item) { webmaster@1: $parts = explode(':', $item, 2); webmaster@1: webmaster@1: if (count($parts) == 2) { webmaster@1: $parsed_message[$parts[0]] = $parts[1]; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: return $parsed_message; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a nonce value - formatted per OpenID spec. webmaster@1: */ webmaster@1: function _openid_nonce() { webmaster@1: // YYYY-MM-DDThh:mm:ssTZD UTC, plus some optional extra unique chars webmaster@1: return gmstrftime('%Y-%m-%dT%H:%M:%S%Z') . webmaster@1: chr(mt_rand(0, 25) + 65) . webmaster@1: chr(mt_rand(0, 25) + 65) . webmaster@1: chr(mt_rand(0, 25) + 65) . webmaster@1: chr(mt_rand(0, 25) + 65); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Pull the href attribute out of an html link element. webmaster@1: */ webmaster@1: function _openid_link_href($rel, $html) { webmaster@1: $rel = preg_quote($rel); webmaster@1: preg_match('||iUs', $html, $matches); webmaster@1: if (isset($matches[3])) { webmaster@1: preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href); webmaster@1: return trim($href[1]); webmaster@1: } webmaster@1: return FALSE; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Pull the http-equiv attribute out of an html meta element webmaster@1: */ webmaster@1: function _openid_meta_httpequiv($equiv, $html) { webmaster@1: preg_match('||iUs', $html, $matches); webmaster@1: if (isset($matches[1])) { webmaster@1: preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content); webmaster@1: if (isset($content[1])) { webmaster@1: return $content[1]; webmaster@1: } webmaster@1: } webmaster@1: return FALSE; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Sign certain keys in a message webmaster@1: * @param $association - object loaded from openid_association or openid_server_association table webmaster@1: * - important fields are ->assoc_type and ->mac_key webmaster@1: * @param $message_array - array of entire message about to be sent webmaster@1: * @param $keys_to_sign - keys in the message to include in signature (without webmaster@1: * 'openid.' appended) webmaster@1: */ webmaster@1: function _openid_signature($association, $message_array, $keys_to_sign) { webmaster@1: $signature = ''; webmaster@1: $sign_data = array(); webmaster@1: webmaster@1: foreach ($keys_to_sign as $key) { webmaster@1: if (isset($message_array['openid.'. $key])) { webmaster@1: $sign_data[$key] = $message_array['openid.'. $key]; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: $message = _openid_create_message($sign_data); webmaster@1: $secret = base64_decode($association->mac_key); webmaster@1: $signature = _openid_hmac($secret, $message); webmaster@1: webmaster@1: return base64_encode($signature); webmaster@1: } webmaster@1: webmaster@1: function _openid_hmac($key, $text) { webmaster@1: if (strlen($key) > OPENID_SHA1_BLOCKSIZE) { webmaster@1: $key = _openid_sha1($key, true); webmaster@1: } webmaster@1: webmaster@1: $key = str_pad($key, OPENID_SHA1_BLOCKSIZE, chr(0x00)); webmaster@1: $ipad = str_repeat(chr(0x36), OPENID_SHA1_BLOCKSIZE); webmaster@1: $opad = str_repeat(chr(0x5c), OPENID_SHA1_BLOCKSIZE); webmaster@1: $hash1 = _openid_sha1(($key ^ $ipad) . $text, true); webmaster@1: $hmac = _openid_sha1(($key ^ $opad) . $hash1, true); webmaster@1: webmaster@1: return $hmac; webmaster@1: } webmaster@1: webmaster@1: function _openid_sha1($text) { webmaster@1: $hex = sha1($text); webmaster@1: $raw = ''; webmaster@1: for ($i = 0; $i < 40; $i += 2) { webmaster@1: $hexcode = substr($hex, $i, 2); webmaster@1: $charcode = (int)base_convert($hexcode, 16, 10); webmaster@1: $raw .= chr($charcode); webmaster@1: } webmaster@1: return $raw; webmaster@1: } webmaster@1: webmaster@1: function _openid_dh_base64_to_long($str) { webmaster@1: $b64 = base64_decode($str); webmaster@1: webmaster@1: return _openid_dh_binary_to_long($b64); webmaster@1: } webmaster@1: webmaster@1: function _openid_dh_long_to_base64($str) { webmaster@1: return base64_encode(_openid_dh_long_to_binary($str)); webmaster@1: } webmaster@1: webmaster@1: function _openid_dh_binary_to_long($str) { webmaster@1: $bytes = array_merge(unpack('C*', $str)); webmaster@1: webmaster@1: $n = 0; webmaster@1: foreach ($bytes as $byte) { webmaster@1: $n = bcmul($n, pow(2, 8)); webmaster@1: $n = bcadd($n, $byte); webmaster@1: } webmaster@1: webmaster@1: return $n; webmaster@1: } webmaster@1: webmaster@1: function _openid_dh_long_to_binary($long) { webmaster@1: $cmp = bccomp($long, 0); webmaster@1: if ($cmp < 0) { webmaster@1: return FALSE; webmaster@1: } webmaster@1: webmaster@1: if ($cmp == 0) { webmaster@1: return "\x00"; webmaster@1: } webmaster@1: webmaster@1: $bytes = array(); webmaster@1: webmaster@1: while (bccomp($long, 0) > 0) { webmaster@1: array_unshift($bytes, bcmod($long, 256)); webmaster@1: $long = bcdiv($long, pow(2, 8)); webmaster@1: } webmaster@1: webmaster@1: if ($bytes && ($bytes[0] > 127)) { webmaster@1: array_unshift($bytes, 0); webmaster@1: } webmaster@1: webmaster@1: $string = ''; webmaster@1: foreach ($bytes as $byte) { webmaster@1: $string .= pack('C', $byte); webmaster@1: } webmaster@1: webmaster@1: return $string; webmaster@1: } webmaster@1: webmaster@1: function _openid_dh_xorsecret($shared, $secret) { webmaster@1: $dh_shared_str = _openid_dh_long_to_binary($shared); webmaster@1: $sha1_dh_shared = _openid_sha1($dh_shared_str); webmaster@1: $xsecret = ""; webmaster@1: for ($i = 0; $i < strlen($secret); $i++) { webmaster@1: $xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i])); webmaster@1: } webmaster@1: webmaster@1: return $xsecret; webmaster@1: } webmaster@1: webmaster@1: function _openid_dh_rand($stop) { webmaster@1: static $duplicate_cache = array(); webmaster@1: webmaster@1: // Used as the key for the duplicate cache webmaster@1: $rbytes = _openid_dh_long_to_binary($stop); webmaster@1: webmaster@1: if (array_key_exists($rbytes, $duplicate_cache)) { webmaster@1: list($duplicate, $nbytes) = $duplicate_cache[$rbytes]; webmaster@1: } webmaster@1: else { webmaster@1: if ($rbytes[0] == "\x00") { webmaster@1: $nbytes = strlen($rbytes) - 1; webmaster@1: } webmaster@1: else { webmaster@1: $nbytes = strlen($rbytes); webmaster@1: } webmaster@1: webmaster@1: $mxrand = bcpow(256, $nbytes); webmaster@1: webmaster@1: // If we get a number less than this, then it is in the webmaster@1: // duplicated range. webmaster@1: $duplicate = bcmod($mxrand, $stop); webmaster@1: webmaster@1: if (count($duplicate_cache) > 10) { webmaster@1: $duplicate_cache = array(); webmaster@1: } webmaster@1: webmaster@1: $duplicate_cache[$rbytes] = array($duplicate, $nbytes); webmaster@1: } webmaster@1: webmaster@1: do { webmaster@1: $bytes = "\x00". _openid_get_bytes($nbytes); webmaster@1: $n = _openid_dh_binary_to_long($bytes); webmaster@1: // Keep looping if this value is in the low duplicated range. webmaster@1: } while (bccomp($n, $duplicate) < 0); webmaster@1: webmaster@1: return bcmod($n, $stop); webmaster@1: } webmaster@1: webmaster@1: function _openid_get_bytes($num_bytes) { webmaster@1: static $f = null; webmaster@1: $bytes = ''; webmaster@1: if (!isset($f)) { webmaster@1: $f = @fopen(OPENID_RAND_SOURCE, "r"); webmaster@1: } webmaster@1: if (!$f) { webmaster@1: // pseudorandom used webmaster@1: $bytes = ''; webmaster@1: for ($i = 0; $i < $num_bytes; $i += 4) { webmaster@1: $bytes .= pack('L', mt_rand()); webmaster@1: } webmaster@1: $bytes = substr($bytes, 0, $num_bytes); webmaster@1: } webmaster@1: else { webmaster@1: $bytes = fread($f, $num_bytes); webmaster@1: } webmaster@1: return $bytes; webmaster@1: } webmaster@1: webmaster@1: function _openid_response($str = NULL) { webmaster@1: $data = array(); webmaster@1: webmaster@1: if (isset($_SERVER['REQUEST_METHOD'])) { webmaster@1: $data = _openid_get_params($_SERVER['QUERY_STRING']); webmaster@1: webmaster@1: if ($_SERVER['REQUEST_METHOD'] == 'POST') { webmaster@1: $str = file_get_contents('php://input'); webmaster@1: webmaster@1: $post = array(); webmaster@1: if ($str !== false) { webmaster@1: $post = _openid_get_params($str); webmaster@1: } webmaster@1: webmaster@1: $data = array_merge($data, $post); webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: return $data; webmaster@1: } webmaster@1: webmaster@1: function _openid_get_params($str) { webmaster@1: $chunks = explode("&", $str); webmaster@1: webmaster@1: $data = array(); webmaster@1: foreach ($chunks as $chunk) { webmaster@1: $parts = explode("=", $chunk, 2); webmaster@1: webmaster@1: if (count($parts) == 2) { webmaster@1: list($k, $v) = $parts; webmaster@1: $data[$k] = urldecode($v); webmaster@1: } webmaster@1: } webmaster@1: return $data; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Provide bcpowmod support for PHP4. webmaster@1: */ webmaster@1: if (!function_exists('bcpowmod')) { webmaster@1: function bcpowmod($base, $exp, $mod) { webmaster@1: $square = bcmod($base, $mod); webmaster@1: $result = 1; webmaster@1: while (bccomp($exp, 0) > 0) { webmaster@1: if (bcmod($exp, 2)) { webmaster@1: $result = bcmod(bcmul($result, $square), $mod); webmaster@1: } webmaster@1: $square = bcmod(bcmul($square, $square), $mod); webmaster@1: $exp = bcdiv($exp, 2); webmaster@1: } webmaster@1: return $result; webmaster@1: } webmaster@1: }