>
> Dave I have written my .own classes handler,configuration(please refer to 
> the attached files).What i observe is My handler is getting registered 
> properly but when i give the credentials the method "
> authenticateUsernamePasswordInternal" is not getting called. properties 
> are same as above .

-- 
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
--- 
You received this message because you are subscribed to the Google Groups "CAS 
Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/a/apereo.org/d/msgid/cas-user/8179af60-49fd-44fc-bcb4-6bd00adae092%40apereo.org.
package org.apereo.cas.config;

import com.google.common.collect.Multimap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.CoreAuthenticationUtils;
import org.apereo.cas.authentication.LdapAuthenticationHandler;
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.authentication.principal.PrincipalNameTransformerUtils;
import org.apereo.cas.authentication.principal.PrincipalResolver;
import org.apereo.cas.authentication.support.DefaultLdapLdapAccountStateHandler;
import org.apereo.cas.authentication.support.DefaultLdapPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.GroovyLdapPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.LdapPasswordPolicyConfiguration;
import org.apereo.cas.authentication.support.LdapPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.OptionalWarningLdapLdapAccountStateHandler;
import org.apereo.cas.authentication.support.RejectResultCodeLdapPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.support.password.PasswordEncoderUtils;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.model.core.authentication.PasswordPolicyProperties;
import org.apereo.cas.configuration.model.support.ldap.LdapAuthenticationProperties;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.LdapUtils;
import org.ldaptive.auth.AuthenticationResponseHandler;
import org.ldaptive.auth.Authenticator;
import org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler;
import org.ldaptive.auth.ext.EDirectoryAuthenticationResponseHandler;
import org.ldaptive.auth.ext.FreeIPAAuthenticationResponseHandler;
import org.ldaptive.auth.ext.PasswordExpirationAuthenticationResponseHandler;
import org.ldaptive.auth.ext.PasswordPolicyAuthenticationResponseHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.io.Resource;

import java.time.Period;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

/**
 * This is {@link LdapAuthenticationConfiguration} that attempts to create
 * relevant authentication handlers for LDAP.
 *
 * @author Misagh Moayyed
 * @author Dmitriy Kopylenko
 * @since 5.0.0
 */
@Configuration("lTldapAuthenticationConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Slf4j
public class LTLdapAuthenticationConfiguration {


    @Autowired
    private CasConfigurationProperties casProperties;

    @Autowired
    @Qualifier("personDirectoryPrincipalResolver")
    private PrincipalResolver personDirectoryPrincipalResolver;

    @Autowired
    @Qualifier("servicesManager")
    private ServicesManager servicesManager;

    @ConditionalOnMissingBean(name = "ldapPrincipalFactory")
    @Bean
    public PrincipalFactory ldapPrincipalFactory() {
        return new DefaultPrincipalFactory();
    }

    @ConditionalOnMissingBean(name = "ldapAuthenticationHandlers")
    @Bean
    @RefreshScope
    public Collection<AuthenticationHandler> ldapAuthenticationHandlers() {
        final Collection<AuthenticationHandler> handlers = new HashSet<>();
        System.out.println("================================");
        System.out.println("In Collection Handlers");
        System.out.println("================================");
        casProperties.getAuthn().getLdap()
                .stream()
                .filter(ldapInstanceConfigurationPredicate())
                .forEach(l -> {
                    final Multimap<String, String> multiMapAttributes = 
                            CoreAuthenticationUtils.transformPrincipalAttributesListIntoMultiMap(l.getPrincipalAttributeList());
                    
                    
                    final Authenticator authenticator = LdapUtils.newLdaptiveAuthenticator(l);
                    System.out.println("=====================Multimap=================================");
                    System.out.println(multiMapAttributes.keySet());

                    
                    final LdapPasswordPolicyHandlingStrategy strategy = createLdapPasswordPolicyHandlingStrategy(l);

                    
                    final LTLdapAuthenticationHandler handler = new LTLdapAuthenticationHandler(l.getName(),
                            servicesManager, ldapPrincipalFactory(), l.getOrder(), authenticator, strategy);
                    handler.setCollectDnAttribute(l.isCollectDnAttribute());

                    final List<String> additionalAttributes = l.getAdditionalAttributes();
                    if (StringUtils.isNotBlank(l.getPrincipalAttributeId())) {
                        additionalAttributes.add(l.getPrincipalAttributeId());
                    }
                    if (StringUtils.isNotBlank(l.getPrincipalDnAttributeName())) {
                        handler.setPrincipalDnAttributeName(l.getPrincipalDnAttributeName());
                    }
                    handler.setAllowMultiplePrincipalAttributeValues(l.isAllowMultiplePrincipalAttributeValues());
                    handler.setAllowMissingPrincipalAttributeValue(l.isAllowMissingPrincipalAttributeValue());
                    handler.setPasswordEncoder(PasswordEncoderUtils.newPasswordEncoder(l.getPasswordEncoder()));
                    handler.setPrincipalNameTransformer(PrincipalNameTransformerUtils.newPrincipalNameTransformer(l.getPrincipalTransformation()));

                    if (StringUtils.isNotBlank(l.getCredentialCriteria())) {
                        
                        handler.setCredentialSelectionPredicate(CoreAuthenticationUtils.newCredentialSelectionPredicate(l.getCredentialCriteria()));
                    }

                    if (StringUtils.isBlank(l.getPrincipalAttributeId())) {
                        
                    } else {
                        handler.setPrincipalIdAttribute(l.getPrincipalAttributeId());
                        
                    }

                    if (l.getPasswordPolicy().isEnabled()) {
                       
                        final LdapPasswordPolicyConfiguration cfg = createLdapPasswordPolicyConfiguration(l, authenticator, multiMapAttributes);
                        handler.setPasswordPolicyConfiguration(cfg);
                    }

                    // final Map<String, Collection<String>> attributes = CollectionUtils.wrap(multiMapAttributes);
                    // handler.setPrincipalAttributeMap(attributes);
                    System.out.println("===========Collection Utils================");
                    System.out.println(CollectionUtils.wrap(multiMapAttributes));

                   
                    handler.initialize();
                    handlers.add(handler);
                });
        return handlers;
    }


    private static Predicate<LdapAuthenticationProperties> ldapInstanceConfigurationPredicate() {
        return l -> {
            if (l.getType() == null) {
               
                return false;
            }
            if (StringUtils.isBlank(l.getLdapUrl())) {
               
                return false;
            }
            return true;
        };
    }

    private LdapPasswordPolicyHandlingStrategy createLdapPasswordPolicyHandlingStrategy(final LdapAuthenticationProperties l) {
        // if (l.getPasswordPolicy().getStrategy() == PasswordPolicyProperties.PasswordPolicyHandlingOptions.REJECT_RESULT_CODE) {
        //     LOGGER.debug("Created LDAP password policy handling strategy based on blacklisted authentication result codes");
        //     return new RejectResultCodeLdapPasswordPolicyHandlingStrategy();
        // }
        
        // final Resource location = l.getPasswordPolicy().getGroovy().getLocation();
        // if (l.getPasswordPolicy().getStrategy() == PasswordPolicyProperties.PasswordPolicyHandlingOptions.GROOVY && location != null) {
        //     LOGGER.debug("Created LDAP password policy handling strategy based on Groovy script [{}]", location);
        //     return new GroovyLdapPasswordPolicyHandlingStrategy(location);
        // }

        // LOGGER.debug("Created default LDAP password policy handling strategy");
        return new DefaultLdapPasswordPolicyHandlingStrategy();
    }

    private LdapPasswordPolicyConfiguration createLdapPasswordPolicyConfiguration(final LdapAuthenticationProperties l,
                                                                                  final Authenticator authenticator,
                                                                                  final Multimap<String, String> attributes) {
        final LdapPasswordPolicyConfiguration cfg =
            new LdapPasswordPolicyConfiguration(l.getPasswordPolicy());
        final Set<AuthenticationResponseHandler> handlers = new HashSet<>();

        final String customPolicyClass = l.getPasswordPolicy().getCustomPolicyClass();
        if (StringUtils.isNotBlank(customPolicyClass)) {
            try {
                
                final Class<AuthenticationResponseHandler> clazz = (Class<AuthenticationResponseHandler>)
                        Class.forName(customPolicyClass);
                handlers.add(clazz.getDeclaredConstructor().newInstance());
            } catch (final Exception e) {
               
            }
        }
        // LOGGER.debug("Password policy authentication response handler is set to accommodate directory type: [{}]", l.getPasswordPolicy().getType());
        switch (l.getPasswordPolicy().getType()) {
            case AD:
                handlers.add(new ActiveDirectoryAuthenticationResponseHandler(Period.ofDays(cfg.getPasswordWarningNumberOfDays())));
                Arrays.stream(ActiveDirectoryAuthenticationResponseHandler.ATTRIBUTES).forEach(a -> {
                    
                    attributes.put(a, a);
                });
                break;
            case EDirectory:
                Arrays.stream(EDirectoryAuthenticationResponseHandler.ATTRIBUTES).forEach(a -> {
                   
                    attributes.put(a, a);
                });
                handlers.add(new EDirectoryAuthenticationResponseHandler(Period.ofDays(cfg.getPasswordWarningNumberOfDays())));
                break;
            default:
                handlers.add(new PasswordPolicyAuthenticationResponseHandler());
                handlers.add(new PasswordExpirationAuthenticationResponseHandler());
                break;
        }
        authenticator.setAuthenticationResponseHandlers((AuthenticationResponseHandler[]) handlers.toArray(new AuthenticationResponseHandler[handlers.size()]));

        

        if (StringUtils.isNotBlank(l.getPasswordPolicy().getWarningAttributeName())
                && StringUtils.isNotBlank(l.getPasswordPolicy().getWarningAttributeValue())) {

            final OptionalWarningLdapLdapAccountStateHandler accountHandler = new OptionalWarningLdapLdapAccountStateHandler();
            accountHandler.setDisplayWarningOnMatch(l.getPasswordPolicy().isDisplayWarningOnMatch());
            accountHandler.setWarnAttributeName(l.getPasswordPolicy().getWarningAttributeName());
            accountHandler.setWarningAttributeValue(l.getPasswordPolicy().getWarningAttributeValue());
            accountHandler.setAttributesToErrorMap(l.getPasswordPolicy().getPolicyAttributes());
            cfg.setAccountStateHandler(accountHandler);
            
        } else {
            final DefaultLdapLdapAccountStateHandler accountHandler = new DefaultLdapLdapAccountStateHandler();
            accountHandler.setAttributesToErrorMap(l.getPasswordPolicy().getPolicyAttributes());
            cfg.setAccountStateHandler(accountHandler);
           
        }
        return cfg;
    }

    @ConditionalOnMissingBean(name = "lTldapAuthenticationEventExecutionPlanConfigurer")
    @Bean
    public AuthenticationEventExecutionPlanConfigurer lTldapAuthenticationEventExecutionPlanConfigurer() {
        System.out.println("================================");
        System.out.println("In Planregister");
        System.out.println("====================================");
        return plan -> ldapAuthenticationHandlers().forEach(handler -> {
           
            plan.registerAuthenticationHandlerWithPrincipalResolver(handler, personDirectoryPrincipalResolver);
        });
    }
}
package org.apereo.cas.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.MessageDescriptor;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.Principal;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.authentication.support.LdapPasswordPolicyConfiguration;
import org.apereo.cas.authentication.support.LdapPasswordPolicyHandlingStrategy;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.UsernamePasswordCredential;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.CollectionUtils;
import org.ldaptive.LdapAttribute;
import org.ldaptive.LdapEntry;
import org.ldaptive.LdapException;
import org.ldaptive.ReturnAttributes;
import org.ldaptive.auth.AuthenticationRequest;
import org.ldaptive.auth.AuthenticationResponse;
import org.ldaptive.auth.AuthenticationResultCode;
import org.ldaptive.auth.Authenticator;

import javax.annotation.PostConstruct;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


@Slf4j
public class LTLdapAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {

    
    /**
     * Mapping of LDAP attribute name to principal attribute name.
     */
    protected Map<String, Collection<String>> principalAttributeMap = new HashMap<>();

    /**
     * Decide how to execute password policy handling, if at all.
     */
    protected LdapPasswordPolicyHandlingStrategy passwordPolicyHandlingStrategy;
    
    /**
     * Performs LDAP authentication given username/password.
     **/
    private final Authenticator authenticator;

    /**
     * Name of attribute to be used for resolved principal.
     */
    private String principalIdAttribute;

    /**
     * Flag indicating whether multiple values are allowed fo principalIdAttribute.
     */
    private boolean allowMultiplePrincipalAttributeValues;

    /**
     * Flag to indicate whether CAS should block authentication
     * if a specific/configured principal id attribute is not found.
     */
    private boolean allowMissingPrincipalAttributeValue = true;

    /**
     * Set of LDAP attributes fetch from an entry as part of the authentication process.
     */
    private String[] authenticatedEntryAttributes = ReturnAttributes.NONE.value();

    private boolean collectDnAttribute;
    /**
     * Name of attribute to be used for principal's DN.
     */
    private String principalDnAttributeName = "principalLdapDn";

    /**
     * Creates a new authentication handler that delegates to the given authenticator.
     *
     * @param name             the name
     * @param servicesManager  the services manager
     * @param principalFactory the principal factory
     * @param order            the order
     * @param authenticator    Ldaptive authenticator component.
     * @param strategy         the strategy
     */
    public LTLdapAuthenticationHandler(final String name, final ServicesManager servicesManager, final PrincipalFactory principalFactory,
                                     final Integer order, final Authenticator authenticator, final LdapPasswordPolicyHandlingStrategy strategy) {
        super(name, servicesManager, principalFactory, order);
        this.authenticator = authenticator;
        this.passwordPolicyHandlingStrategy = strategy;
        System.out.println("==================================");
        System.out.println("In Handler");
        System.out.println("====================================");
    }

    /**
     * Sets the name of the LDAP principal attribute whose value should be used for the
     * principal ID.
     *
     * @param attributeName LDAP attribute name.
     */
    public void setPrincipalIdAttribute(final String attributeName) {
        this.principalIdAttribute = attributeName;
    }

    /**
     * Sets the name of the principal's dn attribute.
     *
     * @param principalDnAttributeName principal's DN attribute name.
     */
    public void setPrincipalDnAttributeName(final String principalDnAttributeName) {
        this.principalDnAttributeName = principalDnAttributeName;
    }

    /**
     * Sets a flag that determines whether multiple values are allowed for the {@link #principalIdAttribute}.
     * This flag only has an effect if {@link #principalIdAttribute} is configured. If multiple values are detected
     * when the flag is false, the first value is used and a warning is logged. If multiple values are detected
     * when the flag is true, an exception is raised.
     *
     * @param allowed True to allow multiple principal ID attribute values, false otherwise.
     */
    public void setAllowMultiplePrincipalAttributeValues(final boolean allowed) {
        this.allowMultiplePrincipalAttributeValues = allowed;
    }

    /**
     * Sets the mapping of additional principal attributes where the key is the LDAP attribute
     * name and the value is the principal attribute name. The key set defines the set of
     * attributes read from the LDAP entry at authentication time. Note that the principal ID attribute
     * should not be listed among these attributes.
     *
     * @param attributeNameMap Map of LDAP attribute name to principal attribute name.
     */
    public void setPrincipalAttributeMap(final Map<String, Collection<String>> attributeNameMap) {
        this.principalAttributeMap = attributeNameMap;
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential upc,
                                                                                        final String originalPassword)
        throws GeneralSecurityException, PreventedException {
        final AuthenticationResponse response;
        System.out.println("==================================");
        System.out.println("In Main Method");
        System.out.println(upc.getUsername());
        System.out.println(upc.getPassword());
        System.out.println("====================================");
        try {
            final AuthenticationRequest request = new AuthenticationRequest(upc.getUsername(),
                    new org.ldaptive.Credential(upc.getPassword()), authenticatedEntryAttributes);
            response = authenticator.authenticate(request);
            System.out.println(response);
        } catch (final LdapException e) {
           
            throw new PreventedException("Unexpected LDAP error", e);
        }
        

        if (!passwordPolicyHandlingStrategy.supports(response)) {
           
            throw new FailedLoginException("Invalid credentials");
        }

        
        final List<MessageDescriptor> messageList = passwordPolicyHandlingStrategy.handle(response,
                (LdapPasswordPolicyConfiguration) getPasswordPolicyConfiguration());
        
        if (response.getResult()) {
            
            final Principal principal = createPrincipal(upc.getUsername(), response.getLdapEntry());
            return createHandlerResult(upc, principal, messageList);
        }

        if (AuthenticationResultCode.DN_RESOLUTION_FAILURE == response.getAuthenticationResultCode()) {
            
            throw new AccountNotFoundException(upc.getUsername() + " not found.");
        }
        throw new FailedLoginException("Invalid credentials");
    }

    /**
     * Creates a CAS principal with attributes if the LDAP entry contains principal attributes.
     *
     * @param username  Username that was successfully authenticated which is used for principal ID when
     *                  {@link #setPrincipalIdAttribute(String)} is not specified.
     * @param ldapEntry LDAP entry that may contain principal attributes.
     * @return Principal if the LDAP entry contains at least a principal ID attribute value, null otherwise.
     * @throws LoginException On security policy errors related to principal creation.
     */
    protected Principal createPrincipal(final String username, final LdapEntry ldapEntry) throws LoginException {
       
        final String id = getLdapPrincipalIdentifier(username, ldapEntry);
        

        final Map<String, Object> attributeMap = collectAttributesForLdapEntry(ldapEntry, id);

       
        return this.principalFactory.createPrincipal(id, attributeMap);
    }

    /**
     * Collect attributes for ldap entry.
     *
     * @param ldapEntry the ldap entry
     * @param username  the username
     * @return the map
     */
    protected Map<String, Object> collectAttributesForLdapEntry(final LdapEntry ldapEntry, final String username) {
        final Map<String, Object> attributeMap = new LinkedHashMap<>(this.principalAttributeMap.size());
        
        this.principalAttributeMap.forEach((key, attributeNames) -> {
            final LdapAttribute attr = ldapEntry.getAttribute(key);
            if (attr != null) {
                

                if (attributeNames.isEmpty()) {
                    
                    attributeMap.put(key, CollectionUtils.wrap(attr.getStringValues()));
                } else {
                    attributeNames.forEach(s -> {
                       
                        attributeMap.put(s, CollectionUtils.wrap(attr.getStringValues()));
                    });
                }
            } else {
                
            }
        });

        if (this.collectDnAttribute) {
           
            attributeMap.put(this.principalDnAttributeName, ldapEntry.getDn());
        }
        
        return attributeMap;
    }

    /**
     * Gets ldap principal identifier. If the principal id attribute is defined, it's retrieved.
     * If no attribute value is found, a warning is generated and the provided username is used instead.
     * If no attribute is defined, username is used instead.
     *
     * @param username  the username
     * @param ldapEntry the ldap entry
     * @return the ldap principal identifier
     * @throws LoginException in case the principal id cannot be determined.
     */
    protected String getLdapPrincipalIdentifier(final String username, final LdapEntry ldapEntry) throws LoginException {
        if (StringUtils.isNotBlank(this.principalIdAttribute)) {
            final LdapAttribute principalAttr = ldapEntry.getAttribute(this.principalIdAttribute);
            if (principalAttr == null || principalAttr.size() == 0) {

                if (this.allowMissingPrincipalAttributeValue) {
                    
                    return username;
                }
                
                throw new LoginException("Principal id attribute is not found for " + principalAttr);
            }

            if (principalAttr.size() > 1) {
                if (!this.allowMultiplePrincipalAttributeValues) {
                    throw new LoginException("Multiple principal values are not allowed: " + principalAttr);
                }
                
            }
            
            return principalAttr.getStringValue();
        }

       
        return username;
    }

    public void setAllowMissingPrincipalAttributeValue(final boolean allowMissingPrincipalAttributeValue) {
        this.allowMissingPrincipalAttributeValue = allowMissingPrincipalAttributeValue;
    }

    /**
     * Initialize the handler, setup the authentication entry attributes.
     */
    @PostConstruct
    public void initialize() {
        /*
         * Use a set to ensure we ignore duplicates.
         */
        final Set<String> attributes = new HashSet<>();

       
        if (StringUtils.isNotBlank(this.principalIdAttribute)) {
           
            attributes.add(this.principalIdAttribute);
        }
        if (this.principalAttributeMap != null && !this.principalAttributeMap.isEmpty()) {
            final Set<String> attrs = this.principalAttributeMap.keySet();
            attributes.addAll(attrs);
            
        }

        if (authenticator.getReturnAttributes() != null) {
            final List<String> authenticatorAttributes = CollectionUtils.wrapList(authenticator.getReturnAttributes());
            if (!authenticatorAttributes.isEmpty()) {
                
                attributes.removeIf(authenticatorAttributes::contains);
            }
        }
        this.authenticatedEntryAttributes = attributes.toArray(new String[attributes.size()]);
        
    }

    public void setCollectDnAttribute(final boolean collectDnAttribute) {
        this.collectDnAttribute = collectDnAttribute;
    }
}

Reply via email to