Allow configuration of anonymous through nested builder

Issue: gh-5557
This commit is contained in:
Eleftheria Stein 2019-07-04 15:08:00 -04:00
parent a5943fbafb
commit ae8e12f049
2 changed files with 168 additions and 8 deletions

View File

@ -1531,6 +1531,76 @@ public final class HttpSecurity extends
return getOrApply(new AnonymousConfigurer<>()); return getOrApply(new AnonymousConfigurer<>());
} }
/**
* Allows configuring how an anonymous user is represented. This is automatically
* applied when used in conjunction with {@link WebSecurityConfigurerAdapter}. By
* default anonymous users will be represented with an
* {@link org.springframework.security.authentication.AnonymousAuthenticationToken}
* and contain the role "ROLE_ANONYMOUS".
*
* <h2>Example Configuration</h2>
*
* The following configuration demonstrates how to specify that anonymous users should
* contain the role "ROLE_ANON" instead.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class AnononymousSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .authorizeRequests(authorizeRequests ->
* authorizeRequests
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* )
* .formLogin(withDefaults())
* // sample anonymous customization
* .anonymous(anonymous ->
* anonymous
* .authorities(&quot;ROLE_ANON&quot;)
* )
* }
* }
* </pre>
*
* The following demonstrates how to represent anonymous users as null. Note that this
* can cause {@link NullPointerException} in code that assumes anonymous
* authentication is enabled.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class AnonymousSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .authorizeRequests(authorizeRequests ->
* authorizeRequests
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* )
* .formLogin(withDefaults())
* // sample anonymous customization
* .anonymous(anonymous ->
* anonymous.disabled()
* );
* }
* }
* </pre>
*
* @param anonymousCustomizer the {@link Customizer} to provide more options for
* the {@link AnonymousConfigurer}
* @return the {@link HttpSecurity} for further customizations
* @throws Exception
*/
public HttpSecurity anonymous(Customizer<AnonymousConfigurer<HttpSecurity>> anonymousCustomizer) throws Exception {
anonymousCustomizer.customize(getOrApply(new AnonymousConfigurer<>()));
return HttpSecurity.this;
}
/** /**
* Specifies to support form based authentication. If * Specifies to support form based authentication. If
* {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page * {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 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.
@ -18,18 +18,22 @@ package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
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.config.test.SpringTestRule; import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/** /**
* @author Rob Winch * @author Rob Winch
@ -44,7 +48,7 @@ public class AnonymousConfigurerTests {
@Test @Test
public void requestWhenAnonymousTwiceInvokedThenDoesNotOverride() throws Exception { public void requestWhenAnonymousTwiceInvokedThenDoesNotOverride() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverride.class).autowire(); this.spring.register(InvokeTwiceDoesNotOverride.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/")) this.mockMvc.perform(get("/"))
.andExpect(content().string("principal")); .andExpect(content().string("principal"));
@ -63,13 +67,99 @@ public class AnonymousConfigurerTests {
.and() .and()
.anonymous(); .anonymous();
} }
}
@RestController @Test
static class PrincipalController { public void requestWhenAnonymousPrincipalInLambdaThenPrincipalUsed() throws Exception {
@GetMapping("/") this.spring.register(AnonymousPrincipalInLambdaConfig.class, PrincipalController.class).autowire();
String principal(@AuthenticationPrincipal String principal) {
return principal; this.mockMvc.perform(get("/"))
} .andExpect(content().string("principal"));
}
@EnableWebSecurity
@EnableWebMvc
static class AnonymousPrincipalInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.anonymous(anonymous ->
anonymous
.principal("principal")
);
// @formatter:on
}
}
@Test
public void requestWhenAnonymousDisabledInLambdaThenRespondsWithForbidden() throws Exception {
this.spring.register(AnonymousDisabledInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class AnonymousDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.anyRequest().permitAll()
)
.anonymous(AbstractHttpConfigurer::disable);
// @formatter:on
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void requestWhenAnonymousWithDefaultsInLambdaThenRespondsWithOk() throws Exception {
this.spring.register(AnonymousWithDefaultsInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class AnonymousWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.anyRequest().permitAll()
)
.anonymous(withDefaults());
// @formatter:on
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@RestController
static class PrincipalController {
@GetMapping("/")
String principal(@AuthenticationPrincipal String principal) {
return principal;
} }
} }
} }