The login handling does not allow for logging in with email. The settings allow to get close, but user name is used in a few places.

Current Setup:

  • Server Settings: AuthName attribute = mail
  • Email Registration module to process mail to user name

Caveats:

  1. The email_registration module sets $form_state['values']['name'] to the existing account's user name to allow normal authentication.
    • _ldap_authentication_user_login_authenticate_validate() uses $form_state['values']['name'] as the $authname for LDAP. This could be alleviated by checking for $form_state['values']['email'] and then using that as the authname; however, that still feels clunky.
  2. LDAP authorizations do not provision for existing Drupal users
    • Authorizations passes the user object to LdapServer::groupMembershipsFromUser() which calls LdapServer::userUserToExistingLdapEntry() which uses $user->name to find the existing LDAP entry for the user.

Possible Solutions ...

  • An authentication setting for "Drupal account property that correlates to the login name". Then that could be used in areas where the user object is used to query LDAP.

Thoughts?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

recrit’s picture

Status: Active » Needs review
FileSize
6.59 KB

The attached patch adds:

  • function ldap_user_get_authname - takes a variant input and returns the authmap authname. This provides a common way to determine the authname when you have the username, uid, or user object.
  • Updates to ldap_authentication, ldap_authorization, ldap_servers to use the new function
  • A new hook: hook_ldap_servers_username_to_ldapname_alter() that allows other modules to alter the transformed user name in LdapServer::userUsernameToLdapNameTransform(). The ldap_user module implements this hook to set it to the authname if the name has not been altered already, ie though php eval code setting
recrit’s picture

Adjusted patch to
* determine the "entered" login name by checking if $form_state['values']['email'] exists

* find existing users by mail in ldap_authentication_corresponding_drupal_user

recrit’s picture

updated patch to properly set authmap when a drupal user is created during ldap authentication

recrit’s picture

re-rolled patch with whitespace so it applies correctly

recrit’s picture

Updated patch to account for updating existing users found via puid, ie "VI.A: Drupal account doesn't exist with $authname used to logon, but puid exists in another Drupal account; this means username has changed and needs to be saved in Drupal account"

johnbarclay’s picture

Title: Improve login credential handling to allow login with email address » Ldap Authentication: Improve login credential handling to allow login with email address

This looks good. I committed it. Please continue to test.

johnbarclay’s picture

Issue summary: View changes

fixed spelling of function name

validoll’s picture

If I set AuthName attribute to mail value, then get error on login

Server Error: Failed to create Drupal user account for %user_name

In ldap_authentication.inc:460 I change
$drupal_account = $auth_conf->ldapUser->provisionDrupalAccount(NULL, $user_edit, NULL, TRUE);
to
$drupal_account = $auth_conf->ldapUser->provisionDrupalAccount(NULL, $user_edit, $ldap_user, TRUE);

This is right? How I can login with LDAP mail?

kenorb’s picture

I've some issue with LDAP, Email Registration and above patch which were commited to dev (#5).
The scenario is:
- there is Drupal 6 site which authenticates with LDAP credentials only (both username and e-mail)
- there is new site on Drupal 7 which authenticates with LDAP credentials only (only via e-mail using Email Registration module).

The problem is:
- when I'm creating the new user, uid is set to username, but when LDAP authenticate the user, it's looking for e-mail address in uid
Call: _ldap_authentication_user_login_authenticate_validate ()/ldap_authentication_test_credentials()/userUserNameToExistingLdapEntry(uid=foo@example.com)

Code:

  // Email registration module populates name even though user entered email
  if (!empty($form_state['values']['email'])) {
    $entered_name = $form_state['values']['email'];
    $authname_drupal_property = 'mail';
  }

- also I can't fully store e-mail address in uid property, as there are other existing users which were created by a standard method (uid=username).

So I'm not sure what's the proper solution for problem. Either to remove the above condition, override validation function or improve the logic.

kenorb’s picture

Status: Needs review » Needs work

Proposed change:

--- a/ldap_authentication/ldap_authentication.inc
+++ b/ldap_authentication/ldap_authentication.inc
@@ -158,12 +158,6 @@ function _ldap_authentication_user_login_authenticate_validate(&$form_state, $re
   $entered_name = $form_state['values']['name'];
   $authname_drupal_property = 'name';
 
-  // Email registration module populates name even though user entered email
-  if (!empty($form_state['values']['email'])) {
-    $entered_name = $form_state['values']['email'];
-    $authname_drupal_property = 'mail';
-  }
-
   // $authname is the name the user is authenticated with from the logon form // patch 1599632
   $authname = $entered_name;

Or we need to handle the authentication of LDAP users in different way rather than just e-mail address against the uid property.

kenorb’s picture

I did some more tests and I think the patch is necessary, otherwise the authentication is inconsistent. We should authenticate username against LDAP uid property and not change the logic (e-mail instead of username) depending if some module is enabled or not, otherwise it'll always break the functionality to existing users.
I've successfully tested the attached patch as well with another patch at #2037887: Edit user password should use LDAP to authenticate (#10).

The test I did:
- I've created new user (registered with e-mail via Email Registration module),
- I was able log-in with the right credentials.
- I've tested password change and I was able log-in with the new credentials.

kenorb’s picture

Here is validation function which can be used to validate user via e-mail against LDAP, if user doesn't exist in Drupal yet:

function foo_checkout_register_ldap_user_login_validate($form, &$form_state) {
  if (!empty($form_state['values']['account']['login']['pass'])) {
    $form_state['values']['name'] = $form_state['values']['account']['login']['name'];
    $form_state['values']['pass'] = $form_state['values']['account']['login']['pass'];
    ldap_user_ldap_provision_pwd('set', $form_state['values']['account']['login']['pass']);
    ldap_servers_module_load_include('inc', 'ldap_authentication', 'ldap_authentication');
    _ldap_authentication_login_form_alter($form, $form_state, 'user_login');
  }
}

Example usage as part of custom login form:

     $form['account']['login']['name'] = array(
         '#type' => 'hidden',
         '#value' => $result[0]['uid'][0],
     );
 
     $form['account']['login']['login_now'] = array(
         '#type' => 'submit',
         '#value' => t('Login now'),
         '#limit_validation_errors' => array(array('account')),
         '#validate' => array('commerce_checkout_login_checkout_form_validate'),
         '#submit' => array('commerce_checkout_login_checkout_form_submit'),
         '#validate' => array('foo_checkout_register_ldap_user_login_validate', 'user_login_name_validate', 'ldap_authentication_core_override_user_login_authenticate_validate', 'ldap_authentication_user_login_authenticate_validate', 'user_login_final_validate'),
         '#submit' => array('user_login_submit'),
     );
     ldap_servers_disable_http_check($form);
agerson’s picture

I agree we should authenticate username against LDAP and not change the logic (e-mail instead of username) depending if some module is enabled or not.

kenorb, Is your patch in #10 based on some previous patches, it just appears to remove some lines of a previous patch. Does it patch the original ldap_authentication.inc?

agerson’s picture

Ok, I have figured out where the two modules are bumping into each other. The LDAP module uses the presence of $form_state['values']['email'], which it sets to know if people are using email_registration.

The email_registration.module on line 208 says:

// Keep the email value in form state for further use/validation.
    $form_state['values']['email'] = $form_state['values']['name'];

When I comment this line out I am able to log into both local and LDAP account with username and email address. And it doesnt appear to be used elsewhere in email_registration. But I dont think this is the right way to handle it.

It does appear that the presence of ldap_authentication.inc line 162 breaks integration with email_registration when it implies it supposed to support it:

 // Email registration module populates name even though user entered email
  if (!empty($form_state['values']['email'])) {
    $entered_name = $form_state['values']['email'];
    $authname_drupal_property = 'mail';
  }
grahl’s picture

Status: Needs review » Needs work
grahl’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 10: ldap_authentication.inc-2017251.patch, failed testing.

grahl’s picture

Status: Needs work » Closed (won't fix)

I'm marking this as wontfix since we don't have a viable patch here.

If someone is interested in getting email_registration and LDAP working nicely together, please feel free to reopen.