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?
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 fetch all the users from AD server. There are 7000 users in AD server but while I am running my java code it is returning only 1000 user names. Is there any restriction that it will fetch only max 1000 users at a time ?
Could any one please tell me how can I fetch all the 7000 users at a time.
Here is Java Code -
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class FetchAllUsers {
public static void main(String args[])
{
String username = "username";
String password = "password";
String ldapURL = "url";
String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
String securityAuthentication = "simple";
fetchUserList(username,password,ldapURL,contextFactory,securityAuthentication);
}
public static void fetchUserList(String username,String password,String ldapURL,String contextFactory,String securityAuthentication) {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
// set security credentials
env.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
// connect to my domain controller
env.put(Context.PROVIDER_URL, ldapURL);
try {
List<String> usersList = new ArrayList<String>();
LdapContext ctx = new InitialLdapContext(env, null);
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// specify the LDAP search filter
String searchFilter = "(&(objectCategory=user))";
// Specify the Base for the search
String searchBase = "DC=domain,DC=com";
// initialize counter to total the results
int totalResults = 0;
// Search for objects using the filter
NamingEnumeration<SearchResult> fetchData = ctx.search(searchBase, searchFilter, searchCtls);
// Loop through the search results
while (fetchData.hasMoreElements()) {
SearchResult sr = (SearchResult) fetchData.next();
totalResults++;
String names[] = sr.getName().split(",");
String name[] = names[0].split("=");
usersList.add(name[1]);
}
System.out.println("Total number of users in AD server : " + totalResults);
System.out.println(usersList);
} catch (NamingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
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 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;
}
}