summaryrefslogtreecommitdiff
path: root/modules/openid
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-03-02 08:55:42 +0000
committerDries Buytaert <dries@buytaert.net>2010-03-02 08:55:42 +0000
commit094a6b4f85de525d32a0b8787e533e5e77925f7d (patch)
tree01d3c193446a3383f658344f5cb9f7bb52062ffd /modules/openid
parentc3760557bda91fa2ad044f289dcfd2ede999363d (diff)
downloadbrdo-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.inc68
-rw-r--r--modules/openid/openid.module59
-rw-r--r--modules/openid/openid.test35
-rw-r--r--modules/openid/tests/openid_test.module1
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">