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;
}
}