| 6 user.module | user_external_login_register($name, $module) |
| 7 user.module | user_external_login_register($name, $module) |
| 8 user.module | user_external_login_register($name, $module) |
Helper function for authentication modules. Either logs in or registers the current user, based on username. Either way, the global $user object is populated and login tasks are performed.
File
- modules/
user/ user.module, line 2250 - Enables the user registration and login system.
Code
function user_external_login_register($name, $module) {
$account = user_external_load($name);
if (!$account) {
// Register this new user.
$userinfo = array(
'name' => $name,
'pass' => user_password(),
'init' => $name,
'status' => 1,
'access' => REQUEST_TIME,
);
$account = user_save(drupal_anonymous_user(), $userinfo);
// Terminate if an error occurred during user_save().
if (!$account) {
drupal_set_message(t("Error saving user account."), 'error');
return;
}
user_set_authmaps($account, array("authname_$module" => $name));
}
// Log user in.
$form_state['uid'] = $account->uid;
user_login_submit(array(), $form_state);
}
Login or register to post comments
Comments
Registering and Logging an externally authenticated user
In Drupal 7, setting up a Single-Sign On scenario involves the core user.module. The example scenario in this comment will review how to setup a module that would interact with the user.module to enable SSO.
First, review the main method that will be invoked in the user.module:
<?php/**
* Helper function for authentication modules. Either logs in or registers
* the current user, based on username. Either way, the global $user object is
* populated and login tasks are performed.
*/
function user_external_login_register($name, $module) {
?>
To get to the point to invoke this method, we need to get the users... username. We can pull this value from the Drupal login form values. Write a hook for the login form:
<?php/**
* Implementation of hook_form_alter().
* Change the normal form login form behaviour.
*/
function project_authentication_form_user_login_alter( &$form, $form_state )
{
$form['#validate'] = array( 'user_login_name_validate', 'project_authentication_login_validate', 'user_login_final_validate' );
}
?>
By setting up a hook on the user login form, we are able to override the validate methods. Within the validate method, we can authenticate the username and password on an external server.
<?php/**
* The project_authentication_auth() function attempts to authenticate a user off the external system using their e-mail address.
*/
function project_authentication_login_validate( $form, &$form_state )
{
$username = $form_state['values']['name'];
$response = project_authentication_check_user($username, $form_state['values']['pass'] );
if ($response != false)
{
user_external_login_register( $username, 'project_authentication' );
$account = user_external_load($username);
$form_state['uid'] = $account->uid;
} // else drop through to the end and return nothing - Drupal will handle the rejection for us
}
?>
There are some peculiar steps going on here, let's talk about this method.
The $username is pulled from the login form input. That username along with the form associated password is validated through the method 'project_authentication_check_user':
<?phpfunction project_authentication_check_user($email,$password){
try
{
$result = ....<external system authentication code>
if($result->size) {
$info = ....<external system information>
return $info;
}
return false;
}
catch (Exception $e) {
watchdog('prjauth', 'Error %error_message.', array('%error_message' => $e->faultstring), WATCHDOG_NOTICE);
return false;
}
}
?>
Since the username and password passed through the method 'project_authentication_check_user', we can continue in the method 'project_authentication_login_validate' and finally invoke:
<?phpuser_external_login_register( $username, 'project_authentication' );
?>
This method will register the username if that username does not yet exist in our system... Yes, we are able to login users into Drupal that don't exist in our system because they exist in the external system. We register them based on the information passed from the 'project_authentication_check_user' method.
Logging in the user is based on the flag 'project_authentication' that was passed into the user_external_login_register method. How is that possible? Do you have access to the Drupal database? Take a look at the AUTHMAP table.
The AUTHMAP table has a field called MODULE. The value 'project_authentication' is stored in the MODULE field. That way, the field AUTHNAME must have an entry that matches the $username value that was passed into the method 'user_external_login_register'. Based on that mapping, the user is logged into Drupal.
Of course, there needs to be some trust between Drupal and the external system. This is outside of this tutorial, but you can either have trust based on tightly coupled systems or use SAML (http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language). It is probably much easier to leverage the openID asset provided by Drupal: http://drupal.org/handbook/modules/openid
There is one last important note to discuss about the method 'project_authentication_login_validate'. We are populating $form_state with the users identifier.
<?php$account = user_external_load($username);
$form_state['uid'] = $account->uid;
?>
We do this because a part of our login form hook was to involve 'user_login_name_validate'. This is being called so that form submit doesn't get called after validate is completed since the method 'user_external_login_register' has invoked form submit for us. The method 'user_login_name_validate' needs the users identifier to be able to operate, so we populate the form_state when completing the 'user_external_login_register' method.
By the way, the method 'user_external_load' that we leveraged to get the users identifier is still referencing the AUTHMAP table. Based on the username that we are using as part of our SSO experience, we assume it is unique in the AUTHMAP.authname field.
So, that is it. Did you think there was anything more to do? Possibly there is. The roles still need to be dealt with. You can map the external user with a role mapping and manually edit the role as the user registers.
Also, when a user forget's a password, they don't actually ever use the Drupal password since it resides in the external system. That will be in another tutorial coming soon.
Really nice tutorial
Thank you for sharing!
However, some people may be wondering how to connect to different databases. It may come a little tricky in hand, but it's actually easier that you've thought.
This is how your database settings look in your settings.php (sites\default\settings.php)
<?php$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupaldb',
'username' => 'root',
'password' => 'password',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
),
),
);
?>
Now, in order to add a new database connection, we will need to modify this, but not to much. The following example is with multiple database connection (watch the comments in the code):
<?php$databases = array (
'default' => // main drupal db starts from here
array (
'default' =>
array (
'database' => 'drupaldb', // main drupal db name
'username' => 'root', // main drupal db username
'password' => 'password', // main drupal db password
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
),
),'yourcustomdb' => // additional database starts here
array (
'default' =>
array (
'database' => 'database', // additional database name
'username' => 'root', // additional database username
'password' => 'password', // additional database password
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
)
),
);
?>
Okey, we've got the databases set up. Now we need to know how to call one and another. Don't panic, it's easy and very convenient. In the module where you'd need it, it's something like this:
<?php
db_set_active('yourcustomdb'); // we call our custom db
$query = db_query("....."); // we do our query here...
db_set_active('default'); // we swich back to the drupal core db
// Now we do whatever we want with that query...
?>
Hope this was helpful.