/* * 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 javax.servlet.http.HttpServletResponse; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter; /** * Adds form based authentication. All attributes have reasonable defaults * making all parameters are optional. If no {@link #loginPage(String)} is * specified, a default login page will be generated by the framework. * * <h2>Security Filters</h2> * * The following Filters are populated * * <ul> * <li> * {@link UsernamePasswordAuthenticationFilter} * </li> * </ul> * * <h2>Shared Objects Created</h2> * * The following shared objects are populated * * <ul> * <li> {@link AuthenticationEntryPoint} </li> * </ul> * * <h2>Shared Objects Used</h2> * * The following shared objects are used: * * <ul> * <li>{@link HttpSecurity#getAuthenticationManager()}</li> * <li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}</li> * <li>{@link SessionAuthenticationStrategy} - is optionally used. See {@link SessionManagementConfigurer}</li> * <li>{@link DefaultLoginPageViewFilter} - if present will be populated with information from the configuration</li> * </ul> * * @author Rob Winch * @since 3.2 */ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H,FormLoginConfigurer<H>,UsernamePasswordAuthenticationFilter> { /** * Creates a new instance * @see HttpSecurity#formLogin() */ public FormLoginConfigurer() { super(createUsernamePasswordAuthenticationFilter(),"/login"); usernameParameter("username"); passwordParameter("password"); } /** * <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. In general, the login page should * create a form that submits a request with the following requirements to * work with {@link UsernamePasswordAuthenticationFilter}: * </p> * * <ul> * <li>It must be an HTTP POST</li> * <li>It must be submitted to {@link #loginProcessingUrl(String)}</li> * <li>It should include the username as an HTTP parameter by the name of * {@link #usernameParameter(String)}</li> * <li>It should include the password as an HTTP parameter by the name of * {@link #passwordParameter(String)}</li> * </ul> * * <h2>Example login.jsp</h2> * * Login pages can be rendered with any technology you choose so long as the * rules above are followed. Below is an example login.jsp that can be used as * a quick start when using JSP's or as a baseline to translate into another view * technology. * * <pre> * <!-- loginProcessingUrl should correspond to FormLoginConfigurer#loginProcessingUrl. Don't forget to perform a POST --> * <c:url value="/login" var="loginProcessingUrl"/> * <form action="${loginProcessingUrl}" method="post"> * <fieldset> * <legend>Please Login</legend> * <!-- use param.error assuming FormLoginConfigurer#failureUrl contains the query parameter error --> * <c:if test="${param.error != null}"> * <div> * Failed to login. * <c:if test="${SPRING_SECURITY_LAST_EXCEPTION != null}"> * Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" /> * </c:if> * </div> * </c:if> * <!-- the configured LogoutConfigurer#logoutSuccessUrl is /login?logout and contains the query param logout --> * <c:if test="${param.logout != null}"> * <div> * You have been logged out. * </div> * </c:if> * <p> * <label for="username">Username</label> * <input type="text" id="username" name="username"/> * </p> * <p> * <label for="password">Password</label> * <input type="password" id="password" name="password"/> * </p> * <!-- if using RememberMeConfigurer make sure remember-me matches RememberMeConfigurer#rememberMeParameter --> * <p> * <label for="remember-me">Remember Me?</label> * <input type="checkbox" id="remember-me" name="remember-me"/> * </p> * <div> * <button type="submit" class="btn">Log in</button> * </div> * </fieldset> * </form> * </pre> * * @param loginPage * the login page to redirect to if authentication is required * (i.e. "/login") * @return the {@link FormLoginConfigurer} for additional customization */ public FormLoginConfigurer<H> loginPage(String loginPage) { return super.loginPage(loginPage); } /** * The HTTP parameter to look for the username when performing * authentication. Default is "username". * * @param usernameParameter * the HTTP parameter to look for the username when performing * authentication * @return the {@link FormLoginConfigurer} for additional customization */ public FormLoginConfigurer<H> usernameParameter(String usernameParameter) { getAuthenticationFilter().setUsernameParameter(usernameParameter); return this; } /** * The HTTP parameter to look for the password when performing * authentication. Default is "password". * * @param passwordParameter * the HTTP parameter to look for the password when performing * authentication * @return the {@link FormLoginConfigurer} for additional customization */ public FormLoginConfigurer<H> passwordParameter(String passwordParameter) { getAuthenticationFilter().setPasswordParameter(passwordParameter); return this; } @Override public void init(H http) throws Exception { super.init(http); initDefaultLoginFilter(http); } /** * Gets the HTTP parameter that is used to submit the username. * * @return the HTTP parameter that is used to submit the username */ private String getUsernameParameter() { return getAuthenticationFilter().getUsernameParameter(); } /** * Gets the HTTP parameter that is used to submit the password. * * @return the HTTP parameter that is used to submit the password */ private String getPasswordParameter() { return getAuthenticationFilter().getPasswordParameter(); } /** * If available, initializes the {@link DefaultLoginPageViewFilter} shared object. * * @param http the {@link HttpSecurityBuilder} to use */ private void initDefaultLoginFilter(H http) { DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class); if(loginPageGeneratingFilter != null && !isCustomLoginPage()) { loginPageGeneratingFilter.setFormLoginEnabled(true); loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter()); loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter()); loginPageGeneratingFilter.setLoginPageUrl(getLoginPage()); loginPageGeneratingFilter.setFailureUrl(getFailureUrl()); loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl()); } } private static UsernamePasswordAuthenticationFilter createUsernamePasswordAuthenticationFilter() { return new UsernamePasswordAuthenticationFilter() { @Override protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { return "POST".equals(request.getMethod()) && super.requiresAuthentication(request, response); } }; } }