go to  ForumEasy.com   
LdapPro  
 
 
   Home  |  MyForum  |  FAQ  |  Archive    You are not logged in. [Login] or [Register]  
Forum Home » Native LDAP Servers -- AD, OpenLdap, etc. » How to add an active user account to Active Directory
Email To Friend  |   Set Alert To This Topic Rewarding Points Availabe: 0 (What's this) New Topic  |   Post Reply
Author Topic: How to add an active user account to Active Directory
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:24:46 PM    Edit  |   Quote  |   Report 
How to add an active user account to Active Directory
Why does it matter?

Let's first look at the code below:
/**
 * Sample JNDI example code to add a user account to SunOne
 */
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;

public class JNDI_Add_User {
        
    public static void main(String[] args)
    {
    	
        String ldapURL = "ldap://mySunOne.myCompany.com:389";
        String bindDn = "cn=Directory Manager";
        String bindPwd = "password";
    	
        // Set up the environment for creating the initial context
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
        		"com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapURL);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, bindDn);
        env.put(Context.SECURITY_CREDENTIALS, bindPwd);

        try {
                
            // Create the initial context
            DirContext ctx = new InitialDirContext(env);

            // Attributes to represent the user 
            Attributes attrs = new BasicAttributes(true); // case-ignore
            // objectClass
            Attribute attr = new BasicAttribute("objectClass");
            attr.add("top");
            attr.add("person");
            attr.add("organizationalPerson");
            attr.add("inetOrgPerson");
            attrs.put(attr);
            // MUST attribute
            attrs.put("cn", "John Smith");
            // MAY attribute 
            attrs.put("givenName", "John");
            attrs.put("sn", "Smith");
            attrs.put("userPassword", "password");

            // Create the user account
            ctx.createSubcontext(
            		"cn=John Smith,ou=People,dc=example,dc=com", 
            		attrs);

            // close 
            ctx.close();

        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
}


It's working perfectly for most LDAP compliant directory servers including openLDAP, openDJ and SunOne. The newly added user account can be used to provide authentication service.

Now run the same code (with necessary changes on objectclass and others) to add user into AD (Active Directory).
/**
 * Sample JNDI example code to add a user account in Active Directory
 */
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;

public class JNDI_Add_User {
        
    public static void main(String[] args)
    {
    	
        String ldapURL = "ldap://myAD.myCompany.com:389";
        String bindDn = "CN=Administrator,CN=Users,DC=myCompany,DC=com";
        String bindPwd = "password";
    	
        // Set up the environment for creating the initial context
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
        		"com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapURL);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, bindDn);
        env.put(Context.SECURITY_CREDENTIALS, bindPwd);

        try {
                
            // Create the initial context
            DirContext ctx = new InitialDirContext(env);

            // Attributes to represent the user 
            Attributes attrs = new BasicAttributes(true); // case-ignore
            // objectClass
            Attribute attr = new BasicAttribute("objectClass");
            attr.add("top");
            attr.add("person");
            attr.add("organizationalPerson");
            attr.add("user");
            attrs.put(attr);
            // MAY attribute 
            attrs.put("cn", "John Smith");
            attrs.put("givenName", "John");
            attrs.put("sn", "Smith");
            attrs.put("userPassword", "password");

            // Create the user account
            ctx.createSubcontext(
            		"cn=John Smith,CN=Users,DC=myCompany,DC=com", 
            		attrs);

            // close 
            ctx.close();

        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
}


The user account is added. But when this account is used for authentication, you will get the error similar like this:
javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9,
comment: AcceptSecurityContext error, data 52e, v1db1


The account is useless! Why?

 Profile | Reply Points Earned: 0
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:33:43 PM    Edit  |   Quote  |   Report 
Bumpy road to add user into Active Directory -- userAccountControl=default
UserAccountControl is Active Directory's attribute that can control the behavior of user account. With this attribute, Active Directory can prevent unauthorized changes from messing up the user account. The value that is assigned to the attribute is cumulative with the most common flags as listed below:
    2 -- ACCOUNTDISABLE
   32 -- PASSWD_NOTREQD
  512 -- NORMAL_ACCOUNT

For details, please check at: http://support.microsoft.com/kb/305144

The user account created in the above example bears the attribute userAccountControl with value of 546, which is default.
dn: cn=John Smith,CN=Users,DC=myCompany,DC=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
sAMAccountName: $N41000-S9ETGFD3FG6DS
userPassword:: DA9sjHg7y9UW8bf==
cn: John Smith
givenName: John
sn: Smith
userAccountControl: 546


Here, 546 = 512(NORMAL_ACCOUNT) + 32(PASSWD_NOTREQD) + 2(ACCOUNTDISABLE) which internally flags the account as: ACCOUNTDISABLE. That perfectly explains why the above newly added account is useless.

 Profile | Reply Points Earned: 0
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:38:24 PM    Edit  |   Quote  |   Report 
Bumpy road to add user into Active Directory -- userAccountControl=544
Let's force it to be enabled:
        try {
                
            // Create the initial context
            DirContext ctx = new InitialDirContext(env);

            // Attributes to represent the user 
            Attributes attrs = new BasicAttributes(true); // case-ignore
            // objectClass
            Attribute attr = new BasicAttribute("objectClass");
            attr.add("top");
            attr.add("person");
            attr.add("organizationalPerson");
            attr.add("user");
            attrs.put(attr);
            // MAY attribute 
            attrs.put("cn", "John Smith");
            attrs.put("givenName", "John");
            attrs.put("sn", "Smith");
            attrs.put("userPassword", "password");
            attrs.put("userAccountControl", "544");

            // Create the user account
            ctx.createSubcontext(
            		"cn=John Smith,CN=Users,DC=myCompany,DC=com", 
            		attrs);

            // close 
            ctx.close();

        } catch (NamingException e) {
            e.printStackTrace();
        }


Here, 544 = 512(NORMAL_ACCOUNT) + 32(PASSWD_NOTREQD) which intentionally flags the account NOT as: ACCOUNTDISABLE. But when this account is used for authentication, you still get the same error as before:
javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9,
comment: AcceptSecurityContext error, data 52e, v1db1


Wait a minute, look at the flag 32(PASSWD_NOTREQD). Does that means what the user provided through userPassword was not even treated as password?

 Profile | Reply Points Earned: 0
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:41:25 PM    Edit  |   Quote  |   Report 
Bumpy road to add user into Active Directory -- userAccountControl=512
Ok, let's try one more step with userAccountControl being 512 - We want to create a normal active account with password:
        try {
                
            // Create the initial context
            DirContext ctx = new InitialDirContext(env);

            // Attributes to represent the user 
            Attributes attrs = new BasicAttributes(true); // case-ignore
            // objectClass
            Attribute attr = new BasicAttribute("objectClass");
            attr.add("top");
            attr.add("person");
            attr.add("organizationalPerson");
            attr.add("user");
            attrs.put(attr);
            // MAY attribute 
            attrs.put("cn", "John Smith");
            attrs.put("givenName", "John");
            attrs.put("sn", "Smith");
            attrs.put("userPassword", "password");
            attrs.put("userAccountControl", "512");

            // Create the user account
            ctx.createSubcontext(
            		"cn=John Smith,CN=Users,DC=myCompany,DC=com", 
            		attrs);

            // close 
            ctx.close();

        } catch (NamingException e) {
            e.printStackTrace();
        }

Sorry, you are not allowed to do that. Here is the error message:
javax.naming.OperationNotSupportedException: [LDAP: error code 53 - 0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0


Hmmm?
 Profile | Reply Points Earned: 0
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:44:28 PM    Edit  |   Quote  |   Report 
Bumpy road to add user into Active Directory -- SSL/StartTLS

Let's try it again with SSL a or StartTLS secure connection.
        String ldapURL = "ldaps://myAD.myCompany.com:636";
        String bindDn = "CN=Administrator,CN=Users,DC=myCompany,DC=com";
        String bindPwd = "password";


Sorry, it doesn't help. Same error:
javax.naming.OperationNotSupportedException: [LDAP: error code 53 - 0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0


Ouch!?

 Profile | Reply Points Earned: 0
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:48:45 PM    Edit  |   Quote  |   Report 
Bumpy road to add user into Active Directory -- unicodePwd
As shown above, Microsoft does not allow client application to directly manipulate attribute userPassword. Instead, Microsoft introduced a mysterious attribute unicodePwd which requires the password value be enclosed in double quotes and then each character (including the quotes) must be converted to its UTF16 unicode equivalent (because Windows conforms to UTF16). If you want to batch load users with LDIF, it must be further converted to Base64 encoding.

For example, for the password is Abcd1234, the LDIF representation should NOT be
userPassword: Abcd1234


Instead, it MUST be:
unicodePwd:: IgBBAGIAYwBkADEAMgAzADQAIgA=


Here is the whole chain of conversion:
       Abcd1234
          |
          |
          v
      "Abcd1234"
          |
          |
          v
 0x22 00 41 00 62 00 63 00 64 00 31 00 32 00 33 00 34 00 22 00
          |
          |
          v
IgBBAGIAYwBkADEAMgAzADQAIgA=


Whoa, that's really a myth!
 Profile | Reply Points Earned: 0
JNDI
member
offline   
 
posts: 19
joined: 05/18/2007
from: GA
  posted on: 10/03/2012 08:53:03 PM    Edit  |   Quote  |   Report 
Bumpy road to add user into Active Directory -- the End.
Finally, if you want to create a normal active user account with password Abcd1234, here is the complete code:
/**
 * Sample JNDI example code to add a user account in Active Directory
 */
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;

public class JNDI_Add_User {
        
    public static void main(String[] args)
    {
    	
        String ldapURL = "ldaps://myAD.myCompany.com:636"; // SSL
        String bindDn = "CN=Administrator,CN=Users,DC=myCompany,DC=com";
        String bindPwd = "password";
    	
        // Set up the environment for creating the initial context
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
        		"com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapURL);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, bindDn);
        env.put(Context.SECURITY_CREDENTIALS, bindPwd);

        try {
                
            // Create the initial context
            DirContext ctx = new InitialDirContext(env);

            // Attributes to represent the user 
            Attributes attrs = new BasicAttributes(true); // case-ignore
            // objectClass
            Attribute attr = new BasicAttribute("objectClass");
            attr.add("top");
            attr.add("person");
            attr.add("organizationalPerson");
            attr.add("user");
            attrs.put(attr);

            // MUST attribute 
            attrs.put("unicodePwd", "\"Abcd1234\"".getBytes("UTF-16LE") );
            attrs.put("userAccountControl", "512");

            // MAY attribute 
            attrs.put("cn", "John Smith");
            attrs.put("givenName", "John");
            attrs.put("sn", "Smith");

            // Create the user account
            ctx.createSubcontext(
            		"cn=John Smith,CN=Users,DC=myCompany,DC=com", 
            		attrs);

            // close 
            ctx.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}



Note:
  • unicodePwd with the mysterious conversion is required;
  • userAccountControl=512 is required, otherwise it will be defaulted to 546;
  • SSL or StartTLS secure connection is required;
  • There may be some password policy you have to follow, like minimum length of password.


  •  Profile | Reply Points Earned: 0
    asakhi
    member
    offline   
     
    posts:
    joined: 04/08/2014
    from: Toronto, ON
      posted on: 04/08/2014 03:28:00 PM    Edit  |   Quote  |   Report 
    I know this is an old thread.
    I am doing something similar, but reseting user's password in AD. I am having trouble getting the unicoded password value. Can you please tell us how did you get the value of the password in unicode? i.e. the final value in this example (IgBBAGIAYwBkADEAMgAzADQAIgA=).

    I used the following, but it appears that it returns memory location and not actual value.

    quotedPassword.getBytes("UTF-16LE");

    Help please??





    Here is the whole chain of conversion:
    Abcd1234
    |
    |
    v
    "Abcd1234"
    |
    |
    v
    0x22 00 41 00 62 00 63 00 64 00 31 00 32 00 33 00 34 00 22 00
    |
    |
    v
    IgBBAGIAYwBkADEAMgAzADQAIgA=
     Profile | Reply Points Earned: 0
    asakhi
    member
    offline   
     
    posts:
    joined: 04/08/2014
    from: Toronto, ON
      posted on: 04/08/2014 03:28:30 PM    Edit  |   Quote  |   Report 
    I know this is an old thread.
    I am doing something similar, but reseting user's password in AD. I am having trouble getting the unicoded password value. Can you please tell us how did you get the value of the password in unicode? i.e. the final value in this example (IgBBAGIAYwBkADEAMgAzADQAIgA=).

    I used the following, but it appears that it returns memory location and not actual value.

    quotedPassword.getBytes("UTF-16LE");

    Help please??





    Here is the whole chain of conversion:
    Abcd1234
    |
    |
    v
    "Abcd1234"
    |
    |
    v
    0x22 00 41 00 62 00 63 00 64 00 31 00 32 00 33 00 34 00 22 00
    |
    |
    v
    IgBBAGIAYwBkADEAMgAzADQAIgA=
     Profile | Reply Points Earned: 0
    asakhi
    member
    offline   
     
    posts:
    joined: 04/08/2014
    from: Toronto, ON
      posted on: 04/08/2014 03:28:59 PM    Edit  |   Quote  |   Report 
    I know this is an old thread.
    I am doing something similar, but reseting user's password in AD. I am having trouble getting the unicoded password value. Can you please tell us how did you get the value of the password in unicode? i.e. the final value in this example (IgBBAGIAYwBkADEAMgAzADQAIgA=).

    I used the following, but it appears that it returns memory location and not actual value.

    quotedPassword.getBytes("UTF-16LE");

    Help please??





    Here is the whole chain of conversion:
    Abcd1234
    |
    |
    v
    "Abcd1234"
    |
    |
    v
    0x22 00 41 00 62 00 63 00 64 00 31 00 32 00 33 00 34 00 22 00
    |
    |
    v
    IgBBAGIAYwBkADEAMgAzADQAIgA=
     Profile | Reply Points Earned: 0
    asakhi
    member
    offline   
     
    posts:
    joined: 04/08/2014
    from: Toronto, ON
      posted on: 04/08/2014 03:55:14 PM    Edit  |   Quote  |   Report 
    duplicate
     Profile | Reply Points Earned: 0

     
    Powered by ForumEasy © 2003-2005, All Rights Reserved. | Privacy Policy | Terms of Use
     
    Get your own forum today. It's easy and free.