All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.ldap.LDAPClient Maven / Gradle / Ivy

There is a newer version: 20241122
Show newest version
package com.hfg.ldap;


import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Logger;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.InvalidNameException;
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.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;

import com.hfg.exception.InvalidValueException;
import com.hfg.ldap.ad.ActiveDirectory;
import com.hfg.security.LoginCredentials;
import com.hfg.util.StringUtil;
import com.hfg.util.collection.CollectionUtil;

//------------------------------------------------------------------------------
/**
 Simple LDAP Client.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class LDAPClient { private String mLDAP_ServerURL; private LdapName mLDAP_UserContext; private LdapName mLDAP_GroupContext; private String mLDAP_PrincipalFieldName = "uid"; private LdapName mLDAP_PrincipalContext; private String mLDAP_PrincipalSuffix; private LoginCredentials mLDAP_PrincipalCredentials; private LDAP_UserObjFactory mUserFactory = new LDAP_UserFactory(); private static final Logger LOGGER = Logger.getLogger(LDAPClient.class.getPackage().getName()); static { LOGGER.setUseParentHandlers(false); } //--------------------------------------------------------------------------- public LDAPClient setServerURL(String inValue) { mLDAP_ServerURL = inValue; return this; } //--------------------------------------------------------------------------- public LDAPClient setUserContext(String inValue) { try { setUserContext(inValue != null ? new LdapName(inValue) : null); } catch (InvalidNameException e) { throw new RuntimeException(e); } return this; } //--------------------------------------------------------------------------- public LDAPClient setUserContext(LdapName inValue) { mLDAP_UserContext = inValue; return this; } //--------------------------------------------------------------------------- public LDAPClient setGroupContext(String inValue) { try { setGroupContext(inValue != null ? new LdapName(inValue) : null); } catch (InvalidNameException e) { throw new RuntimeException(e); } return this; } //--------------------------------------------------------------------------- public LDAPClient setGroupContext(LdapName inValue) { mLDAP_GroupContext = inValue; return this; } //--------------------------------------------------------------------------- public LDAPClient setPrincipalContext(String inValue) { try { setPrincipalContext(inValue != null ? new LdapName(inValue) : null); } catch (InvalidNameException e) { throw new RuntimeException(e); } return this; } //--------------------------------------------------------------------------- public LDAPClient setPrincipalContext(LdapName inValue) { mLDAP_PrincipalContext = inValue; return this; } //--------------------------------------------------------------------------- public LDAPClient setPrincipalSuffix(String inValue) { mLDAP_PrincipalSuffix = inValue; return this; } //--------------------------------------------------------------------------- /** Specifies the credentials to be used to access the LDAP server. * @param inValue the security principal credentials * @return this LDAPClient object to facilitate method chaining */ public LDAPClient setPrincipalCredentials(LoginCredentials inValue) { mLDAP_PrincipalCredentials = inValue; return this; } //--------------------------------------------------------------------------- public LDAPClient setPrincipalFieldName(String inValue) { mLDAP_PrincipalFieldName = inValue; return this; } //--------------------------------------------------------------------------- public LDAP_UserObjFactory getUserFactory() { return mUserFactory; } //--------------------------------------------------------------------------- public LDAPClient setUserFactory(LDAP_UserObjFactory inValue) { if (null == inValue) { throw new InvalidValueException("The user factory cannot be set to null!"); } mUserFactory = inValue; return this; } //--------------------------------------------------------------------------- // TODO: Should this method return a more complex result that could contain more info about failures? public boolean authenticate(LoginCredentials inCredentials) { crosscheck(); boolean authenticated = false; DirContext ctx = null; try { // Create the initial context ctx = getInitialDirContext(inCredentials); if (ctx != null) { authenticated = true; } /* // get more attributes about this user SearchControls scs = new SearchControls(); scs.setSearchScope(SearchControls.SUBTREE_SCOPE); String[] attrNames = { "mail", "cn" }; scs.setReturningAttributes(attrNames); NamingEnumeration nes = ctx.search(mLDAP_UserContext, "uid=" + userName, scs); if(nes.hasMore()) { Attributes attrs = ((SearchResult) nes.next()).getAttributes(); System.out.println("mail: " + attrs.get("mail").get()); System.out.println("cn: " + attrs.get("cn").get()); } */ } catch (AuthenticationException e) { // If it looks like an Active Directory exception, try to decode it... String msg = ActiveDirectory.decodeAuthenticationException(e); if (StringUtil.isSet(msg)) { new LDAP_Exception(msg, e).printStackTrace(); } else { e.printStackTrace(); } } catch (NamingException e) { e.printStackTrace(); } finally { if (ctx != null) { try { ctx.close(); } catch (NamingException e) { // Ignore } } } return authenticated; } //--------------------------------------------------------------------------- public U getInfoForUser(String inQuery) { return getInfoForUser(inQuery, null); } //--------------------------------------------------------------------------- public U getInfoForUser(String inQuery, List inFields) { return getInfoForUser(null, inQuery, inFields); } //--------------------------------------------------------------------------- public U getInfoForUser(LdapName inBaseDN, String inQuery) { return getInfoForUser(inBaseDN, inQuery, null); } //--------------------------------------------------------------------------- public U getInfoForUser(LdapName inBaseDN, String inQuery, List inFields) { List users = getInfoForUsers(inBaseDN, inQuery, inFields); return (CollectionUtil.hasValues(users) ? users.get(0) : null); } //--------------------------------------------------------------------------- public List getInfoForUsers(String inQuery) { return getInfoForUsers(inQuery, null); } //--------------------------------------------------------------------------- public List getInfoForUsers(String inFilter, List inFields) { return getInfoForUsers(null, inFilter, inFields); } //--------------------------------------------------------------------------- public List getInfoForUsers(LdapName inBaseDN, String inFilter, List inFields) { List users = null; DirContext ctx = null; try { // Create the initial context ctx = getInitialDirContext(mLDAP_PrincipalCredentials); // get more attributes about this user SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); Map fieldMap = null; String[] attributesToRetrieve = new String[] {"*"}; // Default to all attributes if (CollectionUtil.hasValues(inFields)) { fieldMap = new HashMap<>(inFields.size()); List attrNames = new ArrayList<>(inFields.size()); for (LDAP_UserField field : inFields) { attrNames.add(field.name()); fieldMap.put(field.name(), field); } attributesToRetrieve = attrNames.toArray(new String[] {}); } LdapName baseDN = inBaseDN; if (null == baseDN) { baseDN = mLDAP_UserContext; // Use the default user context } searchControls.setReturningAttributes(attributesToRetrieve); LOGGER.info("LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(baseDN)); NamingEnumeration enumeration = ctx.search(baseDN, inFilter, searchControls); while (enumeration.hasMore()) { if (null == users) { users = new ArrayList<>(); } U user = getUserFactory().createUserObj(); users.add(user); Attributes attrs = ((SearchResult) enumeration.next()).getAttributes(); NamingEnumeration attrEnum = attrs.getIDs(); while (attrEnum.hasMoreElements()) { String attrID = attrEnum.nextElement(); if (fieldMap != null) { LDAP_UserField field = fieldMap.get(attrID); if (field != null) { Method setter = field.getUserObjectSetter(); if (setter != null) { try { setter.invoke(user, attrs.get(attrID).get().toString()); } catch (Exception e) { } } } } user.setField(attrID, attrs.get(attrID).get().toString()); } } } catch (NamingException e) { throw new LDAP_Exception(e); } finally { if (ctx != null) { try { ctx.close(); } catch (NamingException e) { } } } return users; } //--------------------------------------------------------------------------- public List getUsersForGroup(String inFilter) { List users = null; DirContext ctx = null; try { // Create the initial context ctx = getInitialDirContext(mLDAP_PrincipalCredentials); // get more attributes about this user SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); Map fieldMap = null; String[] attributesToRetrieve = new String[] {"*"}; // Default to all attributes searchControls.setReturningAttributes(attributesToRetrieve); LOGGER.info("LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(mLDAP_GroupContext)); NamingEnumeration enumeration = ctx.search(mLDAP_GroupContext, inFilter, searchControls); while (enumeration.hasMore()) { Attributes attrs = ((SearchResult) enumeration.next()).getAttributes(); NamingEnumeration attrEnum = attrs.getIDs(); while (attrEnum.hasMoreElements()) { String attrID = attrEnum.nextElement(); if (attrID.equalsIgnoreCase("member") || attrID.equalsIgnoreCase("uniquemember")) { Attribute attr = attrs.get(attrID); users = new ArrayList<>(attr.size()); NamingEnumeration memberEnum = (NamingEnumeration) attr.getAll(); while (memberEnum.hasMoreElements()) { LdapName userDN = new LdapName(memberEnum.nextElement()); users.add(getInfoForUser(userDN, userDN.remove(userDN.size() - 1).toString())); } } } } } catch (NamingException e) { throw new LDAP_Exception(e); } finally { if (ctx != null) { try { ctx.close(); } catch (NamingException e) { } } } return users; } //########################################################################### // PRIVATE METHODS //########################################################################### //--------------------------------------------------------------------------- /** Checks to run before an operation. */ private void crosscheck() { if (null == mLDAP_ServerURL) { throw new LDAP_Exception("No LDAP server has been specified!"); } } //--------------------------------------------------------------------------- private InitialDirContext getInitialDirContext(LoginCredentials inCredentials) throws NamingException { crosscheck(); // creating environment for initial context Hashtable env = new Hashtable<>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); LOGGER.info("Setting provider URL to " + StringUtil.singleQuote(mLDAP_ServerURL)); env.put(Context.PROVIDER_URL, mLDAP_ServerURL); // env.put(Context.SECURITY_AUTHENTICATION, "simple"); if (null == inCredentials) { throw new LDAP_Exception("No credentials specified!"); } String securityPrincipal = inCredentials.getUser(); // Active Directory may not want more than this if (mLDAP_PrincipalContext != null) { securityPrincipal = mLDAP_PrincipalFieldName + "=" + inCredentials.getUser() + (mLDAP_PrincipalContext != null ? "," + mLDAP_PrincipalContext : ""); } else if (StringUtil.isSet(mLDAP_PrincipalSuffix)) { securityPrincipal += mLDAP_PrincipalSuffix; } LOGGER.info("Setting security principal to " + StringUtil.singleQuote(securityPrincipal)); env.put(Context.SECURITY_PRINCIPAL, securityPrincipal); env.put(Context.SECURITY_CREDENTIALS, inCredentials.getPasswordString()); LOGGER.info("Establishing LDAP connection..."); // Create the initial context return new InitialDirContext(env); } }