Преглед изворни кода

Polish MFA Samples

This commit removes unneeded AuthorizationManagerFactory
implementations, simplifies the custom AuthorizationManagerFactory
example, and updates usage of hasAllAuthorities.

Issue gh-17934
Josh Cummings пре 1 недеља
родитељ
комит
ad6fe4fdc3

+ 2 - 6
docs/src/test/java/org/springframework/security/docs/servlet/authentication/authorizationmanagerfactory/ListAuthoritiesEverywhereConfiguration.java

@@ -13,10 +13,6 @@ import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler;
 import org.springframework.security.web.authentication.ott.RedirectOneTimeTokenGenerationSuccessHandler;
 
-import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
-import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
-import static org.springframework.security.authorization.AuthorizationManagers.allOf;
-
 @EnableWebSecurity
 @Configuration(proxyBeanMethods = false)
 public class ListAuthoritiesEverywhereConfiguration {
@@ -27,8 +23,8 @@ public class ListAuthoritiesEverywhereConfiguration {
 		// @formatter:off
 		http
 			.authorizeHttpRequests((authorize) -> authorize
-				.requestMatchers("/admin/**").access(allOf(hasAuthority(GrantedAuthorities.FACTOR_PASSWORD_AUTHORITY), hasAuthority(GrantedAuthorities.FACTOR_OTT_AUTHORITY), hasRole("ADMIN"))) // <1>
-				.anyRequest().access(allOf(hasAuthority(GrantedAuthorities.FACTOR_PASSWORD_AUTHORITY), hasAuthority(GrantedAuthorities.FACTOR_OTT_AUTHORITY)))
+				.requestMatchers("/admin/**").hasAllAuthorities(GrantedAuthorities.FACTOR_PASSWORD_AUTHORITY, GrantedAuthorities.FACTOR_OTT_AUTHORITY, "ROLE_ADMIN") // <1>
+				.anyRequest().hasAllAuthorities(GrantedAuthorities.FACTOR_PASSWORD_AUTHORITY, GrantedAuthorities.FACTOR_OTT_AUTHORITY)
 			)
 			.formLogin(Customizer.withDefaults())
 			.oneTimeTokenLogin(Customizer.withDefaults());

+ 12 - 36
docs/src/test/java/org/springframework/security/docs/servlet/authentication/customauthorizationmanagerfactory/CustomAuthorizationManagerFactory.java

@@ -1,16 +1,12 @@
 package org.springframework.security.docs.servlet.authentication.customauthorizationmanagerfactory;
 
-import java.util.Collection;
 import java.util.function.Supplier;
 
-import org.jspecify.annotations.NullMarked;
 import org.jspecify.annotations.Nullable;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.access.expression.SecurityExpressionOperations;
-import org.springframework.security.access.expression.SecurityExpressionRoot;
-import org.springframework.security.authorization.AuthorityAuthorizationDecision;
+import org.springframework.security.authorization.AuthorityAuthorizationManager;
 import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.authorization.AuthorizationManagerFactory;
@@ -21,10 +17,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthorities;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.PasswordEncodedUser;
 import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler;
 import org.springframework.security.web.authentication.ott.RedirectOneTimeTokenGenerationSuccessHandler;
@@ -51,50 +46,31 @@ class CustomAuthorizationManagerFactory {
 
 	// tag::authorizationManager[]
 	@Component
-	class OptInToMfaAuthorizationManager implements AuthorizationManager<Object> {
+	class UserBasedOttAuthorizationManager implements AuthorizationManager<Object> {
 		@Override
 		public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication, Object context) {
-			MyPrincipal principal = (MyPrincipal) authentication.get().getPrincipal();
-			if (principal.optedIn()) {
-				SecurityExpressionOperations sec = new SecurityExpressionRoot<>(authentication, context) {};
-				return new AuthorityAuthorizationDecision(sec.hasAuthority(GrantedAuthorities.FACTOR_OTT_AUTHORITY),
-						AuthorityUtils.createAuthorityList(GrantedAuthorities.FACTOR_OTT_AUTHORITY));
+			if ("admin".equals(authentication.get().getName())) {
+				return AuthorityAuthorizationManager.hasAuthority(GrantedAuthorities.FACTOR_OTT_AUTHORITY)
+						.authorize(authentication, context);
+			} else {
+				return new AuthorizationDecision(true);
 			}
-			return new AuthorizationDecision(true);
 		}
 	}
 	// end::authorizationManager[]
 
 	// tag::authorizationManagerFactory[]
 	@Bean
-	AuthorizationManagerFactory<Object> authorizationManagerFactory(OptInToMfaAuthorizationManager optIn) {
+	AuthorizationManagerFactory<Object> authorizationManagerFactory(UserBasedOttAuthorizationManager optIn) {
 		DefaultAuthorizationManagerFactory<Object> defaults = new DefaultAuthorizationManagerFactory<>();
 		defaults.setAdditionalAuthorization(optIn);
 		return defaults;
 	}
 	// end::authorizationManagerFactory[]
 
-	@NullMarked
-	record MyPrincipal(String username, boolean optedIn) implements UserDetails {
-		@Override
-		public Collection<? extends GrantedAuthority> getAuthorities() {
-			return AuthorityUtils.createAuthorityList("app");
-		}
-
-		@Override
-		public @Nullable String getPassword() {
-			return null;
-		}
-
-		@Override
-		public String getUsername() {
-			return this.username;
-		}
-	}
-
 	@Bean
-	UserDetailsService users() {
-		return (username) -> new MyPrincipal(username, username.equals("optedin"));
+	public UserDetailsService users() {
+		return new InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin());
 	}
 
 	@Bean

+ 16 - 20
docs/src/test/java/org/springframework/security/docs/servlet/authentication/customauthorizationmanagerfactory/CustomAuthorizationManagerFactoryTests.java

@@ -20,19 +20,18 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.config.test.SpringTestContext;
 import org.springframework.security.config.test.SpringTestContextExtension;
 import org.springframework.security.core.GrantedAuthorities;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.docs.servlet.authentication.servletx509config.CustomX509Configuration;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
 import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
@@ -43,7 +42,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
  *
  * @author Rob Winch
  */
-@ExtendWith(SpringTestContextExtension.class)
+@ExtendWith({SpringExtension.class, SpringTestContextExtension.class})
+@TestExecutionListeners(WithSecurityContextTestExecutionListener.class)
 public class CustomAuthorizationManagerFactoryTests {
 
 	public final SpringTestContext spring = new SpringTestContext(this);
@@ -51,40 +51,36 @@ public class CustomAuthorizationManagerFactoryTests {
 	@Autowired
 	MockMvc mockMvc;
 
-	@Autowired
-	UserDetailsService users;
-
 	@Test
-	void getWhenOptedInThenRedirectsToOtt() throws Exception {
+	@WithMockUser(username = "admin")
+	void getWhenAdminThenRedirectsToOtt() throws Exception {
 		this.spring.register(CustomAuthorizationManagerFactory.class, Http200Controller.class).autowire();
-		UserDetails user = this.users.loadUserByUsername("optedin");
 		// @formatter:off
-		this.mockMvc.perform(get("/").with(user(user)))
+		this.mockMvc.perform(get("/"))
 			.andExpect(status().is3xxRedirection())
 			.andExpect(redirectedUrl("http://localhost/login?factor=ott"));
 		// @formatter:on
 	}
 
 	@Test
-	void getWhenNotOptedInThenAllows() throws Exception {
+	@WithMockUser
+	void getWhenNotAdminThenAllows() throws Exception {
 		this.spring.register(CustomAuthorizationManagerFactory.class, Http200Controller.class).autowire();
-		UserDetails user = this.users.loadUserByUsername("user");
 		// @formatter:off
-		this.mockMvc.perform(get("/").with(user(user)))
+		this.mockMvc.perform(get("/"))
 			.andExpect(status().isOk())
 			.andExpect(authenticated().withUsername("user"));
 		// @formatter:on
 	}
 
 	@Test
-	void getWhenOptedAndHasFactorThenAllows() throws Exception {
+	@WithMockUser(username = "admin", authorities = GrantedAuthorities.FACTOR_OTT_AUTHORITY)
+	void getWhenAdminAndHasFactorThenAllows() throws Exception {
 		this.spring.register(CustomAuthorizationManagerFactory.class, Http200Controller.class).autowire();
-		UserDetails user = this.users.loadUserByUsername("optedin");
-		TestingAuthenticationToken token = new TestingAuthenticationToken(user, "", GrantedAuthorities.FACTOR_OTT_AUTHORITY);
 		// @formatter:off
-		this.mockMvc.perform(get("/").with(authentication(token)))
+		this.mockMvc.perform(get("/"))
 			.andExpect(status().isOk())
-			.andExpect(authenticated().withUsername("optedin"));
+			.andExpect(authenticated().withUsername("admin"));
 		// @formatter:on
 	}
 

+ 2 - 5
docs/src/test/java/org/springframework/security/docs/servlet/authentication/multifactorauthentication/ListAuthoritiesConfiguration.java

@@ -13,9 +13,6 @@ import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler;
 import org.springframework.security.web.authentication.ott.RedirectOneTimeTokenGenerationSuccessHandler;
 
-import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
-import static org.springframework.security.authorization.AuthorizationManagers.allOf;
-
 @EnableWebSecurity
 @Configuration(proxyBeanMethods = false)
 class ListAuthoritiesConfiguration {
@@ -26,7 +23,7 @@ class ListAuthoritiesConfiguration {
 		// @formatter:off
 		http
 			.authorizeHttpRequests((authorize) -> authorize
-				.anyRequest().access(allOf(hasAuthority(GrantedAuthorities.FACTOR_PASSWORD_AUTHORITY), hasAuthority(GrantedAuthorities.FACTOR_OTT_AUTHORITY))) // <1>
+				.anyRequest().hasAllAuthorities(GrantedAuthorities.FACTOR_PASSWORD_AUTHORITY, GrantedAuthorities.FACTOR_OTT_AUTHORITY) // <1>
 			)
 			.formLogin(Customizer.withDefaults())
 			.oneTimeTokenLogin(Customizer.withDefaults());
@@ -36,7 +33,7 @@ class ListAuthoritiesConfiguration {
 	// end::httpSecurity[]
 
 	@Bean
-	UserDetailsService userDetailsService() {
+	UserDetailsService users() {
 		return new InMemoryUserDetailsManager(
 				User.withDefaultPasswordEncoder()
 						.username("user")

+ 4 - 80
docs/src/test/java/org/springframework/security/docs/servlet/authentication/obtainingmoreauthorization/MissingAuthorityConfiguration.java

@@ -8,8 +8,6 @@ import jakarta.servlet.http.HttpServletResponse;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authorization.AuthorizationDecision;
-import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.authorization.AuthorizationManagerFactory;
 import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
 import org.springframework.security.config.Customizer;
@@ -22,12 +20,8 @@ import org.springframework.security.oauth2.client.registration.InMemoryClientReg
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.SecurityFilterChain;
-import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 import org.springframework.stereotype.Component;
 
-import static org.springframework.security.authorization.AllAuthoritiesAuthorizationManager.hasAllAuthorities;
-import static org.springframework.security.authorization.AuthorizationManagers.allOf;
-
 @EnableWebSecurity
 @Configuration(proxyBeanMethods = false)
 class MissingAuthorityConfiguration {
@@ -53,83 +47,13 @@ class MissingAuthorityConfiguration {
 
 	// tag::authorizationManagerFactoryBean[]
 	@Bean
-	AuthorizationManagerFactory<RequestAuthorizationContext> authz() {
-		return new FactorAuthorizationManagerFactory(hasAllAuthorities(GrantedAuthorities.FACTOR_X509_AUTHORITY, GrantedAuthorities.FACTOR_AUTHORIZATION_CODE_AUTHORITY));
+	AuthorizationManagerFactory<Object> authz() {
+		return DefaultAuthorizationManagerFactory.builder()
+				.requireAdditionalAuthorities(GrantedAuthorities.FACTOR_X509_AUTHORITY, GrantedAuthorities.FACTOR_AUTHORIZATION_CODE_AUTHORITY)
+				.build();
 	}
 	// end::authorizationManagerFactoryBean[]
 
-	// tag::authorizationManagerFactory[]
-	class FactorAuthorizationManagerFactory implements AuthorizationManagerFactory<RequestAuthorizationContext> {
-		private final AuthorizationManager<RequestAuthorizationContext> hasAuthorities;
-		private final DefaultAuthorizationManagerFactory<RequestAuthorizationContext> delegate =
-				new DefaultAuthorizationManagerFactory<>();
-
-		FactorAuthorizationManagerFactory(AuthorizationManager<RequestAuthorizationContext> hasAuthorities) {
-			this.hasAuthorities = hasAuthorities;
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> permitAll() {
-			return this.delegate.permitAll();
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> denyAll() {
-			return this.delegate.denyAll();
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> hasRole(String role) {
-			return hasAnyRole(role);
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> hasAnyRole(String... roles) {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.hasAnyRole(roles));
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> hasAllRoles(String... roles) {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.hasAllRoles(roles));
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> hasAuthority(String authority) {
-			return hasAnyAuthority(authority);
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> hasAnyAuthority(String... authorities) {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.hasAnyAuthority(authorities));
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> hasAllAuthorities(String... authorities) {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.hasAllAuthorities(authorities));
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> authenticated() {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.authenticated());
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> fullyAuthenticated() {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.fullyAuthenticated());
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> rememberMe() {
-			return allOf(new AuthorizationDecision(false), this.hasAuthorities, this.delegate.rememberMe());
-		}
-
-		@Override
-		public AuthorizationManager<RequestAuthorizationContext> anonymous() {
-			return this.delegate.anonymous();
-		}
-	}
-	// end::authorizationManagerFactory[]
-
 	// tag::authenticationEntryPoint[]
 	@Component
 	class ScopeRetrievingAuthenticationEntryPoint implements AuthenticationEntryPoint {

+ 10 - 32
docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customauthorizationmanagerfactory/CustomAuthorizationManagerFactory.kt

@@ -1,19 +1,16 @@
 package org.springframework.security.kt.docs.servlet.authentication.customauthorizationmanagerfactory
 
-import org.jspecify.annotations.NullMarked
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
-import org.springframework.security.access.expression.SecurityExpressionRoot
 import org.springframework.security.authorization.*
 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.invoke
 import org.springframework.security.core.Authentication
 import org.springframework.security.core.GrantedAuthorities
-import org.springframework.security.core.GrantedAuthority
-import org.springframework.security.core.authority.AuthorityUtils
-import org.springframework.security.core.userdetails.UserDetails
+import org.springframework.security.core.userdetails.PasswordEncodedUser
 import org.springframework.security.core.userdetails.UserDetailsService
+import org.springframework.security.provisioning.InMemoryUserDetailsManager
 import org.springframework.security.web.SecurityFilterChain
 import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler
 import org.springframework.security.web.authentication.ott.RedirectOneTimeTokenGenerationSuccessHandler
@@ -43,50 +40,31 @@ internal class CustomAuthorizationManagerFactory {
 
     // tag::authorizationManager[]
     @Component
-    internal open class OptInToMfaAuthorizationManager : AuthorizationManager<Object> {
+    internal open class UserBasedOttAuthorizationManager : AuthorizationManager<Object> {
         override fun authorize(
             authentication: Supplier<out Authentication?>, context: Object): AuthorizationResult {
-            val principal = authentication.get().getPrincipal() as MyPrincipal?
-            if (principal!!.optedIn) {
-                val root = object : SecurityExpressionRoot<Object>(authentication, context) { }
-                return AuthorityAuthorizationDecision(
-                    root.hasAuthority(GrantedAuthorities.FACTOR_OTT_AUTHORITY),
-                    AuthorityUtils.createAuthorityList(GrantedAuthorities.FACTOR_OTT_AUTHORITY)
-                )
+            return if ("admin" == authentication.get().name) {
+                AuthorityAuthorizationManager.hasAuthority<Object>(GrantedAuthorities.FACTOR_OTT_AUTHORITY)
+                    .authorize(authentication, context)
+            } else {
+                AuthorizationDecision(true)
             }
-            return AuthorizationDecision(true)
         }
     }
     // end::authorizationManager[]
 
     // tag::authorizationManagerFactory[]
     @Bean
-    fun authorizationManagerFactory(optIn: OptInToMfaAuthorizationManager?): AuthorizationManagerFactory<Object> {
+    fun authorizationManagerFactory(optIn: UserBasedOttAuthorizationManager?): AuthorizationManagerFactory<Object> {
         val defaults = DefaultAuthorizationManagerFactory<Object>()
         defaults.setAdditionalAuthorization(optIn)
         return defaults
     }
     // end::authorizationManagerFactory[]
 
-    @NullMarked
-    class MyPrincipal(val user: String, val optedIn: Boolean) : UserDetails {
-        override fun getAuthorities(): MutableCollection<out GrantedAuthority> {
-            return AuthorityUtils.createAuthorityList("app")
-        }
-
-        override fun getPassword(): String? {
-            return null
-        }
-
-        override fun getUsername(): String {
-            return this.user
-        }
-
-    }
-
     @Bean
     fun users(): UserDetailsService {
-        return UserDetailsService { username: String? -> MyPrincipal(username!!, username == "optedin") }
+        return InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin())
     }
 
     @Bean

+ 28 - 29
docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customauthorizationmanagerfactory/CustomAuthorizationManagerFactoryTests.kt

@@ -18,16 +18,18 @@ package org.springframework.security.kt.docs.servlet.authentication.customauthor
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.security.authentication.TestingAuthenticationToken
 import org.springframework.security.config.test.SpringTestContext
 import org.springframework.security.config.test.SpringTestContextExtension
 import org.springframework.security.core.GrantedAuthorities
-import org.springframework.security.core.userdetails.UserDetailsService
-import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
-import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers
+import org.springframework.security.test.context.support.WithMockUser
+import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener
+import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
+import org.springframework.test.context.TestExecutionListeners
+import org.springframework.test.context.junit.jupiter.SpringExtension
 import org.springframework.test.web.servlet.MockMvc
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
 import org.springframework.web.bind.annotation.GetMapping
 import org.springframework.web.bind.annotation.RestController
 
@@ -36,7 +38,8 @@ import org.springframework.web.bind.annotation.RestController
  *
  * @author Rob Winch
  */
-@ExtendWith(SpringTestContextExtension::class)
+@ExtendWith(SpringExtension::class, SpringTestContextExtension::class)
+@TestExecutionListeners(WithSecurityContextTestExecutionListener::class)
 class CustomAuthorizationManagerFactoryTests {
     @JvmField
     val spring: SpringTestContext = SpringTestContext(this)
@@ -44,44 +47,40 @@ class CustomAuthorizationManagerFactoryTests {
     @Autowired
     var mockMvc: MockMvc? = null
 
-    @Autowired
-    var users: UserDetailsService? = null
-
     @Test
     @Throws(Exception::class)
-    fun getWhenOptedInThenRedirectsToOtt() {
+    @WithMockUser(username = "admin")
+    fun getWhenAdminThenRedirectsToOtt() {
         this.spring.register(CustomAuthorizationManagerFactory::class.java, Http200Controller::class.java).autowire()
-        val user = this.users!!.loadUserByUsername("optedin")
         // @formatter:off
-        this.mockMvc!!.perform(MockMvcRequestBuilders.get("/").with(SecurityMockMvcRequestPostProcessors.user(user)))
-        .andExpect(MockMvcResultMatchers.status().is3xxRedirection())
-        .andExpect(MockMvcResultMatchers.redirectedUrl("http://localhost/login?factor=ott"))
-    		// @formatter:on
+        this.mockMvc!!.perform(get("/"))
+            .andExpect(status().is3xxRedirection())
+            .andExpect(redirectedUrl("http://localhost/login?factor=ott"))
+        // @formatter:on
     }
 
     @Test
     @Throws(Exception::class)
-    fun getWhenNotOptedInThenAllows() {
+    @WithMockUser
+    fun getWhenNotAdminThenAllows() {
         this.spring.register(CustomAuthorizationManagerFactory::class.java, Http200Controller::class.java).autowire()
-        val user = this.users!!.loadUserByUsername("user")
         // @formatter:off
-        this.mockMvc!!.perform(MockMvcRequestBuilders.get("/").with(SecurityMockMvcRequestPostProcessors.user(user)))
-        .andExpect(MockMvcResultMatchers.status().isOk())
-        .andExpect(SecurityMockMvcResultMatchers.authenticated().withUsername("user"))
-    		// @formatter:on
+        this.mockMvc!!.perform(get("/"))
+            .andExpect(status().isOk())
+            .andExpect(authenticated().withUsername("user"))
+    	// @formatter:on
     }
 
     @Test
     @Throws(Exception::class)
-    fun getWhenOptedAndHasFactorThenAllows() {
+    @WithMockUser(username = "admin", authorities = [GrantedAuthorities.FACTOR_OTT_AUTHORITY])
+    fun getWhenAdminAndHasFactorThenAllows() {
         this.spring.register(CustomAuthorizationManagerFactory::class.java, Http200Controller::class.java).autowire()
-        val user = this.users!!.loadUserByUsername("optedin")
-        val token = TestingAuthenticationToken(user, "", GrantedAuthorities.FACTOR_OTT_AUTHORITY)
         // @formatter:off
-        this.mockMvc!!.perform(MockMvcRequestBuilders.get("/").with(SecurityMockMvcRequestPostProcessors.authentication(token)))
-        .andExpect(MockMvcResultMatchers.status().isOk())
-        .andExpect(SecurityMockMvcResultMatchers.authenticated().withUsername("optedin"))
-    		// @formatter:on
+        this.mockMvc!!.perform(get("/"))
+            .andExpect(status().isOk())
+            .andExpect(authenticated().withUsername("admin"))
+    	// @formatter:on
     }
 
     @RestController

+ 4 - 61
docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/obtainingmoreauthorization/MissingAuthorityConfiguration.kt

@@ -58,70 +58,13 @@ internal class MissingAuthorityConfiguration {
 
     // tag::authorizationManagerFactoryBean[]
     @Bean
-    fun authz(): AuthorizationManagerFactory<RequestAuthorizationContext> {
-        return FactorAuthorizationManagerFactory(hasAllAuthorities(GrantedAuthorities.FACTOR_X509_AUTHORITY, GrantedAuthorities.FACTOR_AUTHORIZATION_CODE_AUTHORITY))
+    fun authz(): AuthorizationManagerFactory<Object> {
+        return DefaultAuthorizationManagerFactory.builder<Object>()
+                .requireAdditionalAuthorities(GrantedAuthorities.FACTOR_X509_AUTHORITY, GrantedAuthorities.FACTOR_AUTHORIZATION_CODE_AUTHORITY)
+                .build()
     }
     // end::authorizationManagerFactoryBean[]
 
-    // tag::authorizationManagerFactory[]
-    internal inner class FactorAuthorizationManagerFactory(private val hasAuthorities: AuthorizationManager<RequestAuthorizationContext>) :
-        AuthorizationManagerFactory<RequestAuthorizationContext> {
-        private val delegate = DefaultAuthorizationManagerFactory<RequestAuthorizationContext>()
-
-        override fun permitAll(): AuthorizationManager<RequestAuthorizationContext> {
-            return this.delegate.permitAll()
-        }
-
-        override fun denyAll(): AuthorizationManager<RequestAuthorizationContext> {
-            return this.delegate.denyAll()
-        }
-
-        override fun hasRole(role: String): AuthorizationManager<RequestAuthorizationContext> {
-            return hasAnyRole(role)
-        }
-
-        override fun hasAnyRole(vararg roles: String): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.hasAnyRole(*roles))
-        }
-
-        override fun hasAllRoles(vararg roles: String): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.hasAllRoles(*roles))
-        }
-
-        override fun hasAuthority(authority: String): AuthorizationManager<RequestAuthorizationContext> {
-            return hasAnyAuthority(authority)
-        }
-
-        override fun hasAnyAuthority(vararg authorities: String): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.hasAnyAuthority(*authorities))
-        }
-
-        override fun hasAllAuthorities(vararg authorities: String): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.hasAllAuthorities(*authorities))
-        }
-
-        override fun authenticated(): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.authenticated())
-        }
-
-        override fun fullyAuthenticated(): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.fullyAuthenticated())
-        }
-
-        override fun rememberMe(): AuthorizationManager<RequestAuthorizationContext> {
-            return addFactors(this.delegate.rememberMe())
-        }
-
-        override fun anonymous(): AuthorizationManager<RequestAuthorizationContext> {
-            return this.delegate.anonymous()
-        }
-
-        private fun addFactors(delegate: AuthorizationManager<RequestAuthorizationContext>): AuthorizationManager<RequestAuthorizationContext> {
-            return allOf(AuthorizationDecision(false), this.hasAuthorities, delegate)
-        }
-    }
-    // end::authorizationManagerFactory[]
-
     @Bean
     fun clients(): ClientRegistrationRepository {
         return InMemoryClientRegistrationRepository(TestClientRegistrations.clientRegistration().build())