[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/modules/openid/ -> openid.inc (source)

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


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7