I'm trying to get the elements out of a namingenumeration.
The namingenumeration itself is not null, but hasNext() gives me false.
What am I doing wrong?
public static void main(String[] args) {
try {
DirContext context = new InitialDirContext(
Environment.getEnvironment());
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = { "cn", "givenname", "sn", "mail" };
controls.setReturningAttributes(attrIDs);
NamingEnumeration enumResult = context.search(
"DC=PORTAL,DC=COMPANY,DC=BE", "(CN=*)",
controls);
System.out.println(enumResult.hasMore());
context.close();
} catch (AuthenticationException e) {
System.out.println("Invalid credentials");
} catch (NamingException e) {
System.out.println("Lookup failed: " + e);
}
}
Structure of AD (on Localhost using AD-LDS)
DC=PORTAL,DC=COMPANY,DC=BE
->OU=Accounts
==>CN=John Doe
==>CN=Jane Doe
->CN=LostAndFound
->CN=NTDS Quotas
->CN=Roles
->OU=System Accounts
==>CN=PortalAdmin
Narrowing my searchbase to "OU=ACCOUNTS,DC=PORTAL,DC=COMPANY,DC=BE" gives the following error
Lookup failed: javax.naming.NameNotFoundException: [LDAP: error code
32 - 000020 8D: NameErr: DSID-031522C9, problem 2001 (NO_OBJECT), data
0, best match of: 'DC=PORTAL,DC=COMPANY,DC=BE' ]; remaining name 'OU=ACCOUNTS,DC=PORTAL,DC=COMPANY,DC=BE'
solution:
try {
DirContext ctx = new InitialDirContext(Environment.getEnvironment());
// Get all the attributes of named object
Attributes attrs = ctx
.getAttributes("cn=John Doe,ou=Accounts,DC=PORTAL,DC=COMPANY,DC=BE");
if (attrs == null) {
System.out.println("No attributes");
} else {
/* Print each attribute */
try {
for (NamingEnumeration ae = attrs.getAll(); ae.hasMore();) {
Attribute attr = (Attribute) ae.next();
System.out.println("attribute: " + attr.getID());
/* print each value */
for (NamingEnumeration e = attr.getAll(); e.hasMore(); System.out
.println("value: " + e.next()))
;
}
} catch (NamingException e) {
e.printStackTrace();
}
}
ctx.close();
} catch (AuthenticationException e) {
System.out.println("Invalid credentials");
} catch (NamingException e) {
System.out.println("Lookup failed: " + e);
}
Start with doing some basic sanity checks. For instance, that the data returned by Environment.getEnvironment() is correct (url, port, user, password) and allows a connection to the directory server. Also check that there are no network problems and that you can, in fact, access the server.
Try limiting the search base a bit more, for instance: "OU=Accounts,DC=PORTAL,DC=COMPANY,DC=BE" and see if some results are returned. Also check if the objects in the expected results actually have the attributes "cn", "givenname", "sn", "mail".
Other than that, there are no obvious mistakes in the code shown in the question, it should work fine.
Related
Is their any way to fetch duplicates from AD using java ? I see we can do it in power shell by grouping all usernames and then checking count >1.
https://gallery.technet.microsoft.com/scriptcenter/Find-Active-Directory-c8789b42
Please help :).
you should get all objects of a special type(such as user, group , ...) and their attributes. then check duplicate attributes of all objects. for do this, you can insert each attributes in a hasp map as a key, and insert all value of attribute per each object and check is duplicated or not ?
use JAVA JNDI to access AD server as follow:
/**
* retrieve all attributes of a named object.
*
*/
class GetAllAttrs {
static void printAttrs(Attributes attrs) {
if (attrs == null) {
System.out.println("No attributes");
} else {
/* Print each attribute */
try {
for (NamingEnumeration ae = attrs.getAll(); ae.hasMore();) {
Attribute attr = (Attribute) ae.next();
System.out.println("attribute: " + attr.getID());
/* print each value */
for (NamingEnumeration e = attr.getAll(); e.hasMore(); System.out
.println("value: " + e.next()))
;
}
} catch (NamingException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// Set up the environment for creating the initial context
Hashtable<String, Object> env = new Hashtable<String, Object>(11);
env
.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
try {
// Create the initial context
DirContext ctx = new InitialDirContext(env);
// Get all the attributes of named object
Attributes answer = ctx.getAttributes("cn=Ted Geisel, ou=People");
// Print the answer
printAttrs(answer);
// Close the context when we're done
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
also you can use search filter to limit your outputs:
public class LdapSearch {
public static void main(String[] args) throws Exception {
Hashtable env = new Hashtable();
String sp = "com.sun.jndi.ldap.LdapCtxFactory";
env.put(Context.INITIAL_CONTEXT_FACTORY, sp);
String ldapUrl = "ldap://localhost:389/dc=yourName, dc=com";
env.put(Context.PROVIDER_URL, ldapUrl);
DirContext dctx = new InitialDirContext(env);
String base = "ou=People";
SearchControls sc = new SearchControls();
String[] attributeFilter = { "cn", "mail" };
sc.setReturningAttributes(attributeFilter);
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(sn=W*)(l=Criteria*))";
NamingEnumeration results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
Attribute attr = attrs.get("cn");
System.out.print(attr.get() + ": ");
attr = attrs.get("mail");
System.out.println(attr.get());
}
dctx.close();
}
}
When i am trying to search password of user from ldap server this
below error displayed
In this code its doesn't return user Password in String. It throws
java.lang.ClassCastException: [B cannot be cast to java.lang.String
Code:
public class selectEntry {
DirContext ldapContext = null;
public selectEntry() {
try {
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, url);
environment.put(Context.SECURITY_AUTHENTICATION, conntype);
environment.put(Context.SECURITY_PRINCIPAL, AdminDn);
environment.put(Context.SECURITY_CREDENTIALS, password);
ldapContext = new InitialDirContext(environment);
System.out.println("Bind successful");
} catch (Exception exception) {
exception.printStackTrace();
}
}
public void getEntry() {
try {
SearchControls searcCon = new SearchControls();
searcCon.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results
= ldapContext.search("uid=aruhat.aruhat,ou=openzki,dc=aruhat,dc=co,dc=in", "(uid=aruhat.aruhat)", searcCon);
if (results != null) {
while (results.hasMore()) {
SearchResult res = (SearchResult) results.next();
Attributes atbs = res.getAttributes();
Attribute atb = atbs.get("userPassword");
String name = (String) atb.get();
System.out.println("Name is :=> " + name);
}
} else {
System.out.println("fail");
}
} catch (Exception e) {
System.out.println("Exception Type:=> "+e);
System.out.println("Exception Message:=> "+e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
new selectEntry().getEntry();
}
}
LDAP passwords are stored as hashes, not strings. The attribute value is returned as a byte[], as the exception says.
However you don't have any good reason for obtaining the hashed password attribute in the first place. It won't do you any good. Review your requirement. You should be binding as the user using the old password to test whether it's valid, not trying to read the password, which you won't get.
Retreiving binary attributes requires the ;binary suffix, e.g., userCertificate;binary. Then you have the Attribute object. Invoke
byte[] bytes = (byte[]) attr.get()
and you are done. Don't work with toString() or (String) cast.
I am trying to implement Active Directory authentication in Java which will be ran from a Linux machine. Our AD set-up will consist of multiple servers that share trust relationships with one another so for our test environment we have two domain controllers:
test1.ad1.foo.com who trusts test2.ad2.bar.com.
Using the code below I can successfully authenticate a user from test1 but not on test2:
public class ADDetailsProvider implements ResultSetProvider {
private String domain;
private String user;
private String password;
public ADDetailsProvider(String user, String password) {
//extract domain name
if (user.contains("\\")) {
this.user = user.substring((user.lastIndexOf("\\") + 1), user.length());
this.domain = user.substring(0, user.lastIndexOf("\\"));
} else {
this.user = user;
this.domain = "";
}
this.password = password;
}
/* Test from the command line */
public static void main (String[] argv) throws SQLException {
ResultSetProvider res = processADLogin(argv[0], argv[1]);
ResultSet results = null;
res.assignRowValues(results, 0);
System.out.println(argv[0] + " " + argv[1]);
}
public boolean assignRowValues(ResultSet results, int currentRow)
throws SQLException
{
// Only want a single row
if (currentRow >= 1) return false;
try {
ADAuthenticator adAuth = new ADAuthenticator();
LdapContext ldapCtx = adAuth.authenticate(this.domain, this.user, this.password);
NamingEnumeration userDetails = adAuth.getUserDetails(ldapCtx, this.user);
// Fill the result set (throws SQLException).
while (userDetails.hasMoreElements()) {
Attribute attr = (Attribute)userDetails.next();
results.updateString(attr.getID(), attr.get().toString());
}
results.updateInt("authenticated", 1);
return true;
} catch (FileNotFoundException fnf) {
Logger.getAnonymousLogger().log(Level.WARNING,
"Caught File Not Found Exception trying to read cris_authentication.properties");
results.updateInt("authenticated", 0);
return false;
} catch (IOException ioe) {
Logger.getAnonymousLogger().log(Level.WARNING,
"Caught IO Excpetion processing login");
results.updateInt("authenticated", 0);
return false;
} catch (AuthenticationException aex) {
Logger.getAnonymousLogger().log(Level.WARNING,
"Caught Authentication Exception attempting to bind to LDAP for [{0}]",
this.user);
results.updateInt("authenticated", 0);
return true;
} catch (NamingException ne) {
Logger.getAnonymousLogger().log(Level.WARNING,
"Caught Naming Exception performing user search or LDAP bind for [{0}]",
this.user);
results.updateInt("authenticated", 0);
return true;
}
}
public void close() {
// nothing needed here
}
/**
* This method is called via a Postgres function binding to access the
* functionality provided by this class.
*/
public static ResultSetProvider processADLogin(String user, String password) {
return new ADDetailsProvider(user, password);
}
}
public class ADAuthenticator {
public ADAuthenticator()
throws FileNotFoundException, IOException {
Properties props = new Properties();
InputStream inStream = this.getClass().getClassLoader().
getResourceAsStream("com/bar/foo/ad/authentication.properties");
props.load(inStream);
this.domain = props.getProperty("ldap.domain");
inStream.close();
}
public LdapContext authenticate(String domain, String user, String pass)
throws AuthenticationException, NamingException, IOException {
Hashtable env = new Hashtable();
this.domain = domain;
env.put(Context.INITIAL_CONTEXT_FACTORY, com.sun.jndi.ldap.LdapCtxFactory);
env.put(Context.PROVIDER_URL, "ldap://" + test1.ad1.foo.com + ":" + 3268);
env.put(Context.SECURITY_AUTHENTICATION, simple);
env.put(Context.REFERRAL, follow);
env.put(Context.SECURITY_PRINCIPAL, (domain + "\\" + user));
env.put(Context.SECURITY_CREDENTIALS, pass);
// Bind using specified username and password
LdapContext ldapCtx = new InitialLdapContext(env, null);
return ldapCtx;
}
public NamingEnumeration getUserDetails(LdapContext ldapCtx, String user)
throws NamingException {
// List of attributes to return from LDAP query
String returnAttributes[] = {"ou", "sAMAccountName", "givenName", "sn", "memberOf"};
//Create the search controls
SearchControls searchCtls = new SearchControls();
searchCtls.setReturningAttributes(returnAttributes);
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Specify the user to search against
String searchFilter = "(&(objectClass=*)(sAMAccountName=" + user + "))";
//Perform the search
NamingEnumeration answer = ldapCtx.search("dc=dev4,dc=dbt,dc=ukhealth,dc=local", searchFilter, searchCtls);
// Only care about the first tuple
Attributes userAttributes = ((SearchResult)answer.next()).getAttributes();
if (userAttributes.size() <= 0) throw new NamingException();
return (NamingEnumeration) userAttributes.getAll();
}
From what I understand of the trust relationship, if trust1 receives a login attempt for a user in trust2, then it should forward the login attempt on to it and it works this out from the user's domain name.
Is this correct or am I missing something or is this not possible using the method above?
--EDIT--
The stack trace from the LDAP bind is
{java.naming.provider.url=ldap://test1.ad1.foo.com:3268, java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.authentication=simple, java.naming.referral=follow}
30-Oct-2012 13:16:02
ADDetailsProvider assignRowValues
WARNING: Caught Authentication Exception attempting to bind to LDAP for [trusttest]
Auth error is [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db0]
As far as I know, you should set Context.REFERRAL to true.
Is this what you meant in your code?
In addition, when I switched to GSSAPI/Kerberos,
I defined trust relationships between the kerberos realms and it worked for me.
I'm trying to enable a user in the Active Directory with LDAP and Java (1.4).
However I keep getting the following error:
java.lang.NullPointerException at
com.sun.jndi.ldap.LdapCtx.c_modifyAttributes(LdapCtx.java:1432) at
com.sun.jndi.toolkit.ctx.ComponentDirContext.p_modifyAttributes(ComponentDir
Context.java:255) at
com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.modifyAttributes(Partial
CompositeDirContext.java:172) at
com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.modifyAttributes(Partial
CompositeDirContext.java:161) at
javax.naming.directory.InitialDirContext.modifyAttributes(InitialDirContext.
java:146) at be.ideal.LDAP.newuser.main(newuser.java:61) Exception in
thread "main"
I already confirmed that my user has a password, I just can't seem to change his status to active
My code:
public static void main(String[] args) {
String userName = "cn=Albert Einstein,ou=Accounts,DC=PORTAL,DC=COMPANY,DC=BE";
String groupName = "cn=Administrators,cn=Roles,DC=PORTAL,DC=COMPANY,DC=BE";
boolean isDisabled = false;
try {
System.out.println("Creating initial directory context...");
LdapContext ctx = new InitialLdapContext(X_Ldap.getEnvironment(),
null);
Attributes attrs = new BasicAttributes(true);
attrs.put("objectClass", "user");
attrs.put("cn", "Albert Einstein");
String newQuotedPassword = "\"Pass123\"";
byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
attrs.put(new BasicAttribute("unicodePwd", newUnicodePassword));
attrs.put(new BasicAttribute("msDS-UserAccountDisabled", "FALSE"));
System.out.println("Creating context...");
Context result = ctx.createSubcontext(userName, attrs);
System.out.println("Created account for: " + userName);
System.out.println("Creating context...");
Context result = ctx.createSubcontext(userName, attrs);
System.out.println("Created account for: " + userName);
try {
ModificationItem member[] = new ModificationItem[1];
member[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
new BasicAttribute("member", userName));
ctx.modifyAttributes(groupName, member);
System.out.println("Added user to group: " + groupName);
} catch (NamingException e) {
System.err.println("Problem adding user to group: " + e);
}
ctx.close();
System.out.println("Successfully created User: " + userName);
} catch (NamingException e) {
System.err.println("Problem creating object: " + e);
}
catch (IOException e) {
System.err.println("Problem creating object: " + e);
}
}
PS: I am using AD LDS for my active directory
Found it:
Needed to use DirContext.ADD_ATTRIBUTE instead of DirContext.REPLACE_ATTRIBUTE
I am having some trouble with the HashMaps in my program. I have several declared at the top class like so:
public HashMap<String, Object> hmClass = new HashMap<String ,Object>();
public HashMap<String, Object> hmIns = new HashMap<String, Object>();
public HashMap<String, Object> hmCon = new HashMap<String, Object>();
public HashMap<String, Object> hmParam = new HashMap<String, Object>();
public HashMap<String, Object> hmResult = new HashMap<String, Object>();
In a separate method, I am putting values into them like this:
public String newInstanceCreate(Class c3, String classInstance)//void ??
{
Class c = c3;
String cI = classInstance;
Object instance = null;
Object con = null;
String instanceName = null;
try{
instanceName = JOptionPane.showInputDialog(null, "Under what name would you like to store this Instance?",
"Create an Instance of a Class", JOptionPane.QUESTION_MESSAGE);
}catch(NullPointerException e)
{
newInstanceCreate(c,cI);
}
hmClass.put(instanceName, c); //add the name of the instance as key and class as value to the hashmap
System.out.println(hmClass);
con = JOptionPane.showInputDialog(null,"Choose Constructor for " + c, "Create an Instance of a Class", 3, null, getConstructors(c), JOptionPane.QUESTION_MESSAGE);
System.out.println("worked + " + con);
hmCon.put(instanceName, con); //add the name of the instance as key and constructor as value to the hashmap
System.out.println(hmCon);
try {
instance = c3.getDeclaredConstructor().newInstance(); //create the instance --KEY
hmIns.put(instanceName, instance);
System.out.println("23" + instance);
hmParam.put(instanceName, getParams(c3, con)); //ask the user for the parameters (doubles) that they want in the instance constructor
// add the name of the instance as key and parameters(array) as value
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e){
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.print("hmClass: \n" + hmClass + "hmIns: \n" + hmIns + "hmCon: \n" + hmCon + "hmParam: \n" + hmParam);
return classInstance;
}
But when I try access them from a another method, it seems that they have all been reset.
public void option4()
{
System.out.println("hmIns: " + hmIns);
String stringInstance = JOptionPane.showInputDialog(null, "Which Instance would you like to stringify? " ,
"Stringify an Instance of a Class", JOptionPane.QUESTION_MESSAGE);
//get all the required info for making the instance
/*
* needed: name of stored instance
* name of correct and stored constructor
* name of parameters that were created by user (doubles?)
*/
System.out.println(stringInstance);
if(hmIns.isEmpty())
System.out.println("EMPTY");
Object ins = hmIns.get(stringInstance);
System.out.println("ins before: " + ins);
Object cons = hmCon.get(stringInstance);
System.out.println("cons before: " + cons);
Object par = hmParam.get(stringInstance);
System.out.println("par before: " + par);
//construct an instance and run toString() here
try {
ins = ((Constructor)cons).newInstance(par);
System.out.println(" ins: " + ins);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//result from toString
/*
* stored: name of result
* result itself (stored as string for now)
*/
JOptionPane.showMessageDialog(null, "result here??--how to get result to double??", "Stringified Instance of: ", 0);
mainWindow();
}
In the last method listed, I tested to see if the HashMap had null values instead of actually being empty, but it returns as having no values at all. Why is the HashMap resetting after I exit the first method?
Thank you so much for any insight.
Fran
It doesn't reset. I suggest you look at your code in a debugger and check if they are looking at the same object/map. I suspect you have two objects which contain maps.