I am trying to write a method that, given the information for connecting to and searching an LDAP (e.g., the hostname, base DN, etc., can retrieve an attribute that contains a CA certificate (the "caCertificate" attribute).
I've seen some suggestions about how to do this, but so far have not been able to get one working.
I think that I'm able to do the LDAP search and retrieval but have not been able to figure out how to handle the byte array that is the certificate attribute value.
Here's a snippet of the part I think is working:
Date theReturnedDate = null;
String base = "ou=CAs,dc=test,dc=com";
String filter = "(objectclass=CertificationAuthority)";
System.out.println("In LDAPUpdate.checkReadLdap: Entering, theLdapCn = [" + theLdapCn + "]...");
Hashtable envRead = new Hashtable(11);
envRead.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
envRead.put(Context.PROVIDER_URL, "ldap://my.test.ldap:389");
envRead.put(Context.SECURITY_AUTHENTICATION, "simple");
envRead.put(Context.SECURITY_PRINCIPAL, "cn=admin,ou=people,dc=test,dc=com");
envRead.put(Context.SECURITY_CREDENTIALS, "xxx");
//specify attributes to be returned in binary format
envRead.put("java.naming.ldap.attributes.binary","caCertificate");
SearchControls searchCtls = new SearchControls();
//Specify the attributes to return
String returnedAtts[]={"caCertificate"};
searchCtls.setReturningAttributes(returnedAtts);
DirContext ctx = null;
try
{
// Create the initial directory context
InitialDirContext initialContext = new InitialDirContext(envRead);
ctx = (DirContext)initialContext;
System.out.println("Context Sucessfully Initialized");
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results = ctx.search(base, filter, constraints);
while(results != null && results.hasMore())
{
SearchResult sr = (SearchResult) results.next();
String dn = sr.getName() + "," + base;
System.out.println("Distinguished Name is " + dn);
Attributes ar = ctx.getAttributes(dn, returnedAtts);
if(ar == null)
{
System.out.println("Entry " + dn);
System.out.println(" has none of the specified attributes\n");
}
else
{
System.out.println("In LDAPUpdate.readCheckLdap: returnedAtts.length=[" + returnedAtts.length + "]");
for(int i=0; i<returnedAtts.length; i++)
{
Attribute attr = ar.get(returnedAtts[i]);
System.out.println(returnedAtts[i] + ":");
for(Enumeration vals=attr.getAll(); vals.hasMoreElements();)
{
System.out.println("\t" + vals.nextElement());
}
}
}
}
}
catch(Exception e)
{
System.err.println(e);
}
Can anyone tell how to do the rest of what I need, i.e., to take the attribute that is returning with the CA certificate and turn it into an X509Certificate object?
Can anyone tell how to do the rest of what I need, i.e., to take the attribute that is returning with the CA certificate and turn it into an X509Certificate object?
Something like this:
import java.io.ByteArrayInputStream;
import java.security.cert.*;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(bytes));
E&OE
I think that I got it working!
For the record, here is full working example. I left some debug code in there that might be helpful. This will bind to an LDAP server, then retrieve an entry then extract the caCertificate attribute into an X509Certificate object. Then, it displays the Subject DN from the X509Certificate to test that the object was instantiated ok.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class GoodReadACertFromLdap{
public static void main(String[] args) {
System.out.println("This Java application demonstrates how to retrieve a caCertificate object from an LDAP server");
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://myldapserver:389/");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=directory manager");
env.put(Context.SECURITY_CREDENTIALS, "XXXX");
Object cert = null;
Attributes attrs = null;
Attribute attr = null;
try {
LdapContext ctx = new InitialLdapContext(env, null);
ctx.setRequestControls(null);
NamingEnumeration<?> namingEnum = ctx.search("CN=mycert,ou=CAs,dc=whatever,dc=com", "(objectclass=*)", getSimpleSearchControls());
while (namingEnum.hasMore ()) {
SearchResult result = (SearchResult) namingEnum.next ();
attrs = result.getAttributes ();
System.out.println(attrs.get("cn"));
cert = attrs.get("caCertificate;binary");
System.out.println(cert);
System.out.println(attrs.get("objectclass"));
}
namingEnum.close();
} catch (Exception e) {
e.printStackTrace();
}
if (((Attribute)cert).size() == 0) {
System.out.println("The cert attribute was cert.size == 0!");
System.exit(0);
}
System.out.println("The cert attribute cert.size was NOT 0, so will now try to make it into a certificate object!");
System.out.println("The cert attribute cert.size was: [" + ((Attribute)cert).size() + "]");
System.out.println("Here's cert again: [" + cert + "]");
try {
X509Certificate certOut = null;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
attr = attrs.get("caCertificate;binary"); // get the caCertificate attribute so we can make a NamingEnumeration from it...
for (NamingEnumeration e = attr.getAll();e.hasMore();) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream( (byte[])e.next());
certOut = (X509Certificate)cf.generateCertificate(bais);
} catch (Exception ex ) {
System.out.println("While converting Attribute object to a X509Certificate, EXCEPTION = " + ex);
} // end catch()
}
System.out.println("certOut.getSubjectDN = [" + certOut.getSubjectDN() + "]");
} catch (Exception e) {
e.printStackTrace();
}
} // end main()
private static SearchControls getSimpleSearchControls() {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setTimeLimit(30000);
String[] attrIDs = {"cn", "caCertificate", "objectclass"};
searchControls.setReturningAttributes(attrIDs);
return searchControls;
} // end getSimpleSearchControls()
} // end CLASS
Related
I'm trying to authenticate a set of credentials against an LDAP server and I was able to authenticate them successfully. Now am trying to get the full name or the display name of the user logged-in into the server. Am unable to get the same. Being new to LDAP concepts, am unable to figure out a way to get the full display name of the user. Can some please help me how to get the full display name of the user logged in.
Below is the shiro.ini file am using:
[main]
activeDirectoryRealm =
org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm
activeDirectoryRealm.systemUsername = adminusername
activeDirectoryRealm.systemPassword = adminpswd
activeDirectoryRealm.searchBase = "OU=User Accounts,DC=dmn,DC=net"
activeDirectoryRealm.url = ldaps://localhost:389
My Java code is as below:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class ExampleActiveDirectory {
public static final String userName = "myusername";
public static final String password = "mypassword";
public static void main(String[] args)
{
//Factory<SecurityManager> factory = new IniSecurityManagerFactory("N:\\workspace\\LdapAuthentication\\src\\auth.ini");
Factory<SecurityManager> factory = new IniSecurityManagerFactory("N:\\workspace\\LdapAuthentication\\src\\shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager( securityManager );
System.out.println( "userName is : " +userName);
System.out.println( "password is : " +password);
UsernamePasswordToken token = new UsernamePasswordToken( userName,password );
Subject currentUser = SecurityUtils.getSubject();
try
{
//currentUser.login( token ) ;
securityManager.login(currentUser,token).isAuthenticated();
System.out.println( "We've authenticated! :)" );
}
catch ( AuthenticationException e )
{
System.out.println( "We did not authenticate :(" );
e.printStackTrace();
}
}
}
Thanks for the info.
link - http://www.deepakgaikwad.net/index.php/2009/09/24/retrieve-basic-user-attributes-from-active-directory-using-ldap-in-java.html
Found a solution as below:
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import org.apache.shiro.web.tags.UserTag;
public class RetrieveUserAttributes {
public static void main(String[] args) {
RetrieveUserAttributes retrieveUserAttributes = new RetrieveUserAttributes();
retrieveUserAttributes.getUserBasicAttributes("username", retrieveUserAttributes.getLdapContext());
}
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.SECURITY_AUTHENTICATION, "Simple");
env.put(Context.SECURITY_PRINCIPAL, "adminusername");
env.put(Context.SECURITY_CREDENTIALS, "adminpswrd");
env.put(Context.PROVIDER_URL, "ldaps://localhost:389");
ctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
}catch(NamingException nex){
System.out.println("LDAP Connection: FAILED");
nex.printStackTrace();
}
return ctx;
}
UserTag getUserBasicAttributes(String username, LdapContext ctx) {
UserTag user=null;
try {
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = { "distinguishedName",
"sn",
"givenname",
"mail",
"telephonenumber"};
constraints.setReturningAttributes(attrIDs);
//First input parameter is search bas, it can be "CN=Users,DC=YourDomain,DC=com"
//Second Attribute can be uid=username
NamingEnumeration answer = ctx.search("DC=domain,DC=com", "sAMAccountName="
+ "username", 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;
}
}
I am trying to find a user's OU within an LDAP tree in JSP. I can retrieve many of the user's LDAP attributes with the following code:
Hashtable<String, String> tenv = new Hashtable<String, String>();
tenv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
tenv.put(Context.PROVIDER_URL, "ldap://xx.xx.xx.xx:389/");
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
LdapContext lctx = new InitialLdapContext(tenv, null);
String filter = "cn=" + userid;
NamingEnumeration res = lctx.search ("dc=my,dc=dom,dc=org", filter, sc);
while (res.hasMore())
{
SearchResult s = (SearchResult) res.next();
Attributes attrs = s.getAttributes();
Attribute attr = attrs.get("SN");
out.println ("<font color=red>" + attr + "</font>");
}
When I run ldapsearch at the Linux command line, with similar search parameters, I can see a DN: which shows the OU the user is in (dn: uid=username,ou=users,dc=my,dc=dom,dc=org).
I've tried attrs.get("DN") and was returned null. How can I retrieve this DN: in JSP?
Apparently there is "there is no direct way of obtaining the Distinguished Name (DN) from the search results."
This code will do it:
import java.util.Hashtable;
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.InitialDirContext;
import javax.naming.ldap.*;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
class GetAllAttrs
{
public static void main(String[] args)
{
String filter = "cn=myuser"; // this is the user to look for
String baseDN = "dc=my,dc=dom,dc=org";
String ldapURL = "ldap://192.168.101.1:389";
// 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, ldapURL);
try
{
// Create the initial context
LdapContext ctx = new InitialLdapContext(env, null);
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration res = ctx.search (baseDN, filter, sc);
while (res.hasMore())
{
SearchResult s = (SearchResult) res.next();
// print user's DN
System.out.println(">>" + s.getNameInNamespace());
}
// Close the context when we're done
ctx.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
I have a code which authenticates, interacts with the Active Directory and fetches some information. But I just want to be sure that I close the connection and return it to the pool. How can I ensure them?
Here is my code:
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class LDAPExaminer {
public static void main(String[] args) {
LDAPExaminer ldapExaminer = new LDAPExaminer();
// NOTE: replace theUserName below with the Active Directory/LDAP user whose attribites you want printed.
ldapExaminer.printUserBasicAttributes("<strong>theUserName</strong>", ldapExaminer.getLdapContext());
}
public LdapContext getLdapContext() {
LdapContext ctx = null;
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "Simple");
// NOTE: replace user#domain.com with a User that is present in your Active Directory/LDAP
env.put(Context.SECURITY_PRINCIPAL, "<strong>user#domain.com</strong>");
// NOTE: replace userpass with passwd of this user.
env.put(Context.SECURITY_CREDENTIALS, "userpass");
// NOTE: replace ADorLDAPHost with your Active Directory/LDAP Hostname or IP.
env.put(Context.PROVIDER_URL, "ldap://ActiveDirOrLDAPHost:389");
System.out.println("Attempting to Connect...");
ctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
} catch (NamingException nex) {
System.out.println("LDAP Connection: FAILED");
nex.printStackTrace();
}
return ctx;
}
private void printUserBasicAttributes(String username, LdapContext ctx) {
try {
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// NOTE: The attributes mentioned in array below are the ones that will be retrieved, you can add more.
String[] attrIDs = { "distinguishedName", "sn", "givenname", "mail", "telephonenumber", "canonicalName",
"userAccountControl", "accountExpires" };
constraints.setReturningAttributes(attrIDs);
// NOTE: replace DC=domain,DC=com below with your domain info. It is essentially the Base Node for Search.
NamingEnumeration answer = ctx.search("DC=YourDomain,DC=com", "sAMAccountName=" + username, constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
System.out.println(attrs.get("distinguishedName"));
System.out.println(attrs.get("givenname"));
System.out.println(attrs.get("sn"));
System.out.println(attrs.get("mail"));
System.out.println(attrs.get("telephonenumber"));
System.out.println(attrs.get("canonicalName"));
System.out.println(attrs.get("userAccountControl"));
System.out.println(attrs.get("accountExpires"));
} else {
throw new Exception("Invalid User");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
a couple of things
1) possible duplicate of Java LDAP graceful disconnect
2) try adding this in the appropriate place(s) [in at least one catch and in main]
ctx.close();
if you're going to keep this function based, I'd write one more to put your 'main' code into, including the close().
I used apacheds(as LDAP server) and inserted entries into it using apache directory studio. For the userPassword atribute I selected plain text only. but, apache directory studio is encrypting it. i don't know why is that. Now, my java program to retrieve that entry is giving me a ssha encrypted password. can anyone out there help me in how to decode it ?
import java.util.Hashtable;
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.InitialDirContext;
class GetAttrs {
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:10389/o=mojo");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
try {
// Create initial context
DirContext ctx = new InitialDirContext(env);
// Specify the ids of the attributes to return
String[] attrIDs = { "cn", "sn", "uid", "userPassword" };
// Get the attributes requested
Attributes answer = ctx
.getAttributes("cn=Harish Koppala, ou=Users", attrIDs);
// Print the answer
printAttrs(answer);
// Close the context when we're done
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
static void printAttrs(Attributes attrs) throws Exception{
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.print(attr.getID()+" : ");
/* print each value */
if("userpassword".equalsIgnoreCase(attr.getID())){
for (
NamingEnumeration e = attr.getAll();
e.hasMore();
System.out.println(new String((byte[])e.next()))
);
}else{
for (
NamingEnumeration e = attr.getAll();
e.hasMore();
System.out.println(e.next())
);
}
}
} catch (NamingException e) {
e.printStackTrace();
}
}
}
}
output:
userPassword : {SSHA}SKA8QY7BBX0tgdZlzL+3sEDFnIBsJwd8VHjexw==
uid : hwilliams
sn : Williams
cn : Hugo Williams
It isn't encrypting it. It is securely hashing it. You can't decrypt or decode it.
I have successfully used the code below to authenticate users in an LDAP environment for a number of years. Now, I have a client who wants me to log into to the LDAP directory (it's an Active Directory LDAP environment) prior to authentication and then do the authentication. In other words, I would pass two sets of credentials to the server, one to gain access to the LDAP directory, and the second to actually do the authentication. Is there an easy way to modify my existing code to do this? Are their alternative code patterns that would allow this to be done easily?
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
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.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class ADAuthenticator {
private String domain;
private String ldapHost;
private String searchBase;
public ADAuthenticator()
{
this.domain = "<your domain>";
this.ldapHost = "ldap://<your AD controller>";
this.searchBase = "your AD root e.g. dc=abbl,dc=org";
}
public ADAuthenticator(String domain, String host, String dn)
{
this.domain = domain;
this.ldapHost = host;
this.searchBase = dn;
}
public Map authenticate(String user, String pass)
{
String returnedAtts[] ={ "sn", "givenName", "mail" };
String searchFilter = "(&(objectClass=user)(sAMAccountName=" + user + "))";
//Create the search controls
SearchControls searchCtls = new SearchControls();
searchCtls.setReturningAttributes(returnedAtts);
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapHost);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, user + "#" + domain);
env.put(Context.SECURITY_CREDENTIALS, pass);
LdapContext ctxGC = null;
try
{
ctxGC = new InitialLdapContext(env, null);
//Search objects in GC using filters
NamingEnumeration answer = ctxGC.search(searchBase, searchFilter, searchCtls);
while (answer.hasMoreElements())
{
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
Map amap = null;
if (attrs != null)
{
amap = new HashMap();
NamingEnumeration ne = attrs.getAll();
while (ne.hasMore())
{
Attribute attr = (Attribute) ne.next();
amap.put(attr.getID(), attr.get());
}
ne.close();
}
return amap;
}
}
catch (NamingException ex)
{
ex.printStackTrace();
}
return null;
}
}