/*
* 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
*
* http://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.web.configurers;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
/**
* Base class for confuring {@link AbstractAuthenticationFilterConfigurer}. This is intended for internal use only.
*
* @see FormLoginConfigurer
* @see OpenIDLoginConfigurer
*
* @param T refers to "this" for returning the current configurer
* @param F refers to the {@link AbstractAuthenticationProcessingFilter} that is being built
*
* @author Rob Winch
* @since 3.2
*/
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>,T extends AbstractAuthenticationFilterConfigurer<B,T, F>, F extends AbstractAuthenticationProcessingFilter> extends AbstractHttpConfigurer<B> {
private final F authFilter;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
private boolean customLoginPage;
private String loginPage;
private String loginProcessingUrl;
private AuthenticationFailureHandler failureHandler;
private boolean permitAll;
private String failureUrl;
/**
* Creates a new instance
* @param authenticationFilter the {@link AbstractAuthenticationProcessingFilter} to use
* @param defaultLoginProcessingUrl the default URL to use for {@link #loginProcessingUrl(String)}
*/
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter, String defaultLoginProcessingUrl) {
this.authFilter = authenticationFilter;
loginUrl("/login");
failureUrl("/login?error");
loginProcessingUrl(defaultLoginProcessingUrl);
this.customLoginPage = false;
}
/**
* Specifies where users will go after authenticating successfully if they
* have not visited a secured page prior to authenticating. This is a
* shortcut for calling {@link #defaultSuccessUrl(String)}.
*
* @param defaultSuccessUrl
* the default success url
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T defaultSuccessUrl(String defaultSuccessUrl) {
return defaultSuccessUrl(defaultSuccessUrl, false);
}
/**
* Specifies where users will go after authenticating successfully if they
* have not visited a secured page prior to authenticating or
* {@code alwaysUse} is true. This is a shortcut for calling
* {@link #successHandler(AuthenticationSuccessHandler)}.
*
* @param defaultSuccessUrl
* the default success url
* @param alwaysUse
* true if the {@code defaultSuccesUrl} should be used after
* authentication despite if a protected page had been previously
* visited
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse) {
SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
handler.setDefaultTargetUrl(defaultSuccessUrl);
handler.setAlwaysUseDefaultTargetUrl(alwaysUse);
return successHandler(handler);
}
/**
* Specifies the URL used to log in. If the request matches the URL and is an HTTP POST, the
* {@link UsernamePasswordAuthenticationFilter} will attempt to authenticate
* the request. Otherwise, if the request matches the URL the user will be sent to the login form.
*
* @param loginUrl the URL used to perform authentication
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T loginUrl(String loginUrl) {
loginProcessingUrl(loginUrl);
return loginPage(loginUrl);
}
/**
* Specifies the URL to validate the credentials.
*
* @param loginProcessingUrl
* the URL to validate username and password
* @return the {@link FormLoginConfigurer} for additional customization
*/
public T loginProcessingUrl(String loginProcessingUrl) {
this.loginProcessingUrl = loginProcessingUrl;
authFilter.setFilterProcessesUrl(loginProcessingUrl);
return getSelf();
}
/**
* Specifies a custom {@link AuthenticationDetailsSource}. The default is {@link WebAuthenticationDetailsSource}.
*
* @param authenticationDetailsSource the custom {@link AuthenticationDetailsSource}
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T authenticationDetailsSource(AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
this.authenticationDetailsSource = authenticationDetailsSource;
return getSelf();
}
/**
* Specifies the {@link AuthenticationSuccessHandler} to be used. The
* default is {@link SavedRequestAwareAuthenticationSuccessHandler} with no
* additional properites set.
*
* @param successHandler
* the {@link AuthenticationSuccessHandler}.
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T successHandler(AuthenticationSuccessHandler successHandler) {
this.successHandler = successHandler;
return getSelf();
}
/**
* Equivalent of invoking permitAll(true)
* @return
*/
public final T permitAll() {
return permitAll(true);
}
/**
* Ensures the urls for {@link #failureUrl(String)} and
* {@link #loginUrl(String)} are granted access to any user.
*
* @param permitAll true to grant access to the URLs false to skip this step
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T permitAll(boolean permitAll) {
this.permitAll = permitAll;
return getSelf();
}
/**
* The URL to send users if authentication fails. This is a shortcut for
* invoking {@link #failureHandler(AuthenticationFailureHandler)}. The
* default is "/login?error".
*
* @param authenticationFailureUrl
* the URL to send users if authentication fails (i.e.
* "/login?error").
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T failureUrl(String authenticationFailureUrl) {
T result = failureHandler(new SimpleUrlAuthenticationFailureHandler(authenticationFailureUrl));
this.failureUrl = authenticationFailureUrl;
return result;
}
/**
* Specifies the {@link AuthenticationFailureHandler} to use when
* authentication fails. The default is redirecting to "/login?error" using
* {@link SimpleUrlAuthenticationFailureHandler}
*
* @param authenticationFailureHandler
* the {@link AuthenticationFailureHandler} to use when
* authentication fails.
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T failureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
this.failureUrl = null;
this.failureHandler = authenticationFailureHandler;
return getSelf();
}
@Override
public void init(B http) throws Exception {
if(permitAll) {
PermitAllSupport.permitAll(http, loginPage, loginProcessingUrl, failureUrl);
}
http.setSharedObject(AuthenticationEntryPoint.class, postProcess(authenticationEntryPoint));
}
@Override
public void configure(B http) throws Exception {
PortMapper portMapper = http.getSharedObject(PortMapper.class);
if(portMapper != null) {
authenticationEntryPoint.setPortMapper(portMapper);
}
authFilter.setAuthenticationManager(http.getAuthenticationManager());
authFilter.setAuthenticationSuccessHandler(successHandler);
authFilter.setAuthenticationFailureHandler(failureHandler);
if(authenticationDetailsSource != null) {
authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
}
SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
if(sessionAuthenticationStrategy != null) {
authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if(rememberMeServices != null) {
authFilter.setRememberMeServices(rememberMeServices);
}
F filter = postProcess(authFilter);
http.addFilter(filter);
}
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link WebSecurityConfigurerAdapter} a default login page will be
* generated when this attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjuction with
* {@link WebSecurityConfigurerAdapter}, users are required to process the
* specified URL to generate a login page.
* </p>
*/
protected T loginPage(String loginPage) {
this.loginPage = loginPage;
this.authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(loginPage);
this.customLoginPage = true;
return getSelf();
}
/**
*
* @return true if a custom login page has been specified, else false
*/
public final boolean isCustomLoginPage() {
return customLoginPage;
}
/**
* Gets the Authentication Filter
* @return
*/
protected final F getAuthenticationFilter() {
return authFilter;
}
/**
* Gets the login page
* @return the login page
*/
protected final String getLoginPage() {
return loginPage;
}
/**
* Gets the URL to submit an authentication request to (i.e. where
* username/password must be submitted)
*
* @return the URL to submit an authentication request to
*/
protected final String getLoginProcessingUrl() {
return loginProcessingUrl;
}
/**
* Gets the URL to send users to if authentication fails
* @return
*/
protected final String getFailureUrl() {
return failureUrl;
}
@SuppressWarnings("unchecked")
private T getSelf() {
return (T) this;
}
}