annotate modules/openid/openid.inc @ 13:134d4b2e75f6

updated quicktabs and google analytics modules
author danieleb <danielebarchiesi@me.com>
date Tue, 29 Oct 2013 13:48:59 +0000
parents ff03f76ab3fe
children
rev   line source
danielebarchiesi@0 1 <?php
danielebarchiesi@0 2
danielebarchiesi@0 3 /**
danielebarchiesi@0 4 * @file
danielebarchiesi@0 5 * OpenID utility functions.
danielebarchiesi@0 6 */
danielebarchiesi@0 7
danielebarchiesi@0 8 /**
danielebarchiesi@0 9 * Diffie-Hellman Key Exchange Default Value.
danielebarchiesi@0 10 *
danielebarchiesi@0 11 * This is used to establish an association between the Relying Party and the
danielebarchiesi@0 12 * OpenID Provider.
danielebarchiesi@0 13 *
danielebarchiesi@0 14 * See RFC 2631: http://www.ietf.org/rfc/rfc2631.txt
danielebarchiesi@0 15 */
danielebarchiesi@0 16 define('OPENID_DH_DEFAULT_MOD', '155172898181473697471232257763715539915724801' .
danielebarchiesi@0 17 '966915404479707795314057629378541917580651227423698188993727816152646631' .
danielebarchiesi@0 18 '438561595825688188889951272158842675419950341258706556549803580104870537' .
danielebarchiesi@0 19 '681476726513255747040765857479291291572334510643245094715007229621094194' .
danielebarchiesi@0 20 '349783925984760375594985848253359305585439638443');
danielebarchiesi@0 21
danielebarchiesi@0 22 /**
danielebarchiesi@0 23 * Diffie-Hellman generator; used for Diffie-Hellman key exchange computations.
danielebarchiesi@0 24 */
danielebarchiesi@0 25 define('OPENID_DH_DEFAULT_GEN', '2');
danielebarchiesi@0 26
danielebarchiesi@0 27 /**
danielebarchiesi@0 28 * SHA-1 hash block size; used for Diffie-Hellman key exchange computations.
danielebarchiesi@0 29 */
danielebarchiesi@0 30 define('OPENID_SHA1_BLOCKSIZE', 64);
danielebarchiesi@0 31
danielebarchiesi@0 32 /**
danielebarchiesi@0 33 * Random number generator; used for Diffie-Hellman key exchange computations.
danielebarchiesi@0 34 */
danielebarchiesi@0 35 define('OPENID_RAND_SOURCE', '/dev/urandom');
danielebarchiesi@0 36
danielebarchiesi@0 37 /**
danielebarchiesi@0 38 * OpenID Authentication 2.0 namespace URL.
danielebarchiesi@0 39 */
danielebarchiesi@0 40 define('OPENID_NS_2_0', 'http://specs.openid.net/auth/2.0');
danielebarchiesi@0 41
danielebarchiesi@0 42 /**
danielebarchiesi@0 43 * OpenID Authentication 1.1 namespace URL; used for backwards-compatibility.
danielebarchiesi@0 44 */
danielebarchiesi@0 45 define('OPENID_NS_1_1', 'http://openid.net/signon/1.1');
danielebarchiesi@0 46
danielebarchiesi@0 47 /**
danielebarchiesi@0 48 * OpenID Authentication 1.0 namespace URL; used for backwards-compatibility.
danielebarchiesi@0 49 */
danielebarchiesi@0 50 define('OPENID_NS_1_0', 'http://openid.net/signon/1.0');
danielebarchiesi@0 51
danielebarchiesi@0 52 /**
danielebarchiesi@0 53 * OpenID namespace used in Yadis documents.
danielebarchiesi@0 54 */
danielebarchiesi@0 55 define('OPENID_NS_OPENID', 'http://openid.net/xmlns/1.0');
danielebarchiesi@0 56
danielebarchiesi@0 57 /**
danielebarchiesi@0 58 * OpenID Simple Registration extension.
danielebarchiesi@0 59 */
danielebarchiesi@0 60 define('OPENID_NS_SREG', 'http://openid.net/extensions/sreg/1.1');
danielebarchiesi@0 61
danielebarchiesi@0 62 /**
danielebarchiesi@0 63 * OpenID Attribute Exchange extension.
danielebarchiesi@0 64 */
danielebarchiesi@0 65 define('OPENID_NS_AX', 'http://openid.net/srv/ax/1.0');
danielebarchiesi@0 66
danielebarchiesi@0 67 /**
danielebarchiesi@0 68 * Extensible Resource Descriptor documents.
danielebarchiesi@0 69 */
danielebarchiesi@0 70 define('OPENID_NS_XRD', 'xri://$xrd*($v*2.0)');
danielebarchiesi@0 71
danielebarchiesi@0 72 /**
danielebarchiesi@0 73 * Performs an HTTP 302 redirect (for the 1.x protocol).
danielebarchiesi@0 74 */
danielebarchiesi@0 75 function openid_redirect_http($url, $message) {
danielebarchiesi@0 76 $query = array();
danielebarchiesi@0 77 foreach ($message as $key => $val) {
danielebarchiesi@0 78 $query[] = $key . '=' . urlencode($val);
danielebarchiesi@0 79 }
danielebarchiesi@0 80
danielebarchiesi@0 81 $sep = (strpos($url, '?') === FALSE) ? '?' : '&';
danielebarchiesi@0 82 header('Location: ' . $url . $sep . implode('&', $query), TRUE, 302);
danielebarchiesi@0 83
danielebarchiesi@0 84 drupal_exit();
danielebarchiesi@0 85 }
danielebarchiesi@0 86
danielebarchiesi@0 87 /**
danielebarchiesi@0 88 * Creates a js auto-submit redirect for (for the 2.x protocol)
danielebarchiesi@0 89 */
danielebarchiesi@0 90 function openid_redirect($url, $message) {
danielebarchiesi@0 91 global $language;
danielebarchiesi@0 92
danielebarchiesi@0 93 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n";
danielebarchiesi@0 94 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $language->language . '" lang="' . $language->language . '">' . "\n";
danielebarchiesi@0 95 $output .= "<head>\n";
danielebarchiesi@0 96 $output .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
danielebarchiesi@0 97 $output .= "<title>" . t('OpenID redirect') . "</title>\n";
danielebarchiesi@0 98 $output .= "</head>\n";
danielebarchiesi@0 99 $output .= "<body>\n";
danielebarchiesi@0 100 $elements = drupal_get_form('openid_redirect_form', $url, $message);
danielebarchiesi@0 101 $output .= drupal_render($elements);
danielebarchiesi@0 102 $output .= '<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>' . "\n";
danielebarchiesi@0 103 $output .= "</body>\n";
danielebarchiesi@0 104 $output .= "</html>\n";
danielebarchiesi@0 105 print $output;
danielebarchiesi@0 106
danielebarchiesi@0 107 drupal_exit();
danielebarchiesi@0 108 }
danielebarchiesi@0 109
danielebarchiesi@0 110 function openid_redirect_form($form, &$form_state, $url, $message) {
danielebarchiesi@0 111 $form['#action'] = $url;
danielebarchiesi@0 112 $form['#method'] = "post";
danielebarchiesi@0 113 foreach ($message as $key => $value) {
danielebarchiesi@0 114 $form[$key] = array(
danielebarchiesi@0 115 '#type' => 'hidden',
danielebarchiesi@0 116 '#name' => $key,
danielebarchiesi@0 117 '#value' => $value,
danielebarchiesi@0 118 );
danielebarchiesi@0 119 }
danielebarchiesi@0 120 $form['actions'] = array('#type' => 'actions');
danielebarchiesi@0 121 $form['actions']['submit'] = array(
danielebarchiesi@0 122 '#type' => 'submit',
danielebarchiesi@0 123 '#prefix' => '<noscript><div>',
danielebarchiesi@0 124 '#suffix' => '</div></noscript>',
danielebarchiesi@0 125 '#value' => t('Send'),
danielebarchiesi@0 126 );
danielebarchiesi@0 127
danielebarchiesi@0 128 return $form;
danielebarchiesi@0 129 }
danielebarchiesi@0 130
danielebarchiesi@0 131 /**
danielebarchiesi@0 132 * Parse an XRDS document.
danielebarchiesi@0 133 *
danielebarchiesi@0 134 * @param $raw_xml
danielebarchiesi@0 135 * A string containing the XRDS document.
danielebarchiesi@0 136 * @return
danielebarchiesi@0 137 * An array of service entries.
danielebarchiesi@0 138 */
danielebarchiesi@0 139 function _openid_xrds_parse($raw_xml) {
danielebarchiesi@0 140 $services = array();
danielebarchiesi@0 141
danielebarchiesi@0 142 // For PHP version >= 5.2.11, we can use this function to protect against
danielebarchiesi@0 143 // malicious doctype declarations and other unexpected entity loading.
danielebarchiesi@0 144 // However, we will not rely on it, and reject any XML with a DOCTYPE.
danielebarchiesi@0 145 $disable_entity_loader = function_exists('libxml_disable_entity_loader');
danielebarchiesi@0 146 if ($disable_entity_loader) {
danielebarchiesi@0 147 $load_entities = libxml_disable_entity_loader(TRUE);
danielebarchiesi@0 148 }
danielebarchiesi@0 149
danielebarchiesi@0 150 // Load the XML into a DOM document.
danielebarchiesi@0 151 $dom = new DOMDocument();
danielebarchiesi@0 152 @$dom->loadXML($raw_xml);
danielebarchiesi@0 153
danielebarchiesi@0 154 // Since DOCTYPE declarations from an untrusted source could be malicious, we
danielebarchiesi@0 155 // stop parsing here and treat the XML as invalid since XRDS documents do not
danielebarchiesi@0 156 // require, and are not expected to have, a DOCTYPE.
danielebarchiesi@0 157 if (isset($dom->doctype)) {
danielebarchiesi@0 158 return array();
danielebarchiesi@0 159 }
danielebarchiesi@0 160
danielebarchiesi@0 161 // Parse the DOM document for the information we need.
danielebarchiesi@0 162 if ($xml = simplexml_import_dom($dom)) {
danielebarchiesi@0 163 foreach ($xml->children(OPENID_NS_XRD)->XRD as $xrd) {
danielebarchiesi@0 164 foreach ($xrd->children(OPENID_NS_XRD)->Service as $service_element) {
danielebarchiesi@0 165 $service = array(
danielebarchiesi@0 166 'priority' => $service_element->attributes()->priority ? (int)$service_element->attributes()->priority : PHP_INT_MAX,
danielebarchiesi@0 167 'types' => array(),
danielebarchiesi@0 168 'uri' => (string)$service_element->children(OPENID_NS_XRD)->URI,
danielebarchiesi@0 169 'service' => $service_element,
danielebarchiesi@0 170 'xrd' => $xrd,
danielebarchiesi@0 171 );
danielebarchiesi@0 172 foreach ($service_element->Type as $type) {
danielebarchiesi@0 173 $service['types'][] = (string)$type;
danielebarchiesi@0 174 }
danielebarchiesi@0 175 if ($service_element->children(OPENID_NS_XRD)->LocalID) {
danielebarchiesi@0 176 $service['identity'] = (string)$service_element->children(OPENID_NS_XRD)->LocalID;
danielebarchiesi@0 177 }
danielebarchiesi@0 178 elseif ($service_element->children(OPENID_NS_OPENID)->Delegate) {
danielebarchiesi@0 179 $service['identity'] = (string)$service_element->children(OPENID_NS_OPENID)->Delegate;
danielebarchiesi@0 180 }
danielebarchiesi@0 181 else {
danielebarchiesi@0 182 $service['identity'] = FALSE;
danielebarchiesi@0 183 }
danielebarchiesi@0 184 $services[] = $service;
danielebarchiesi@0 185 }
danielebarchiesi@0 186 }
danielebarchiesi@0 187 }
danielebarchiesi@0 188
danielebarchiesi@0 189 // Return the LIBXML options to the previous state before returning.
danielebarchiesi@0 190 if ($disable_entity_loader) {
danielebarchiesi@0 191 libxml_disable_entity_loader($load_entities);
danielebarchiesi@0 192 }
danielebarchiesi@0 193
danielebarchiesi@0 194 return $services;
danielebarchiesi@0 195 }
danielebarchiesi@0 196
danielebarchiesi@0 197 /**
danielebarchiesi@0 198 * Select a service element.
danielebarchiesi@0 199 *
danielebarchiesi@0 200 * The procedure is described in OpenID Authentication 2.0, section 7.3.2.
danielebarchiesi@0 201 *
danielebarchiesi@0 202 * A new entry is added to the returned array with the key 'version' and the
danielebarchiesi@0 203 * value 1 or 2 specifying the protocol version used by the service.
danielebarchiesi@0 204 *
danielebarchiesi@0 205 * @param $services
danielebarchiesi@0 206 * An array of service arrays as returned by openid_discovery().
danielebarchiesi@0 207 * @return
danielebarchiesi@0 208 * The selected service array, or NULL if no valid services were found.
danielebarchiesi@0 209 */
danielebarchiesi@0 210 function _openid_select_service(array $services) {
danielebarchiesi@0 211 // Extensible Resource Identifier (XRI) Resolution Version 2.0, section 4.3.3:
danielebarchiesi@0 212 // Find the service with the highest priority (lowest integer value). If there
danielebarchiesi@0 213 // is a tie, select a random one, not just the first in the XML document.
danielebarchiesi@0 214 shuffle($services);
danielebarchiesi@0 215 $selected_service = NULL;
danielebarchiesi@0 216 $selected_type_priority = FALSE;
danielebarchiesi@0 217
danielebarchiesi@0 218 // Search for an OP Identifier Element.
danielebarchiesi@0 219 foreach ($services as $service) {
danielebarchiesi@0 220 if (!empty($service['uri'])) {
danielebarchiesi@0 221 $type_priority = FALSE;
danielebarchiesi@0 222 if (in_array('http://specs.openid.net/auth/2.0/server', $service['types'])) {
danielebarchiesi@0 223 $service['version'] = 2;
danielebarchiesi@0 224 $type_priority = 1;
danielebarchiesi@0 225 }
danielebarchiesi@0 226 elseif (in_array('http://specs.openid.net/auth/2.0/signon', $service['types'])) {
danielebarchiesi@0 227 $service['version'] = 2;
danielebarchiesi@0 228 $type_priority = 2;
danielebarchiesi@0 229 }
danielebarchiesi@0 230 elseif (in_array(OPENID_NS_1_0, $service['types']) || in_array(OPENID_NS_1_1, $service['types'])) {
danielebarchiesi@0 231 $service['version'] = 1;
danielebarchiesi@0 232 $type_priority = 3;
danielebarchiesi@0 233 }
danielebarchiesi@0 234
danielebarchiesi@0 235 if ($type_priority
danielebarchiesi@0 236 && (!$selected_service
danielebarchiesi@0 237 || $type_priority < $selected_type_priority
danielebarchiesi@0 238 || ($type_priority == $selected_type_priority && $service['priority'] < $selected_service['priority']))) {
danielebarchiesi@0 239 $selected_service = $service;
danielebarchiesi@0 240 $selected_type_priority = $type_priority;
danielebarchiesi@0 241 }
danielebarchiesi@0 242 }
danielebarchiesi@0 243 }
danielebarchiesi@0 244
danielebarchiesi@0 245 if ($selected_service) {
danielebarchiesi@0 246 // Unset SimpleXMLElement instances that cannot be saved in $_SESSION.
danielebarchiesi@0 247 unset($selected_service['xrd']);
danielebarchiesi@0 248 unset($selected_service['service']);
danielebarchiesi@0 249 }
danielebarchiesi@0 250
danielebarchiesi@0 251 return $selected_service;
danielebarchiesi@0 252 }
danielebarchiesi@0 253
danielebarchiesi@0 254 /**
danielebarchiesi@0 255 * Determine if the given identifier is an XRI ID.
danielebarchiesi@0 256 */
danielebarchiesi@0 257 function _openid_is_xri($identifier) {
danielebarchiesi@0 258 // Strip the xri:// scheme from the identifier if present.
danielebarchiesi@0 259 if (stripos($identifier, 'xri://') === 0) {
danielebarchiesi@0 260 $identifier = substr($identifier, 6);
danielebarchiesi@0 261 }
danielebarchiesi@0 262
danielebarchiesi@0 263 // Test whether the identifier starts with an XRI global context symbol or (.
danielebarchiesi@0 264 $firstchar = substr($identifier, 0, 1);
danielebarchiesi@0 265 if (strpos("=@+$!(", $firstchar) !== FALSE) {
danielebarchiesi@0 266 return TRUE;
danielebarchiesi@0 267 }
danielebarchiesi@0 268
danielebarchiesi@0 269 return FALSE;
danielebarchiesi@0 270 }
danielebarchiesi@0 271
danielebarchiesi@0 272 /**
danielebarchiesi@0 273 * Normalize the given identifier.
danielebarchiesi@0 274 *
danielebarchiesi@0 275 * The procedure is described in OpenID Authentication 2.0, section 7.2.
danielebarchiesi@0 276 */
danielebarchiesi@0 277 function openid_normalize($identifier) {
danielebarchiesi@0 278 $methods = module_invoke_all('openid_normalization_method_info');
danielebarchiesi@0 279 drupal_alter('openid_normalization_method_info', $methods);
danielebarchiesi@0 280
danielebarchiesi@0 281 // Execute each method in turn, stopping after the first method accepted
danielebarchiesi@0 282 // the identifier.
danielebarchiesi@0 283 foreach ($methods as $method) {
danielebarchiesi@0 284 $result = $method($identifier);
danielebarchiesi@0 285 if ($result !== NULL) {
danielebarchiesi@0 286 $identifier = $result;
danielebarchiesi@0 287 break;
danielebarchiesi@0 288 }
danielebarchiesi@0 289 }
danielebarchiesi@0 290
danielebarchiesi@0 291 return $identifier;
danielebarchiesi@0 292 }
danielebarchiesi@0 293
danielebarchiesi@0 294 /**
danielebarchiesi@0 295 * OpenID normalization method: normalize XRI identifiers.
danielebarchiesi@0 296 */
danielebarchiesi@0 297 function _openid_xri_normalize($identifier) {
danielebarchiesi@0 298 if (_openid_is_xri($identifier)) {
danielebarchiesi@0 299 if (stristr($identifier, 'xri://') !== FALSE) {
danielebarchiesi@0 300 $identifier = substr($identifier, 6);
danielebarchiesi@0 301 }
danielebarchiesi@0 302 return $identifier;
danielebarchiesi@0 303 }
danielebarchiesi@0 304 }
danielebarchiesi@0 305
danielebarchiesi@0 306 /**
danielebarchiesi@0 307 * OpenID normalization method: normalize URL identifiers.
danielebarchiesi@0 308 */
danielebarchiesi@0 309 function _openid_url_normalize($url) {
danielebarchiesi@0 310 $normalized_url = $url;
danielebarchiesi@0 311
danielebarchiesi@0 312 if (stristr($url, '://') === FALSE) {
danielebarchiesi@0 313 $normalized_url = 'http://' . $url;
danielebarchiesi@0 314 }
danielebarchiesi@0 315
danielebarchiesi@0 316 // Strip the fragment and fragment delimiter if present.
danielebarchiesi@0 317 $normalized_url = strtok($normalized_url, '#');
danielebarchiesi@0 318
danielebarchiesi@0 319 if (substr_count($normalized_url, '/') < 3) {
danielebarchiesi@0 320 $normalized_url .= '/';
danielebarchiesi@0 321 }
danielebarchiesi@0 322
danielebarchiesi@0 323 return $normalized_url;
danielebarchiesi@0 324 }
danielebarchiesi@0 325
danielebarchiesi@0 326 /**
danielebarchiesi@0 327 * Create a serialized message packet as per spec: $key:$value\n .
danielebarchiesi@0 328 */
danielebarchiesi@0 329 function _openid_create_message($data) {
danielebarchiesi@0 330 $serialized = '';
danielebarchiesi@0 331
danielebarchiesi@0 332 foreach ($data as $key => $value) {
danielebarchiesi@0 333 if ((strpos($key, ':') !== FALSE) || (strpos($key, "\n") !== FALSE) || (strpos($value, "\n") !== FALSE)) {
danielebarchiesi@0 334 return NULL;
danielebarchiesi@0 335 }
danielebarchiesi@0 336 $serialized .= "$key:$value\n";
danielebarchiesi@0 337 }
danielebarchiesi@0 338 return $serialized;
danielebarchiesi@0 339 }
danielebarchiesi@0 340
danielebarchiesi@0 341 /**
danielebarchiesi@0 342 * Encode a message from _openid_create_message for HTTP Post
danielebarchiesi@0 343 */
danielebarchiesi@0 344 function _openid_encode_message($message) {
danielebarchiesi@0 345 $encoded_message = '';
danielebarchiesi@0 346
danielebarchiesi@0 347 $items = explode("\n", $message);
danielebarchiesi@0 348 foreach ($items as $item) {
danielebarchiesi@0 349 $parts = explode(':', $item, 2);
danielebarchiesi@0 350
danielebarchiesi@0 351 if (count($parts) == 2) {
danielebarchiesi@0 352 if ($encoded_message != '') {
danielebarchiesi@0 353 $encoded_message .= '&';
danielebarchiesi@0 354 }
danielebarchiesi@0 355 $encoded_message .= rawurlencode(trim($parts[0])) . '=' . rawurlencode(trim($parts[1]));
danielebarchiesi@0 356 }
danielebarchiesi@0 357 }
danielebarchiesi@0 358
danielebarchiesi@0 359 return $encoded_message;
danielebarchiesi@0 360 }
danielebarchiesi@0 361
danielebarchiesi@0 362 /**
danielebarchiesi@0 363 * Convert a direct communication message
danielebarchiesi@0 364 * into an associative array.
danielebarchiesi@0 365 */
danielebarchiesi@0 366 function _openid_parse_message($message) {
danielebarchiesi@0 367 $parsed_message = array();
danielebarchiesi@0 368
danielebarchiesi@0 369 $items = explode("\n", $message);
danielebarchiesi@0 370 foreach ($items as $item) {
danielebarchiesi@0 371 $parts = explode(':', $item, 2);
danielebarchiesi@0 372
danielebarchiesi@0 373 if (count($parts) == 2) {
danielebarchiesi@0 374 $parsed_message[$parts[0]] = $parts[1];
danielebarchiesi@0 375 }
danielebarchiesi@0 376 }
danielebarchiesi@0 377
danielebarchiesi@0 378 return $parsed_message;
danielebarchiesi@0 379 }
danielebarchiesi@0 380
danielebarchiesi@0 381 /**
danielebarchiesi@0 382 * Return a nonce value - formatted per OpenID spec.
danielebarchiesi@0 383 */
danielebarchiesi@0 384 function _openid_nonce() {
danielebarchiesi@0 385 // YYYY-MM-DDThh:mm:ssZ, plus some optional extra unique characters.
danielebarchiesi@0 386 return gmdate('Y-m-d\TH:i:s\Z') .
danielebarchiesi@0 387 chr(mt_rand(0, 25) + 65) .
danielebarchiesi@0 388 chr(mt_rand(0, 25) + 65) .
danielebarchiesi@0 389 chr(mt_rand(0, 25) + 65) .
danielebarchiesi@0 390 chr(mt_rand(0, 25) + 65);
danielebarchiesi@0 391 }
danielebarchiesi@0 392
danielebarchiesi@0 393 /**
danielebarchiesi@0 394 * Pull the href attribute out of an html link element.
danielebarchiesi@0 395 */
danielebarchiesi@0 396 function _openid_link_href($rel, $html) {
danielebarchiesi@0 397 $rel = preg_quote($rel);
danielebarchiesi@0 398 preg_match('|<link\s+rel=["\'](.*)' . $rel . '(.*)["\'](.*)/?>|iUs', $html, $matches);
danielebarchiesi@0 399 if (isset($matches[3])) {
danielebarchiesi@0 400 preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href);
danielebarchiesi@0 401 return trim($href[1]);
danielebarchiesi@0 402 }
danielebarchiesi@0 403 return FALSE;
danielebarchiesi@0 404 }
danielebarchiesi@0 405
danielebarchiesi@0 406 /**
danielebarchiesi@0 407 * Pull the http-equiv attribute out of an html meta element
danielebarchiesi@0 408 */
danielebarchiesi@0 409 function _openid_meta_httpequiv($equiv, $html) {
danielebarchiesi@0 410 preg_match('|<meta\s+http-equiv=["\']' . $equiv . '["\'](.*)/?>|iUs', $html, $matches);
danielebarchiesi@0 411 if (isset($matches[1])) {
danielebarchiesi@0 412 preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content);
danielebarchiesi@0 413 if (isset($content[1])) {
danielebarchiesi@0 414 return $content[1];
danielebarchiesi@0 415 }
danielebarchiesi@0 416 }
danielebarchiesi@0 417 return FALSE;
danielebarchiesi@0 418 }
danielebarchiesi@0 419
danielebarchiesi@0 420 /**
danielebarchiesi@0 421 * Sign certain keys in a message
danielebarchiesi@0 422 * @param $association - object loaded from openid_association or openid_server_association table
danielebarchiesi@0 423 * - important fields are ->assoc_type and ->mac_key
danielebarchiesi@0 424 * @param $message_array - array of entire message about to be sent
danielebarchiesi@0 425 * @param $keys_to_sign - keys in the message to include in signature (without
danielebarchiesi@0 426 * 'openid.' appended)
danielebarchiesi@0 427 */
danielebarchiesi@0 428 function _openid_signature($association, $message_array, $keys_to_sign) {
danielebarchiesi@0 429 $signature = '';
danielebarchiesi@0 430 $sign_data = array();
danielebarchiesi@0 431
danielebarchiesi@0 432 foreach ($keys_to_sign as $key) {
danielebarchiesi@0 433 if (isset($message_array['openid.' . $key])) {
danielebarchiesi@0 434 $sign_data[$key] = $message_array['openid.' . $key];
danielebarchiesi@0 435 }
danielebarchiesi@0 436 }
danielebarchiesi@0 437
danielebarchiesi@0 438 $message = _openid_create_message($sign_data);
danielebarchiesi@0 439 $secret = base64_decode($association->mac_key);
danielebarchiesi@0 440 $signature = _openid_hmac($secret, $message);
danielebarchiesi@0 441
danielebarchiesi@0 442 return base64_encode($signature);
danielebarchiesi@0 443 }
danielebarchiesi@0 444
danielebarchiesi@0 445 function _openid_hmac($key, $text) {
danielebarchiesi@0 446 if (strlen($key) > OPENID_SHA1_BLOCKSIZE) {
danielebarchiesi@0 447 $key = sha1($key, TRUE);
danielebarchiesi@0 448 }
danielebarchiesi@0 449
danielebarchiesi@0 450 $key = str_pad($key, OPENID_SHA1_BLOCKSIZE, chr(0x00));
danielebarchiesi@0 451 $ipad = str_repeat(chr(0x36), OPENID_SHA1_BLOCKSIZE);
danielebarchiesi@0 452 $opad = str_repeat(chr(0x5c), OPENID_SHA1_BLOCKSIZE);
danielebarchiesi@0 453 $hash1 = sha1(($key ^ $ipad) . $text, TRUE);
danielebarchiesi@0 454 $hmac = sha1(($key ^ $opad) . $hash1, TRUE);
danielebarchiesi@0 455
danielebarchiesi@0 456 return $hmac;
danielebarchiesi@0 457 }
danielebarchiesi@0 458
danielebarchiesi@0 459 function _openid_dh_base64_to_long($str) {
danielebarchiesi@0 460 $b64 = base64_decode($str);
danielebarchiesi@0 461
danielebarchiesi@0 462 return _openid_dh_binary_to_long($b64);
danielebarchiesi@0 463 }
danielebarchiesi@0 464
danielebarchiesi@0 465 function _openid_dh_long_to_base64($str) {
danielebarchiesi@0 466 return base64_encode(_openid_dh_long_to_binary($str));
danielebarchiesi@0 467 }
danielebarchiesi@0 468
danielebarchiesi@0 469 function _openid_dh_binary_to_long($str) {
danielebarchiesi@0 470 $bytes = array_merge(unpack('C*', $str));
danielebarchiesi@0 471
danielebarchiesi@0 472 $n = 0;
danielebarchiesi@0 473 foreach ($bytes as $byte) {
danielebarchiesi@0 474 $n = _openid_math_mul($n, pow(2, 8));
danielebarchiesi@0 475 $n = _openid_math_add($n, $byte);
danielebarchiesi@0 476 }
danielebarchiesi@0 477
danielebarchiesi@0 478 return $n;
danielebarchiesi@0 479 }
danielebarchiesi@0 480
danielebarchiesi@0 481 function _openid_dh_long_to_binary($long) {
danielebarchiesi@0 482 $cmp = _openid_math_cmp($long, 0);
danielebarchiesi@0 483 if ($cmp < 0) {
danielebarchiesi@0 484 return FALSE;
danielebarchiesi@0 485 }
danielebarchiesi@0 486
danielebarchiesi@0 487 if ($cmp == 0) {
danielebarchiesi@0 488 return "\x00";
danielebarchiesi@0 489 }
danielebarchiesi@0 490
danielebarchiesi@0 491 $bytes = array();
danielebarchiesi@0 492
danielebarchiesi@0 493 while (_openid_math_cmp($long, 0) > 0) {
danielebarchiesi@0 494 array_unshift($bytes, _openid_math_mod($long, 256));
danielebarchiesi@0 495 $long = _openid_math_div($long, pow(2, 8));
danielebarchiesi@0 496 }
danielebarchiesi@0 497
danielebarchiesi@0 498 if ($bytes && ($bytes[0] > 127)) {
danielebarchiesi@0 499 array_unshift($bytes, 0);
danielebarchiesi@0 500 }
danielebarchiesi@0 501
danielebarchiesi@0 502 $string = '';
danielebarchiesi@0 503 foreach ($bytes as $byte) {
danielebarchiesi@0 504 $string .= pack('C', $byte);
danielebarchiesi@0 505 }
danielebarchiesi@0 506
danielebarchiesi@0 507 return $string;
danielebarchiesi@0 508 }
danielebarchiesi@0 509
danielebarchiesi@0 510 function _openid_dh_xorsecret($shared, $secret) {
danielebarchiesi@0 511 $dh_shared_str = _openid_dh_long_to_binary($shared);
danielebarchiesi@0 512 $sha1_dh_shared = sha1($dh_shared_str, TRUE);
danielebarchiesi@0 513 $xsecret = "";
danielebarchiesi@0 514 for ($i = 0; $i < strlen($secret); $i++) {
danielebarchiesi@0 515 $xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i]));
danielebarchiesi@0 516 }
danielebarchiesi@0 517
danielebarchiesi@0 518 return $xsecret;
danielebarchiesi@0 519 }
danielebarchiesi@0 520
danielebarchiesi@0 521 function _openid_dh_rand($stop) {
danielebarchiesi@0 522 $duplicate_cache = &drupal_static(__FUNCTION__, array());
danielebarchiesi@0 523
danielebarchiesi@0 524 // Used as the key for the duplicate cache
danielebarchiesi@0 525 $rbytes = _openid_dh_long_to_binary($stop);
danielebarchiesi@0 526
danielebarchiesi@0 527 if (isset($duplicate_cache[$rbytes])) {
danielebarchiesi@0 528 list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
danielebarchiesi@0 529 }
danielebarchiesi@0 530 else {
danielebarchiesi@0 531 if ($rbytes[0] == "\x00") {
danielebarchiesi@0 532 $nbytes = strlen($rbytes) - 1;
danielebarchiesi@0 533 }
danielebarchiesi@0 534 else {
danielebarchiesi@0 535 $nbytes = strlen($rbytes);
danielebarchiesi@0 536 }
danielebarchiesi@0 537
danielebarchiesi@0 538 $mxrand = _openid_math_pow(256, $nbytes);
danielebarchiesi@0 539
danielebarchiesi@0 540 // If we get a number less than this, then it is in the
danielebarchiesi@0 541 // duplicated range.
danielebarchiesi@0 542 $duplicate = _openid_math_mod($mxrand, $stop);
danielebarchiesi@0 543
danielebarchiesi@0 544 if (count($duplicate_cache) > 10) {
danielebarchiesi@0 545 $duplicate_cache = array();
danielebarchiesi@0 546 }
danielebarchiesi@0 547
danielebarchiesi@0 548 $duplicate_cache[$rbytes] = array($duplicate, $nbytes);
danielebarchiesi@0 549 }
danielebarchiesi@0 550
danielebarchiesi@0 551 do {
danielebarchiesi@0 552 $bytes = "\x00" . _openid_get_bytes($nbytes);
danielebarchiesi@0 553 $n = _openid_dh_binary_to_long($bytes);
danielebarchiesi@0 554 // Keep looping if this value is in the low duplicated range.
danielebarchiesi@0 555 } while (_openid_math_cmp($n, $duplicate) < 0);
danielebarchiesi@0 556
danielebarchiesi@0 557 return _openid_math_mod($n, $stop);
danielebarchiesi@0 558 }
danielebarchiesi@0 559
danielebarchiesi@0 560 function _openid_get_bytes($num_bytes) {
danielebarchiesi@0 561 $f = &drupal_static(__FUNCTION__);
danielebarchiesi@0 562 $bytes = '';
danielebarchiesi@0 563 if (!isset($f)) {
danielebarchiesi@0 564 $f = @fopen(OPENID_RAND_SOURCE, "r");
danielebarchiesi@0 565 }
danielebarchiesi@0 566 if (!$f) {
danielebarchiesi@0 567 // pseudorandom used
danielebarchiesi@0 568 $bytes = '';
danielebarchiesi@0 569 for ($i = 0; $i < $num_bytes; $i += 4) {
danielebarchiesi@0 570 $bytes .= pack('L', mt_rand());
danielebarchiesi@0 571 }
danielebarchiesi@0 572 $bytes = substr($bytes, 0, $num_bytes);
danielebarchiesi@0 573 }
danielebarchiesi@0 574 else {
danielebarchiesi@0 575 $bytes = fread($f, $num_bytes);
danielebarchiesi@0 576 }
danielebarchiesi@0 577 return $bytes;
danielebarchiesi@0 578 }
danielebarchiesi@0 579
danielebarchiesi@0 580 function _openid_response($str = NULL) {
danielebarchiesi@0 581 $data = array();
danielebarchiesi@0 582
danielebarchiesi@0 583 if (isset($_SERVER['REQUEST_METHOD'])) {
danielebarchiesi@0 584 $data = _openid_get_params($_SERVER['QUERY_STRING']);
danielebarchiesi@0 585
danielebarchiesi@0 586 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
danielebarchiesi@0 587 $str = file_get_contents('php://input');
danielebarchiesi@0 588
danielebarchiesi@0 589 $post = array();
danielebarchiesi@0 590 if ($str !== FALSE) {
danielebarchiesi@0 591 $post = _openid_get_params($str);
danielebarchiesi@0 592 }
danielebarchiesi@0 593
danielebarchiesi@0 594 $data = array_merge($data, $post);
danielebarchiesi@0 595 }
danielebarchiesi@0 596 }
danielebarchiesi@0 597
danielebarchiesi@0 598 return $data;
danielebarchiesi@0 599 }
danielebarchiesi@0 600
danielebarchiesi@0 601 function _openid_get_params($str) {
danielebarchiesi@0 602 $chunks = explode("&", $str);
danielebarchiesi@0 603
danielebarchiesi@0 604 $data = array();
danielebarchiesi@0 605 foreach ($chunks as $chunk) {
danielebarchiesi@0 606 $parts = explode("=", $chunk, 2);
danielebarchiesi@0 607
danielebarchiesi@0 608 if (count($parts) == 2) {
danielebarchiesi@0 609 list($k, $v) = $parts;
danielebarchiesi@0 610 $data[$k] = urldecode($v);
danielebarchiesi@0 611 }
danielebarchiesi@0 612 }
danielebarchiesi@0 613 return $data;
danielebarchiesi@0 614 }
danielebarchiesi@0 615
danielebarchiesi@0 616 /**
danielebarchiesi@0 617 * Extract all the parameters belonging to an extension in a response message.
danielebarchiesi@0 618 *
danielebarchiesi@0 619 * OpenID 2.0 defines a simple extension mechanism, based on a namespace prefix.
danielebarchiesi@0 620 *
danielebarchiesi@0 621 * Each request or response can define a prefix using:
danielebarchiesi@0 622 * @code
danielebarchiesi@0 623 * openid.ns.[prefix] = [extension_namespace]
danielebarchiesi@0 624 * openid.[prefix].[key1] = [value1]
danielebarchiesi@0 625 * openid.[prefix].[key2] = [value2]
danielebarchiesi@0 626 * ...
danielebarchiesi@0 627 * @endcode
danielebarchiesi@0 628 *
danielebarchiesi@0 629 * This function extracts all the keys belonging to an extension namespace in a
danielebarchiesi@0 630 * response, optionally using a fallback prefix if none is provided in the response.
danielebarchiesi@0 631 *
danielebarchiesi@0 632 * Note that you cannot assume that a given extension namespace will use the same
danielebarchiesi@0 633 * prefix on the response and the request: each party may use a different prefix
danielebarchiesi@0 634 * to refer to the same namespace.
danielebarchiesi@0 635 *
danielebarchiesi@0 636 * @param $response
danielebarchiesi@0 637 * The response array.
danielebarchiesi@0 638 * @param $extension_namespace
danielebarchiesi@0 639 * The namespace of the extension.
danielebarchiesi@0 640 * @param $fallback_prefix
danielebarchiesi@0 641 * An optional prefix that will be used in case no prefix is found for the
danielebarchiesi@0 642 * target extension namespace.
danielebarchiesi@0 643 * @param $only_signed
danielebarchiesi@0 644 * Return only keys that are included in the message signature in openid.sig.
danielebarchiesi@0 645 * Unsigned fields may have been modified or added by other parties than the
danielebarchiesi@0 646 * OpenID Provider.
danielebarchiesi@0 647 *
danielebarchiesi@0 648 * @return
danielebarchiesi@0 649 * An associative array containing all the parameters in the response message
danielebarchiesi@0 650 * that belong to the extension. The keys are stripped from their namespace
danielebarchiesi@0 651 * prefix.
danielebarchiesi@0 652 *
danielebarchiesi@0 653 * @see http://openid.net/specs/openid-authentication-2_0.html#extensions
danielebarchiesi@0 654 */
danielebarchiesi@0 655 function openid_extract_namespace($response, $extension_namespace, $fallback_prefix = NULL, $only_signed = FALSE) {
danielebarchiesi@0 656 $signed_keys = explode(',', $response['openid.signed']);
danielebarchiesi@0 657
danielebarchiesi@0 658 // Find the namespace prefix.
danielebarchiesi@0 659 $prefix = $fallback_prefix;
danielebarchiesi@0 660 foreach ($response as $key => $value) {
danielebarchiesi@0 661 if ($value == $extension_namespace && preg_match('/^openid\.ns\.([^.]+)$/', $key, $matches)) {
danielebarchiesi@0 662 $prefix = $matches[1];
danielebarchiesi@0 663 if ($only_signed && !in_array('ns.' . $matches[1], $signed_keys)) {
danielebarchiesi@0 664 // The namespace was defined but was not signed as required. In this
danielebarchiesi@0 665 // case we do not fall back to $fallback_prefix.
danielebarchiesi@0 666 $prefix = NULL;
danielebarchiesi@0 667 }
danielebarchiesi@0 668 break;
danielebarchiesi@0 669 }
danielebarchiesi@0 670 }
danielebarchiesi@0 671
danielebarchiesi@0 672 // Now extract the namespace keys from the response.
danielebarchiesi@0 673 $output = array();
danielebarchiesi@0 674 if (!isset($prefix)) {
danielebarchiesi@0 675 return $output;
danielebarchiesi@0 676 }
danielebarchiesi@0 677 foreach ($response as $key => $value) {
danielebarchiesi@0 678 if (preg_match('/^openid\.' . $prefix . '\.(.+)$/', $key, $matches)) {
danielebarchiesi@0 679 $local_key = $matches[1];
danielebarchiesi@0 680 if (!$only_signed || in_array($prefix . '.' . $local_key, $signed_keys)) {
danielebarchiesi@0 681 $output[$local_key] = $value;
danielebarchiesi@0 682 }
danielebarchiesi@0 683 }
danielebarchiesi@0 684 }
danielebarchiesi@0 685
danielebarchiesi@0 686 return $output;
danielebarchiesi@0 687 }
danielebarchiesi@0 688
danielebarchiesi@0 689 /**
danielebarchiesi@0 690 * Extracts values from an OpenID AX Response.
danielebarchiesi@0 691 *
danielebarchiesi@0 692 * The values can be returned in two forms:
danielebarchiesi@0 693 * - only openid.ax.value.<alias> (for single-valued answers)
danielebarchiesi@0 694 * - both openid.ax.count.<alias> and openid.ax.value.<alias>.<count> (for both
danielebarchiesi@0 695 * single and multiple-valued answers)
danielebarchiesi@0 696 *
danielebarchiesi@0 697 * @param $values
danielebarchiesi@0 698 * An array as returned by openid_extract_namespace(..., OPENID_NS_AX).
danielebarchiesi@0 699 * @param $uris
danielebarchiesi@0 700 * An array of identifier URIs.
danielebarchiesi@0 701 * @return
danielebarchiesi@0 702 * An array of values.
danielebarchiesi@0 703 * @see http://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_response
danielebarchiesi@0 704 */
danielebarchiesi@0 705 function openid_extract_ax_values($values, $uris) {
danielebarchiesi@0 706 $output = array();
danielebarchiesi@0 707 foreach ($values as $key => $value) {
danielebarchiesi@0 708 if (in_array($value, $uris) && preg_match('/^type\.([^.]+)$/', $key, $matches)) {
danielebarchiesi@0 709 $alias = $matches[1];
danielebarchiesi@0 710 if (isset($values['count.' . $alias])) {
danielebarchiesi@0 711 for ($i = 1; $i <= $values['count.' . $alias]; $i++) {
danielebarchiesi@0 712 $output[] = $values['value.' . $alias . '.' . $i];
danielebarchiesi@0 713 }
danielebarchiesi@0 714 }
danielebarchiesi@0 715 elseif (isset($values['value.' . $alias])) {
danielebarchiesi@0 716 $output[] = $values['value.' . $alias];
danielebarchiesi@0 717 }
danielebarchiesi@0 718 break;
danielebarchiesi@0 719 }
danielebarchiesi@0 720 }
danielebarchiesi@0 721 return $output;
danielebarchiesi@0 722 }
danielebarchiesi@0 723
danielebarchiesi@0 724 /**
danielebarchiesi@0 725 * Determine the available math library GMP vs. BCMath, favouring GMP for performance.
danielebarchiesi@0 726 */
danielebarchiesi@0 727 function _openid_get_math_library() {
danielebarchiesi@0 728 // Not drupal_static(), because a function is not going to disappear and
danielebarchiesi@0 729 // change the output of this under any circumstances.
danielebarchiesi@0 730 static $library;
danielebarchiesi@0 731
danielebarchiesi@0 732 if (empty($library)) {
danielebarchiesi@0 733 if (function_exists('gmp_add')) {
danielebarchiesi@0 734 $library = 'gmp';
danielebarchiesi@0 735 }
danielebarchiesi@0 736 elseif (function_exists('bcadd')) {
danielebarchiesi@0 737 $library = 'bcmath';
danielebarchiesi@0 738 }
danielebarchiesi@0 739 }
danielebarchiesi@0 740
danielebarchiesi@0 741 return $library;
danielebarchiesi@0 742 }
danielebarchiesi@0 743
danielebarchiesi@0 744 /**
danielebarchiesi@0 745 * Calls the add function from the available math library for OpenID.
danielebarchiesi@0 746 */
danielebarchiesi@0 747 function _openid_math_add($x, $y) {
danielebarchiesi@0 748 $library = _openid_get_math_library();
danielebarchiesi@0 749 switch ($library) {
danielebarchiesi@0 750 case 'gmp':
danielebarchiesi@0 751 return gmp_strval(gmp_add($x, $y));
danielebarchiesi@0 752 case 'bcmath':
danielebarchiesi@0 753 return bcadd($x, $y);
danielebarchiesi@0 754 }
danielebarchiesi@0 755 }
danielebarchiesi@0 756
danielebarchiesi@0 757 /**
danielebarchiesi@0 758 * Calls the mul function from the available math library for OpenID.
danielebarchiesi@0 759 */
danielebarchiesi@0 760 function _openid_math_mul($x, $y) {
danielebarchiesi@0 761 $library = _openid_get_math_library();
danielebarchiesi@0 762 switch ($library) {
danielebarchiesi@0 763 case 'gmp':
danielebarchiesi@0 764 return gmp_mul($x, $y);
danielebarchiesi@0 765 case 'bcmath':
danielebarchiesi@0 766 return bcmul($x, $y);
danielebarchiesi@0 767 }
danielebarchiesi@0 768 }
danielebarchiesi@0 769
danielebarchiesi@0 770 /**
danielebarchiesi@0 771 * Calls the div function from the available math library for OpenID.
danielebarchiesi@0 772 */
danielebarchiesi@0 773 function _openid_math_div($x, $y) {
danielebarchiesi@0 774 $library = _openid_get_math_library();
danielebarchiesi@0 775 switch ($library) {
danielebarchiesi@0 776 case 'gmp':
danielebarchiesi@0 777 return gmp_div($x, $y);
danielebarchiesi@0 778 case 'bcmath':
danielebarchiesi@0 779 return bcdiv($x, $y);
danielebarchiesi@0 780 }
danielebarchiesi@0 781 }
danielebarchiesi@0 782
danielebarchiesi@0 783 /**
danielebarchiesi@0 784 * Calls the cmp function from the available math library for OpenID.
danielebarchiesi@0 785 */
danielebarchiesi@0 786 function _openid_math_cmp($x, $y) {
danielebarchiesi@0 787 $library = _openid_get_math_library();
danielebarchiesi@0 788 switch ($library) {
danielebarchiesi@0 789 case 'gmp':
danielebarchiesi@0 790 return gmp_cmp($x, $y);
danielebarchiesi@0 791 case 'bcmath':
danielebarchiesi@0 792 return bccomp($x, $y);
danielebarchiesi@0 793 }
danielebarchiesi@0 794 }
danielebarchiesi@0 795
danielebarchiesi@0 796 /**
danielebarchiesi@0 797 * Calls the mod function from the available math library for OpenID.
danielebarchiesi@0 798 */
danielebarchiesi@0 799 function _openid_math_mod($x, $y) {
danielebarchiesi@0 800 $library = _openid_get_math_library();
danielebarchiesi@0 801 switch ($library) {
danielebarchiesi@0 802 case 'gmp':
danielebarchiesi@0 803 return gmp_mod($x, $y);
danielebarchiesi@0 804 case 'bcmath':
danielebarchiesi@0 805 return bcmod($x, $y);
danielebarchiesi@0 806 }
danielebarchiesi@0 807 }
danielebarchiesi@0 808
danielebarchiesi@0 809 /**
danielebarchiesi@0 810 * Calls the pow function from the available math library for OpenID.
danielebarchiesi@0 811 */
danielebarchiesi@0 812 function _openid_math_pow($x, $y) {
danielebarchiesi@0 813 $library = _openid_get_math_library();
danielebarchiesi@0 814 switch ($library) {
danielebarchiesi@0 815 case 'gmp':
danielebarchiesi@0 816 return gmp_pow($x, $y);
danielebarchiesi@0 817 case 'bcmath':
danielebarchiesi@0 818 return bcpow($x, $y);
danielebarchiesi@0 819 }
danielebarchiesi@0 820 }
danielebarchiesi@0 821
danielebarchiesi@0 822 /**
danielebarchiesi@0 823 * Calls the mul function from the available math library for OpenID.
danielebarchiesi@0 824 */
danielebarchiesi@0 825 function _openid_math_powmod($x, $y, $z) {
danielebarchiesi@0 826 $library = _openid_get_math_library();
danielebarchiesi@0 827 switch ($library) {
danielebarchiesi@0 828 case 'gmp':
danielebarchiesi@0 829 return gmp_powm($x, $y, $z);
danielebarchiesi@0 830 case 'bcmath':
danielebarchiesi@0 831 return bcpowmod($x, $y, $z);
danielebarchiesi@0 832 }
danielebarchiesi@0 833 }
danielebarchiesi@0 834
danielebarchiesi@0 835 /**
danielebarchiesi@0 836 * Provides transition for accounts with possibly invalid OpenID identifiers in authmap.
danielebarchiesi@0 837 *
danielebarchiesi@0 838 * This function provides a less safe but more unobtrusive procedure for users
danielebarchiesi@0 839 * who cannot login with their OpenID identifiers. OpenID identifiers in the
danielebarchiesi@0 840 * authmap could be incomplete due to invalid OpenID implementation in previous
danielebarchiesi@0 841 * versions of Drupal (e.g. fragment part of the identifier could be missing).
danielebarchiesi@0 842 * For more information see http://drupal.org/node/1120290.
danielebarchiesi@0 843 *
danielebarchiesi@0 844 * @param string $identity
danielebarchiesi@0 845 * The user's claimed OpenID identifier.
danielebarchiesi@0 846 *
danielebarchiesi@0 847 * @return
danielebarchiesi@0 848 * A fully-loaded user object if the user is found or FALSE if not found.
danielebarchiesi@0 849 */
danielebarchiesi@0 850 function _openid_invalid_openid_transition($identity, $response) {
danielebarchiesi@0 851 $account = FALSE;
danielebarchiesi@0 852 $fallback_account = NULL;
danielebarchiesi@0 853 $fallback_identity = $identity;
danielebarchiesi@0 854
danielebarchiesi@0 855 // Try to strip the fragment if it is present.
danielebarchiesi@0 856 if (strpos($fallback_identity, '#') !== FALSE) {
danielebarchiesi@0 857 $fallback_identity = preg_replace('/#.*/', '', $fallback_identity);
danielebarchiesi@0 858 $fallback_account = user_external_load($fallback_identity);
danielebarchiesi@0 859 }
danielebarchiesi@0 860
danielebarchiesi@0 861 // Try to replace HTTPS with HTTP. OpenID providers often redirect
danielebarchiesi@0 862 // from http to https, but Drupal didn't follow the redirect.
danielebarchiesi@0 863 if (!$fallback_account && strpos($fallback_identity, 'https://') !== FALSE) {
danielebarchiesi@0 864 $fallback_identity = str_replace('https://', 'http://', $fallback_identity);
danielebarchiesi@0 865 $fallback_account = user_external_load($fallback_identity);
danielebarchiesi@0 866 }
danielebarchiesi@0 867
danielebarchiesi@0 868 // Try to use original identifier.
danielebarchiesi@0 869 if (!$fallback_account && isset($_SESSION['openid']['user_login_values']['openid_identifier'])) {
danielebarchiesi@0 870 $fallback_identity = openid_normalize($_SESSION['openid']['user_login_values']['openid_identifier']);
danielebarchiesi@0 871 $fallback_account = user_external_load($fallback_identity);
danielebarchiesi@0 872 }
danielebarchiesi@0 873
danielebarchiesi@0 874 if ($fallback_account) {
danielebarchiesi@0 875 // Try to extract e-mail address from Simple Registration (SREG) or
danielebarchiesi@0 876 // Attribute Exchanges (AX) keys.
danielebarchiesi@0 877 $email = '';
danielebarchiesi@0 878 $sreg_values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg', TRUE);
danielebarchiesi@0 879 $ax_values = openid_extract_namespace($response, OPENID_NS_AX, 'ax', TRUE);
danielebarchiesi@0 880 if (!empty($sreg_values['email']) && valid_email_address($sreg_values['email'])) {
danielebarchiesi@0 881 $email = $sreg_values['email'];
danielebarchiesi@0 882 }
danielebarchiesi@0 883 elseif ($ax_mail_values = openid_extract_ax_values($ax_values, array('http://axschema.org/contact/email', 'http://schema.openid.net/contact/email'))) {
danielebarchiesi@0 884 $email = current($ax_mail_values);
danielebarchiesi@0 885 }
danielebarchiesi@0 886
danielebarchiesi@0 887 // If this e-mail address is the same as the e-mail address found in user
danielebarchiesi@0 888 // account, login the user and update the claimed identifier.
danielebarchiesi@0 889 if ($email && ($email == $fallback_account->mail || $email == $fallback_account->init)) {
danielebarchiesi@0 890 $query = db_insert('authmap')
danielebarchiesi@0 891 ->fields(array(
danielebarchiesi@0 892 'authname' => $identity,
danielebarchiesi@0 893 'uid' => $fallback_account->uid,
danielebarchiesi@0 894 'module' => 'openid',
danielebarchiesi@0 895 ))
danielebarchiesi@0 896 ->execute();
danielebarchiesi@0 897 drupal_set_message(t('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity. To finish the invalid OpenID transition process, please go to your <a href="@openid_url">OpenID identities page</a> and remove the old identifier %invalid_identity.', array('%invalid_identity' => $fallback_identity, '%identity' => $identity, '@openid_url' => 'user/' . $fallback_account->uid . '/openid')));
danielebarchiesi@0 898 // Set the account to the found one.
danielebarchiesi@0 899 $account = $fallback_account;
danielebarchiesi@0 900 }
danielebarchiesi@0 901 else {
danielebarchiesi@0 902 drupal_set_message(t('There is already an existing account associated with the OpenID identifier that you have provided. However, due to a bug in the previous version of the authentication system, we can\'t be sure that this account belongs to you. If you are new on this site, please continue registering the new user account. If you already have a registered account on this site associated with the provided OpenID identifier, please try to <a href="@url_password">reset the password</a> or contact the site administrator.', array('@url_password' => 'user/password')), 'warning');
danielebarchiesi@0 903 }
danielebarchiesi@0 904 }
danielebarchiesi@0 905
danielebarchiesi@0 906 return $account;
danielebarchiesi@0 907 }