diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc index 6945f34..f19f273 100644 --- a/modules/openid/openid.inc +++ b/modules/openid/openid.inc @@ -365,36 +365,44 @@ function _openid_nonce() { chr(mt_rand(0, 25) + 65) . chr(mt_rand(0, 25) + 65) . chr(mt_rand(0, 25) + 65); } /** * Pull the href attribute out of an html link element. */ function _openid_link_href($rel, $html) { - $rel = preg_quote($rel); - preg_match('||iUs', $html, $matches); - if (isset($matches[3])) { - preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href); - return trim($href[1]); + $html_dom = @DOMDocument::loadHTML($html); + if ($html_dom) { + $html_element = simplexml_import_dom($html_dom); + foreach ($html_element->head->link as $link) { + // The rel attribute contains a space-separated list of case-insensitive + // link types. + if (preg_match('/(\s|^)' . $rel . '(\s|$)/i', $link['rel'])) { + return trim($link['href']); + } + } } return FALSE; } /** - * Pull the http-equiv attribute out of an html meta element + * Pull the content attribute out of an X-XRDS-Location meta http-equiv element. */ -function _openid_meta_httpequiv($equiv, $html) { - preg_match('||iUs', $html, $matches); - if (isset($matches[1])) { - preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content); - if (isset($content[1])) { - return $content[1]; +function _openid_meta_httpequiv($html) { + $html_dom = @DOMDocument::loadHTML($html); + if ($html_dom) { + $html_element = simplexml_import_dom($html_dom); + foreach ($html_element->head->meta as $meta) { + // The http-equiv attribute is case-insensitive. + if (strtolower(trim($meta['http-equiv'])) == 'x-xrds-location') { + return trim($meta['content']); + } } } return FALSE; } /** * Sign certain keys in a message * @param $association - object loaded from openid_association or openid_server_association table * - important fields are ->assoc_type and ->mac_key diff --git a/modules/openid/openid.module b/modules/openid/openid.module index e312866..39d92c0 100644 --- a/modules/openid/openid.module +++ b/modules/openid/openid.module @@ -464,19 +464,19 @@ function _openid_xrds_discovery($claimed_id) { $services = _openid_xrds_parse($result->data); } else { $xrds_url = NULL; if (isset($result->headers['x-xrds-location'])) { $xrds_url = $result->headers['x-xrds-location']; } else { // Look for meta http-equiv link in HTML head - $xrds_url = _openid_meta_httpequiv('X-XRDS-Location', $result->data); + $xrds_url = _openid_meta_httpequiv($result->data); } if (!empty($xrds_url)) { $headers = array('Accept' => 'application/xrds+xml'); $xrds_result = drupal_http_request($xrds_url, array('headers' => $headers)); if (!isset($xrds_result->error)) { $services = _openid_xrds_parse($xrds_result->data); } } } diff --git a/modules/openid/tests/openid_test.module b/modules/openid/tests/openid_test.module index bad1184..20c5795 100644 --- a/modules/openid/tests/openid_test.module +++ b/modules/openid/tests/openid_test.module @@ -162,19 +162,19 @@ function openid_test_yadis_x_xrds_location() { } /** * Menu callback; regular HTML page with element. */ function openid_test_yadis_http_equiv() { $element = array( '#tag' => 'meta', '#attributes' => array( - 'http-equiv' => 'X-XRDS-Location', + 'http-equiv' => "X-XRDS-Location\n", 'content' => url('openid-test/yadis/xrds', array('absolute' => TRUE)), ), ); drupal_add_html_head($element, 'openid_test_yadis_http_equiv'); return t('This page includes a <meta equiv=...> element containing the URL of an XRDS document.'); } /** * Menu callback; regular HTML page with OpenID 1.0 element. @@ -183,19 +183,20 @@ function openid_test_html_openid1() { drupal_add_html_head_link(array('rel' => 'openid.server', 'href' => url('openid-test/endpoint', array('absolute' => TRUE)))); drupal_add_html_head_link(array('rel' => 'openid.delegate', 'href' => 'http://example.com/html-openid1')); return t('This page includes a <link rel=...> element containing the URL of an OpenID Provider Endpoint.'); } /** * Menu callback; regular HTML page with OpenID 2.0 element. */ function openid_test_html_openid2() { - drupal_add_html_head_link(array('rel' => 'openid2.provider', 'href' => url('openid-test/endpoint', array('absolute' => TRUE)))); + // Use unusual values in order to test proper parsing of HTML attributes. + drupal_add_html_head_link(array('rel' => "foo\nopenid2.PROVIDER\tbar", 'href' => "\n" . url('openid-test/endpoint', array('absolute' => TRUE)))); drupal_add_html_head_link(array('rel' => 'openid2.local_id', 'href' => 'http://example.com/html-openid2')); return t('This page includes a <link rel=...> element containing the URL of an OpenID Provider Endpoint.'); } /** * Menu callback; OpenID Provider Endpoint. * * It accepts "associate" requests directly from the Relying Party, and * "checkid_setup" requests made by the user's browser based on HTTP redirects