home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / CMS / drupal-6.0.exe / drupal-6.0 / modules / openid / openid.inc < prev    next >
Encoding:
Text File  |  2008-01-31  |  10.4 KB  |  440 lines

  1. <?php
  2. // $Id: openid.inc,v 1.8 2008/01/30 22:11:22 goba Exp $
  3.  
  4. /**
  5.  * @file
  6.  * OpenID utility functions.
  7.  */
  8.  
  9. // Diffie-Hellman Key Exchange Default Value.
  10. define('OPENID_DH_DEFAULT_MOD', '155172898181473697471232257763715539915724801'.
  11.        '966915404479707795314057629378541917580651227423698188993727816152646631'.
  12.        '438561595825688188889951272158842675419950341258706556549803580104870537'.
  13.        '681476726513255747040765857479291291572334510643245094715007229621094194'.
  14.        '349783925984760375594985848253359305585439638443');
  15.  
  16. // Constants for Diffie-Hellman key exchange computations.
  17. define('OPENID_DH_DEFAULT_GEN', '2');
  18. define('OPENID_SHA1_BLOCKSIZE', 64);
  19. define('OPENID_RAND_SOURCE', '/dev/urandom');
  20.  
  21. // OpenID namespace URLs
  22. define('OPENID_NS_2_0', 'http://specs.openid.net/auth/2.0');
  23. define('OPENID_NS_1_1', 'http://openid.net/signon/1.1');
  24. define('OPENID_NS_1_0', 'http://openid.net/signon/1.0');
  25.  
  26. /**
  27.  * Performs an HTTP 302 redirect (for the 1.x protocol).
  28.  */
  29. function openid_redirect_http($url, $message) {
  30.   $query = array();
  31.   foreach ($message as $key => $val) {
  32.     $query[] = $key .'='. urlencode($val);
  33.   }
  34.  
  35.   $sep = (strpos($url, '?') === FALSE) ? '?' : '&';
  36.   header('Location: '. $url . $sep . implode('&', $query), TRUE, 302);
  37.   exit;
  38. }
  39.  
  40. /**
  41.  * Creates a js auto-submit redirect for (for the 2.x protocol)
  42.  */
  43. function openid_redirect($url, $message) {
  44.   $output = '<html><head><title>'. t('OpenID redirect') ."</title></head>\n<body>";
  45.   $output .= drupal_get_form('openid_redirect_form', $url, $message);
  46.   $output .= '<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>';
  47.   $output .= "</body></html>\n";
  48.   print $output;
  49.   exit;
  50. }
  51.  
  52. function openid_redirect_form(&$form_state, $url, $message) {
  53.   $form = array();
  54.   $form['#action'] = $url;
  55.   $form['#method'] = "post";
  56.   foreach ($message as $key => $value) {
  57.     $form[$key] = array(
  58.       '#type' => 'hidden',
  59.       '#name' => $key,
  60.       '#value' => $value,
  61.     );
  62.   }
  63.   $form['submit'] = array(
  64.     '#type' => 'submit',
  65.     '#prefix' => '<noscript>',
  66.     '#suffix' => '</noscript>',
  67.     '#value' => t('Send'),
  68.   );
  69.  
  70.   return $form;
  71. }
  72.  
  73. /**
  74.  * Determine if the given identifier is an XRI ID.
  75.  */
  76. function _openid_is_xri($identifier) {
  77.   $firstchar = substr($identifier, 0, 1);
  78.   if ($firstchar == "@" || $firstchar == "=")
  79.     return TRUE;
  80.  
  81.   if (stristr($identifier, 'xri://') !== FALSE) {
  82.     return TRUE;
  83.   }
  84.  
  85.   return FALSE;
  86. }
  87.  
  88. /**
  89.  * Normalize the given identifier as per spec.
  90.  */
  91. function _openid_normalize($identifier) {
  92.   if (_openid_is_xri($identifier)) {
  93.     return _openid_normalize_xri($identifier);
  94.   }
  95.   else {
  96.     return _openid_normalize_url($identifier);
  97.   }
  98. }
  99.  
  100. function _openid_normalize_xri($xri) {
  101.   $normalized_xri = $xri;
  102.   if (stristr($xri, 'xri://') !== FALSE) {
  103.     $normalized_xri = substr($xri, 6);
  104.   }
  105.   return $normalized_xri;
  106. }
  107.  
  108. function _openid_normalize_url($url) {
  109.   $normalized_url = $url;
  110.  
  111.   if (stristr($url, '://') === FALSE) {
  112.     $normalized_url = 'http://'. $url;
  113.   }
  114.  
  115.   if (substr_count($normalized_url, '/') < 3) {
  116.     $normalized_url .= '/';
  117.   }
  118.  
  119.   return $normalized_url;
  120. }
  121.  
  122. /**
  123.  * Create a serialized message packet as per spec: $key:$value\n .
  124.  */
  125. function _openid_create_message($data) {
  126.   $serialized = '';
  127.  
  128.   foreach ($data as $key => $value) {
  129.     if ((strpos($key, ':') !== FALSE) || (strpos($key, "\n") !== FALSE) || (strpos($value, "\n") !== FALSE)) {
  130.       return null;
  131.     }
  132.     $serialized .= "$key:$value\n";
  133.   }
  134.   return $serialized;
  135. }
  136.  
  137. /**
  138.  * Encode a message from _openid_create_message for HTTP Post
  139.  */
  140. function _openid_encode_message($message) {
  141.   $encoded_message = '';
  142.  
  143.   $items = explode("\n", $message);
  144.   foreach ($items as $item) {
  145.     $parts = explode(':', $item, 2);
  146.  
  147.     if (count($parts) == 2) {
  148.       if ($encoded_message != '') {
  149.         $encoded_message .= '&';
  150.       }
  151.       $encoded_message .= rawurlencode(trim($parts[0])) .'='. rawurlencode(trim($parts[1]));
  152.     }
  153.   }
  154.  
  155.   return $encoded_message;
  156. }
  157.  
  158. /**
  159.  * Convert a direct communication message
  160.  * into an associative array.
  161.  */
  162. function _openid_parse_message($message) {
  163.   $parsed_message = array();
  164.  
  165.   $items = explode("\n", $message);
  166.   foreach ($items as $item) {
  167.     $parts = explode(':', $item, 2);
  168.  
  169.     if (count($parts) == 2) {
  170.       $parsed_message[$parts[0]] = $parts[1];
  171.     }
  172.   }
  173.  
  174.   return $parsed_message;
  175. }
  176.  
  177. /**
  178.  * Return a nonce value - formatted per OpenID spec.
  179.  */
  180. function _openid_nonce() {
  181.   // YYYY-MM-DDThh:mm:ssTZD UTC, plus some optional extra unique chars
  182.   return gmstrftime('%Y-%m-%dT%H:%M:%S%Z') .
  183.     chr(mt_rand(0, 25) + 65) .
  184.     chr(mt_rand(0, 25) + 65) .
  185.     chr(mt_rand(0, 25) + 65) .
  186.     chr(mt_rand(0, 25) + 65);
  187. }
  188.  
  189. /**
  190.  * Pull the href attribute out of an html link element.
  191.  */
  192. function _openid_link_href($rel, $html) {
  193.   $rel = preg_quote($rel);
  194.   preg_match('|<link\s+rel=["\'](.*)'. $rel .'(.*)["\'](.*)/?>|iUs', $html, $matches);
  195.   if (isset($matches[3])) {
  196.     preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href);
  197.     return trim($href[1]);
  198.   }
  199.   return FALSE;
  200. }
  201.  
  202. /**
  203.  * Pull the http-equiv attribute out of an html meta element
  204.  */
  205. function _openid_meta_httpequiv($equiv, $html) {
  206.   preg_match('|<meta\s+http-equiv=["\']'. $equiv .'["\'](.*)/?>|iUs', $html, $matches);
  207.   if (isset($matches[1])) {
  208.     preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content);
  209.     if (isset($content[1])) {
  210.       return $content[1];
  211.     }
  212.   }
  213.   return FALSE;
  214. }
  215.  
  216. /**
  217.  * Sign certain keys in a message
  218.  * @param $association - object loaded from openid_association or openid_server_association table
  219.  *              - important fields are ->assoc_type and ->mac_key
  220.  * @param $message_array - array of entire message about to be sent
  221.  * @param $keys_to_sign - keys in the message to include in signature (without
  222.  *  'openid.' appended)
  223.  */
  224. function _openid_signature($association, $message_array, $keys_to_sign) {
  225.   $signature = '';
  226.   $sign_data = array();
  227.  
  228.   foreach ($keys_to_sign as $key) {
  229.     if (isset($message_array['openid.'. $key])) {
  230.       $sign_data[$key] = $message_array['openid.'. $key];
  231.     }
  232.   }
  233.  
  234.   $message = _openid_create_message($sign_data);
  235.   $secret = base64_decode($association->mac_key);
  236.   $signature = _openid_hmac($secret, $message);
  237.  
  238.   return base64_encode($signature);
  239. }
  240.  
  241. function _openid_hmac($key, $text) {
  242.   if (strlen($key) > OPENID_SHA1_BLOCKSIZE) {
  243.     $key = _openid_sha1($key, true);
  244.   }
  245.  
  246.   $key = str_pad($key, OPENID_SHA1_BLOCKSIZE, chr(0x00));
  247.   $ipad = str_repeat(chr(0x36), OPENID_SHA1_BLOCKSIZE);
  248.   $opad = str_repeat(chr(0x5c), OPENID_SHA1_BLOCKSIZE);
  249.   $hash1 = _openid_sha1(($key ^ $ipad) . $text, true);
  250.   $hmac = _openid_sha1(($key ^ $opad) . $hash1, true);
  251.  
  252.   return $hmac;
  253. }
  254.  
  255. function _openid_sha1($text) {
  256.   $hex = sha1($text);
  257.   $raw = '';
  258.   for ($i = 0; $i < 40; $i += 2) {
  259.     $hexcode = substr($hex, $i, 2);
  260.     $charcode = (int)base_convert($hexcode, 16, 10);
  261.     $raw .= chr($charcode);
  262.   }
  263.   return $raw;
  264. }
  265.  
  266. function _openid_dh_base64_to_long($str) {
  267.   $b64 = base64_decode($str);
  268.  
  269.   return _openid_dh_binary_to_long($b64);
  270. }
  271.  
  272. function _openid_dh_long_to_base64($str) {
  273.   return base64_encode(_openid_dh_long_to_binary($str));
  274. }
  275.  
  276. function _openid_dh_binary_to_long($str) {
  277.   $bytes = array_merge(unpack('C*', $str));
  278.  
  279.   $n = 0;
  280.   foreach ($bytes as $byte) {
  281.     $n = bcmul($n, pow(2, 8));
  282.     $n = bcadd($n, $byte);
  283.   }
  284.  
  285.   return $n;
  286. }
  287.  
  288. function _openid_dh_long_to_binary($long) {
  289.   $cmp = bccomp($long, 0);
  290.   if ($cmp < 0) {
  291.     return FALSE;
  292.   }
  293.  
  294.   if ($cmp == 0) {
  295.     return "\x00";
  296.   }
  297.  
  298.   $bytes = array();
  299.  
  300.   while (bccomp($long, 0) > 0) {
  301.     array_unshift($bytes, bcmod($long, 256));
  302.     $long = bcdiv($long, pow(2, 8));
  303.   }
  304.  
  305.   if ($bytes && ($bytes[0] > 127)) {
  306.     array_unshift($bytes, 0);
  307.   }
  308.  
  309.   $string = '';
  310.   foreach ($bytes as $byte) {
  311.     $string .= pack('C', $byte);
  312.   }
  313.  
  314.   return $string;
  315. }
  316.  
  317. function _openid_dh_xorsecret($shared, $secret) {
  318.   $dh_shared_str = _openid_dh_long_to_binary($shared);
  319.   $sha1_dh_shared = _openid_sha1($dh_shared_str);
  320.   $xsecret = "";
  321.   for ($i = 0; $i < strlen($secret); $i++) {
  322.     $xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i]));
  323.   }
  324.  
  325.   return $xsecret;
  326. }
  327.  
  328. function _openid_dh_rand($stop) {
  329.   static $duplicate_cache = array();
  330.  
  331.   // Used as the key for the duplicate cache
  332.   $rbytes = _openid_dh_long_to_binary($stop);
  333.  
  334.   if (array_key_exists($rbytes, $duplicate_cache)) {
  335.     list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
  336.   }
  337.   else {
  338.     if ($rbytes[0] == "\x00") {
  339.       $nbytes = strlen($rbytes) - 1;
  340.     }
  341.     else {
  342.       $nbytes = strlen($rbytes);
  343.     }
  344.  
  345.     $mxrand = bcpow(256, $nbytes);
  346.  
  347.     // If we get a number less than this, then it is in the
  348.     // duplicated range.
  349.     $duplicate = bcmod($mxrand, $stop);
  350.  
  351.     if (count($duplicate_cache) > 10) {
  352.       $duplicate_cache = array();
  353.     }
  354.  
  355.     $duplicate_cache[$rbytes] = array($duplicate, $nbytes);
  356.   }
  357.  
  358.   do {
  359.     $bytes = "\x00". _openid_get_bytes($nbytes);
  360.     $n = _openid_dh_binary_to_long($bytes);
  361.     // Keep looping if this value is in the low duplicated range.
  362.   } while (bccomp($n, $duplicate) < 0);
  363.  
  364.   return bcmod($n, $stop);
  365. }
  366.  
  367. function _openid_get_bytes($num_bytes) {
  368.   static $f = null;
  369.   $bytes = '';
  370.   if (!isset($f)) {
  371.     $f = @fopen(OPENID_RAND_SOURCE, "r");
  372.   }
  373.   if (!$f) {
  374.     // pseudorandom used
  375.     $bytes = '';
  376.     for ($i = 0; $i < $num_bytes; $i += 4) {
  377.       $bytes .= pack('L', mt_rand());
  378.     }
  379.     $bytes = substr($bytes, 0, $num_bytes);
  380.   }
  381.   else {
  382.     $bytes = fread($f, $num_bytes);
  383.   }
  384.   return $bytes;
  385. }
  386.  
  387. function _openid_response($str = NULL) {
  388.   $data = array();
  389.   
  390.   if (isset($_SERVER['REQUEST_METHOD'])) {
  391.     $data = _openid_get_params($_SERVER['QUERY_STRING']);
  392.  
  393.     if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  394.       $str = file_get_contents('php://input');
  395.  
  396.       $post = array();
  397.       if ($str !== false) {
  398.         $post = _openid_get_params($str);
  399.       }
  400.  
  401.       $data = array_merge($data, $post);
  402.     }
  403.   }
  404.  
  405.   return $data;
  406. }
  407.  
  408. function _openid_get_params($str) {
  409.   $chunks = explode("&", $str);
  410.  
  411.   $data = array();
  412.   foreach ($chunks as $chunk) {
  413.     $parts = explode("=", $chunk, 2);
  414.  
  415.     if (count($parts) == 2) {
  416.       list($k, $v) = $parts;
  417.       $data[$k] = urldecode($v);
  418.     }
  419.   }
  420.   return $data;
  421. }
  422.  
  423. /**
  424.  * Provide bcpowmod support for PHP4.
  425.  */
  426. if (!function_exists('bcpowmod')) {
  427.   function bcpowmod($base, $exp, $mod) {
  428.     $square = bcmod($base, $mod);
  429.     $result = 1;
  430.     while (bccomp($exp, 0) > 0) {
  431.       if (bcmod($exp, 2)) {
  432.         $result = bcmod(bcmul($result, $square), $mod);
  433.       }
  434.       $square = bcmod(bcmul($square, $square), $mod);
  435.       $exp = bcdiv($exp, 2);
  436.     }
  437.     return $result;
  438.   }
  439. }
  440.