After utilizing the openid provider module i was making it work with the openid module in drupal core. The module would not allow users to be logged in because when trying to go to http://example.com/user/ the page would return a 403 forbidden and hence stop all processing for the module.

To resolve this issue i believe that openid_provider module needs to hold its own path that can be accessed with the user in order that the xrds document can be retrieved from the server. i.e.

  $items['openid/provider/user/%'] = array(
    'title' => 'OpenID Login',
    'description' => 'Menu callback with full access so no forbiddens are given from server requests',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );

This will just allow the page to be displayed and from the xrds_simple module will provide the pertinent information on where to find the user.

Attached are three patches for the module as it works now.

I have incorporated into the patches the one from Chris Johnson http://drupal.org/node/307760

Two from sandhurs http://drupal.org/node/311727 and http://drupal.org/node/313166

Please let me know if any of these patches need work and we can look into it.

Comments

Chris Johnson’s picture

subscribing

Chris Johnson’s picture

If the provider path changes in the URL, the "user information" display of their OpenID URL needs to likewise change in openid_provider_user(), '#value', to correctly match the new path.

  '#value' => t('You may login to other OpenID enabled sites using %url', array('%url' => url('user/' . $account->uid, array('absolute' => TRUE)))),
darren.ferguson’s picture

Yep i have altered and will put the patch up in the next hour or so

Chris Johnson’s picture

Hmm, this still doesn't seem to be right. It doesn't fully support the OpenID 2.0 protocol correctly.

When I set up Moodle as an RP and Drupal 6 as the IdP with or without this patch above, I get a failure while the Moodle RP is verifying the discovered services. It's looking for http://specs.openid.net/auth/2.0/signon in the type URI but is finding http://specs.openid.net/auth/2.0/server instead.

Drupal is sending http://specs.openid.net/auth/2.0/server because $account is NULL when the XRDS document is generated.

I would think that when the URL of http://identityprovider.com/openid/provider/user/5 is given as the OpenID, the account should be known. Drupal defaults to getting the /xrds document, instead of the /user/5/xrds document.

I haven't been able to find out why.

darren.ferguson’s picture

Is this because of in the xrds hook in the openid_provider that the $data['LocalID'] = array(url('user/'. $account->uid, array('absolute' => TRUE))); is being set to that instead of the /openid/provider/user/userid ??

The patch might need updated with that information and maybe drupals core openid module is only working by luck??

Chris Johnson’s picture

I think what you are saying is close (I'm not sure I know exactly what you're saying).

What happens is this:

  1. I use OpenID http://localhost:7064/openid/provider/user/5 to try to log into Moodle.
  2. Moodle hits URL http://localhost:7064/openid/provider/user/5 on my Drupal 6 install with your above patch.
  3. openid_provider's hook_menu() matches /openid/provider/user/% but that menu callback has no 'page callback' defined, so the parent (more general) path of /openid/provider is used. The 'page callback' value is to call openid_provider_endpoint().
  4. openid_provider_endpoint() is called with no arguments, i.e. $request becomes an empty array.
  5. Hence, _openid_response() [in core] is called, which returns $data with just the parsed into an array $_SERVER['QUERY_STRING'], i.e. $data['q'] = 'openid/provider/user/5'
  6. openid_provider_endpoint() finds no 'openid' values set in $request, and exits.

I'm not sure exactly what happens subsequently (I need to separate my HTTP logs for my virtual servers so I can find out what Moodle and Drupal are doing), but the end result is that the Drupal routines in openid_provider and xrds are called without a valid $account, and hence the XRDS document sent to Moodle contains the /server path instead of the /signon path. Moodle is expecting a /signon path and fails. According to the spec, the type URis have to match exactly, so even if I fudge Moodle and add both /signon and /server to its expected reply, it still fails.

I will continue my debugging to see what the next steps are in the above list to see if I can pinpoint where things go wrong.

darren.ferguson’s picture

Chris

mmmm yes something seems wrong, i might have to re-read the specification to see incase i made an error somewhere also.

Chris Johnson’s picture

Here's the Apache access log for the Drupal 6 instance acting as the OpenID identity provider. This is for one attempt by Moodle as an RP to authenticate.

::1 - - [15/Oct/2008:22:14:16 -0500] "GET /openid/provider/user/5 HTTP/1.1" 200 -
::1 - - [15/Oct/2008:22:14:16 -0500] "GET /xrds HTTP/1.1" 200 373
::1 - - [15/Oct/2008:22:14:16 -0500] "POST /openid/provider HTTP/1.1" 200 167
::1 - - [15/Oct/2008:22:14:16 -0500] "POST /openid/provider HTTP/1.1" 302 -
::1 - - [15/Oct/2008:22:14:16 -0500] "GET /openid/provider/user/1 HTTP/1.1" 200 -
::1 - - [15/Oct/2008:22:14:17 -0500] "GET /xrds HTTP/1.1" 200 373

A "GET /user/5/xrds" would have produced the correct results. So perhaps there is something in the first exchange of messages that's not providing the correct follow up URL.

The 302 redirect later may have something to do with it. Also that after the redirect it goes after UID 1 instead of the original UID 5 is rather odd.

I'll continue to track this down.

darren.ferguson’s picture

Yeah that is weird, i will try and check it out why it is going back to user 1, maybe some global $user or something that is there that is causing that issue.

Chris Johnson’s picture

I think the way the log should look to make Moodle work correctly is the first 2 entries should have read:

::1 - - [15/Oct/2008:22:14:16 -0500] "GET /openid/provider/user/5 HTTP/1.1" 200 -
::1 - - [15/Oct/2008:22:14:16 -0500] "GET /user/5/xrds HTTP/1.1" 200 373

Instead of:

::1 - - [15/Oct/2008:22:14:16 -0500] "GET /openid/provider/user/5 HTTP/1.1" 200 -
::1 - - [15/Oct/2008:22:14:16 -0500] "GET /xrds HTTP/1.1" 200 373   (<= wrong)

But I don't quite yet understand how to get that to happen.

Indeed, this happens because of the response to the initial GET:

48 obmbp:~% telnet localhost 7064
Trying ::1...
Connected to localhost.
Escape character is '^]'.

GET /openid/provider/user/5 http/1.1
Host: localhost:7064

HTTP/1.1 200 OK
Date: Thu, 16 Oct 2008 17:31:28 GMT
Server: Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.7l DAV/2 PHP/5.2.6
X-Powered-By: PHP/5.2.6
Set-Cookie: SESS01908a7ba7f3bb734825ef9ce78b0507=d53b18bed34077f3258d2e4a6f3c3a19; expires=Sat, 08 Nov 2008 21:04:55 GMT; path=/
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Thu, 16 Oct 2008 17:31:35 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
X-XRDS-Location: http://localhost:7064/xrds
X-Yadis-Location: http://localhost:7064/xrds
Content-Length: 0
Content-Type: text/html; charset=utf-8

GET /xrds http/1.1
Host: localhost:7064

HTTP/1.1 200 OK
Date: Thu, 16 Oct 2008 17:37:03 GMT
Server: Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.7l DAV/2 PHP/5.2.6
X-Powered-By: PHP/5.2.6
Set-Cookie: SESS01908a7ba7f3bb734825ef9ce78b0507=c78961143d0622125ad5045e0309102e; expires=Sat, 08 Nov 2008 21:10:30 GMT; path=/
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Thu, 16 Oct 2008 17:37:10 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
X-XRDS-Location: http://localhost:7064/xrds
X-Yadis-Location: http://localhost:7064/xrds
Content-Length: 373
Content-Type: application/xrds+xml

<?xml version="1.0" encoding="UTF-8" ?>
<XRDS xmlns="xri://$xrds">
  <XRD xmlns="xri://$xrd*($v*2.0)" version="2.0" xmlns:simple="http://xrds-simple.net/core/1.0">
    <Type>xri://$xrds*simple</Type>
    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/server</Type>
      <URI>http://localhost:7064/openid/provider</URI>
    </Service>
  </XRD>
</XRDS>

Connection closed by foreign host.

So, the problem appears to be that the /openid/provider/user/5 path does not return a more specific endpoint path. I'm assuming that because Moodle expects such it is protocol correct, because I don't actually know the protocol that well -- yet. :-p

darren.ferguson’s picture

Chris

Looks like you are correct the wrong information is coming back but Drupal openid module some how just lets it pass.

[darren@myhost ~]$ telnet www.example.com 80
Trying 65.217.55.36...
Connected to www.example.com.
Escape character is '^]'.
GET /openid/provider/user/1 HTTP/1.1
Host: www.example.com

HTTP/1.1 200 OK
Date: Thu, 16 Oct 2008 18:23:37 GMT
Server: Apache/2.2.9 (Unix) DAV/2 mod_ssl/2.2.9 OpenSSL/0.9.8h
Set-Cookie: SESS98a9fa8a83720689dc7a815daf922ae0=gkfr16kctg0il8irla8us1du54; expires=Sat, 08 Nov 2008 21:57:02 GMT; path=/; domain=.www.example.com
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Thu, 16 Oct 2008 18:23:42 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
X-XRDS-Location: http://www.example.com/xrds
X-Yadis-Location: http://www.example.com/xrds
Content-Length: 0
Content-Type: text/html; charset=utf-8

So looks like it just works because it is a fluke and not because it is. So will need to check what the provider is doing and indeed why the account information is not showing.

Chris Johnson’s picture

Ok, the reason the URL http://localhost:7064/openid/provider/user/5 fails is because the openid_provider module only returns an empty document, but the HTTP headers in that document are set by a call to hook_init(), which sets the path to /xrds for the X-XRDS-Location and X-Yadis-Location headers because arg(0) is not 'user'.

However, if we use the URL http://localhost:7064/user/5 (the normal user view path),, then hook_init() gets arg(0) set to 'user' and arg(1) is the numeric UID. Then the XRDS and Yadis locations get set right in the HTTP headers, and the empty HTML document is sent as before. But now the OpenID RP code knows the UID when it sees the XRDS and Yadis headers, and does a GET on the /user/5/xrds path and obtains the correct XRDS document.

Here's the XRDS and Yadis headers from telnet:

54 obmbp:~/Sites/6.4% telnet localhost 7064
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /user/5 http/1.1
Host: localhost:7064

HTTP/1.1 200 OK
Date: Thu, 16 Oct 2008 18:22:05 GMT
Server: Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.7l DAV/2 PHP/5.2.6
X-Powered-By: PHP/5.2.6
Set-Cookie: SESS01908a7ba7f3bb734825ef9ce78b0507=89ce0c1ed28772edc475e1a68477f620; expires=Sat, 08 Nov 2008 21:55:31 GMT; path=/
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Thu, 16 Oct 2008 18:22:11 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
X-XRDS-Location: http://localhost:7064/user/5/xrds
X-Yadis-Location: http://localhost:7064/user/5/xrds
Content-Length: 5754
Content-Type: text/html; charset=utf-8

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
  <head>
    <title>FOOBAR | d6 localhost</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="openid2.provider" href="http://localhost:7064/openid/provider" />

<link rel="openid.server" href="http://localhost:7064/openid/provider" />

<meta http-equiv="X-XRDS-Location" content="http://localhost:7064/user/5/xrds" />
<meta http-equiv="X-Yadis-Location" content="http://localhost:7064/user/5/xrds" />

You can see that the HTTP headers as well as the meta http-equiv HTML bits have the correct paths with the UID now included. (As a side note, the link rel= HTML bits still only have the general discovery path, but that may be right.)

Despite this, Moodle still fails, but in a different way, so that's a good thing. It's a different problem to track down.

So the real problem with this patch to add the open access path of /openid/provider/user/UID does not work the same as the /user/UID path, which it should. The problem with the /user/UID path, of course, is that it is NOT accessible until the user has already logged in.

I'll add some more details in a while as I dig deeper into the new problem, and think about the path/access problem a bit more.

anarcat’s picture

Now that the URL patch about user/N/identity (#322764: Adding patch to support new OpenID Provider Path) has landed, is this still relevant? And how is this different from #322761: Adding patch to support new OpenID Provider Path?

aron novak’s picture

Status: Needs review » Closed (duplicate)

I'm sure this is a duplicate of #322764