I'm having an issue with adding a user to my LDAP server in Java.
Here's what my code looks like
import java.util.Hashtable;
import java.util.Properties;
import java.util.jar.Attributes;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class LdapProgram {
public static void main(String[] args) {
String dn = "";
String password = "";
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
properties.put(Context.PROVIDER_URL, "ldap://127.0.0.1");
properties.put(Context.SECURITY_AUTHENTICATION,"none");
properties.put(Context.SECURITY_PRINCIPAL,password);
properties.put(Context.SECURITY_CREDENTIALS,dn);
// TODO code application logic here
// entry's DN
String entryDN = "uid=test_user,ou=people,dc=test123,dc=com";
// entry's attributes
Attribute cn = new BasicAttribute("cn", "tester");
Attribute uid = new BasicAttribute("uid", "tester");
Attribute gecos = new BasicAttribute("gecos", "test");
Attribute oc = new BasicAttribute("objectClass");
oc.add("top");
oc.add("person");
oc.add("organizationalPerson");
oc.add("inetOrgPerson");
DirContext ctx = null;
try {
// get a handle to an Initial DirContext
ctx = new InitialDirContext(properties);
// build the entry
BasicAttributes entry = new BasicAttributes();
entry.put(cn);
entry.put(uid);
entry.put(gecos);
entry.put(oc);
// Add the entry
ctx.createSubcontext(entryDN, entry);
// System.out.println( "AddUser: added entry " + entryDN + ".");
} catch (NamingException e) {
System.err.println("AddUser: error adding entry.\n" + e);
}
}
}
Here is the error code I get: javax.naming.AuthenticationNotSupportedException: [LDAP: error code 8 - modifications require authentication]; remaining name 'uid=test_user,ou=people,dc=test123,dc=com'
I'm not understanding why it's saying it requires authentication when I'm already binded to the server with the admin user and password.
I am developing a project in java and JSP that needs to access an active directory for login and retrieving some values. I have done the login part(authentication) but i am not able to get help over the retrieval part.I am completely new to active directory concept, so please aid me accordingly.
I am giving the code of the java class that i have used for user authentication:
package classes;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class AD_Auth {
private static final String CONTEXT_FACTORY_CLASS ="com.sun.jndi.ldap.LdapCtxFactory";
private static final String domainName = "#xyz.IN";
private static final String providerUrl = "ldap://srdeladc02.xyz.in:123";
public static boolean authenticate(String username, String password) {
try {
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY_CLASS);
env.put(Context.PROVIDER_URL, providerUrl);
env.put(Context.SECURITY_PRINCIPAL, username + domainName);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.SECURITY_AUTHENTICATION, "strong");
DirContext ctx = new InitialDirContext(env);
ctx.close();
return true;
} catch (NamingException e) {
System.out.println("Dear User, The username or password you have entered is in correct, please try again.");
}
return false;
}
public static void main(String[] args) {
// if someone emailid is myemail#icar.gov.in then username will be myemail
//System.out.println(AD_Auth.authenticate("username", "password"));
}
}
I want to find all the groups a user is part of, including nested groups.
Like if user is part of group A1 and group A1 is part of A, then I want to get A as well.
Following is code , I have tried variuos filterstrings... but nothing is given expected output.
String samAccountName = "group";
String searchFilter = "(&(objectclass=user)(memberof: 1.2.840.113556.1.4.1941:="+samAccountName+"))";
//String searchFilter = "(&(objectCategory=person)(memberOf=CN="+samAccountName+"))";
//String searchFilter = "(&(objectcategory=user)(memberof=CN="+samAccountName+",OU=Users,DC=new,DC=com))";
String searchBase = "DC=new,DC=com";
NamingEnumeration answer = ctx.search(searchBase, searchFilter, ontrols);
List rolesList = new ArrayList();
while(answer.hasMoreElements()){
SearchResult sr = (SearchResult)answer.next();
...
Any help is appreciated.
I expect you'll have to recursively search the memberOf attribute list for a user. e.g. if a user has the following ldif-style result from an ldapsearch call:
cn: user1
memberOf: CN=group1,DC=foo,DC=example,DC=com
memberOf: CN=group2,DC=foo,DC=example,DC=com
..then you'll want to recursively look up group1 and group2 with additional ldap searches, and so on for groups which those groups are membersOf.
I'm doing something similar right now, but in perl and to get flat lists of all members of all groups from Active Directory. AD uses objectClass: group whereas OpenLDAP tends to use objectClass: groupOfUniqueNames or perhaps objectClass: posixGroup, depending on the use (posix groups for unix-y clients such as Linux boxes, groupOfUniqueNames groups for more general information. It depends entirely on the clients using the information from the directory).
Edit: In AD there is also supposed to be an attribute called tokenGroups which contains the SIDs of security groups for users, but this didn't work for me. I'm guessing it's optional and not enabled on my site's AD server.
Below code works finding the list of groups that the user belongs to.Sun LDAP implementation is being used
package pack;
import static javax.naming.directory.SearchControls.SUBTREE_SCOPE;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import com.sun.jndi.ldap.LdapCtxFactory;
class App4
{
public static void main(String[] args)
{
String username = "userName";
String password = "password";
String serverName = "server";
String domainName = "comp.BIZ";
System.out.println("Authenticating " + username + "#" + domainName
+ " through " + serverName + "." + domainName);
// bind by using the specified username/password
Hashtable<String,String> props = new Hashtable<String,String>();
String principalName = username + "#" + domainName;
props.put(Context.SECURITY_PRINCIPAL, principalName);
props.put(Context.SECURITY_CREDENTIALS, password);
DirContext context;
try {
context = LdapCtxFactory.getLdapCtxInstance("ldap://" + serverName
+ "." + domainName + '/', props);
System.out.println("Authentication succeeded!");
// locate this user's record
SearchControls controls = new SearchControls();
controls.setSearchScope(SUBTREE_SCOPE);
NamingEnumeration<SearchResult> renum = context.search(
toDC(domainName), "(& (userPrincipalName=" + principalName
+ ")(objectClass=user))", controls);
if (!renum.hasMore())
{
System.out.println("Cannot locate user information for "
+ username);
System.exit(1);
}
SearchResult result = renum.next();
List<GrantedAuthority> groups = new ArrayList<GrantedAuthority>();
Attribute memberOf = result.getAttributes().get("memberOf");
if (memberOf != null)
{// null if this user belongs to no group at
// all
for (int i = 0; i < memberOf.size(); i++)
{
Attributes atts = context.getAttributes(memberOf.get(i)
.toString(), new String[] { "CN" });
Attribute att = atts.get("CN");
groups.add(new GrantedAuthorityImpl(att.get().toString()));
}
}
context.close();
System.out.println();
System.out.println("User belongs to: ");
Iterator<GrantedAuthority> ig = groups.iterator();
while (ig.hasNext())
{
System.out.println(" " + ig.next().toString());
}
} catch (AuthenticationException a)
{
System.out.println("Authentication failed: " + a);
System.exit(1);
} catch (NamingException e)
{
System.out
.println("Failed to bind to LDAP / get account information: "
+ e);
System.exit(1);
}
}
private static String toDC(String domainName)
{
StringBuilder buf = new StringBuilder();
for (String token : domainName.split("\\."))
{
if (token.length() == 0)
continue; // defensive check
if (buf.length() > 0)
buf.append(",");
buf.append("DC=").append(token);
}
return buf.toString();
}
}
String searchFilter ="(&(objectClass=person)(samaccountname="+userName+"))"
I modidfied the searchFilter and it works.
In LDAP we can query if a User belongs to a given group once you have established a connection you can query using either member or memberOf attribute.
Query for memberOf Attribute :
filter used : (&(Group Member Attribute=Group DN)(objectClass=Group Object class))
Ex : (&(memberOf=CN=group,ou=qa_ou,dc=ppma,dc=org)(objectClass=group))
Using member Attribute :
filter used : (&(Group Member Attribute=User DN)(objectClass=Group Object class))
Ex : (&(member=CN=user,ou=qa_ou,dc=ppma,dc=org)(objectClass=group))
But You'll have to search recursively using the member or memberOf attribute list for a user. e.g. if a user has the following group hierarchy :
cn: user1
memberOf: CN=group1,DC=foo,DC=example,DC=com
memberOf: CN=group2,DC=foo,DC=example,DC=com
then you'll want to recursively lookup group1 and group2 with additional LDAP searches, and so on for groups which those groups are members of.
Below is the sample code to query all the nested groups a User belongs to :
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class MemberDemo {
private static final String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
private static final String connectionURL = "ldap://10.224.243.133:389";
private static final String connectionName = "CN=administrator,CN=users,DC=ppma,DC=org";
private static final String connectionPassword = "Conleyqa12345";
public static int nestLevel = 3;
public static int level = 1;
// Optional
private static final String authentication = null;
private static final String protocol = null;
private static String userBase = "OU=qa_OU,DC=ppma,DC=org";
public static void main(String[] args) throws NamingException {
long start = System.currentTimeMillis();
Hashtable<String, String> env = new Hashtable<String, String>();
// Configure our directory context environment.
env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
env.put(Context.PROVIDER_URL, connectionURL);
env.put(Context.SECURITY_PRINCIPAL, connectionName);
env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
if (authentication != null)
env.put(Context.SECURITY_AUTHENTICATION, authentication);
if (protocol != null)
env.put(Context.SECURITY_PROTOCOL, protocol);
InitialDirContext context = new InitialDirContext(env);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
Set<String> traversedGroups = new HashSet<String>();
Set<String> relatedGroups = new HashSet<String>();
List<String> tempParentColl = new CopyOnWriteArrayList<String>();
List<String> tempGroups = new ArrayList<String>();
String loginUser = "CN=qa20Nest,OU=qa_OU,DC=ppma,DC=org";
String filter = "(&(member=" + loginUser + ")(objectClass=group))";
tempGroups = findNestedGroups(tempGroups, context, filter, loginUser, constraints,
tempParentColl, traversedGroups, getUserName(loginUser));
relatedGroups.addAll(tempGroups);
System.out.println("Parent Groups :");
for (String group : relatedGroups) {
System.out.println(group);
}
long end = System.currentTimeMillis();
long elapsedTime = end - start;
System.out.println("Total time taken in sec : " + elapsedTime / 1000);
}
#SuppressWarnings("rawtypes")
public static List<String> findNestedGroups(List<String> tempGrpRelations, InitialDirContext context, String filter,
String groupName, SearchControls constraints, List<String> tempParentColl, Set<String> traversedGrp,
String groupIdentifier) {
NamingEnumeration results;
try {
traversedGrp.add(groupName);
results = context.search(userBase, filter, constraints);
// Fail if no entries found
if (results == null || !results.hasMore()) {
System.out.println("No result found for :" + groupName);
if (tempParentColl.isEmpty()) {
return tempGrpRelations;
} else {
tempParentColl.remove(groupName);
}
}
while (results.hasMore()) {
SearchResult result = (SearchResult) results.next();
System.out.println("DN - " + result.getNameInNamespace());
tempParentColl.add(result.getNameInNamespace());
tempGrpRelations.add(result.getNameInNamespace());
}
Iterator<String> itr = tempParentColl.iterator();
while (itr.hasNext()) {
String groupDn = itr.next();
String nfilter = "(&(member=" + groupDn + ")(objectClass=group))";
tempParentColl.remove(groupDn);
if (!traversedGrp.contains(groupDn)) {
findNestedGroups(tempGrpRelations, context, nfilter, groupDn, constraints, tempParentColl,
traversedGrp, getUserName(groupDn));
}
}
} catch (NamingException e) {
e.printStackTrace();
}
return tempGrpRelations;
}
public static String getUserName(String cnName) {
String name = cnName.substring(cnName.indexOf("CN=")).split(",")[0].split("=")[1];
return name;
}
}
I am facing some difficulties while listing all the users in the Active Directory. I reached to the group, but unfortunately, I could not retrieve all the users. I am looking for the user Full Names, usernames, directorate. My code is:
package client;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.*;
import java.util.Enumeration;
import javax.naming.NamingEnumeration;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.directory.*;
public class AD1 {
public AD1() {
super();
}
public static String usersContainer = "cn=XX,ou=XX,ou=Groups,dc=XX,dc=XX,dc=XXX";
public static void main(String[] args) {
try {
LdapContext ctx = null;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "Simple");
//it can be <domain\\userid> something that you use for windows login
//it can also be
env.put(Context.SECURITY_PRINCIPAL, "username");
// env.put(Context.SECURITY_CREDENTIALS, "password");
try {
env.put(Context.SECURITY_CREDENTIALS, "password".getBytes("UTF8"));
}
catch (java.io.UnsupportedEncodingException e) { /* ignore */ }
//in following property we specify ldap protocol and connection url.
//generally the port is 389
env.put(Context.PROVIDER_URL, "ldap://IP:PORT");
ctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
DirContext ctx1 = new InitialDirContext(env);
SearchControls ctls = new SearchControls();
String[] attrIDs = { "distinguishedName","cn","name","uid",
"sn",
"givenname",
"memberOf",
"samaccountname",
"userPrincipalName" };
ctls.setReturningAttributes(attrIDs);
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
NamingEnumeration answer = ctx1.search( usersContainer, "(objectClass=user)", ctls );
System.out.print("Out while loop");
while(answer.hasMore()) {
System.out.print("while loop11");
SearchResult rslt = (SearchResult)answer.next();
Attributes attrs = rslt.getAttributes();
System.out.println(attrs.get("uid"));
ctx1.close();
}
} catch(NamingException nex) {
System.out.println("Active Directory Connection: FAILED");
nex.printStackTrace();
}
}
}
Can anyone help.
As it's active directory and not real ldap your talking about, can you help us with more details about ldap/active directory configuration ?
It's kind hard to help you with informations you give
Edit 1:
your problem is here no ?
while(answer.hasMore()) {
System.out.print("while loop11");
SearchResult rslt = (SearchResult)answer.next();
Attributes attrs = rslt.getAttributes();
//System.out.println(attrs.get("uid"));
System.out.println(attrs.get("cn"));
ctx1.close();
}
I'm trying to get in contact with an AD. I have tried to use this code to connect, but it doesn't seem to connect at all. I'm sorry for not being able to be more specific than this, but that's simply all I know. Nothing happens. I've removed what I viewed as the non-essential part of this class, where the result is dealt with, because at this point there simply isn't any result at all to deal with. I don't get any errors in Netbeans, but.. Nothing happens when I try to connect.
What's going on? What am I doing wrong?
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
import java.util.Hashtable;
import java.util.*;
public class AD {
public static void main(String[] args) {
String userName = "xx"; //AD username
String password = "xx"; //AD password
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://192.168.1.102:389/dc=agileworks,dc=com"); //AD Server URL - dc lader til at være "domain content"
//env.put(Context.SECURITY_AUTHENTICATION, "simple"); //virker ikke nødvendig
//env.put(Context.SECURITY_PRINCIPAL, new String("agileworks" + "\\" + userName));
env.put(Context.SECURITY_PRINCIPAL, "agileworks" + "\\" + userName); //måske er tabelnavn\\ ikke nødvendig?
env.put(Context.SECURITY_CREDENTIALS, password); //password
DirContext ctx = null; //initialisering
NamingEnumeration results = null; //initialisering
}
}
You need to create a context not just the variable. You basically just put some data into the hash table and that's it.
I don't specifically know about LDAP but with JNDI you'd need to call new InitialContext() in order to actually create a context. After that you might have to call a method on that context in order to make something happen.
So in case of an LDAP context you'd need something like this:
DirContext ctx = new InitialLdapContext(env, new Control[0]);
NamingEnumeration results = ctx.search(....);