Directory Programming .NET

Active Directory and ADAM programming support for .NET developers
Welcome to Directory Programming .NET Sign in | Join | Help
in Search

create user password with SDS.P

Last post 04-13-2009, 1:05 PM by joe. 14 replies.
Sort Posts: Previous Next
  •  04-07-2009, 3:58 PM 6123

    create user password with SDS.P

    Hi,

    I am trying to create new user account in AD by using SDS.P.

    I was following this sample, which I found here in another post:

    SDS.P

    LdapConnection con = new LdapConnection("fabrikam.com");
    //this allows LDAP pwd changes!
    con.SessionOptions.Sealing = true;
    con.Bind();

    DirectoryAttribute samName = new DirectoryAttribute("sAMAccountName", "User1Acct");
    DirectoryAttribute objectClass = new DirectoryAttribute("objectClass", "user");
    DirectoryAttribute sn = new DirectoryAttribute("sn", "User");
    DirectoryAttribute givenName = new DirectoryAttribute("givenName", "One");

    //fancy formatting for password data
    byte[] pwdData = Encoding.Unicode.GetBytes("\"pAssw0rdO1\"");
    DirectoryAttribute unicodePwd = new DirectoryAttribute("unicodePwd", pwdData);

    DirectoryAttribute pwdLastSet = new DirectoryAttribute("pwdLastSet", "0");
    DirectoryAttribute uac = new DirectoryAttribute("userAccountControl", "512");
          
    DirectoryAttribute[] dirAttribs = new DirectoryAttribute[]
    {samName, objectClass, sn, givenName, unicodePwd, pwdLastSet, uac};

    AddRequest add =
        new AddRequest("CN=User1Acct,ou=TechWriters,dc=fabrikam,dc=com", dirAttribs);
    con.SendRequest(add); 

    The problem I have is with the password attribute. If I remove password from the list, user account is created successfully.

    When password is in the list of attributes, I have this error:

    DirectoryOperationException in CreateObject: UnwillingToPerform - [The server cannot handle directory requests.]

    Here is my connection object:

    _ldapConnObject = new LdapConnection(_adServerPath);
    _ldapConnObject.AuthType = AuthType.Negotiate;
    cred = new NetworkCredential(adminAcct, adminPassword, domain);
    _ldapConnObject.Credential = cred;
    _ldapConnObject.SessionOptions.Sealing = true;

    Thank you in advance for any help.

  •  04-07-2009, 8:09 PM 6125 in reply to 6123

    Re: create user password with SDS.P

    I found the problem. I've passed the password value which does not meet the requirements.

    As soon as I tried to create the same user with the same password in ADUC, I saw the actual error message about the password format.

    But go figure that this

    DirectoryOperationException in CreateObject: UnwillingToPerform - [The server cannot handle directory requests.]

    means incorrect password....

  •  04-08-2009, 5:06 PM 6136 in reply to 6125

    Re: create user password with SDS.P

    It is sometimes hard to diagnose the complexity problems.  In the detailed error message there is usually a code that can be used to discover the underlying problem but this value is sometimes hard to get or interpret.  Glad you got it working otherwise.  I had not had a chance to test that sample. :)
  •  04-08-2009, 6:57 PM 6138 in reply to 6136

    Re: create user password with SDS.P

    Actually it was too early for me saying it was working :(.

    I can set the "unicodePwd" attribute indeed. But it seems that it's not a real password!

    First, after user was created programmatically, I still see this flag set: ADS_UF_PASSWD_NOTREQD. User account, created through the ADUC does not have it.

    Second, when I try to authenticate the user created by my code, I have "Invalid credentials" error.

    I tried this code sample:

    public static bool DoDigestAuth(NetworkCredential cred)
    {
        const int LDAP_INVALID_CREDENTIALS = 49;
        LdapConnection conn =
            new LdapConnection("adam.joekaplan.net:389");
        conn.AuthType = AuthType.Digest;
        conn.Credential = cred;

        try
        {
            conn.Bind();
            return true;
        }
        catch (LdapException ex)
        {
            if (ex.ErrorCode == LDAP_INVALID_CREDENTIALS)
            {
                return false;
            }
            else
            {
                throw;
            }
        }
    }

    as well as direct bind in ldf.exe:

    Error <49>: ldap_bind_s() failed: Invalid Credentials.

    Please help.

  •  04-08-2009, 8:50 PM 6145 in reply to 6138

    Re: create user password with SDS.P

    Make sure the userAccountControl is set to the right value by comparing the raw value in LDP.  It should work fine but I might have had the hard coded value wrong there.  Unfortunately I don't have an easy way to test it myself right now but maybe I can tomorrow if you are still having problems.
  •  04-09-2009, 11:55 AM 6163 in reply to 6145

    Re: create user password with SDS.P

    Hi Joe,

    I have fixed the first issue by adding these attributes to the user account upon creation:

    attrs.Add(new DirectoryAttribute("pwdLastSet", "0"));

    attrs.Add(new DirectoryAttribute("userAccountControl", "512"));

    So now both accounts (created programmatically and created with ADUC) look identical.

    But I still cannot resolve authentication issue. I tried to bind with ldp.exe (settings: Function Type = Generic, Method = Digest, both Synchronous and Use auth. Identity are checked). User created by ADUC was boud successfully, user created by my code had Invalid credentials error.

    When I tried to bind both of them through the code, both accounts returned Invalid credentials error.

  •  04-09-2009, 4:12 PM 6170 in reply to 6163

    Re: create user password with SDS.P

    If you set pwdLastSet to 0, the user must change password at next logon and LDAP binds will fail until the password is changed via interactive logon.  Try setting the password in code and just setting userAccountControl to 512.  That should give you the required behavior.

    If you create the account and pwdLastSet is set to a valid date, it should just work for auth.

  •  04-09-2009, 8:25 PM 6175 in reply to 6170

    Re: create user password with SDS.P

    Still no luck.

    These are the attributes I set upon creation:

     sAMAccountName=test1.user
     userPrincipalName=test1.user
     givenname=Test1
     sn=User
     unicodePwd=System.Byte[] (the actual value is "Password?")
     userAccountControl=66048 (I used NormalAccount=512 + PasswordDoesNotExpire=65536)

    I removed pwdLastSet attribute, so now after user is created I see the valid timestamp (today).

    Where else should I look?

    Thanks.

  •  04-09-2009, 11:47 PM 6177 in reply to 6175

    Re: create user password with SDS.P

    Are you actually setting the password value using the Unicode encoding with the quote characters embedded as I showed in my sample?  That part is important, as the unicodePwd attribute must be set a specific way.

  •  04-10-2009, 10:43 AM 6184 in reply to 6177

    Re: create user password with SDS.P

    Yes, I do:

    private static byte[] getPasswordData(string password)

    {

    string formattedPassword = String.Format("\"{0}\"", password);

    return (Encoding.Unicode.GetBytes(formattedPassword));

    }

    And then:

    attrs.Add(new DirectoryAttribute("unicodePwd", getPasswordData("Password?")));

  •  04-10-2009, 12:50 PM 6185 in reply to 6184

    Re: create user password with SDS.P

    I kinda made a little progress (I hope) as I can bind to AD with this user credentials with ldp.exe.

    So my assumption that the user actually was created properly.

    I can see this message in ldp.exe:

    res = ldap_bind_s(ld, NULL, &NtAuthIdentity, 16518); // v.3
     {NtAuthIdentity: User='test1.user'; Pwd= <unavailable>; domain = 'adtest'.}
    Authenticated as dn:'test1.user'.

    I have made a reverse engineering of LdapConnection object to see the bind source code.

    And I found this:

     errorCode = Wldap32.ldap_bind_s(this.ldapHandle, null, credentials, method);


    By comparing it with ldp log message, I noticed "&NtAuthIdentity" value was passed as "credentials". When I went to ldp Bind options window and unchecked "Use Auth. Identity", the bind failed and the bind call had a different format:

    res = ldap_bind_s(ld, 'test1.user', <unavailable>, 16518); // v.3

    Now my question is: how this option "Use Auth identity" is translated into the LdapConnection object properties? Signing? Sealing? Or something else?

    Also I noticed that domain is mandatory for the Digest bind in ldp.exe. As soon as I uncheck domain, it switches Method value back to Simple. 

  •  04-10-2009, 6:59 PM 6187 in reply to 6185

    Re: create user password with SDS.P

    I was able to make it working only by switching from AuthType.Digest to AuthType.Negotiate.

    This is a best I could do. I don't know why Digest is not working from the code. It works just fine in ldp.exe.

  •  04-11-2009, 6:48 PM 6189 in reply to 6187

    Re: create user password with SDS.P

    Digest can be tricky as there is some issue with case sensitivity with username, but it should work.  At the same time, you generally should be using Negotiate auth anyway.  Any specific reason why you are trying to do Digest?

    Glad you got the user creation working in any event.

  •  04-13-2009, 12:14 PM 6202 in reply to 6189

    Re: create user password with SDS.P

    Thank you Joe.

    There is no special reason of using Digest, I just followed your sample :).

     

  •  04-13-2009, 1:05 PM 6203 in reply to 6202

    Re: create user password with SDS.P

    The primary attraction for using Digest is really with ADAM.  In ADAM with ADAM users, Digest is the only secure authentication protocol available out of the box.  The only other option is simple bind which requires SSL for security, but SSL requires a certificate which is not always an option.

    For AD, digest is more attractive for non-Windows clients that can't use SPNEGO auth because it is not supported in their API.

    Like I said, it should work but it can be a little picky.

View as RSS news feed in XML