RememberMe JavaConfig Validation

Add validation when rememberMeServices and rememberMeCookieName are
provided

Fixes gh-3909
This commit is contained in:
Eddú Meléndez 2016-06-02 23:44:14 +10:00 committed by Rob Winch
parent 8f880aea0e
commit 87224f62e4
2 changed files with 75 additions and 8 deletions

View File

@ -79,12 +79,13 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
*/ */
public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<RememberMeConfigurer<H>, H> { extends AbstractHttpConfigurer<RememberMeConfigurer<H>, H> {
public static final String REMEMBER_ME = "remember-me";
private AuthenticationSuccessHandler authenticationSuccessHandler; private AuthenticationSuccessHandler authenticationSuccessHandler;
private String key; private String key;
private RememberMeServices rememberMeServices; private RememberMeServices rememberMeServices;
private LogoutHandler logoutHandler; private LogoutHandler logoutHandler;
private String rememberMeParameter = "remember-me"; private String rememberMeParameter = REMEMBER_ME;
private String rememberMeCookieName = "remember-me"; private String rememberMeCookieName = REMEMBER_ME;
private String rememberMeCookieDomain; private String rememberMeCookieDomain;
private PersistentTokenRepository tokenRepository; private PersistentTokenRepository tokenRepository;
private UserDetailsService userDetailsService; private UserDetailsService userDetailsService;
@ -244,6 +245,7 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void init(H http) throws Exception { public void init(H http) throws Exception {
validateInput();
String key = getKey(); String key = getKey();
RememberMeServices rememberMeServices = getRememberMeServices(http, key); RememberMeServices rememberMeServices = getRememberMeServices(http, key);
http.setSharedObject(RememberMeServices.class, rememberMeServices); http.setSharedObject(RememberMeServices.class, rememberMeServices);
@ -273,6 +275,17 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
http.addFilter(rememberMeFilter); http.addFilter(rememberMeFilter);
} }
/**
* Validate rememberMeServices and rememberMeCookieName have not been set at
* the same time.
*/
private void validateInput() {
if (this.rememberMeServices != null && this.rememberMeCookieName != REMEMBER_ME) {
throw new IllegalArgumentException("Can not set rememberMeCookieName " +
"and custom rememberMeServices.");
}
}
/** /**
* Returns the HTTP parameter used to indicate to remember the user at time of login. * Returns the HTTP parameter used to indicate to remember the user at time of login.
* @return the HTTP parameter used to indicate to remember the user * @return the HTTP parameter used to indicate to remember the user

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,24 +17,27 @@ package org.springframework.security.config.annotation.web.configurers
import javax.servlet.http.Cookie import javax.servlet.http.Cookie
import org.springframework.beans.factory.BeanCreationException
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.mock.web.MockFilterChain import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.mock.web.MockHttpSession import org.springframework.mock.web.MockHttpSession
import org.springframework.security.authentication.RememberMeAuthenticationToken import org.springframework.security.authentication.RememberMeAuthenticationToken
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.AnyObjectPostProcessor import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContext import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager
import org.springframework.security.web.authentication.RememberMeServices
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter
import org.springframework.security.web.context.HttpRequestResponseHolder import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository import org.springframework.security.web.context.HttpSessionSecurityContextRepository
@ -43,6 +46,7 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
* Tests for RememberMeConfigurer that flex edge cases. {@link NamespaceRememberMeTests} demonstrate mapping of the XML namespace to Java Config. * Tests for RememberMeConfigurer that flex edge cases. {@link NamespaceRememberMeTests} demonstrate mapping of the XML namespace to Java Config.
* *
* @author Rob Winch * @author Rob Winch
* @author Eddú Meléndez
*/ */
public class RememberMeConfigurerTests extends BaseSpringSpec { public class RememberMeConfigurerTests extends BaseSpringSpec {
@ -155,7 +159,7 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
response.getRedirectedUrl() == "http://localhost/login" response.getRedirectedUrl() == "http://localhost/login"
} }
def "http/remember-me with cookied domain"() { def "http/remember-me with cookie domain"() {
setup: setup:
loadConfig(RememberMeCookieDomainConfig) loadConfig(RememberMeCookieDomainConfig)
when: when:
@ -172,6 +176,29 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
rememberMeCookie.domain == "spring.io" rememberMeCookie.domain == "spring.io"
} }
def "http/remember-me with cookie name and custom rememberMeServices throws BeanCreationException"() {
setup:
RememberMeCookieDomainCustomRememberMeServicesConfig.REMEMBER_ME = Mock(RememberMeServices)
when:
loadConfig(RememberMeCookieDomainCustomRememberMeServicesConfig)
then: "response contains remember me cookie"
def ex = thrown(BeanCreationException)
ex instanceof BeanCreationException
}
def "http/remember-me with cookie name and custom rememberMeServices throws IllegalArgumentException"() {
setup:
def httpSec = new HttpSecurity(Mock(ObjectPostProcessor), Mock(AuthenticationManagerBuilder), [:])
RememberMeConfigurer<HttpSecurity> config = new RememberMeConfigurer<HttpSecurity>();
config.rememberMeCookieName("COOKIE_NAME")
config.rememberMeServices(Mock(RememberMeServices))
when:
config.init(httpSec)
then:
IllegalArgumentException ex = thrown()
ex.message == 'Can not set rememberMeCookieName and custom rememberMeServices.'
}
@EnableWebSecurity @EnableWebSecurity
static class RememberMeConfig extends WebSecurityConfigurerAdapter { static class RememberMeConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
@ -213,6 +240,33 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
} }
} }
@EnableWebSecurity
static class RememberMeCookieDomainCustomRememberMeServicesConfig extends
WebSecurityConfigurerAdapter {
static RememberMeServices REMEMBER_ME
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
.rememberMeCookieName("SPRING_COOKIE_DOMAIN")
.rememberMeCookieDomain("spring.io")
.rememberMeServices(REMEMBER_ME);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
Cookie createRememberMeCookie() { Cookie createRememberMeCookie() {
MockHttpServletRequest request = new MockHttpServletRequest() MockHttpServletRequest request = new MockHttpServletRequest()
MockHttpServletResponse response = new MockHttpServletResponse() MockHttpServletResponse response = new MockHttpServletResponse()