org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.java

Source

/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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 org.springframework.security.config.annotation.authentication.builders;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsAwareConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.Assert;

/**
 * {@link SecurityBuilder} used to create an {@link AuthenticationManager}. Allows for
 * easily building in memory authentication, LDAP authentication, JDBC based
 * authentication, adding {@link UserDetailsService}, and adding
 * {@link AuthenticationProvider}'s.
 *
 * @author Rob Winch
 * @since 3.2
 */
public class AuthenticationManagerBuilder
        extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
        implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
    private final Log logger = LogFactory.getLog(getClass());

    private AuthenticationManager parentAuthenticationManager;
    private List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
    private UserDetailsService defaultUserDetailsService;
    private Boolean eraseCredentials;
    private AuthenticationEventPublisher eventPublisher;

    /**
     * Creates a new instance
     * @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
     */
    public AuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
        super(objectPostProcessor, true);
    }

    /**
     * Allows providing a parent {@link AuthenticationManager} that will be tried if this
     * {@link AuthenticationManager} was unable to attempt to authenticate the provided
     * {@link Authentication}.
     *
     * @param authenticationManager the {@link AuthenticationManager} that should be used
     * if the current {@link AuthenticationManager} was unable to attempt to authenticate
     * the provided {@link Authentication}.
     * @return the {@link AuthenticationManagerBuilder} for further adding types of
     * authentication
     */
    public AuthenticationManagerBuilder parentAuthenticationManager(AuthenticationManager authenticationManager) {
        if (authenticationManager instanceof ProviderManager) {
            eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());
        }
        this.parentAuthenticationManager = authenticationManager;
        return this;
    }

    /**
     * Sets the {@link AuthenticationEventPublisher}
     *
     * @param eventPublisher the {@link AuthenticationEventPublisher} to use
     * @return the {@link AuthenticationManagerBuilder} for further customizations
     */
    public AuthenticationManagerBuilder authenticationEventPublisher(AuthenticationEventPublisher eventPublisher) {
        Assert.notNull(eventPublisher, "AuthenticationEventPublisher cannot be null");
        this.eventPublisher = eventPublisher;
        return this;
    }

    /**
     *
     *
     * @param eraseCredentials true if {@link AuthenticationManager} should clear the
     * credentials from the {@link Authentication} object after authenticating
     * @return the {@link AuthenticationManagerBuilder} for further customizations
     */
    public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
        this.eraseCredentials = eraseCredentials;
        return this;
    }

    /**
     * Add in memory authentication to the {@link AuthenticationManagerBuilder} and return
     * a {@link InMemoryUserDetailsManagerConfigurer} to allow customization of the in
     * memory authentication.
     *
     * <p>
     * This method also ensure that a {@link UserDetailsService} is available for the
     * {@link #getDefaultUserDetailsService()} method. Note that additional
     * {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
     * default.
     * </p>
     *
     * @return a {@link InMemoryUserDetailsManagerConfigurer} to allow customization of
     * the in memory authentication
     * @throws Exception if an error occurs when adding the in memory authentication
     */
    public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
            throws Exception {
        return apply(new InMemoryUserDetailsManagerConfigurer<>());
    }

    /**
     * Add JDBC authentication to the {@link AuthenticationManagerBuilder} and return a
     * {@link JdbcUserDetailsManagerConfigurer} to allow customization of the JDBC
     * authentication.
     *
     * <p>
     * When using with a persistent data store, it is best to add users external of
     * configuration using something like <a href="https://flywaydb.org/">Flyway</a> or <a
     * href="https://www.liquibase.org/">Liquibase</a> to create the schema and adding
     * users to ensure these steps are only done once and that the optimal SQL is used.
     * </p>
     *
     * <p>
     * This method also ensure that a {@link UserDetailsService} is available for the
     * {@link #getDefaultUserDetailsService()} method. Note that additional
     * {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
     * default. See the <a href=
     * "https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#user-schema"
     * >User Schema</a> section of the reference for the default schema.
     * </p>
     *
     * @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
     * JDBC authentication
     * @throws Exception if an error occurs when adding the JDBC authentication
     */
    public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
        return apply(new JdbcUserDetailsManagerConfigurer<>());
    }

    /**
     * Add authentication based upon the custom {@link UserDetailsService} that is passed
     * in. It then returns a {@link DaoAuthenticationConfigurer} to allow customization of
     * the authentication.
     *
     * <p>
     * This method also ensure that the {@link UserDetailsService} is available for the
     * {@link #getDefaultUserDetailsService()} method. Note that additional
     * {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
     * default.
     * </p>
     *
     * @return a {@link DaoAuthenticationConfigurer} to allow customization of the DAO
     * authentication
     * @throws Exception if an error occurs when adding the {@link UserDetailsService}
     * based authentication
     */
    public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
            T userDetailsService) throws Exception {
        this.defaultUserDetailsService = userDetailsService;
        return apply(new DaoAuthenticationConfigurer<>(userDetailsService));
    }

    /**
     * Add LDAP authentication to the {@link AuthenticationManagerBuilder} and return a
     * {@link LdapAuthenticationProviderConfigurer} to allow customization of the LDAP
     * authentication.
     *
     * <p>
     * This method <b>does NOT</b> ensure that a {@link UserDetailsService} is available
     * for the {@link #getDefaultUserDetailsService()} method.
     *
     * @return a {@link LdapAuthenticationProviderConfigurer} to allow customization of
     * the LDAP authentication
     * @throws Exception if an error occurs when adding the LDAP authentication
     */
    public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication()
            throws Exception {
        return apply(new LdapAuthenticationProviderConfigurer<>());
    }

    /**
     * Add authentication based upon the custom {@link AuthenticationProvider} that is
     * passed in. Since the {@link AuthenticationProvider} implementation is unknown, all
     * customizations must be done externally and the {@link AuthenticationManagerBuilder}
     * is returned immediately.
     *
     * <p>
     * This method <b>does NOT</b> ensure that the {@link UserDetailsService} is available
     * for the {@link #getDefaultUserDetailsService()} method.
     *
     * Note that an {@link Exception} might be thrown if an error occurs when adding the {@link AuthenticationProvider}.
     *
     * @return a {@link AuthenticationManagerBuilder} to allow further authentication to
     * be provided to the {@link AuthenticationManagerBuilder}
     */
    public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
        this.authenticationProviders.add(authenticationProvider);
        return this;
    }

    @Override
    protected ProviderManager performBuild() throws Exception {
        if (!isConfigured()) {
            logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
            return null;
        }
        ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
        if (eraseCredentials != null) {
            providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
        }
        if (eventPublisher != null) {
            providerManager.setAuthenticationEventPublisher(eventPublisher);
        }
        providerManager = postProcess(providerManager);
        return providerManager;
    }

    /**
     * Determines if the {@link AuthenticationManagerBuilder} is configured to build a non
     * null {@link AuthenticationManager}. This means that either a non-null parent is
     * specified or at least one {@link AuthenticationProvider} has been specified.
     *
     * <p>
     * When using {@link SecurityConfigurer} instances, the
     * {@link AuthenticationManagerBuilder} will not be configured until the
     * {@link SecurityConfigurer#configure(SecurityBuilder)} methods. This means a
     * {@link SecurityConfigurer} that is last could check this method and provide a
     * default configuration in the {@link SecurityConfigurer#configure(SecurityBuilder)}
     * method.
     *
     * @return true, if {@link AuthenticationManagerBuilder} is configured, otherwise false
     */
    public boolean isConfigured() {
        return !authenticationProviders.isEmpty() || parentAuthenticationManager != null;
    }

    /**
     * Gets the default {@link UserDetailsService} for the
     * {@link AuthenticationManagerBuilder}. The result may be null in some circumstances.
     *
     * @return the default {@link UserDetailsService} for the
     * {@link AuthenticationManagerBuilder}
     */
    public UserDetailsService getDefaultUserDetailsService() {
        return this.defaultUserDetailsService;
    }

    /**
     * Captures the {@link UserDetailsService} from any {@link UserDetailsAwareConfigurer}
     * .
     *
     * @param configurer the {@link UserDetailsAwareConfigurer} to capture the
     * {@link UserDetailsService} from.
     * @return the {@link UserDetailsAwareConfigurer} for further customizations
     * @throws Exception if an error occurs
     */
    private <C extends UserDetailsAwareConfigurer<AuthenticationManagerBuilder, ? extends UserDetailsService>> C apply(
            C configurer) throws Exception {
        this.defaultUserDetailsService = configurer.getUserDetailsService();
        return super.apply(configurer);
    }
}