package org.apereo.cas.authorization; import org.apereo.cas.configuration.support.Beans; import org.ldaptive.ConnectionFactory; import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; import org.ldaptive.LdapException; import org.ldaptive.Response; import org.ldaptive.SearchExecutor; import org.ldaptive.SearchResult; import org.pac4j.core.authorization.generator.AuthorizationGenerator; import org.pac4j.core.context.WebContext; import org.pac4j.core.exception.AccountNotFoundException; import org.pac4j.core.profile.CommonProfile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.Assert; import java.util.Collections; /** * This is {@link BaseUseAttributesAuthorizationGenerator}. * * @author Misagh Moayyed * @since 5.1.0 */ public abstract class BaseUseAttributesAuthorizationGenerator implements AuthorizationGenerator<CommonProfile> { private static final Logger LOGGER = LoggerFactory.getLogger(BaseUseAttributesAuthorizationGenerator.class); /** * Search connection factory. */ protected final ConnectionFactory connectionFactory; private final SearchExecutor userSearchExecutor; private final boolean allowMultipleResults; public BaseUseAttributesAuthorizationGenerator(final ConnectionFactory connectionFactory, final SearchExecutor userSearchExecutor, final boolean allowMultipleResults) { this.connectionFactory = connectionFactory; this.userSearchExecutor = userSearchExecutor; this.allowMultipleResults = allowMultipleResults; } /** * Add profile roles. * * @param userEntry the user entry * @param profile the profile * @param attribute the attribute * @param prefix the prefix */ protected void addProfileRoles(final LdapEntry userEntry, final CommonProfile profile, final LdapAttribute attribute, final String prefix) { addProfileRolesFromAttributes(profile, attribute, prefix); } /** * Add profile roles from attributes. * * @param profile the profile * @param ldapAttribute the ldap attribute * @param prefix the prefix */ protected void addProfileRolesFromAttributes(final CommonProfile profile, final LdapAttribute ldapAttribute, final String prefix) { ldapAttribute.getStringValues().forEach(value -> profile.addRole(prefix.concat(value.toUpperCase()))); } @Override public CommonProfile generate(final WebContext context, final CommonProfile profile) { Assert.notNull(this.connectionFactory, "connectionFactory must not be null"); Assert.notNull(this.userSearchExecutor, "userSearchExecutor must not be null"); final String username = profile.getId(); final SearchResult userResult; try { LOGGER.debug("Attempting to get details for user [{}].", username); final Response<SearchResult> response = this.userSearchExecutor.search( this.connectionFactory, Beans.newLdaptiveSearchFilter(this.userSearchExecutor.getSearchFilter().getFilter(), Beans.LDAP_SEARCH_FILTER_DEFAULT_PARAM_NAME, Collections.singletonList(username))); LOGGER.debug("LDAP user search response: [{}]", response); userResult = response.getResult(); if (userResult.size() == 0) { throw new RuntimeException(new AccountNotFoundException(username + " not found.")); } if (userResult.size() > 1 && !this.allowMultipleResults) { throw new IllegalStateException( "Found multiple results for user which is not allowed (allowMultipleResults=false)."); } final LdapEntry userEntry = userResult.getEntry(); return generateAuthorizationForLdapEntry(profile, userEntry); } catch (final LdapException e) { throw new RuntimeException("LDAP error fetching details for user.", e); } } /** * Generate authorization for ldap entry. * * @param profile the profile * @param userEntry the user entry * @return the common profile */ protected CommonProfile generateAuthorizationForLdapEntry(final CommonProfile profile, final LdapEntry userEntry) { return profile; } }