participate


Naming and Directory (JNDI) - JNDI, Active Directory and Group Memberships
<<   Back to Forum  |   Give us Feedback
This topic has 21 replies on 2 pages.    1 | 2 | Next »
adler_steven
Posts:669
Registered: 12/9/04
JNDI, Active Directory and Group Memberships   
Dec 21, 2004 11:08 AM

 
Aarrgghhh !

You don't add groups to users, you add users (or groups, or computers ..) to groups !

One of the attributes of a user object is "memberOf" and conversely one of the attributes of a group is "member"

memberOf is not a "real" attribute per se, meaning that it is read only, it contains "links" to groups and that it is constructed from all the groups that the user is a member of in that domain.

The reason why it has links to groups is to ensure referential integrity Eg. if you delete, rename or move a user, the group's membership is correctly maintained.

it is read-only, and if you attempt to modify it's values you wil get a LDAP Error of the form:
javax.naming.OperationNotSupportedException: [LDAP: error code 53 - 0000209A: SvcErr: DSID-031A0DD1, problem 5003 (WILL_NOT_PERFORM),data 0];

One other phenonema is that the user's membership only reflects the groups that are known on the domain controller that is being queried. In a multi-domain or multi-forest environment, a domain controller will only have knowledge of groups in it's own domain.

If the domain controller is a Global Catalog, it will have knowledge of all groups in the forest so it will reflect the list of groups in the forest that a user is a member of.

This is a slight simplification, with Windows Server 2003, branch office scenarios enable caching of group memberships without the need for a global catalog. (Me thinks a description of the Global Catalog is a future forum topic).

Therefore viewing a user's memberOf attribute may not reveal the full list of groups that a user is a member of. In addition, memberOf does not contain the user's Primary Group membership, nor does it reflect groups in other forests that the user may belong to.

The following code demonstrates viewing a user's memberOf attribute
/**
 * memberof.java
 * December 2004
 * Sample JNDI application to determine what groups a user belongs to
 * 
 */
 
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.ldap.*;
import javax.naming.directory.*;
 
public class memberof	{
	public static void main (String[] args)	{
	
		Hashtable env = new Hashtable();
		String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";
		String adminPassword = "XXXXXXX";
		String ldapURL = "ldap://mydc.antipodes.com:389";
		env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
		//set security credentials, note using simple cleartext authentication
		env.put(Context.SECURITY_AUTHENTICATION,"simple");
		env.put(Context.SECURITY_PRINCIPAL,adminName);
		env.put(Context.SECURITY_CREDENTIALS,adminPassword);
				
		//connect to my domain controller
		env.put(Context.PROVIDER_URL,ldapURL);
		
		try {
 
			//Create the initial directory context
			LdapContext ctx = new InitialLdapContext(env,null);
		
			//Create the search controls 		
			SearchControls searchCtls = new SearchControls();
		
			//Specify the search scope
			searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
			//specify the LDAP search filter
			String searchFilter = "(&(objectClass=user)(CN=Andrew Anderson))";
		
			//Specify the Base for the search
			String searchBase = "DC=antipodes,DC=com";
 
			//initialize counter to total the group members
			int totalResults = 0;
 
			//Specify the attributes to return
			String returnedAtts[]={"memberOf"};
			searchCtls.setReturningAttributes(returnedAtts);
		
			//Search for objects using the filter
			NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
 
			//Loop through the search results
			while (answer.hasMoreElements()) {
				SearchResult sr = (SearchResult)answer.next();
 
				System.out.println(">>>" + sr.getName());
 
				//Print out the groups
 
				Attributes attrs = sr.getAttributes();
				if (attrs != null) {
 
					try {
						for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) {
							Attribute attr = (Attribute)ae.next();
							System.out.println("Attribute: " + attr.getID());
							for (NamingEnumeration e = attr.getAll();e.hasMore();totalResults++) {
 
								System.out.println(" " +  totalResults + ". " +  e.next());
							}
 
						}
 
					}	 
					catch (NamingException e)	{
						System.err.println("Problem listing membership: " + e);
					}
				
				}
			}
 
			System.out.println("Total groups: " + totalResults);
			ctx.close();
 
		} 
		
		catch (NamingException e) {
			System.err.println("Problem searching directory: " + e);
           	}
	}
}
 


An alternative is to use another constructed attribute, tokenGroups. It will return the list of Security Identifiers (SID) that are in the user's security token.

There are a few things to be aware of when using tokenGroups:
1. The SID's are in binary format and would need to be formatted into the "S-1-5-aa-bb-cc-dd" format to be human readable
2. You would then need to do searches using the SID to find the distingusihed names of the groups that tehy map to.
3. The search base must be OBJECT_SCOPE
Eg.
//Specify the search scope
searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);
 
//specify the LDAP search filter
String searchFilter = "(objectClass=user)";
		
//Specify the Base for the search
String searchBase = "CN=Andrew Anderson,OU=Research,DC=antipodes,DC=com";
 

And finally another alternative is to examine the members of a group.

Even if a group contains members from other domains, it's membership is complete. It's referential integrity is maintained, for example if a user in another domain is renamed or moved, an Active Directory process called the Infrastructure Master ensure that the membership list is correct.

The following code demonstrates retrieving the list of members from a group.
/**
 * member.java
 * 6 July 2001
 * Sample JNDI application to retrieve group members
 * 
  */
 
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.ldap.*;
import javax.naming.directory.*;
 
public class member	{
	public static void main (String[] args)	{
	
		Hashtable env = new Hashtable();
		String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";
		String adminPassword = "XXXXXXX";
		String ldapURL = "ldap://mydc.antipodes.com:389";
		env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
		//set security credentials, note using simple cleartext authentication
		env.put(Context.SECURITY_AUTHENTICATION,"simple");
		env.put(Context.SECURITY_PRINCIPAL,adminName);
		env.put(Context.SECURITY_CREDENTIALS,adminPassword);
				
		//connect to my domain controller
		env.put(Context.PROVIDER_URL,ldapURL);
		
		try {
 
			//Create the initial directory context
			LdapContext ctx = new InitialLdapContext(env,null);
		
			//Create the search controls 		
			SearchControls searchCtls = new SearchControls();
		
			//Specify the search scope
			searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
			//specify the LDAP search filter
			String searchFilter = "(&(objectClass=group)(CN=All Research))";
		
			//Specify the Base for the search
			String searchBase = "DC=antipodes,DC=com";
 
			//initialize counter to total the group members
			int totalResults = 0;
 
			//Specify the attributes to return
			String returnedAtts[]={"member"};
			searchCtls.setReturningAttributes(returnedAtts);
		
			//Search for objects using the filter
			NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
 
			//Loop through the search results
			while (answer.hasMoreElements()) {
				SearchResult sr = (SearchResult)answer.next();
 
				System.out.println(">>>" + sr.getName());
 
				//Print out the members
 
				Attributes attrs = sr.getAttributes();
				if (attrs != null) {
 
					try {
						for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) {
							Attribute attr = (Attribute)ae.next();
							System.out.println("Attribute: " + attr.getID());
							for (NamingEnumeration e = attr.getAll();e.hasMore();totalResults++) {
 
								System.out.println(" " +  totalResults + ". " +  e.next());
							}
 
						}
 
					}	 
					catch (NamingException e)	{
						System.err.println("Problem listing members: " + e);
					}
				
				}
			}
 
			System.out.println("Total members: " + totalResults);
			ctx.close();
 
		} 
		
		catch (NamingException e) {
			System.err.println("Problem searching directory: " + e);
           	}
	}
}
 


One problems with large group memberships is that a feature of the Active Directory which is designed to ensure performance and limit Denial of Service attacks is that it limits the number of results that may be returned from a mult-valued attribute to 1000 values. Therefore the above code such would only retrieve 1000 members from a group even though it may contain more.

To retrieve all the values of a mult-valued attribute such as the member attribute you need to use the range retrieval control. A description and sample code is available in this forum at:

http://forum.java.sun.com/thread.jspa?threadID=578347&tstart=15

Unlike users, the members attribute is read & write, therefore if you want to add a user to a group, you do this by updating the members attribute.

If you want to add a new member, it is a add operation, if you want to delete a member it is a delete operation etc.

The following is some sample code to add a member to a group:
/**
 * addmember.java
 * 5 July 2001
 * Sample JNDI application that adds a user to a group in the Active Directory.
 * 
 */
 
import java.util.Hashtable;
import javax.naming.directory.*;
import javax.naming.*;
 
public class addmember
{
	public static void main (String[] args)
	{
	
		Hashtable env = new Hashtable();
		String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
		String adminPassword = "XXXXXX";
		String userName = "CN=Andrew Anderson,OU=Research,DC=antipodes,DC=com";
		String groupName = "CN=Telemetry,OU=Research,DC=antipodes,DC=com";
		
		env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
	
		//set security credentials, note using simple cleartext authentication
		env.put(Context.SECURITY_AUTHENTICATION,"simple");
		env.put(Context.SECURITY_PRINCIPAL,adminName);
		env.put(Context.SECURITY_CREDENTIALS,adminPassword);
				
		//connect to my domain controller
		env.put(Context.PROVIDER_URL, "ldap://mydc.antipodes.com:389");
				
		try {
 
			// Create the initial directory context
			InitialDirContext ctx = new InitialDirContext(env);
 
			//Create a LDAP add attribute for the member attribute
			ModificationItem mods[] = new ModificationItem[1];
			mods[0]= new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("member", userName)); 
 
			//update the group
			ctx.modifyAttributes(groupName,mods);
 
			ctx.close();
		
			System.out.println("Added " + userName + " to " + groupName);
		
		} 
 
		catch (NamingException e) {
			System.err.println("Problem adding member: " + e);
		}
	
	}
}
 


One other thing to note is that both the syntax of the member and memberOf attribute is distinguished name. This tends to make it easy to find and bind to other objects in the directory.
 
J.P.P.
Posts:21
Registered: 12/20/04
Re: JNDI, Active Directory and Group Memberships   
Dec 23, 2004 12:34 PM (reply 1 of 21)  (In reply to original post )

 
Steven,

Juan Pablo, Again. Are you loged with Administrator account (or similar) to change this properties?.

I think in SSL authentication, but is really necesary?, I hope no.

this is the exception:

C:\eclipse\workspace\Digest>java addmember
Problem adding member: javax.naming.NamingException: [LDAP: error code 1 - 00000
000: LdapErr: DSID-0C09096B, comment: In order to perform this operation a succe
ssful bind must be completed on the connection., data 0, vece ]; remaining name
'CN=Usuarios,CN=Builtin,DC=desarrollo,DC=tech,DC=net'

But, the user exists and the group too.

How to bind User to group and Group to user?

With this steps?
1.- SSL Authentication (Is really necesary?).
2.- Add user.
3.- Modify user with "userAccountControl" equals "66048".
4.- Modify User (groupName in memberOf).
5.- Modify Group (userName in member).

Sorry by my spell errors.

Thanks.


 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and Group Memberships   
Dec 24, 2004 5:53 AM (reply 2 of 21)  (In reply to #1 )

 
Refer to http://forum.java.sun.com/thread.jspa?threadID=582103

You have not successfully bound to an object, therefore you cannot update it.

Check your credentials.
 
J.P.P.
Posts:21
Registered: 12/20/04
Re: JNDI, Active Directory and Group Memberships   
Dec 27, 2004 5:14 AM (reply 3 of 21)  (In reply to #2 )

 
Thanks, I reading your post.

Thanks.
 
aarjoo
Posts:5
Registered: 1/5/05
Re: JNDI, Active Directory and Group Memberships   
Jan 5, 2005 10:07 PM (reply 4 of 21)  (In reply to original post )

 
1. How do you convert SID into S-1-5-aa-bb-cc-dd?
2. How would you resolve this value into user friendly format? e.g. domain\account

This is very important for me to know. Any help in this regard will be appreciated.



<There are a few things to be aware of when using tokenGroups:
1. The SID's are in binary format and would need to be formatted into the "S-1-5-aa-bb-cc-dd" format to be human readable
2. You would then need to do searches using the SID to find the distingusihed names of the groups that tehy map to.
3. The search base must be OBJECT_SCOPE
Eg.
 
srinivas.bodla
Posts:2
Registered: 1/11/05
Re: JNDI, Active Directory and Group Memberships   
Jan 11, 2005 1:57 AM (reply 5 of 21)  (In reply to original post )

 
Hi,

I tried the "memberof" code to retrieve the meberOf attribute for a user, but get error

[LDAP: error code 1 - 000020D6: SvcErr: DSID-03100684, problem 5012 (DIR_ERROR), data 0]

Any idea?? i am using jdk bundled with SJSAS, (new sun application server 7.1).

This works fine with jdk 1.3 and also in iplanet webserver too, also in earlier versions of iplanet application server....

Thanks
 
J.P.P.
Posts:21
Registered: 12/20/04
Re: JNDI, Active Directory and Group Memberships   
Jan 11, 2005 4:37 AM (reply 6 of 21)  (In reply to #5 )

 
Hi srinivas.bodla, my english is bad, but I can add users to group in Active Directory via LDAP with the following code:

    public void addUserToGroup(LdapContext ctx, String userDN, String groupDN)
        throws NamingException {
        ModificationItem[] mods = new ModificationItem[1];
        mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
                new BasicAttribute("member", userDN));
 
        ctx.modifyAttributes(groupDN, mods);
    }
 
    public void removeUserFromGroup(LdapContext ctx, String userDN,
        String groupDN) throws NamingException {
        ModificationItem[] mods = new ModificationItem[1];
        mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
                new BasicAttribute("member", userDN));
 
        ctx.modifyAttributes(groupDN, mods);
    }
 


Regads.
JPP
 
srinivas.bodla
Posts:2
Registered: 1/11/05
Re: JNDI, Active Directory and Group Memberships   
Jan 11, 2005 7:51 PM (reply 7 of 21)  (In reply to #6 )

 
Hi,

Thanks for the post,

I am using the "public class memberOf" code given in the thread... and trying to retrieve the "memberOf" attribute values which throws the exception previously mentioned in my earlier post.

using jdk1.3 and even 1.4 also works fine, but this exception is being thrown when i use it in application server (7.1 SJSAS).

Any idea??? thanks in advance...

Srinivas.
 
muzso
Posts:3
Registered: 2005.03.17.
Re: JNDI, Active Directory and Group Memberships   
Mar 17, 2005 3:22 AM (reply 8 of 21)  (In reply to #7 )

 
In the exception error message you get the Win32 error code that you can look up on MSDN for the reason.

Your exception was:
[LDAP: error code 1 - 000020D6: SvcErr: DSID-03100684, problem 5012 (DIR_ERROR), data 0]

The error code is "000020D6" (in hexadecimal format) which stands for 8406 ... which means: "ERROR_DS_MISSING_SUPREF 8406, No superior reference has been configured for the directory service. The directory service is therefore unable to issue referrals to objects outside this forest."

The Win32 errorcodes can be found here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp

I cannot interpret the meaning of the above description, but you might find some useful info using Google with the following keywords: 000020D6 "active directory". Note that "active directory" is surrounded by quotes so Google looks for the exact phrase and not just for the words. This search gave me a lot of promising hits ... I hope it helps. :-)
 
muzso
Posts:3
Registered: 2005.03.17.
Re: JNDI, Active Directory and Group Memberships   
Mar 17, 2005 3:30 AM (reply 9 of 21)  (In reply to #8 )

 
There was a question on whether adding a user to a group requires SSL auth. or not. The answer is: no, you do not have to start an SSL session to do that.

SSL (or TLS) encrypted connection is only required for (re)setting (or changing) the password of a user.
 
muzso
Posts:3
Registered: 2005.03.17.
Re: JNDI, Active Directory and Group Memberships   
Mar 17, 2005 3:45 AM (reply 10 of 21)  (In reply to #1 )

 
How to bind User to group and Group to user?
With this steps?
1.- SSL Authentication (Is really necesary?).
2.- Add user.
3.- Modify user with "userAccountControl" equals
"66048".
4.- Modify User (groupName in memberOf).
5.- Modify Group (userName in member).

Step #1 is only required for setting the password. So if you want to create an active user (active = can authenticate against the Active Directory with her/his username and password), then you must do it through an SSL (or TLS) encrypted session.

Step #2 is OK.

In Step #3 I do not know whether the value "66048" is OK (see Steven's other topic on this called "JNDI, Active Directory (Creating new users & demystifying userAccountContro") ... it might be fine.

You definitely must not do step #4 since (as Steven already wrote) the "memberOf" attribute is read-only (!!!), you cannot and must not set it.

Step #5 is OK.

Hope this helps.
:-)

To summarize the correct steps:
1. Authenticate/bind to Active Directory with an administrator's credentials (username+password) using SSL (or TLS) protocol (the latter is working only with Win2003 servers!).
2. Add new (disabled) user.
3. Set password for user.
3. Modify "userAccountControl" of user ( "activate" the user).
4. Modify Group (add user's DN as a "member" attribute).
 
mokojin
Posts:44
Registered: 12/4/04
Re: JNDI, Active Directory and Group Memberships   
Jul 4, 2005 3:49 AM (reply 11 of 21)  (In reply to #10 )

 
Hi i'm trying to use your sample code on windows 2000 server, but I get the error:

Problem searching directory: javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 525, v893

Is a credencials problem? because i'm sure that username\password stuff is correct, does your example work with windows 2000 server?
 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and Group Memberships   
Jul 4, 2005 3:44 PM (reply 12 of 21)  (In reply to #11 )

 
The error code (49) means a credentials error,either incorrect user name or a bad password.

It's ages since I used Win2K, but the same code should work for both Win2K& Win2K3.

(BTW,Microsoft no longer offers mainstream support for Win2K as it is now in its extended support phase)
 
jaya-jndi
Posts:7
Registered: 3/3/04
Re: JNDI, Active Directory and Group Memberships   
Jul 12, 2005 12:17 AM (reply 13 of 21)  (In reply to original post )

 
There are APIs available to determine group membership using the "member" attribute
and perform various other operations to create groups, add members etc.

Please take a look at the JNDI/LDAP Booster Pack that contains these APIs.

The download is available from: http://java.sun.com/jndi/products
 
Dave360
Posts:23
Registered: 5/11/06
Re: JNDI, Active Directory and Group Memberships   
May 11, 2006 7:08 PM (reply 14 of 21)  (In reply to #11 )

 
Maybe try this link:

Java Technology Forums - LDAP: error code 49
http://forum.java.sun.com/thread.jspa?messageID=4227692
 
This topic has 21 replies on 2 pages.    1 | 2 | Next »
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics
    Users Online : 27
  • Guests : 128

About Sun forums
  • Oracle Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Oracle Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums