Commit 094a6b4f authored by Dries's avatar Dries

- Patch #634562 by vgarvardt, Damien Tournoud: added OpenID AX support (in...

- Patch #634562 by vgarvardt, Damien Tournoud: added OpenID AX support (in addition to SREF) so that we can extend our OpenID implementation in contrib.
parent c3760557
......@@ -50,6 +50,16 @@
*/
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).
*/
......@@ -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;
}
......@@ -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));
......
......@@ -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.'));
}
}
/**
......
......@@ -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">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment