Almost all of the users on my site are authenticated via our LDAP server (using the ldap_integration module in Drupal). The passwords for these users are not stored in the drupal users table (well, they are actually blanked out in the table). I tried logging in through the secure site http-auth process using a username/password that is ldap_authentified, and I could not log in. Using a username/password that is local to the drupal database is successful. I'm not sure if this is a secure site issue or an ldap_integration issue, but perhaps you would have some insight.

Thanks
AC

Comments

NaX’s picture

Component: User interface » Code
Assigned: Unassigned » NaX
Category: feature » bug

The secures site module calls user_module_invoke to login the user. This function calls hook_user in all modules. As this is the hook I think other authentication modules would use to integrate into drupal it should work.

I would recommend getting the LDAP module working before enable the secures site module and if it still does not work then please reopen this issue and then we can investigate further.

aclight’s picture

First of all, LDAP authentication works fine when using the standard Drupal login methods (the login block) or /user, so that's not the problem here. I'm still trying to wrap my head around how all the various hooks are called when logging in, and I still haven't quite figured them out. For what it's worth, the LDAP_integration package (ldapauth.module in particular) implements both hook_user and hook_auth, but the code that actually queries the LDAP server to see if the credentials are correct is all within ldapauth_auth. Maybe hook_user results in hook_auth being called, but it seems to me like it might be the other way around. But if that is the case then I don't understand why securesite works at all for users that are in the drupal database and don't need to be authenticated with LDAP.

NaX’s picture

StatusFileSize
new784 bytes

In the user.module user_login_validate is called first. This function calls the user_authenticate. This is were the user is authenticated and were hook_auth</cdoe> is called. Then <code>user_login_submit is called and this is were hook_user is called. This is for users that are already logged in and hook_user('login'...) is for modules to act on the event of a successful login.

The way securesite works is that it calls user_authenticate first then if successful user_module_invoke is called. I have changed this a little in a patch by calling user_login_submit.

Please test this. I don't see why this should not work.

NaX’s picture

Also make sure your user roles have the correct permissions "access site", else secures site will not allow them to login.

aclight’s picture

I applied the patch above and I still could not log in using LDAP authentication. Here are some of the things I tried and the results.

With securesite module/access site permission given to anonymous, authorized users, and admins:
I could not login using the securesite http-auth form and an admin, normal user (not LDAP authenticated), normal user (LDAP authenticated), or a non-existant user. I tried multiple times with each user and was typing the password in correctly. None of the users are blocked. There were no failed login messages in the watchdog log for any of the attempts.

With securesite module/access site permission given to authorized users and admins:
I could login using an admin or normal user that are not LDAP authenticated, but could not sign in using a normal user that is LDAP authenticated.

To further troubleshoot, I added the following line to the beginning of the ldapauth_auth() function in ldapauth.module:

watchdog('ldap_auth',"ldapauth_auth called");<input type="checkbox" name="" value="">

I was never given a message in the log, so I'm guessing that ldapauth_auth isn't getting called when I try to login via securesite. When I login using the built in /user/login box in Drupal, I do get this message in the log if I'm using a LDAP authentified account and don't get it if I'm using a local account.

One other issue with the patch--securesite is now trying to authenticate me when I logout as well as when I try to access a page that is under securesite control. This didn't happen before I applied the patch.

I hope this helps you figure out what the problem is. Let me know if there's something else you need from me.

AC

NaX’s picture

How is your PHP installed is it as an Apache module or as CGI. Have a look at this issue http://drupal.org/node/28408

And maybe try using the html login form to login and see if you are able to login. If you are then it most likely is a PHP CGI issue.

adrian’s picture

StatusFileSize
new1.11 KB

Here is my version of the patch for the same problem.

I added a call to _ldap_authenticate before trying to call user_authenticate, if the function exists. They both return exactly the same thing.

I still have some problems with this though, it was working in our dev environment, but it does not work when brought live.
I'm still trying to get to the bottom of it.

adrian’s picture

Status: Active » Needs review

Oh. and i put this in the code comment, but not in the issue update:

ldap auth uses submit handlers on the login forms to log in. It does not use the drupal auth system.
It does this because it doesn't require the username@service.com format.

NaX’s picture

Status: Needs review » Needs work

I tried following the ldap modules authentication process and from what I can tell it does not use hook_auth to authenticate the user. I don't know why. That is where I would start with a external auth module. You say it is because it does not require the username@service.com format but by bypassing the drupal auth system it makes it very difficult to support as it does not play nice with others.

Calling _ldapauth_user_authenticate is a little bit of a hack but I cant see a way around it with the way ldap is structured.

This is the flow of things as far as I can tell.

 ldapauth_form_alter($form_id, &$form) ( set '#validate' = 'ldapauth_login_validate' )
 |
 |
 |_   ldapauth_login_validate($form_id, $form_values) (called on login form submit)
 |
 |
 |_   _ldapauth_user_authenticate ( check local user first else ... )
       |
       |
       |_   _ldapauth_ldap_login
              |
              |
              |_   ldapauth_auth (if return $ok = true)
              |
              |
              |_   return $user; 

function that set global $user
ldapauth_login_validate
_ldapauth_user_authenticate

darren oh’s picture

Thanks for working on this, NaX. Why don't we set this issue to "won't fix" and submit a bug report to the LDAP Integration module?

adrian’s picture

Darren , there is no way the ldap auth module can work any other way. because drupal's auth system simply isn't flexible enough to do it any other way.

To avoid having the optional support for ldap auth (which i don't think is that much of a hack, i mean lots of programs / modules add support for other modules), perhaps securesite should add it's own auth hook, which can then be added to ldap. But i think is even more of a hack than just having an if function_exists().

Lots of modules optionally extend others.

NaX’s picture

I don't understand why ldap cant use hook_auth. They could set the $user variable and return TRUE/FALSE with hook_auth, maybe theirs more to it that I am just not seeing.

But you are correct. It is not that big a deal to include conditional support for the ldap module. The only problem for me is that it shouldn't need to be this way, if their are already structures in place to handle these kind of things. If a hook or api did not exist then I would understand but when their are ways to integrate and play nice with others then I don't.

I am going to dig a little deeper into the ldap module to understand better, until then I will have to disagree. I will also look at creating a patch for now for people that need it but I don't know if it should be committed.

My big problem is testing, I don't have a ldap server to test against. Hopeful someone else can help with that.

aclight’s picture

Secure site is useless for my purposes unless it works with LDAP (since about 95% of my sites users authenticate via LDAP rather than Drupal itself) so of course I would be willing to test any patches to securesite you create that might add LDAP support. I agree with NaX that the ideal way of handling this would be for the LDAP module to do authentication through the usual Drupal hooks, but I'm not in a position to say whether that is possible or not. If it's not, I would love to see secure site add specific support for handling authentication using the LDAP module. Let me know what I can do to help out.

AC

NaX’s picture

From what I can tell the patch submitted by adrian should work just fine (comment #7).

Only thing is that the ldap module has been re-written and the HEAD version is very different to 4.7. The auth method is still using the same workaround, but many of the function names have changed.

4.7
_ldapauth_user_authenticate($form_values['name'], trim($form_values['pass']));

HEAD
_ldap_integration_code_changed_login_validate($form_values['name'], trim($form_values['pass']));

This will affect the patch depending on the version of ldap you use.

@aclight have you tested adrian's patch.

I also did some digging, and from what I can find ldap decided not to use the authmap method (hook_auth) for integrating. What ldap does is when a user first authenticates on the ldap server then it saves that user using the normal user_save function. But I have not yet found a reason for them dropping the authmap method. Still digging.

aclight’s picture

I haven't tested adrian's patch yet, and I probably won't have time until this weekend, but I'll give it a shot then and let you know what happens.

AC

aclight’s picture

Ok, I tested adrian's patch, and it does seem to work. If I login using a username/password that is valid on the LDAP server but not yet in my Drupal system, I am allowed to authenticate using secure site (which is the expected behavior provided by the LDAP module), however I have a error message in the watchdog log:

details
Type	php
Date	Thursday, November 30, 2006 - 21:44
User	Anonymous
Location	***URL I was trying to access that requires authentication via secure site *****
Referrer	
Message	Duplicate entry 'username' for key 2 query: user_set_authmaps INSERT INTO authmap (authname, uid, module) VALUES ('username', 1159, 'ldapauth') in /home/path_removed/drupal-4.7.4/includes/database.mysql.inc on line 121.
Severity	error
Hostname	***my IP address***

I replaced my actual username with username above. I'm not sure this is related to secure site, but I've never seen this message when just logging in using the LDAP module.

I've also noticed that if I give anonymous users permission to use securesite, that I can't login using any account (local or LDAP, admin or not). If I give permission to only authenticated user, then things work as expected.

I'll need to try some more testing this weekend to see if this really works right and reliably, but my initial impression is that it works, but may cause the error I mentioned above.

AC

NaX’s picture

That is a strange error. The error is triggered by the LDAP Module, but maybe it is something we are doing that is causing it.

Try this. I swapped the 2 round in adrian's patch. Now it will check local accounts first if that fails it will check ldap. I don't know exactly what would be the best way round. Maybe we should not query local accounts at all if ldap is enabled.


  $account = user_authenticate($edit['name'], $edit['pass']);
  /**
   * Attempt to log in using the LDAP auth module.
   * The LDAP auth module does not use Drupal's authentication system,
   * but instead adds a submit handler to the user login form.
   *
   * This is done to not require the username @ service.com format
   */
  if (function_exists('_ldapauth_user_authenticate') && !$account) {
    $account = _ldapauth_user_authenticate($edit['name'], $edit['pass']);
  }

  if ($account->uid && user_access('access site', $account)) {
    // login successful

aclight’s picture

@NaX

The code you suggested did not work, because from what I can tell $account existed and $account->uid = 0 (after the user_authenticate line), and so the next if statement did not evaluate to true and thus the LDAP authenticate wasn't called. I changed your code to the following:

  $account = user_authenticate($edit['name'], $edit['pass']);

  /**
   * Attempt to log in using the LDAP auth module.
   * The LDAP auth module does not use Drupal's authentication system,
   * but instead adds a submit handler to the user login form.
   *
   * This is done to not require the username @ service.com format
   */
  if (function_exists('_ldapauth_user_authenticate') && (!isset($account->uid)) || $account->uid == 0) {
    $account = _ldapauth_user_authenticate($edit['name'], $edit['pass']);
  }
 
  if ($account->uid && user_access('access site', $account)) {
    // login successful

This code now allows a login via the LDAP module, but the the php error message I commented on in #16 is still present.

FYI, I think the ideal thing to do regarding the order to authenticate in (local vs. LDAP) would be to read the value of ldap_login_process. If that evaluates to 0, the meaning is to first use Drupal's own database. If it fails, then look on the LDAP directory. If that evaluates to 1, the meaning is to use the LDAP directory only.

Thanks for working on this
AC

NaX’s picture

I'm a little stumped on this error you are getting. Are you using latest version of the ldap module?

Your modification of my code was correct. I did leave out the uid.

aclight’s picture

My ldapauth.module file is the latest version that I see, // $Id: ldapauth.module,v 1.1.4.12 2006/11/18 16:52:40 pablobm Exp $

moshe weitzman’s picture

ldap users might wish to use mod_ldap and webserver_auth module from contrib

junyor’s picture

@moshe: IINM, webserver_auth and mod_ldap will only allow LDAP users to authenticate. Some users (me included) need to have users from LDAP plus users created in the Drupal setup.

junyor’s picture

@aclight: Will you please check your authmap table to see what other rows use your username? That could help us find the root cause of that error.

aclight’s picture

@Junyor: I'm afraid I don't understand what you're asking. All usernames are unique in my authmap table, but I suspect that's not what you're asking.

AC

junyor’s picture

@aclight: The error message indicates that ldap_auth is trying to add yor username into the authmap table, but can't because an entry already exists. So, I'd like to know the existing entry in the table.

aclight’s picture

@Junyor: I'm sorry, but I still don't understand exactly what you want. For users that have already logged into the system via the ldap integration module, the value of the module field in the table authmap of the drupal database is "ldapauth" (without the quotes). The aid and uid fields contain integers, and the authname field contains the user's username.

I still don't feel that I'm answering your question though. If not, please tell me what specific information you need from me.

Thanks
AC

junyor’s picture

@aclight: Yep, we're not understanding each other. In comment #16, you got an error message saying there was data in the authmap table of your database that prevented the ldapauth module from adding details about your login (which you call "username"). I would like to know what details are in the database already for your account ("username"), so we can tell which module added them and find out why you're getting that error message.

junyor’s picture

In other words, look at the authmap table in your database and tell us the data associated with the row with uid = your uid ("username").

aclight’s picture

Using the versions of LDAP integration and secure site installed on my server (both from around the time when I originally wrote this comment), I am not able to authenticate using secure site when using a username/password combo that are valid on the LDAP server but which do not yet represent an account on my Drupal system. Perhaps secure site has changed enough since I wrote comment #16 so that this doesn't work. I am able to authenticate using a username/password combo for an account that exists and was NOT created by LDAP_integration (in other words, an account created from within Drupal itself).

In any case, I'm still not sure what you want from me.

You say:

you got an error message saying there was data in the authmap table of your database that prevented the ldapauth module from adding details about your login (which you call "username"). I would like to know what details are in the database already for your account ("username"), so we can tell which module added them and find out why you're getting that error message.

I think the fact that there was a row in the table authmap with the uid was the problem here.

You later say:

In other words, look at the authmap table in your database and tell us the data associated with the row with uid = your uid ("username").

The authmap table of my database contains 4 fields: aid, uid, authame, module. I've already described the values of those fields.

If you meant to ask about the users table of the database, and specifically the data field of that table, then the value of that field looks something like this:

a:4:{s:17:"ldap_authentified";b:1;s:7:"ldap_dn";s:46:"uid=XXX123, ou=People, dc=XXXXXXXXXXXX, dc=XXX";s:17:"ldap_drupal_roles";a:0:{}s:14:"XXXXXXXXXXXXXX";s:4:"XXXX";}

but keep in mind that I can't actually replicate the problem I reported in comment #16, and I have since deleted the user that was created at that time, so I can't tell you the exact value of the data field for this user in the users table.

Does that help?
AC

junyor’s picture

OK. No worries.

tonythemediaguy’s picture

Hi, I'm having the exact same issue as the poster above. I can use securesite but only with "real" users in the drupal database. It does not work with users who are being authenticated via ldap integration.

I'm using 5.1 and the latest HEAD of everything.

junyor’s picture

I'm using the following code successfully:

  if (!$account->uid) {
    $account = user_authenticate($edit['name'], $edit['pass']);
  }

  /**
   * Attempt to log in using the LDAP auth module.
   * The LDAP auth module does not use Drupal's authentication system, 
   * but instead adds a submit handler to the user login form.
   *
   * This is done to not require the username@service.com format
   */
  if (function_exists('_ldapauth_user_authenticate') && !$account->uid) {
    $account = _ldapauth_user_authenticate($edit['name'], $edit['pass']);
  }

  if ($account->uid && user_access('access site', $account)) {
    // login successful
junyor’s picture

Version: master » 5.x-1.x-dev
Status: Needs work » Needs review
StatusFileSize
new1.22 KB

Here's the code in patch form.

junyor’s picture

Status: Needs review » Needs work

OK, I spoke too soon. Using this code, ldap_auth tries to connect to example.com to authenticate! It eventually connects to the correct server and authenticates, but it takes several minutes. This happens because ldap_auth must not be getting the correct LDAP information from the database and it primes the server variable to example.com. I'm still looking for a solution.

junyor’s picture

@NaX: From what I can tell, ldap_auth doesn't implement hook_authenticate() because they allow admins to set it up so users authenticate only against the LDAP DB and not Drupal's DB. In user_authenticate(), Drupal first checks the local database, then checks for external auth. And the external auth checks depend on having a server as part of the username, which, as adrian mentioned, the LDAP module also doesn't require.

NaX’s picture

@Junyor: From what I can tell when ldap is setup correctly and working the patch works just fine. Is that also your findings? A while ago I spent a lot time trying to follow the ldap modules processing to see how best we could integrate. I got very lost but yes you are correct as far as I can tell, the ldap module does not use hook_authenticate().

I think we need to find a way to check if the ldap module is installed and setup, rather than just checking if the function exists. If it is setup then we call _ldapauth_user_authenticate.

Alternately we can have a secure site setting to enable or disable ldap integration. So admins can choose to enable ldap integration only when the ldap module is setup and working.

junyor’s picture

StatusFileSize
new1.24 KB

Sorry for all the updates. I found the problem. The proposed patch always calls user_authenticate, then _ldapauth_user_authenticate. ldapauth has a function called ldapauth_auth (AKA hook_auth), so user_authenticate calls ldapauth_auth, which bypasses the ldapauth initialization step. Here's the fixed patch which only calls user_authenticate when LDAP isn't enabled.

@NaX: I'm OK with the current setup, it's just that the code wasn't correct. So, no, it doesn't work correctly with the previous patch. LDAP would always try to authenticate via example.com because _ldapauth_init wasn't called. I guess when the call to user_authenticate failed, securesite then called _ldapauth_user_authenticate, which worked and the user was logged in.

junyor’s picture

Status: Needs work » Needs review
junyor’s picture

The issue with ldapauth_auth is discussed in http://drupal.org/node/158671.

junyor’s picture

Status: Needs review » Fixed

Patch from #37 committed to the DRUPAL-5 branch.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.