Class UnboundidDirectoryProvider

  • All Implemented Interfaces:
    LdapConnectionManagerConfig, org.sakaiproject.user.api.AuthenticationIdUDP, org.sakaiproject.user.api.DisplayAdvisorUDP, org.sakaiproject.user.api.ExternalUserSearchUDP, org.sakaiproject.user.api.UserDirectoryProvider, org.sakaiproject.user.api.UsersShareEmailUDP

    public class UnboundidDirectoryProvider
    extends Object
    implements org.sakaiproject.user.api.UserDirectoryProvider, LdapConnectionManagerConfig, org.sakaiproject.user.api.ExternalUserSearchUDP, org.sakaiproject.user.api.UsersShareEmailUDP, org.sakaiproject.user.api.DisplayAdvisorUDP, org.sakaiproject.user.api.AuthenticationIdUDP

    An implementation of a Sakai UserDirectoryProvider that authenticates/retrieves users from a LDAP directory. Forked from JLDAP in early 2016.

    • Field Detail

      • DEFAULT_LDAP_PORT

        public static final int[] DEFAULT_LDAP_PORT
        Default LDAP connection port
      • DEFAULT_IS_SECURE_CONNECTION

        public static final boolean DEFAULT_IS_SECURE_CONNECTION
        Default secure/unsecure LDAP connection creation behavior
        See Also:
        Constant Field Values
      • DEFAULT_OPERATION_TIMEOUT_MILLIS

        public static final int DEFAULT_OPERATION_TIMEOUT_MILLIS
        Default LDAP access timeout in milliseconds
        See Also:
        Constant Field Values
      • DEFAULT_IS_FOLLOW_REFERRALS

        public static final boolean DEFAULT_IS_FOLLOW_REFERRALS
        Default referral following behavior
        See Also:
        Constant Field Values
      • DEFAULT_IS_SEARCH_ALIASES

        public static final boolean DEFAULT_IS_SEARCH_ALIASES
        See Also:
        Constant Field Values
      • DEFAULT_SEARCH_SCOPE

        public static final com.unboundid.ldap.sdk.SearchScope DEFAULT_SEARCH_SCOPE
        Default search scope for filters executed by #searchDirectory(String, LDAPConnection, LdapEntryMapper, String[], String, int)
      • DEFAULT_POOL_MAX_CONNS

        public static final int DEFAULT_POOL_MAX_CONNS
        Default LDAP maximum number of connections in the pool
        See Also:
        Constant Field Values
      • DEFAULT_RETRY_FAILED_OPERATIONS_DUE_TO_INVALID_CONNECTIONS

        public static final boolean DEFAULT_RETRY_FAILED_OPERATIONS_DUE_TO_INVALID_CONNECTIONS
        See Also:
        Constant Field Values
      • DEFAULT_HEALTH_CHECK_INTERVAL_MILLIS

        public static final long DEFAULT_HEALTH_CHECK_INTERVAL_MILLIS
        See Also:
        Constant Field Values
      • DEFAULT_MAX_RESULT_SIZE

        public static final int DEFAULT_MAX_RESULT_SIZE
        Default LDAP maximum number of objects in a result
        See Also:
        Constant Field Values
      • DEFAULT_BATCH_SIZE

        public static final int DEFAULT_BATCH_SIZE
        Default LDAP maximum number of objects to query for
        See Also:
        Constant Field Values
      • DISPLAY_ID_PROPERTY

        public static final String DISPLAY_ID_PROPERTY
        Property of the user object to store the display ID under
      • DISPLAY_NAME_PROPERTY

        public static final String DISPLAY_NAME_PROPERTY
        Property of the user object to store the display Name under
      • DEFAULT_ALLOW_AUTHENTICATION

        public static final boolean DEFAULT_ALLOW_AUTHENTICATION
        See Also:
        Constant Field Values
      • DEFAULT_ALLOW_AUTHENTICATION_EXTERNAL

        public static final boolean DEFAULT_ALLOW_AUTHENTICATION_EXTERNAL
        See Also:
        Constant Field Values
      • DEFAULT_ALLOW_AUTHENTICATION_ADMIN

        public static final boolean DEFAULT_ALLOW_AUTHENTICATION_ADMIN
        See Also:
        Constant Field Values
      • DEFAULT_ALLOW_SEARCH_EXTERNAL

        public static final boolean DEFAULT_ALLOW_SEARCH_EXTERNAL
        See Also:
        Constant Field Values
      • DEFAULT_ALLOW_GET_EXTERNAL

        public static final boolean DEFAULT_ALLOW_GET_EXTERNAL
        See Also:
        Constant Field Values
      • DEFAULT_AUTHENTICATE_WITH_PROVIDER_FIRST

        public static final boolean DEFAULT_AUTHENTICATE_WITH_PROVIDER_FIRST
        See Also:
        Constant Field Values
    • Constructor Detail

      • UnboundidDirectoryProvider

        public UnboundidDirectoryProvider()
    • Method Detail

      • init

        public void init()
        Typically invoked by Spring to complete bean initialization. Ensures initialization of delegate LdapConnectionManager and LdapAttributeMapper
        See Also:
        #initLdapConnectionManager(), initLdapAttributeMapper()
      • createConnectionPool

        protected boolean createConnectionPool()
        Create the LDAP connection pool
      • initLdapAttributeMapper

        protected void initLdapAttributeMapper()
        Lazily "injects" a LdapAttributeMapper if one has not been assigned already.

        Implementation note: this approach to initing the attrib mgr preserves forward compatibility of existing config, but config should probably be refactored to inject the appropriate config directly into the attrib mgr.

      • destroy

        public void destroy()
        Typically called by Spring to signal bean destruction.
      • clearCache

        public void clearCache()
        Resets the internal LdapUserData cache
      • authenticateUser

        public boolean authenticateUser​(String userLogin,
                                        org.sakaiproject.user.api.UserEdit edit,
                                        String password)
        Authenticates the specified user login by recursively searching for and binding to a DN below the configured base DN. Search results are subsequently added to the cache.

        Caching search results departs from behavior in <= 2.3.0 versions, which removed cache entries following authentication. If the intention is to ensure fresh user data at each login, the most natural approach is probably to clear the cache before executing the authentication process. At this writing, though, the default UserDirectoryService impl will invoke getUser(UserEdit) prior to {authenticateUser(String, UserEdit, String)} if the Sakai's local db does not recognize the specified EID. Therefore, clearing the cache at in {authenticateUser(String, UserEdit, String)} at best leads to confusing mid-session attribute changes. In the future we may want to consider strategizing this behavior, or adding an eid parameter to #destroyAuthentication() so cache records can be invalidated on logout without ugly dependencies on the SessionManager

        Specified by:
        authenticateUser in interface org.sakaiproject.user.api.UserDirectoryProvider
        See Also:
        #lookupUserBindDn(String, LDAPConnection)
      • findUserByEmail

        public boolean findUserByEmail​(org.sakaiproject.user.api.UserEdit edit,
                                       String email)
        Locates a user directory entry using an email address as a key. Updates the specified UserEdit with directory attributes if the search is successful. The UserEdit param is technically optional and will be ignored if null.

        All Exceptions are logged and result in a false return, as do searches which yield no results. (A concession to backward compat.)

        Specified by:
        findUserByEmail in interface org.sakaiproject.user.api.UserDirectoryProvider
        Parameters:
        edit - the UserEdit to update
        email - the search key
        Returns:
        boolean true if the search completed without error and found a directory entry
      • getUser

        public boolean getUser​(org.sakaiproject.user.api.UserEdit edit)
        Effectively the same as getUserByEid(edit, edit.getEid()).
        Specified by:
        getUser in interface org.sakaiproject.user.api.UserDirectoryProvider
        See Also:
        getUserByEid(UserEdit, String)
      • getUserbyAid

        public boolean getUserbyAid​(String aid,
                                    org.sakaiproject.user.api.UserEdit user)
        Specified by:
        getUserbyAid in interface org.sakaiproject.user.api.AuthenticationIdUDP
      • getUsers

        public void getUsers​(Collection<org.sakaiproject.user.api.UserEdit> users)
        Similar to iterating over users passing each element to getUser(UserEdit), removing the UserEdit if that method returns false.

        Adds search retry capability if any one lookup fails with a directory error. Empties users and returns if a retry exits exceptionally

        Specified by:
        getUsers in interface org.sakaiproject.user.api.UserDirectoryProvider
      • authenticateWithProviderFirst

        public boolean authenticateWithProviderFirst​(String id)
        By default returns the global boolean setting configured via setAuthenticateWithProviderFirst(boolean).
        Specified by:
        authenticateWithProviderFirst in interface org.sakaiproject.user.api.UserDirectoryProvider
      • getUserByEid

        protected boolean getUserByEid​(org.sakaiproject.user.api.UserEdit userToUpdate,
                                       String eid)
                                throws com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException
        Finds a user record using an eid as an index. Updates the given UserEdit if a directory entry is found.
        Parameters:
        userToUpdate - the UserEdit to update, may be null
        eid - the user ID
        conn - a LDAPConnection to reuse. may be null
        Returns:
        true if the directory entry was found, false if the search returns without error but without results
        Throws:
        com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException - if the search returns with a directory access error
        See Also:
        #getUserByEid(String, LDAPConnection)
      • getUserByEid

        protected LdapUserData getUserByEid​(String eid)
                                     throws com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException
        Finds a user record using an eid as an index.
        Parameters:
        eid - the Sakai EID to search on
        conn - an optional LDAPConnection
        Returns:
        object representing the found LDAP entry, or null if no results
        Throws:
        com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException - if the search returns with a directory access error
      • lookupUserBindDn

        protected String lookupUserBindDn​(String eid)
                                   throws com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException
        Search the directory for a DN corresponding to a user's EID. Typically, this is the same as DN of the object from which the user's attributes are retrieved, but that need not necessarily be the case.
        Parameters:
        eid - the user's Sakai EID
        conn - an optional LDAPConnection
        Returns:
        the user's bindable DN or null if no matching directory entry
        Throws:
        com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException - if the directory query exits with an error
        See Also:
        #getUserByEid(String, LDAPConnection), LdapAttributeMapper.getUserBindDn(LdapUserData)
      • searchDirectoryForSingleEntry

        protected Object searchDirectoryForSingleEntry​(String filter,
                                                       LdapEntryMapper mapper,
                                                       String[] searchResultPhysicalAttributeNames,
                                                       String searchBaseDn)
                                                throws com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException
        Searches the directory for at most one entry matching the specified filter.
        Parameters:
        filter - a search filter
        conn - an optional LDAPConnection
        searchResultPhysicalAttributeNames -
        searchBaseDn -
        Returns:
        a matching LDAPEntry or null if no match
        Throws:
        com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException - if the search exits with an error
      • searchDirectory

        protected List<LdapUserData> searchDirectory​(String filter,
                                                     LdapEntryMapper passedMapper,
                                                     String[] searchResultPhysicalAttributeNames,
                                                     String unescapedSearchBaseDn,
                                                     int maxResults)
                                              throws com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException
        Execute a directory search using the specified filter and connection. Maps each resulting LDAPEntry to a LdapUserData, returning a List of the latter.
        Parameters:
        filter - the search filter
        conn - an optional LDAPConnection
        mapper - result interpreter. Defaults to defaultLdapEntryMapper if null
        searchResultPhysicalAttributeNames - attributes to retrieve. May be null, in which case defaults to LdapAttributeMapper.getSearchResultAttributes().
        searchBaseDn - base DN from which to begin search. May be null, in which case defaults to assigned basePath
        maxResults - maximum number of retrieved LDAP objects. Ignored if <= 0
        Returns:
        An empty List if no results. Will not return null
        Throws:
        com.unboundid.ldap.sdk.migrate.ldapjdk.LDAPException - if thrown by the search
        RuntimeExction - wrapping any non-LDAPException Exception
      • scrubSearchBaseDn

        protected String scrubSearchBaseDn​(String searchBaseDn)
        Responsible for pre-processing base DNs passed to #searchDirectory(String, LDAPConnection, String[], String, int). As implemented, simply checks for a null reference, in which case it returns the currently cached "basePath". Otherwise returns the received String as is.
        Parameters:
        searchBaseDn - a proposed base DN. May be null
        Returns:
        a default base DN or the received DN, if non null. Return value may be null if no default base DN has been configured
        See Also:
        setBasePath(String)
      • scrubSearchResultPhysicalAttributeNames

        protected String[] scrubSearchResultPhysicalAttributeNames​(String[] searchResultPhysicalAttributeNames)
        Responsible for pre-processing search result attribute names passed to #searchDirectory(String, LDAPConnection, String[], String, int). If the given String[]> is null, will use LdapAttributeMapper.getSearchResultAttributes(). If that method returns null will return an empty String[]>. Otherwise returns the received String[]> as-is.
        Parameters:
        searchResultPhysicalAttributeNames -
        Returns:
      • setLdapUser

        public void setLdapUser​(String ldapUser)
        Specified by:
        setLdapUser in interface LdapConnectionManagerConfig
        Parameters:
        ldapUser - The user to bind to LDAP as, typically a manager acct, leave blank for anonymous.
      • setLdapPassword

        public void setLdapPassword​(String ldapPassword)
        Specified by:
        setLdapPassword in interface LdapConnectionManagerConfig
        Parameters:
        ldapPassword - the LDAP password corresponding to the current default bind-as user.
      • setSecureConnection

        public void setSecureConnection​(boolean secureConnection)
        Set to true if LDAP connections should occur over a secure protocol.
        Specified by:
        setSecureConnection in interface LdapConnectionManagerConfig
      • getBasePath

        public String getBasePath()
      • setBasePath

        public void setBasePath​(String basePath)
      • getAttributeMappings

        public Map<String,​String> getAttributeMappings()
        Returns:
        LDAP attribute map, keys are logical names, values are physical names. may be null
      • setAttributeMappings

        public void setAttributeMappings​(Map<String,​String> attributeMappings)
        Parameters:
        attributeMappings - LDAP attribute map, keys are logical names, values are physical names. may be null
      • isFollowReferrals

        public boolean isFollowReferrals()
        Access LDAP referral following configuration
        Specified by:
        isFollowReferrals in interface LdapConnectionManagerConfig
        Returns:
        if true, directory accesses will follow referrals
      • setFollowReferrals

        public void setFollowReferrals​(boolean followReferrals)
        Configures LDAP referral following
        Specified by:
        setFollowReferrals in interface LdapConnectionManagerConfig
        Parameters:
        followReferrals - if true, directory accesses will follow referrals
      • isAutoBind

        public boolean isAutoBind()
        Access the LDAP auto-bind configuration
        Specified by:
        isAutoBind in interface LdapConnectionManagerConfig
        Returns:
        if true connection allocation (LdapConnectionManager#getConnection()) will include a bind attempt
      • setAutoBind

        public void setAutoBind​(boolean autoBind)
        Configure the LDAP auto-bind configuration param autoBind if true connection allocation (LdapConnectionManager#getConnection()) will include a bind attempt
        Specified by:
        setAutoBind in interface LdapConnectionManagerConfig
      • setPoolMaxConns

        public void setPoolMaxConns​(int poolMaxConns)
        Specified by:
        setPoolMaxConns in interface LdapConnectionManagerConfig
        Parameters:
        poolMaxConns - The maximum number of physical connections in the pool
      • getRetryFailedOperationsDueToInvalidConnections

        public boolean getRetryFailedOperationsDueToInvalidConnections()
      • setRetryFailedOperationsDueToInvalidConnections

        public void setRetryFailedOperationsDueToInvalidConnections​(boolean retryFailedOperationsDueToInvalidConnections)
      • getHealthCheckIntervalMillis

        public long getHealthCheckIntervalMillis()
      • setHealthCheckIntervalMillis

        public void setHealthCheckIntervalMillis​(long healthCheckIntervalMillis)
      • getHealthCheckMappings

        public Map<String,​String> getHealthCheckMappings()
      • setHealthCheckMappings

        public void setHealthCheckMappings​(Map<String,​String> healthCheckMappings)
      • getMaxObjectsToQueryFor

        public int getMaxObjectsToQueryFor()
      • setMaxObjectsToQueryFor

        public void setMaxObjectsToQueryFor​(int maxObjectsToQueryFor)
      • setBatchSize

        public void setBatchSize​(int batchSize)
        Specified by:
        setBatchSize in interface LdapConnectionManagerConfig
        Parameters:
        batchSize - The maximum number objects to lookup in one query.
      • setEnableAid

        public void setEnableAid​(boolean enableAid)
        Specified by:
        setEnableAid in interface LdapConnectionManagerConfig
        Parameters:
        enableAid - If true then perform searches for users by Authentication ID.
      • setMaxResultSize

        public void setMaxResultSize​(int maxResultSize)
        Specified by:
        setMaxResultSize in interface LdapConnectionManagerConfig
        Parameters:
        maxResultSize - The maximum number of results to ever get back from LDAP.
      • setLdapAttributeMapper

        public void setLdapAttributeMapper​(LdapAttributeMapper ldapAttributeMapper)
        Assign the LdapAttributeMapper delegate. This delegate handles LDAP attribute mappings and encapsulates filter writing.
        Parameters:
        ldapAttributeMapper - a LdapAttributeMapper. may be null
      • getEidValidator

        public EidValidator getEidValidator()
        Access the service used to verify EIDs prior to executing searches on those values.
        Returns:
        an EidValidator or null if no such dependency has been configured
        See Also:
        isSearchableEid(String)
      • setEidValidator

        public void setEidValidator​(EidValidator eidValidator)
        Assign the service used to verify EIDs prior to executing searches on those values. This field defaults to null indicating that all EIDs are searchable.
        Parameters:
        eidValidator - an EidValidator or null to indicate that all EIDs are searchable.
      • isAllowAuthentication

        public boolean isAllowAuthentication()
        Access the current global authentication "on/off" switch.
        Returns:
        boolean
        See Also:
        setAllowAuthentication(boolean)
      • setAuthenticateAllowed

        public void setAuthenticateAllowed​(boolean authenticateAllowed)
        An alias of setAllowAuthentication(boolean) for backward compatibility with existing customized deployments of this provider which had already implemented this feature.
        Parameters:
        authenticateAllowed -
      • setAuthenticateWithProviderFirst

        public void setAuthenticateWithProviderFirst​(boolean authenticateWithProviderFirst)
        Configure the global return value of authenticateWithProviderFirst(String). Be aware that future development may expose a first-class extension point for custom implementations of authenticateWithProviderFirst(String), in which case the value configured here will be treated as a default rather than an override.
        Parameters:
        authenticateWithProviderFirst -
      • getDisplayId

        public String getDisplayId​(org.sakaiproject.user.api.User user)
        Specified by:
        getDisplayId in interface org.sakaiproject.user.api.DisplayAdvisorUDP
      • getDisplayName

        public String getDisplayName​(org.sakaiproject.user.api.User user)
        Specified by:
        getDisplayName in interface org.sakaiproject.user.api.DisplayAdvisorUDP
      • getSearchScope

        public com.unboundid.ldap.sdk.SearchScope getSearchScope()
        Access the configured search scope for all filters executed by #searchDirectory(String, LDAPConnection, LdapEntryMapper, String[], String, int). int value corresponds to a constant in LDAPConnection: SCOPE_BASE = 0, SCOPE_ONE = 1, SCOPE_SUB = 2. Defaults to DEFAULT_SEARCH_SCOPE.
      • setSearchScope

        public void setSearchScope​(int searchScope)
                            throws IllegalArgumentException
        Set the configured search scope for all filters executed by #searchDirectory(String, LDAPConnection, LdapEntryMapper, String[], String, int). Validated
        Parameters:
        searchScope -
        Throws:
        IllegalArgumentException - if given scope value is invalid
      • searchExternalUsers

        public List<org.sakaiproject.user.api.UserEdit> searchExternalUsers​(String criteria,
                                                                            int first,
                                                                            int last,
                                                                            org.sakaiproject.user.api.UserFactory factory)
        Search for externally provided users that match this criteria in eid, email, first or last name.

        Returns a List of UserEdit objects. This list will be empty if no results are returned or null if your external provider does not implement this interface.
        The list will also be null if the LDAP server returns an error, for example an '(11) Administrative Limit Exceeded' or '(4) Sizelimit Exceeded', due to a search term being too broad and returning too many results.

        See LdapAttributeMapper.getFindUserByCrossAttributeSearchFilter for the filter used.

        Specified by:
        searchExternalUsers in interface org.sakaiproject.user.api.ExternalUserSearchUDP
        Parameters:
        criteria - The search criteria.
        first - The first record position to return. LDAP does not support paging so this value is unused.
        last - The last record position to return. LDAP does not support paging so this value is unused.
        factory - Use this factory's newUser() method to create the UserEdit objects you populate and return in the List.
        Returns:
        A list (UserEdit) of all the users matching the criteria.
      • findUsersByEmail

        public Collection findUsersByEmail​(String email,
                                           org.sakaiproject.user.api.UserFactory factory)
        Find all user objects which have this email address.
        Specified by:
        findUsersByEmail in interface org.sakaiproject.user.api.UsersShareEmailUDP
        Parameters:
        email - The email address string.
        factory - To create all the UserEdit objects you populate and return in the return collection.
        Returns:
        Collection (UserEdit) of user objects that have this email address, or an empty Collection if there are none.
      • isSearchAliases

        public boolean isSearchAliases()
      • setSearchAliases

        public void setSearchAliases​(boolean searchAliases)