Download & Extend

LDAP User: Password field disabled Makes use case of Provisioning Passwords from Drupal to LDAP unusable

Project:Lightweight Directory Access Protocol (LDAP)
Version:7.x-2.x-dev
Component:Code
Category:bug report
Priority:major
Assigned:Unassigned
Status:closed (fixed)

Issue Summary

I have a token for "Pwd: User or Random" leading to "userPassword". Registration is open to visitors. Authentication works, authorization works, no error messages anywhere. Yet when I try to edit a user's password from the admin panel or user edit panel, it's disabled.

The reset password message states that I should use my "organization's password management sites". But I want Drupal to be that site. What am I doing wrong here? Using the latest dev as of 10 Jan 2013.

Comments

#1

Do you have ldap authentication module enabled? Seems like it should be disabled if you are using drupal authentication.

#2

Ditto. I'm looking to achieve the same configuration as synth3tk. I tried disabling ldap authentication and that enables the form elements for changing passwords, but doesn't seem to work and doesn't look to be updating ldap. Also, without ldap authentication I'll have a few thousand users that won't be able to login. Would I need to somehow synch those passwords to Drupal? Pre-provision all those accounts before making the site live?

I'm using the same ldap directory to authenticate users for multiple web-based applications. I would prefer to use Drupal to handle password reset; we really like the 'one-time login' URL.

#3

Hello, we are experiencing the same problem.
In our company we have an Active Directory server synchronized with drupal6.
By performing the tests of synchronization between the same AD server and drupal7, everything works (also the synch with custom user fields), but not the change password that is also disabled for us.

#4

I am having a related but similar issue, with a more specific use case which I would nonetheless think is common:

1. I would like to use LDAP Authentication -- only users who already exist in my pre-populated directory can log in to Drupal. No other users can create accounts.

2. I would like, once the accounts are connected, to use LDAP User's mapping power to push back password changes to the LDAP server -- i.e. users can change their LDAP password through Drupal without the use of a secondary management page.

It seems like this use case isn't compatible with how the module is presently constructed -- you can get one but not both. Is that correct or am I missing something?

#5

That's exactly the setup I want, too (no creation of users, but sync/update existing ones through Drupal).

And you're correct that it appears not to work in any version of the module currently. Creation seems to work, but updating doesn't.

#6

I'm looking for the same set-up as Kazanir and synth3tk.

#7

The same here.
It seems to be that the "Sync on Drupal account update" option would not working...

Under admin/config/people/ldap/user i enabled "Create or Synch to LDAP entry when a Drupal account is created or updated. Only applied to accounts with a status of approved. "
But when i test it (admin/config/people/ldap/user/test) under "synchToLdapEntry method results " i get the result "On creation or synch of an LDAP entry when a user authenticates. (String, 12 characters ) Not enabled."
Not "failed" but not "enabled", so it a config problem not a mapping/query problem.

#8

Category:support request» bug report

Marking as a bug, then, since something clearly isn't working correctly.

#9

Anyone having any luck on this? This one element is preventing me from updating my site from 6 to 7.

#10

Here's my setup - one central LDAP server, users can log in using LDAP credentials, if user account does not exist in Drupal on login it will be created. Also, users can sign up on Drupal side and will then populated in LDAP. LDAP passwords are using sha password hashes. User first/last name are synced to Drupal when the user authenticates; username/email/first/last/password are pushed to LDAP when the user is created or updated.

I made this work with some improvements to the existing module. Things I had to change:
1. make password field visible and not disabled on profile form
2. alter how the static password is set in ldap_user module
3. alter ldap_server tokens to avoid empty or random password being generated and synced to LDAP

Something to be aware of though - changing a password requires knowing what the user's Drupal password is. Since the passwords aren't stored in plain text anywhere and they cannot be synced from LDAP (sha vs md5) this will require user to use the forgot password functionality to reset Drupal password and LDAP password. While the user logs in with LDAP password they need Drupal password to change the password down the road or update email (if it's allowed).

#11

A patch from #10 would be useful if it didn't conflict with the other password and token functionality worked. Perhaps there needs to be a modifier to tokens that should not be used when they have no values?

#12

nonsie, can you be a bit more specific with what you did to accomplish your setup?

Thanks.

#13

I created a diff between my ldap setup and current dev. Since my version dev with mods is a few weeks old now I'm not sure if the patch is fully functional, I certainly have not tested it.
The code I'm using only has LDAP_AUTHENTICATION_PASSWORD_FIELD_ALLOW option enabled which shows and allows updating password through Drupal user profile form. I ran out of time to work on the other options.
While this is not a full solution it might help you get further along. I've also included the setting screens in case it helps.

AttachmentSize
ldap_passwords-1884922-13.patch 10.7 KB
password-behavior.png 30.31 KB
ldap-provisioning.png 135.49 KB

#14

Status:active» needs review

thanks for picking through this and developing a patch. I committed this (http://drupalcode.org/project/ldap.git/commitdiff/cb3dede7d354e4a6c0bd9f...).

Could everyone working with passwords test this out?

#15

When trying to change my password through the frontend user edit screen, it states Your current password is missing or incorrect; it's required to change the Password. even though I'm putting the correct password into "Current password".

Changing the password using the admin panel acts like everything saves, but the password still doesn't change.

No errors in any of the logs.

#16

Just guessing, but I suspect the lines that remove the password in this patch (http://drupalcode.org/project/ldap.git/commitdiff/cb3dede7d354e4a6c0bd9f...) may be the issue. Do you have the same problem if you comment them out?

#17

In which file? ldap_user.module?

#18

Here's is the patch that I believe corrects #14. I see 2 issues

1. The password tokens weren't implemented correctly. If another token besides password.user-random and password.random needs to be implemented, we should do that. Perhaps password.user-null which is the user's password when available, otherwise empty. We might want to ad a modifier syntax also like password.user-random;md5 so deal with that case.

2. removing the password so it doesn't get double hashed should be done a different way, not by emptying it out in hook_user_update. Whatever is hashing it 2 x is the issue. Other modules may need the password to be there.

AttachmentSize
1884922-18.patch 1.94 KB

#19

#18 That worked! Successfully changed my password both from the backend and as the user on the frontend. Checked the LDAP server to make sure the password was being changed. Login also worked both times I changed it.

#20

I committed #18, but we should still get #13 functionality working (if this breaks it).

#21

Been beating my head against this all day. First of all the line numbers in the patches don't match up with files on a fresh install, which was giving me fits. I think I got that all straightened out, but I still get the "Your current password is missing or incorrect; it's required to change the Password." message.

I noted that if I put in the current password and leave the new password fields blank, it accepts it and says that the changes have been saved, which obviously they haven't.

I also noted that I can use the email to request a new password feature, which would allow someone to login, but s/he would never be able to change the password if it had been forgotten.

#22

I forgot to say thanks for working on this! I appreciate the time spent on improving this module.

#23

#21, make sure you have it set to no encryption, and not Blowfish. That was an issue I had after applying the patch.

And I'd also like to echo my thanks to john for working on this! He is doing an awesome job.

#24

About #21 - in my version this was taken care of by the following lines in the patch

if (!empty($form_state['values']['current_pass_required_values'])) {
  if (!empty($form_state['values']['current_pass']) && empty($form_state['values']['pass'])) {
    ldap_user_ldap_provision_pwd('set', $form_state['values']['current_pass']);
  }
}

This sets the password to the current Drupal password instead of setting it to random like it used to do.
I found the easiest way to debug passwords to add some debug code to ldap_user_ldap_provision_pwd(). This explains when passwords get get set or retrieved and what the values are.

Also, this might help some - in my case LDAP passwords were with SHA password schemes so I had to use hook_ldap_entry_pre_provision_alter() to generate SHA password from Drupal passwords.

#25

I would appreciate a walkthrough of settings on this. I think I have everything right, but I am getting errors when attempting to change a password -- i.e. that my current password is not correct, so Drupal won't let me change it.

a. Drupal is set to synch to LDAP fine -- it pulls the DN correctly and the settings all save fine.
b. Users authenticate with their LDAP password also fine.
c. I have encryption turned off.
d. I have Pwd: User or Random set to synch to [userPassword].
e. Drupal is set to synch FROM LDAP on user login, which I assume would sync the passwords such that I wouldn't run into this error.

This definitely seems like a problem with the stored Drupal-side password not matching up but I have no idea where to look to fix it. Any help would be appreciated.

#26

Upon a little investigation it appears that:

1) The Drupal-side "check current password before allowing update" only checks the stored Drupal-side password, which was unset.

2) If I forcibly set the password of my test user (using uid 1 account), it works, but does not synch to LDAP (despite those settings allegedly being set to happen on user entity update.)

3) Once this is done, the test user can use the above password to change their own password, but it still only applies to the Drupal side and doesn't propagate to LDAP.

#27

@Kazanir - try the attached code. This is the one that I ended up with after modifying the dev version. Note that current dev has significant amount of changes so you will have to get those back in. Also look at the ldap provisioning screenshot in #13.

AttachmentSize
ldap.zip 449.87 KB

#28

Has anyone gotten this working with Active Directory? I've tried several versions of these patches and I'm still getting "Server is unwilling to perform" errors. The only thing I can see that's likely to stand in the way is the password getting sent to the "unicodePwd" attribute.

#29

After some more testing I'm still stumped and I figured I should elaborate on my issue more. Let me know if I should break this out into a separate issue.

I would like admins on my site to be able to create a Drupal account and have this automatically create a LDAP/Active Directory user at the same time, both with the same password.

Right now everything works about this except for saving the password. Users in the AD can authenticate on the site. However, if I try to create a user in Drupal I get 53 - "Server is unwilling to perform". This is because I am trying to pass the Drupal password into the "unicodePwd" AD field. Something seems to be going wrong there. If I remove the password element from the provisioning scheme, then the user is created in Drupal and the AD just fine. But, obviously this isn't functional because that user in the AD doesn't have a password assigned.

I'd be happy to work on some code, but would appreciate any areas to focus my attention. Thanks.

#30

Sounds like a separate issue. Might want to open a new ticket.

#31

nonsie: I have figured this out.

The following block of code is at issue:

/**
* store password from logon forms in ldap_user_ldap_provision_pwd static variable
* for use in provisioing to ldap
*/
function ldap_user_grab_password_validate($form, &$form_state) {
  // This is not a login form but profile form and user is insertingpassword to update email
  if (!empty($form_state['values']['current_pass_required_values'])) {
    if (!empty($form_state['values']['current_pass']) && empty($form_state['values']['pass'])) {
      ldap_user_ldap_provision_pwd('set', $form_state['values']['current_pass']);
    }
  }
  // otherwise a logon form
  elseif (!empty($form_state['values']['pass'])) {
    ldap_user_ldap_provision_pwd('set', $form_state['values']['pass']);
  }

This code is in the dev now, but it doesn't handle all cases -- specifically, it doesn't handle the submission of a user edit form *with password change* by the user, because the first IF statement succeeds and the nested second IF fails (due to [values][pass] being non-empty.) But the "otherwise a logon form" also can't handle it, because it made it inside the first if. To fix this, I changed the code to this:

/**
* store password from logon forms in ldap_user_ldap_provision_pwd static variable
* for use in provisioing to ldap
*/
function ldap_user_grab_password_validate($form, &$form_state) {
  // This is not a login form but profile form and user is inserting password to update email
  if (!empty($form_state['values']['current_pass_required_values'])) {
    if (!empty($form_state['values']['current_pass']) && empty($form_state['values']['pass'])) {
      ldap_user_ldap_provision_pwd('set', $form_state['values']['current_pass']);
    }
    // Or this is a profile form where the user is updating their own password
    elseif (!empty($form_state['values']['pass'])) {
      ldap_user_ldap_provision_pwd('set', $form_state['values']['pass']);
    }
  }
  // otherwise a logon form
  elseif (!empty($form_state['values']['pass'])) {
    ldap_user_ldap_provision_pwd('set', $form_state['values']['pass']);
  }

#32

#13 is headed in the right direction. Since there is no hook to get at the unhashed password, we need to deal with each form that might contain a password. A patch that does that as well as checks which form_id is being submitted (for additional certainty that it is a password form) would be greate to wrap this up.

#33

Priority:normal» major
Status:needs review» needs work

#34

Just to be sure we're all on the same bandwagon here, we also want the user to not need to enter the old password when changing the password, yes? Otherwise the email recovery system doesn't work.

I'm also on Active Directory and unable to get it to respond so I'm not sure what level of functionality everyone else is seeing.

Sorry I can't do more to contribute - it's slightly beyond my skill set. I'll happily test anything though.

#35

One way to contribute without writing code is to articulate tests for the specific use case. This way test coverage will cover the particular issue and it will not break sometime in the future. Articulating a use case is just a matter of saying what configurations are set and step through the forms with what values are set. Then summarize what should have changed in the end.

#36

I'm not trying to muddy the waters here, but I just noticed that I had my dn set wrong for the PROVISIONING FROM DRUPAL TO LDAP MAPPPINGS. I'm using active directory, so I had to grab my first and last name fields that I set up for users, so my mapped dn is:

cn=[field.field_first_name] [field.field_last_name],ou=members,dc=aps,dc=lan

I have Pwd: User or Random mapping to [unicodePwd]

I have Email mapping to [mail].

My users all authenticate just fine and are added to proper groups, but whenever I enable the Provisioning from Drupal to LDAP, I get the following errors:

php: Notice: Undefined variable: old_value_is_scalar in LdapServer::removeUnchangedAttributes() (line 461 of /var/www/sites/all/modules/ldap/ldap_servers/LdapServer.class.php).

ldapServer: LDAP Server ldap_modify(cn=John Jingle,ou=members,dc=aps,dc=lan) in LdapServer::modifyLdapEntry() Error Server ID = primary, LDAP Err No: 50 LDAP Err Message: Insufficient access

ldapUser:LDAP entry on server primary not synched because error. username=jjingle, uid=16

I'm puzzled by the insufficient access one because I know the bind is working.

I submit all this because I wonder if this inability to provision to LDAP is the underlying cause of the inability to update the password.

#37

I make a new bug report for this one, but:

there seems to be a problem with the connection settings configurations. I can set the LDAP port settings to 000 (or any number really) and it will authenticate. This is a problem because I need to hit port 636 via ssl to update passwords using Active Directory.

My connection should be ldaps://[server]:636. I discovered that this was a problem because I kept noting that I was getting an LDAP Err No: 53 LDAP Err Message: Server is unwilling to perform, which suggested that I wasn't making an ssl connection to AD. When I remove the password from the Provision to LDAP setting, I get no errors.

Where should I look to see why it doesn't seem to be picking up the port setting?

Thanks.

#38

Title:LDAP User: Password field disabled» LDAP User: Password field disabled Makes use case of Provisioning Passwords from Drupal to LDAP unusable

Can someone articulate how to replicate this and a patch that works against current dev. This thread is all over the place and needs to be summarized. I've retitled this issue to give it the focus it originally had.

#39

With current dev when authenticating to Active Directory, a user may attempt to update a password, but upon saving gets the following response:

Your current password is missing or incorrect; it's required to change the Password.

#40

I know I'm driving you crazy, but I think I'm on to something this time. The user password for Active Directory is unicodePwd and it has to be encoded in UTF-16. I looked back through LDAPInterface.inc in the old LDAP Integration module (in the Includes directory) and found this:

****************************

function writeAttributes($dn, $attributes) {
foreach ($attributes as $key => $cur_val) {
if ($cur_val == '') {
unset($attributes[$key]);
$old_value = $this->retrieveAttribute($dn, $key);
if (isset($old_value)) {
ldap_mod_del($this->connection, $dn, array($key => $old_value));
}
}
//Encodes password for use in Active Directory
if ($key == "unicodePwd") {
$cur_val = "\"" . $cur_val . "\"";
$attributes[$key] = mb_convert_encoding($cur_val, "UTF-16LE");
}

if (is_array ($cur_val)) {
foreach ($cur_val as $mv_key => $mv_cur_val) {
if ($mv_cur_val == '') {
unset($attributes[$key][$mv_key]);
}
else {
$attributes[$key][$mv_key] = $mv_cur_val;
}
}
}
}

********************

Note that it is making this conversion. I don't see this functionality anywhere in the new module. It needs to make this conversion when it provisions to LDAP.

#41

You are quite possibly correct. I have no idea what forms different ldaps want passwords in. The token system should allows for as many variations as are needed.

there are two places where tokens are dealt with:

ldap_servers_token_tokenize_entry() which is for ldap entry date replacing tokens like [samaccountname:last] , [guid:0;base64_encode], etc.

and ldap_servers_token_tokenize_user_account() which has the form [type.name.conversion] such as [property.name] or [password.user] or [password.user.to-md5]. These are the tokens you see in the ldap user mappings.

So to add a new conversion [password.user.to-UTF-16LE] just add a this code to the case statements of ldap_servers.tokens.inc. around line 420.

If you want it available in the UI for password pulldowns, add themn to the $available_user_attrs around line 360 of ldap_user.module.

Also, the documentation on tokens at http://drupal.org/node/1245736 is a bit out of date. If you can update that to include the user ldap_servers_token_tokenize_user_account that would be helpful.

#42

Well this is challenging (I spent all day on it and still no luck). Do you know a way I can determine if it's actually converting the string to UTF-16? It also has to be in quotes, but I've got that bit sorted out.

#43

You can add a debug line in ldap_servers.tokens.inc where your code is.

watchdog('debug', $YOURVARAIBLE, array(), WATCHDOG_DEBUG);

and look in the logs.

Or if you have devel module enabled, add a line like:

dpm('UTF-16'); dpm( $YOURVARAIBLE);

#44

Re: #38 -- I just deployed a working version of this that has some updates from the dev:

1. I added a "User Only" option for passwords, some code for this was present but non-functional and didn't have a UI option; I updated and fixed it. This means that, if enabled, LDAP should never try to synch a randomized password to the directory. I ran into this as a problem when running a Feeds import on the directory caused Drupal to synch back a random password for EVERYONE (since it wasn't part of a user login form.)

2. I also fixed the "user editing password form" use case as I documented above.

There should probably be documentation about the need for a service account with full powers to change anyone's password (assuming a service account is used rather than user-based binding) as well as the apparent need to pick No Encryption for passwords.

In addition, an outstanding issue is that if a user changes their password and for whatever reason the synch to LDAP fails, Drupal will still have changed its copy of the user's password, resulting in a mismatch where the password needed to log in (LDAP authentication) is different than the password needed to change the password in the user/%/edit screen (which is the Drupal variant.)

A reset password link can fix this, but this possibility is frighteningly bad user experience and if there is any way to prevent it we probably should do so.

I will do a diff later today and post a patch against the current dev, which is what I started from yesterday.

#45

Sorry I haven't been responding lately. Been busy with other projects and life.

#44 I can't wait for that diff. I'll test it when you release it.

#46

Ok, I threw this together since the dev has changed since I updated and I'm far, far, far from being competent with Git. The only changes should be pretty obvious and it should apply to the current dev version.

AttachmentSize
ldap-userpassword_fixes-1884922-46.patch 2.28 KB

#47

This looks good. I let 'user' fall through the case statement so it would still work the same. Something is up with the drupal git server or my git, so I haven't pushed it out yet.

          case 'user-only':
          case 'user':
            $pwd = ldap_user_ldap_provision_pwd('get');
            $value = ($pwd) ? $pwd : NULL;
            break;

#48

Status:needs work» needs review

#49

Status:needs review» closed (fixed)