diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-03-02 08:55:42 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-03-02 08:55:42 +0000 |
commit | 094a6b4f85de525d32a0b8787e533e5e77925f7d (patch) | |
tree | 01d3c193446a3383f658344f5cb9f7bb52062ffd /modules/openid | |
parent | c3760557bda91fa2ad044f289dcfd2ede999363d (diff) | |
download | brdo-094a6b4f85de525d32a0b8787e533e5e77925f7d.tar.gz brdo-094a6b4f85de525d32a0b8787e533e5e77925f7d.tar.bz2 |
- Patch #634562 by vgarvardt, Damien Tournoud: added OpenID AX support (in addition to SREF) so that we can extend our OpenID implementation in contrib.
Diffstat (limited to 'modules/openid')
-rw-r--r-- | modules/openid/openid.inc | 68 | ||||
-rw-r--r-- | modules/openid/openid.module | 59 | ||||
-rw-r--r-- | modules/openid/openid.test | 35 | ||||
-rw-r--r-- | modules/openid/tests/openid_test.module | 1 |
4 files changed, 154 insertions, 9 deletions
diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc index b4cd7aaa3..af40f8eb3 100644 --- a/modules/openid/openid.inc +++ b/modules/openid/openid.inc @@ -51,6 +51,16 @@ define('OPENID_NS_1_1', 'http://openid.net/signon/1.1'); define('OPENID_NS_1_0', 'http://openid.net/signon/1.0'); /** + * OpenID Simple Registration extension. + */ +define('OPENID_NS_SREG', 'http://openid.net/extensions/sreg/1.1'); + +/** + * OpenID Attribute Exchange extension. + */ +define('OPENID_NS_AX', 'http://openid.net/srv/ax/1.0'); + +/** * Performs an HTTP 302 redirect (for the 1.x protocol). */ function openid_redirect_http($url, $message) { @@ -495,3 +505,61 @@ function _openid_get_params($str) { } return $data; } + +/** + * Extract all the parameters belonging to an extension in a response message. + * + * OpenID 2.0 defines a simple extension mechanism, based on a namespace prefix. + * + * Each request or response can define a prefix using: + * @code + * openid.ns.[prefix] = [extension_namespace] + * openid.[prefix].[key1] = [value1] + * openid.[prefix].[key2] = [value2] + * ... + * @endcode + * + * This function extracts all the keys belonging to an extension namespace in a + * response, optionally using a fallback prefix if none is provided in the response. + * + * Note that you cannot assume that a given extension namespace will use the same + * prefix on the response and the request: each party may use a different prefix + * to refer to the same namespace. + * + * @param $response + * The response array. + * @param $extension_namespace + * The namespace of the extension. + * @param $fallback_prefix + * An optional prefix that will be used in case no prefix is found for the + * target extension namespace. + * @return + * An associative array containing all the parameters in the response message + * that belong to the extension. The keys are stripped from their namespace + * prefix. + * @see http://openid.net/specs/openid-authentication-2_0.html#extensions + */ +function openid_extract_namespace($response, $extension_namespace, $fallback_prefix = NULL) { + // Find the namespace prefix. + $prefix = $fallback_prefix; + foreach ($response as $key => $value) { + if ($value == $extension_namespace && preg_match('/^openid\.ns\.([^.]+)$/', $key, $matches)) { + $prefix = $matches[1]; + break; + } + } + + // Now extract the namespace keys from the response. + $output = array(); + if (!isset($prefix)) { + return $output; + } + foreach ($response as $key => $value) { + if (preg_match('/^openid\.' . $prefix . '\.(.+)$/', $key, $matches)) { + $local_key = $matches[1]; + $output[$local_key] = $value; + } + } + + return $output; +} diff --git a/modules/openid/openid.module b/modules/openid/openid.module index 59abd6387..187cbb05b 100644 --- a/modules/openid/openid.module +++ b/modules/openid/openid.module @@ -219,7 +219,7 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) { $identity = $claimed_id; } } - $request = openid_authentication_request($claimed_id, $identity, $return_to, $assoc_handle, $service['version']); + $request = openid_authentication_request($claimed_id, $identity, $return_to, $assoc_handle, $service); if ($service['version'] == 2) { openid_redirect($service['uri'], $request); @@ -452,16 +452,46 @@ function openid_authentication($response) { } } elseif (variable_get('user_register', 1)) { - // Register new user + // Register new user. + + // Extract Simple Registration keys from the response. + $sreg_values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg'); + // Extract Attribute Exchanges keys from the response. + $ax_values = openid_extract_namespace($response, OPENID_NS_AX, 'ax'); + $form_state['build_info']['args'] = array(); $form_state['redirect'] = NULL; - $form_state['values']['name'] = !empty($response['openid.sreg.nickname']) ? $response['openid.sreg.nickname'] : ''; - $form_state['values']['mail'] = !empty($response['openid.sreg.email']) ? $response['openid.sreg.email'] : ''; + + if (!empty($sreg_values['nickname'])) { + // Use the nickname returned by Simple Registration if available. + $form_state['values']['name'] = $sreg_values['nickname']; + } + else if (!empty($ax_values['value.email'])) { + // Else, extract the name part of the email address returned by AX if available. + list ($name, $domain) = explode('@', $ax_values['value.email'], 2); + $form_state['values']['name'] = $name; + } + else { + $form_state['values']['name'] = ''; + } + + if (!empty($sreg_values['email'])) { + // Use the email returned by Simple Registration if available. + $form_state['values']['mail'] = $sreg_values['email']; + } + else if (!empty($ax_values['value.email'])) { + // Else, use the email returned by AX if available. + $form_state['values']['mail'] = $ax_values['value.email']; + } + else { + $form_state['values']['mail'] = ''; + } + $form_state['values']['pass'] = user_password(); $form_state['values']['status'] = variable_get('user_register', 1) == 1; $form_state['values']['response'] = $response; - if (empty($response['openid.sreg.email']) && empty($response['openid.sreg.nickname'])) { + if (empty($form_state['values']['name']) || empty($form_state['values']['mail'])) { drupal_set_message(t('Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), 'warning'); $success = FALSE; } @@ -529,7 +559,7 @@ function openid_association_request($public) { return $request; } -function openid_authentication_request($claimed_id, $identity, $return_to = '', $assoc_handle = '', $version = 2) { +function openid_authentication_request($claimed_id, $identity, $return_to = '', $assoc_handle = '', $service) { module_load_include('inc', 'openid'); $request = array( @@ -539,7 +569,7 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '', 'openid.return_to' => $return_to, ); - if ($version == 2) { + if ($service['version'] == 2) { $request['openid.ns'] = OPENID_NS_2_0; $request['openid.claimed_id'] = $claimed_id; $request['openid.realm'] = url('', array('absolute' => TRUE)); @@ -548,9 +578,20 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '', $request['openid.trust_root'] = url('', array('absolute' => TRUE)); } - // Simple Registration + // Always request Simple Registration. The specification doesn't mandate + // that the Endpoint advertise OPENID_NS_SREG in the service description. + $request['openid.ns.sreg'] = OPENID_NS_SREG; $request['openid.sreg.required'] = 'nickname,email'; - $request['openid.ns.sreg'] = "http://openid.net/extensions/sreg/1.1"; + + // Request Attribute Exchange, if available. + // We only request the minimum attributes we need here, contributed modules + // can alter the request to add more attribute, and map them to profile fields. + if (in_array(OPENID_NS_AX, $service['types'])) { + $request['openid.ns.ax'] = OPENID_NS_AX; + $request['openid.ax.mode'] = 'fetch_request'; + $request['openid.ax.required'] = 'email'; + $request['openid.ax.type.email'] = 'http://schema.openid.net/contact/email'; + } $request = array_merge($request, module_invoke_all('openid', 'request', $request)); diff --git a/modules/openid/openid.test b/modules/openid/openid.test index 2d20f1dba..20f920442 100644 --- a/modules/openid/openid.test +++ b/modules/openid/openid.test @@ -315,6 +315,41 @@ class OpenIDFunctionalTest extends DrupalWebTestCase { $this->clickLink(t('OpenID identities')); $this->assertRaw($identity, t('OpenID identity was registered.')); } + + /** + * Test OpenID auto-registration with a provider that supplies AX information, + * but no SREG. + */ + function testRegisterUserWithAXButNoSREG() { + variable_set('user_email_verification', FALSE); + + // Load the front page to get the user login block. + $this->drupalGet(''); + + // Use a User-supplied Identity that is the URL of an XRDS document. + $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); + + // Tell openid_test.module to respond with these AX fields. + variable_set('openid_test_response', array( + 'openid.ns.ext123' => 'http://openid.net/srv/ax/1.0', + 'openid.ext123.value.email' => 'john@example.com', + )); + + // Fill out and submit the login form. + $edit = array('openid_identifier' => $identity); + $this->drupalPost(NULL, $edit, t('Log in')); + + // Check we are on the OpenID redirect form. + $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + + // Submit form to the OpenID Provider Endpoint. + $this->drupalPost(NULL, array(), t('Send')); + $this->assertLink('john', 0, t('User was logged in.')); + + $user = user_load_by_name('john'); + $this->assertTrue($user, t('User was registered with right username.')); + $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.')); + } } /** diff --git a/modules/openid/tests/openid_test.module b/modules/openid/tests/openid_test.module index 0512555f9..e980bb6c8 100644 --- a/modules/openid/tests/openid_test.module +++ b/modules/openid/tests/openid_test.module @@ -78,6 +78,7 @@ function openid_test_yadis_xrds() { </Service> <Service priority="10"> <Type>http://specs.openid.net/auth/2.0/signon</Type> + <Type>http://openid.net/srv/ax/1.0</Type> <URI>' . url('openid-test/endpoint', array('absolute' => TRUE)) . '</URI> </Service> <Service priority="15"> |