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.
Related
I'm looking for a way to change the OU of a user in my Oracle LDAP, using Java. So far I found only the DirContext.rename method, but that results in a corrupted LDAP entry. Below is the code I tried.
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.REFERRAL, "follow");
environment.put(Context.PROVIDER_URL, "ldap://localhost:10389");
environment.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
environment.put(Context.SECURITY_CREDENTIALS, "admin");
DirContext ctx = null;
try {
ctx = new InitialDirContext(environment);
String oldCn = "uid=wso21,ou=wso2,ou=Users,dc=WSO2,dc=ORG";
String newCn = "uid=wso21,ou=vodafone,ou=Users,dc=WSO2,dc=ORG";
ctx.rename(oldCn, newCn);
} catch (NamingException e) {
e.printStackTrace();
} finally {
try {
ctx.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
After this is executed, the moved entry is there but no attributes are present.
TIA!
Please modify try Block:
try {
ctx = new InitialDirContext(environment);
String oldDn = "uid=wso21,ou=wso2,ou=Users,dc=WSO2,dc=ORG";
String newDn = "uid=wso21,ou=vodafone,ou=Users,dc=WSO2,dc=ORG";
String newCn="newCN";
String newSn="newSN";
Attributes attrs = ctx.getAttributes(oldDn);
ctx.rename(oldDn,newDn);
attrs.remove("cn");
attrs.remove("sn");
//if needed remove more attributes
attrs.put("cn",newCn);
attrs.put("sn",newSn);
//if needed add more attributes
ctx.modifyAttributes(newDn, DirContext.ADD_ATTRIBUTE, attrs);
}
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();
}
}
I want to query my ldap to give me all users where sn contains a specific value (maier). However I always get a single result.
public LdapContext getLdapContext(){
LdapContext ctx = null;
try{
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://ldap.url:389");
ctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
}catch(NamingException nex){
System.out.println("LDAP Connection: FAILED");
nex.printStackTrace();
}
return ctx;
}
private User getUserBasicAttributes(String username, LdapContext ctx) {
User user=null;
try {
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = { "distinguishedName",
"sn",
"givenname",
"mail",
"telephonenumber"};
constraints.setReturningAttributes(attrIDs);
constraints.setCountLimit(200);
NamingEnumeration answer = ctx.search("DC=myDc,DC=com", "sn=*maier*", constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
System.out.println("distinguishedName "+ attrs.get("distinguishedName"));
System.out.println("givenname "+ attrs.get("givenname"));
System.out.println("sn "+ attrs.get("sn"));
System.out.println("mail "+ attrs.get("mail"));
System.out.println("telephonenumber "+ attrs.get("telephonenumber"));
}else{
throw new Exception("Invalid User");
}
} catch (Exception ex) {
ex.printStackTrace();
}
return user;
}
Did I do anything wrong?
You're not looping, so of course you're only getting one result. Change if (answer.hasMore()) to while (answer.hasMore()).
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 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.