Setting Passwords

Mar 30, 2012 at 1:20 AM

What is the guidance for setting passwords on objects derived from the user class?

Coordinator
Mar 30, 2012 at 3:41 AM
Edited Jun 22, 2012 at 1:40 AM

I wrote a blog post about how to do this for AD and AD LDS.  It will vary between directory servers, but it should be similar for each.

Aug 2, 2012 at 9:58 PM

Based on the blog post you need to know the old password.  This appears to be the same with userPassword which is an alias for unicodePwd.  Have you found any way around knowing the old password (i.e. to set a password on a user account for the first time)?

Coordinator
Aug 15, 2012 at 12:40 AM
Edited Oct 22, 2012 at 6:01 PM

If the user is brand new you can issue a password reset (the application can generate it or it can be some simple default) after you've added them.  And then in another operation you can set the pwdLastSet value to 0 which will force the user to change his/her password at next login.  So your logic would look something like this:

 

using (var context = new DirectoryContext(config))
{
    //add user

    //update the user with a reset password

    //update pwdLastSet to 0 for user
}

I don't like that it requires 3 separate operations, but currently this is the only way to do it.  I'll look to see if there's a way to simplify this process.

Apr 18, 2013 at 4:39 PM
Hi,
I am not sure if reseting the password could help me or not.
The architecture for my system is a bit different, the user doesn't connect to AD directly I have services that wrap the user calls so that he doesn't interact with AD:
  • Registration: creates a new user in AD with password
  • Login: check the user+password against AD
I managed to create the user (using your amazing API) but I am stuck with the setting of the password.
Could you possibly complete the code sample here? And will it help my case?

Thanks in advance,
Roy
Coordinator
Apr 23, 2013 at 3:48 AM
Edited Mar 26, 2014 at 4:06 AM
Hi Roy,

I wrote a blog post about managing passwords in AD here. After you reset the password you'll have to force the user to change the password at next login. You can do that by setting the pwdLastSet attribute to 0. You'll have to make sure that their userAccountControl is not set with password never expires.

As for validating a user's credentials, I have not found a simple way to do it other than using NTLM or Kerberos. The best answer I have found is from this stack overflow post. The good thing is S.DS.P just wraps low level ldap calls so you should be able to get to the error result in the exception thrown when a failed login occurs from a Bind request.
using (var connection = new LdapConnection("server")
{
     try
     {
          connection.Bind(new NetworkCredential(...));
     }
     catch (LdapException ex)
     {
          //check the exception
     }
}
Apr 25, 2013 at 3:07 PM
Thank you for the reply.
In the end I found out that I needed to set connection.SessionOptions.Sealing = true since we are not using SSL (the Active Directory server is inside the organization network and the users access it by my services layer - never directly).
And then set userAccountControl to 512 so that the user will be active.

The end result was this:
        private byte[] GetPasswordData(string password)
        {
            var formattedPassword = String.Format("\"{0}\"", password);
            return (Encoding.Unicode.GetBytes(formattedPassword));
        }

        public void SetPassword(NetworkCredential adminCredentials, string userDistinguishedName, string password)
        {
            using (var connection = new LdapConnection(new LdapDirectoryIdentifier(WebConfiguration.ActiveDirectoryServer, WebConfiguration.ActiveDirectoryPort), adminCredentials))
            {
                connection.SessionOptions.Sealing = true;
                var pwdMod = new DirectoryAttributeModification { Name = "unicodePwd" };
                pwdMod.Add(GetPasswordData(password));
                pwdMod.Operation = DirectoryAttributeOperation.Replace;
                var accountControlMod = new DirectoryAttributeModification { Name = "userAccountControl" };
                accountControlMod.Add("512");
                accountControlMod.Operation = DirectoryAttributeOperation.Replace;

                var request = new ModifyRequest(
                  userDistinguishedName,
                  pwdMod,
                  accountControlMod
                  );

                connection.SendRequest(request);
            }
        }