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.
Related
I am currently working on a project like this. When the username and password are entered, the check will be made via LDAP and if it is correct, I need to return a successful transaction, otherwise I want a failed transaction. In short, I will log in via LDAP. We have an ldap server ready now. We have an ldap server ready now. So domain, host, and searchBase have it all. But I'm trying to understand the logic, can I do this using Spring Boot? Because in most tutorials, the name and password are entered manually. But I want the input to be entered by any client, not manually, and check if it exists on my server. If such a thing is not possible in spring boot, how can I check the username and password values sent to the method by LDAP by verifying and returning them in the code we have written below?
package az.expressbank.ldap.test;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
*/
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
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 ControlDomainLogin {
private String domain;
private String ldapHost;
private String searchBase;
public ControlDomainLogin() {
this.domain = "domain.com";
this.ldapHost = "ldap://url";
this.searchBase = "DC=something,DC=com"; // YOUR SEARCH BASE IN LDAP
}
Map<String, Object> amap = null;
// public ADAuthenticator(String domain, String host, String dn)
// {
// this.domain = domain;
// this.ldapHost = host;
// this.searchBase = dn;
// }
public Map<String, Object> authenticate(String user, String pass) {
String[] returnedAtts = {"sn", "givenName", "name", "userPrincipalName", "displayName", "memberOf"};
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<String, String> env = new Hashtable<String, String>();
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);
env.put(Context.SECURITY_PROTOCOL, "SSL");
LdapContext ctxGC = null;
NamingEnumeration<SearchResult> answer = null;
Attributes attrs = null;
SearchResult sr = null;
NamingEnumeration<?> ne = null;
Attribute attr = null;
try {
ctxGC = new InitialLdapContext(env, null);
answer = ctxGC.search(searchBase, searchFilter, searchCtls);
if (answer != null) {
while (answer.hasMoreElements()) {
sr = (SearchResult) answer.next();
attrs = sr.getAttributes();
if (attrs != null) {
amap = new HashMap<String, Object>();
ne = attrs.getAll();
attr = (Attribute) ne.next();
amap.put(attr.getID(), attr.get());
ne.close();
}
ctxGC.close(); // Close and clean up
}
} else {
System.out.println("Answer from domen controller is null!");
}
} catch (NamingException ex) {
System.out.println("Exception: " + ex.toString());
} finally {
System.out.println("");
}
return amap;
}
}
I want me to do this by creating an API. So I will call this method in my service layer and send my username and password there. My method successfully checks the username and password sent to it. For example
#Override
public Optional login(String username, String password, String type) {
/*
for example when I send username and password to the following method
*/
Map<String, Object> authenticate = controlDomainLogin.authenticate(username, password);
/*
I want to match the value of method of login of parametr returned from the following method of authenticate of returned value , if they match, I want to print the correct operation, otherwise the wrong input operation.
*/
return null;
}
What changes can I make to my LDAP authentication method so that I can get the correct password and name values checked there?
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 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
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 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;
}
}