Package com.esri.gpt.framework.security.identity.ldap

Source Code of com.esri.gpt.framework.security.identity.ldap.LdapQueryFunctions

/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.framework.security.identity.ldap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.LimitExceededException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.BasicControl;
import javax.naming.ldap.Control;
import javax.naming.ldap.LdapContext;

import com.esri.gpt.framework.collection.StringSet;
import com.esri.gpt.framework.security.principal.Group;
import com.esri.gpt.framework.security.principal.Groups;
import com.esri.gpt.framework.security.principal.User;
import com.esri.gpt.framework.security.principal.UserAttribute;
import com.esri.gpt.framework.security.principal.UserAttributeMap;
import com.esri.gpt.framework.security.principal.Users;
import com.esri.gpt.framework.util.LogUtil;
import com.esri.gpt.framework.util.Val;

/**
* Handles functionality related to querying an LDAP identity store.
*/
public class LdapQueryFunctions extends LdapFunctions {

// class variables =============================================================

// instance variables ==========================================================

// constructors ================================================================

/** Default constructor. */
protected LdapQueryFunctions() {
  super();
}

/**
* Construct with a supplied configuration.
* @param configuration the configuration
*/
protected LdapQueryFunctions(LdapConfiguration configuration) {
  super(configuration);
}

// properties ==================================================================


// methods =====================================================================

/**
* Appends attribute values to a map (keyed on attribute id).
* @param attributes the attributes to append (from)
* @param values the map of values to populate (to)
* @param stringsOnly if true, only attributes values of type
*        String will be appended
* @throws NamingException if an exception occurs
*/
protected void appendAttributeValues(Attributes attributes,
                                     Map<String,Object> values,
                                     boolean stringsOnly)
  throws NamingException {
  NamingEnumeration<?> enAttr = null;
  try {
    if (attributes != null) {
      enAttr = attributes.getAll();
      while (enAttr.hasMore()) {
        Object oAttr = enAttr.next();
        if (oAttr instanceof Attribute) {
          Attribute attr = (Attribute)oAttr;
          String sId = attr.getID();
          Object oVal = attr.get();
          if (!stringsOnly || (oVal instanceof String)) {
            values.put(sId,oVal);
          } else if (stringsOnly && (oVal == null)) {
            //values.put(sId,"");
          }
          //System.err.println(sId+"="+oVal+" cl="+oVal.getClass().getName());
        }
      }
      enAttr.close();
    }
  }catch (PartialResultException pre) {
   LogUtil.getLogger().finer(pre.toString());
  } catch (LimitExceededException lee) {
   LogUtil.getLogger().finer(lee.toString());
  } finally {
    closeEnumeration(enAttr);
  }
}

/**
* Appends a collection of sub-string attribute values to a list.
* <br/>The sub-attributes are determined by attribute.getAll().
* <br/>Only sub-attributes of type String will be appended.
* @param attribute the attribute containing values to append (from)
* @param values the list of values to populate (to)
* @throws NamingException if an exception occurs
*/
protected void appendSubStringValues(Attribute attribute, StringSet values)
  throws NamingException {
  NamingEnumeration<?> enAttr = null;
  try {
    if (attribute != null) {
      enAttr = attribute.getAll();
      while (enAttr.hasMore()) {
        Object oAttr = enAttr.next();
        if (oAttr instanceof String) {
          values.add((String)oAttr);
        }
      }
    }
  } catch (PartialResultException pre) {
   LogUtil.getLogger().finer(pre.toString());
  } catch (LimitExceededException lee) {
   LogUtil.getLogger().finer(lee.toString());
  } finally {
    closeEnumeration(enAttr);
  }
}

/**
* Determines group membership.
* <br/>This method does not use the dynamic group member attribute.
* <br/>This method doesn't work in all cases and is not used.
* @param memberDN the distinguished name of the member
* @param groupDN the distinguished name of the group
* @return true if the member belongs to the group
* @throws NamingException if an exception occurs
*/
private boolean isGroupMember(DirContext dirContext,
                              String memberDN,
                              String groupDN)
  throws NamingException {
  boolean bIsMember = false;
  NamingEnumeration<SearchResult> enSearch = null;
  memberDN = Val.chkStr(memberDN);
  groupDN = Val.chkStr(groupDN);
  if ((memberDN.length() > 0) && (groupDN.length() > 0)) {
    try {
      String sFilter = getConfiguration().getGroupProperties().returnGroupMemberSearchFilter(memberDN);
      SearchControls controls = new SearchControls();
      controls.setSearchScope(SearchControls.OBJECT_SCOPE);
      enSearch  = dirContext.search(groupDN,sFilter,controls);
      bIsMember = enSearch.hasMore();
    } catch (NamingException e) {
      String sMsg = e.getMessage()+" groupDN:"+groupDN;
      throw new NamingException(sMsg);
    } finally {
      closeEnumeration(enSearch);
    }
  }
  return bIsMember;
}

/**
* Reads the attribute values associated with an attribute name.
* @param dirContext the directory context
* @param attrubuteName attribute name.
* @param objectDN the distinguished name of the object
* @return the list attribute values (strings only are returned)
* @throws NamingException if an exception occurs
*/
protected StringSet readAttribute(DirContext dirContext,
                                  String objectDN,
                                  String attrubuteName)
  throws NamingException {
  StringSet values = new StringSet();
  try{   
    if ((objectDN.length() > 0) && (attrubuteName.length() > 0)) {
      String[] aReturn = new String[1];
      aReturn[0] = attrubuteName;
      try{
      Attributes attributes = dirContext.getAttributes(objectDN,aReturn);
      if (attributes != null) {
        appendSubStringValues(attributes.get(attrubuteName),values);
      }
      }catch(NameNotFoundException nnfe){
        LogUtil.getLogger().finer(nnfe.toString());
      }
    }   
    } catch (PartialResultException pre) {
      LogUtil.getLogger().finer(pre.toString());
    } catch (LimitExceededException lee) {
        LogUtil.getLogger().finer(lee.toString());
    }
  return values;
}

/**
* Reads directory object attributes into a HashMap (keyed on attribute id).
* @param objectDN the distinguished name of the object
* @param stringsOnly if true, consider strings only
* @return the attribute HashMap
* @throws NamingException if an exception occurs
*/
protected Map<String,Object> readAttributes(DirContext dirContext,
                                            String objectDN,
                                            boolean stringsOnly)
  throws NamingException {
  Map<String,Object> map = new HashMap<String,Object>();
  Attributes attributes = dirContext.getAttributes(objectDN);
  appendAttributeValues(attributes,map,stringsOnly);
  return map;
}

/**
* Reads group member name strings into a list.
* @param dirContext the directory context
* @param groupDN the distinguished name of the group
* @return the list of group member strings
* @throws NamingException if an exception occurs
*/
protected StringSet readGroupMembers(DirContext dirContext,
                                     String groupDN)
  throws NamingException {
  StringSet members = new StringSet();
  groupDN = Val.chkStr(groupDN);
  String sDynamic = getConfiguration().getGroupProperties().getGroupDynamicMembersAttribute();
  if (groupDN.length() > 0) {
    if (sDynamic.length() > 0) {
      members = readAttribute(dirContext,groupDN,sDynamic);
    } else {
      Attributes attributes = dirContext.getAttributes(groupDN);
      if (attributes != null) {
        String sMemberTag = getConfiguration().getGroupProperties().getGroupMemberAttribute();
        appendSubStringValues(attributes.get(sMemberTag),members);
      }
    }
  }
  return members;
}

/**
* Retrieves this display name for a user.
* @param dirContext the directory context
* @param userDN the distinguished name for the user
* @return the user display name
* @throws NamingException
*/
protected String readUserDisplayName(DirContext dirContext, String userDN)
  throws NamingException {
  userDN = Val.chkStr(userDN);
  String sDisplayName = userDN;
  String sDisplayAttr = getConfiguration().getUserProperties().getUserDisplayNameAttribute();

  if ((userDN.length() > 0) && (sDisplayAttr.length() > 0)) {
    //try {
      StringSet ss = readAttribute(dirContext,userDN,sDisplayAttr);
      if (ss.size() > 0) {
        sDisplayName = ss.iterator().next();
      }
    //} catch (Exception e) {
    //  sDisplayName = userDN;
      //System.err.println("Error reading user display name for distinguished name: "+userDN);
      //e.printStackTrace(System.err);
    //}
  }
  return sDisplayName;
}

/**
* Reads the groups to which a user belongs.
* @param dirContext the directory context
* @param user the subject user
* @throws NamingException if an LDAP naming exception occurs
*/
protected void readUserGroups(DirContext dirContext, User user)
  throws NamingException {
  NamingEnumeration<SearchResult> enSearch = null;
  try {
    String sUserDN = user.getDistinguishedName();
   
    LdapGroupProperties props = getConfiguration().getGroupProperties();
    String sDynamicAttribute = props.getGroupDynamicMemberAttribute();
    String sNameAttribute = props.getGroupDisplayNameAttribute();
    String recursiveControlId = "";
   
    if (sDynamicAttribute.startsWith("controlid=")) {
      recursiveControlId = Val.chkStr(sDynamicAttribute.substring(10));
      sDynamicAttribute = "";
    }
   
    if (sUserDN.equals("*") || (sDynamicAttribute.length() == 0)) {
     
      // read group membership based upon a search filter
      String sBaseDN = props.getGroupSearchDIT();
      String sFilter = props.returnGroupMemberSearchFilter(sUserDN);
      if ((sUserDN.length() > 0) && (sFilter.length() > 0)) {
       
        // the is to handle an issue with activeDirectory recursion
        if (sUserDN.equals("*")) {
          sFilter = sFilter.replace("member:1.2.840.113556.1.4.1941:=","member=");
        }
       
        // supply a recursion control such as Oracle's CONNECT_BY (2.16.840.1.113894.1.8.3)
        if (!sUserDN.equals("*") && (recursiveControlId.length() > 0)) {
          if (dirContext instanceof LdapContext) {
            LdapContext ldapContext = (LdapContext)dirContext;
            Control[] aControls = ldapContext.getRequestControls();
            Control recursiveControl = new BasicControl(recursiveControlId);
            List<Control> lControls = new ArrayList<Control>();
            if (aControls != null) {
              for (Control ctl: aControls) {
                lControls.add(ctl);
              }
            }
            lControls.add(recursiveControl);
            ldapContext.setRequestControls(lControls.toArray(new Control[0]));
          }
        }
       
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        if (sNameAttribute.length() > 0) {
          String[] aReturn = new String[1];
          aReturn[0] = sNameAttribute;
          controls.setReturningAttributes(aReturn);
        }
       
        enSearch = dirContext.search(sBaseDN,sFilter,controls);
        try {
          while (enSearch.hasMore()) {
            SearchResult result = (SearchResult)enSearch.next();
            String sDN = buildFullDN(result.getName(),sBaseDN);
            if (sDN.length() > 0) {
              String sName = "";
              if (sNameAttribute.length() > 0) {
                Attribute attrName = result.getAttributes().get(sNameAttribute);
                if ((attrName != null) && (attrName.size() > 0)) {
                  sName = Val.chkStr(attrName.get(0).toString());
                }
              }
              Group group = new Group();
              group.setDistinguishedName(sDN);
              group.setKey(group.getDistinguishedName());
              group.setName(sName);
              user.getGroups().add(group);
            }
          }
        } catch (PartialResultException pre) {
          LogUtil.getLogger().finer(pre.toString());
        } catch (LimitExceededException lee) {
            LogUtil.getLogger().finer(lee.toString());
        }
      }
     
    } else {
     
      // read group membership based upon a dynamic attribute
      StringSet groupDNs = readAttribute(dirContext,sUserDN,sDynamicAttribute);
      for (String sDN: groupDNs) {
        sDN = sDN.toLowerCase();
        if (sDN.length() > 0) {
          String sName = "";
          if (sNameAttribute.length() > 0) {
            StringSet ss = readAttribute(dirContext,sDN,sNameAttribute);
            if (ss.size() > 0) {
              sName = ss.iterator().next();
            }
          }
          Group group = new Group(sDN);
          group.setDistinguishedName(sDN);
          group.setName(sName);
          user.getGroups().add(group);
        }
      }
    }
   
  } finally {
    closeEnumeration(enSearch);
  }
}

/**
* Retrieves this username attribute for a user.
* @param dirContext the directory context
* @param userDN the distinguished name for the user
* @return the username
* @throws NamingException if the username attribute does not exist
*/
protected String readUsername(DirContext dirContext, String userDN)
  throws NamingException {
  userDN = Val.chkStr(userDN);
  String sName = userDN;
  LdapNameMapping nameMap =  getConfiguration().getUserProperties().getUserProfileMapping();
  String sAttrName = nameMap.findLdapName(UserAttributeMap.TAG_USER_NAME);
  if (sAttrName.length() == 0) sAttrName = "cn";
  if ((userDN.length() > 0) && (sAttrName.length() > 0)) {
    //try {
      StringSet ss = readAttribute(dirContext,userDN,sAttrName);
      if (ss.size() > 0) {
        sName = ss.iterator().next();
      } else if (!sAttrName.equals("cn")) {
        ss = readAttribute(dirContext,userDN,"cn");
        if (ss.size() > 0) {
          sName = ss.iterator().next();
        }
      }
    //} catch (Exception e) {
    //  sName = userDN;
      //System.err.println("Error reading username for distinguished name: "+userDN);
      //e.printStackTrace(System.err);
    //}
  }
  return sName;
}

/**
* Reads the profile attributes for a user.
* @param dirContext the directory context
* @param user the subject user
* @throws NamingException if an LDAP naming exception occurs
*/
protected void readUserProfile(DirContext dirContext, User user)
  throws NamingException {
  LdapNameMapping nameMap = getConfiguration().getUserProperties().getUserProfileMapping();
  UserAttributeMap userProf = user.getProfile();
  UserAttributeMap configured = getConfiguration().getIdentityConfiguration().getUserAttributeMap();
 
  /* There were some issues with the initial integration of
   * Apache's LDAP implementation. The section below ensures that a user's
   * profile contains all configured attributes, even if they do not exist on
   * the LDAP side.
   */
  boolean bEnsureAllAttributes = true;
  if (bEnsureAllAttributes) {
    for (UserAttribute attr: configured.values()) {
      if (!userProf.containsKey(attr.getKey())) {
        userProf.set(attr.getKey(),"");
      }
    }
  }
 
  String sUserDN = user.getDistinguishedName();
  if (sUserDN.length() > 0) {
   
    // read current LDAP attribute values
    NamingEnumeration<?> enAttr = null;
    try {
      Attributes attributes = dirContext.getAttributes(sUserDN);
           
      if (attributes != null) {
        enAttr = attributes.getAll();
        while (enAttr.hasMore()) {
          Object oAttr = enAttr.next();
          if (oAttr instanceof Attribute) {
            Attribute attr = (Attribute)oAttr;
            String sLdapKey = attr.getID();
            Object oVal = attr.get();
                       
            // set the corresponding application user attribute
            String sAppKey = Val.chkStr(nameMap.findApplicationName(sLdapKey));
            if ((sAppKey.length() > 0) && configured.containsKey(sAppKey)) {
              if (oVal instanceof String) {
                userProf.set(sAppKey,(String)oVal);
              } else if (oVal == null) {
                userProf.set(sAppKey,"");
              }
            }
           
          }
        }
        enAttr.close();
      }
    } finally {
      closeEnumeration(enAttr);
    }   
   
  }
}

/**
* Builds list of ldap users matching filter.
* @param dirContext the directory context
* @param filter the user search filter for ldap
* @return the list of users matching filter
* @throws NamingException if an LDAP naming exception occurs
*/
protected Users readUsers(DirContext dirContext,String filter, String attributeName) throws NamingException
  Users users = new Users();
  NamingEnumeration<SearchResult> enSearch = null;
  try{
    LdapUserProperties userProps = getConfiguration().getUserProperties();
    String sNameAttribute = userProps.getUserDisplayNameAttribute();
      String sBaseDN = userProps.getUserSearchDIT();
      String sFilter = userProps.returnUserLoginSearchFilter(filter);
      if(attributeName != null){     
        sFilter = userProps.returnUserNewRequestSearchFilter(filter, attributeName);
      }
      SearchControls controls = new SearchControls();
      controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
      if (sNameAttribute.length() > 0) {
        String[] aReturn = new String[1];
        aReturn[0] = sNameAttribute;
        controls.setReturningAttributes(aReturn);
      }
     
      enSearch = dirContext.search(sBaseDN,sFilter,controls);
      try {
        while (enSearch.hasMore()) {
          SearchResult result = (SearchResult)enSearch.next();
          String sDN = buildFullDN(result.getName(),sBaseDN);
          if (sDN.length() > 0) {
            String sName = "";
            if (sNameAttribute.length() > 0) {
              Attribute attrName = result.getAttributes().get(sNameAttribute);
              if ((attrName != null) && (attrName.size() > 0)) {
                sName = Val.chkStr(attrName.get(0).toString());
              }
            }

              User user = new User();
              user.setDistinguishedName(sDN);
              user.setKey(user.getDistinguishedName());
              user.setName(sName);
              users.add(user);
          }
        }
      } catch (PartialResultException pre) {
        LogUtil.getLogger().finer(pre.toString());
      } catch (LimitExceededException lee) {
          LogUtil.getLogger().finer(lee.toString());
      }
  }finally {
      closeEnumeration(enSearch);
  }
    return users;
}

/**
* Builds list of ldap groups matching filter.
* @param dirContext the directory context
* @param filter the group search filter for ldap
* @return the list of groups matching filter
* @throws NamingException if an LDAP naming exception occurs
*/
protected Groups readGroups(DirContext dirContext,String filter) throws NamingException
  Groups groups = new Groups();
  NamingEnumeration<SearchResult> enSearch = null;
  try{
    LdapGroupProperties groupProps = getConfiguration().getGroupProperties();
    String sNameAttribute = groupProps.getGroupDisplayNameAttribute();
      String sBaseDN = groupProps.getGroupSearchDIT();
      String sFilter = groupProps.returnGroupNameSearchFilter(filter);
      SearchControls controls = new SearchControls();
      controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
      if (sNameAttribute.length() > 0) {
        String[] aReturn = new String[1];
        aReturn[0] = sNameAttribute;
        controls.setReturningAttributes(aReturn);
      }
     
      enSearch = dirContext.search(sBaseDN,sFilter,controls);
      try {
        while (enSearch.hasMore()) {
          SearchResult result = (SearchResult)enSearch.next();
          String sDN = buildFullDN(result.getName(),sBaseDN);
          if (sDN.length() > 0) {
            String sName = "";
            if (sNameAttribute.length() > 0) {
              Attribute attrName = result.getAttributes().get(sNameAttribute);
              if ((attrName != null) && (attrName.size() > 0)) {
                sName = Val.chkStr(attrName.get(0).toString());
              }
            }

              Group group = new Group();
              group.setDistinguishedName(sDN);
              group.setKey(group.getDistinguishedName());
              group.setName(sName);
              groups.add(group);
          }
        }
      } catch (PartialResultException pre) {
        LogUtil.getLogger().finer(pre.toString());
      } catch (LimitExceededException lee) {
          LogUtil.getLogger().finer(lee.toString());
      }
  }finally {
      closeEnumeration(enSearch);
  }
    return groups;
}

/**
* Returns a list of distinguished names resulting from a search.
* <br/>The search is executed with SearchControls.SUBTREE_SCOPE.
* @param dirContext the directory context
* @param baseDN the baseBN for the search
* @param filter the filter for the search
* @return a collection of distinguished names
* @throws NamingException if an exception occurs
*/
protected StringSet searchDNs(DirContext dirContext,
                              String baseDN,
                              String filter)
  throws NamingException {
  StringSet names = new StringSet(false,false,true);
  NamingEnumeration<SearchResult> enSearch = null;
  try {
    baseDN = Val.chkStr(baseDN);
    filter = Val.chkStr(filter);
    if (filter.length() > 0) {
      SearchControls controls = new SearchControls();
      controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
      enSearch = dirContext.search(baseDN,filter,controls);
      try {
        while (enSearch.hasMore()) {
          SearchResult result = (SearchResult)enSearch.next();
          names.add(buildFullDN(result.getName(),baseDN));
        }
      } catch (PartialResultException pre) {
        LogUtil.getLogger().finer(pre.toString());
      } catch (LimitExceededException lee) {
          LogUtil.getLogger().finer(lee.toString());
      }
    }
  } finally {
    closeEnumeration(enSearch);
  }
  return names;
}

}
TOP

Related Classes of com.esri.gpt.framework.security.identity.ldap.LdapQueryFunctions

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.