Polish MFA Samples
This commit removes unneeded AuthorizationManagerFactory implementations, simplifies the custom AuthorizationManagerFactory example, and updates usage of hasAllAuthorities. Issue gh-17934
This commit is contained in:
parent
f652920bb3
commit
ad6fe4fdc3
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in New Issue