OpenID Detection Methods - Yadis VS HTML

I recently started writing my own PHP OpenID class for a better understanding of openID. As a guide, I referenced the [LightOpenID Class] [1]. For the most part, I understand the code and how OpenID works. My confusion arises when viewing the author's discover function:

 function discover($url) { if(!$url) throw new ErrorException('No identity supplied.'); # We save the original url in case of Yadis discovery failure. # It can happen when we'll be lead to an XRDS document # which does not have any OpenID2 services. $originalUrl = $url; # A flag to disable yadis discovery in case of failure in headers. $yadis = true; # We'll jump a maximum of 5 times, to avoid endless redirections. for($i = 0; $i < 5; $i ++) { if($yadis) { $headers = explode("\n",$this->request($url, 'HEAD')); $next = false; foreach($headers as $header) { if(preg_match('#X-XRDS-Location\s*:\s*(.*)#', $header, $m)) { $url = $this->build_url(parse_url($url), parse_url(trim($m[1]))); $next = true; } if(preg_match('#Content-Type\s*:\s*application/xrds\+xml#i', $header)) { # Found an XRDS document, now let find the server, and optionally delegate. $content = $this->request($url, 'GET'); # OpenID 2 # We ignore it for MyOpenID, as it breaks sreg if using OpenID 2.0 $ns = preg_quote('http://specs.openid.net/auth/2.0/'); if (preg_match('#<Service.*?>(.*)<Type>\s*'.$ns.'(.*?)\s*</Type>(.*)</Service>#s', $content, $m) && !preg_match('/myopenid\.com/i', $this->identity)) { $content = $m[1] . $m[3]; if($m[2] == 'server') $this->identifier_select = true; $content = preg_match('#<URI>(.*)</URI>#', $content, $server); $content = preg_match('#<LocalID>(.*)</LocalID>#', $content, $delegate); if(empty($server)) { return false; } # Does the server advertise support for either AX or SREG? $this->ax = preg_match('#<Type>http://openid.net/srv/ax/1.0</Type>#', $content); $this->sreg = preg_match('#<Type>http://openid.net/sreg/1.0</Type>#', $content); $server = $server[1]; if(isset($delegate[1])) $this->identity = $delegate[1]; $this->version = 2; $this->server = $server; return $server; } # OpenID 1.1 $ns = preg_quote('http://openid.net/signon/1.1'); if(preg_match('#<Service.*?>(.*)<Type>\s*'.$ns.'\s*</Type>(.*)</Service>#s', $content, $m)) { $content = $m[1] . $m[2]; $content = preg_match('#<URI>(.*)</URI>#', $content, $server); $content = preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); if(empty($server)) { return false; } # AX can be used only with OpenID 2.0, so checking only SREG $this->sreg = preg_match('#<Type>http://openid.net/sreg/1.0</Type>#', $content); $server = $server[1]; if(isset($delegate[1])) $this->identity = $delegate[1]; $this->version = 1; $this->server = $server; return $server; } $next = true; $yadis = false; $url = $originalUrl; $content = null; break; } } if($next) continue; # There are no relevant information in headers, so we search the body. $content = $this->request($url, 'GET'); if($location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'value')) { $url = $this->build_url(parse_url($url), parse_url($location)); continue; } } if(!$content) $content = $this->request($url, 'GET'); # At this point, the YADIS Discovery has failed, so we'll switch # to openid2 HTML discovery, then fallback to openid 1.1 discovery. $server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href'); $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href'); $this->version = 2; # Another hack for myopenid.com... if(preg_match('/myopenid\.com/i', $server)) { $server = null; } if(!$server) { # The same with openid 1.1 $server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href'); $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href'); $this->version = 1; } if($server) { # We found an OpenID2 OP Endpoint if($delegate) { # We have also found an OP-Local ID. $this->identity = $delegate; } $this->server = $server; return $server; } throw new ErrorException('No servers found!'); } throw new ErrorException('Endless redirection!'); } [1]: http://gitorious.org/lightopenid 

Ok, here is the logic, as I understand it (mostly):

  • Make sure $url sends you a valid XRDS file, which is then parsed to find out the endpoint of the OpenID provider.
    • In my opinion, this is called the Yadis authentication method.
  • If the XRDS file is not found, check the response body for the HTML <link> tag that contains the endpoint URL.

What .. Heck.

I mean seriously? Essentially the screen clears the answer and hopes you find a link with the corresponding attribute value?

Now, donโ€™t get me wrong, this class works like a charm and it is awesome. I just don't understand two separate methods used to detect the endpoint: XRDS (yadis) and HTML.

My questions

  • Are these two methods used only during the discovery process?
  • Is only OpenID used in version 1.1 and the other in version 2?
  • How important is it to support both methods?
  • The site I encountered the HTML method is Yahoo. Are they nuts?

Thanks again for your time. I apologize if I am a little overwhelmed, but I was really overwhelmed by the methodology as soon as I began to understand what measures were being taken to find the final destination.

+6
php openid lightopenid
source share
1 answer

The specification is your friend.

But answering your question:

  • Yes. These are the only two methods defined by the OpenID specifications (at least for URLs - there is a third method for XRI).
  • No, both can be used with both versions of the protocol. Read this function carefully and you will see that it supports both methods for both versions.
  • If you want your library to work with every provider and user, you are better off. Some users embed HTML tags in their sites, so their site URL can be used as openid.
  • Some vendors even use both methods at the same time to maintain compatibility with consumers who do not implement YADIS discovery (which is not part of OpenID 1.1, but can be used with it). So that makes sense.

And yes, HTML detection is a search for <link> in the body of the response. That's why he called HTML detection.

+5
source share

All Articles