1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Add AuthorizationManagerFactory

Signed-off-by: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com>
This commit is contained in:
Steve Riesenberg
2025-09-02 12:47:53 -05:00
committed by Rob Winch
parent a4f813ab29
commit eeb4574bb3
37 changed files with 2719 additions and 178 deletions
@@ -39,6 +39,7 @@ import org.springframework.security.aot.hint.PrePostAuthorizeHintsRegistrar;
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationManagerFactory;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.MethodInvocationResult;
@@ -121,6 +122,11 @@ final class PrePostMethodSecurityConfiguration implements ImportAware, Applicati
this.expressionHandler.setRoleHierarchy(roleHierarchy);
}
@Autowired(required = false)
void setAuthorizationManagerFactory(AuthorizationManagerFactory<MethodInvocation> authorizationManagerFactory) {
this.expressionHandler.setAuthorizationManagerFactory(authorizationManagerFactory);
}
@Autowired(required = false)
void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) {
this.preFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
@@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.servlet.http.HttpServletRequest;
@@ -27,13 +26,12 @@ import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationManagerFactory;
import org.springframework.security.authorization.AuthorizationManagers;
import org.springframework.security.authorization.SingleResultAuthorizationManager;
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.config.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
@@ -46,13 +44,13 @@ import org.springframework.security.web.access.intercept.RequestMatcherDelegatin
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier;
/**
* Adds a URL based authorization using {@link AuthorizationManager}.
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured.
* @author Evgeniy Cheban
* @author Steve Riesenberg
* @since 5.5
*/
public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
@@ -62,9 +60,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
private final AuthorizationEventPublisher publisher;
private final Supplier<RoleHierarchy> roleHierarchy;
private String rolePrefix = "ROLE_";
private final AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory;
private ObjectPostProcessor<AuthorizationManager<HttpServletRequest>> postProcessor = ObjectPostProcessor
.identity();
@@ -81,13 +77,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
else {
this.publisher = new SpringAuthorizationEventPublisher(context);
}
this.roleHierarchy = SingletonSupplier.of(() -> (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy());
String[] grantedAuthorityDefaultsBeanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaultsBeanNames.length > 0) {
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(GrantedAuthorityDefaults.class);
this.rolePrefix = grantedAuthorityDefaults.getRolePrefix();
}
this.authorizationManagerFactory = getAuthorizationManagerFactory(context);
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class,
ResolvableType.forClassWithGenerics(AuthorizationManager.class, HttpServletRequest.class));
ObjectProvider<ObjectPostProcessor<AuthorizationManager<HttpServletRequest>>> provider = context
@@ -95,6 +85,35 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
provider.ifUnique((postProcessor) -> this.postProcessor = postProcessor);
}
private AuthorizationManagerFactory<RequestAuthorizationContext> getAuthorizationManagerFactory(
ApplicationContext context) {
ResolvableType authorizationManagerFactoryType = ResolvableType
.forClassWithGenerics(AuthorizationManagerFactory.class, RequestAuthorizationContext.class);
// Handle fallback to generic type
if (context.getBeanNamesForType(authorizationManagerFactoryType).length == 0) {
authorizationManagerFactoryType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory.class,
Object.class);
}
ObjectProvider<AuthorizationManagerFactory<RequestAuthorizationContext>> authorizationManagerFactoryProvider = context
.getBeanProvider(authorizationManagerFactoryType);
return authorizationManagerFactoryProvider.getIfAvailable(() -> {
RoleHierarchy roleHierarchy = context.getBeanProvider(RoleHierarchy.class)
.getIfAvailable(NullRoleHierarchy::new);
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class)
.getIfAvailable();
String rolePrefix = (grantedAuthorityDefaults != null) ? grantedAuthorityDefaults.getRolePrefix() : "ROLE_";
DefaultAuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = new DefaultAuthorizationManagerFactory<>();
authorizationManagerFactory.setRoleHierarchy(roleHierarchy);
authorizationManagerFactory.setRolePrefix(rolePrefix);
return authorizationManagerFactory;
});
}
/**
* The {@link AuthorizationManagerRequestMatcherRegistry} is what users will interact
* with after applying the {@link AuthorizeHttpRequestsConfigurer}.
@@ -173,7 +192,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
@Override
protected AuthorizedUrl chainRequestMatchers(List<RequestMatcher> requestMatchers) {
this.unmappedMatchers = requestMatchers;
return new AuthorizedUrl(requestMatchers);
return new AuthorizedUrl(requestMatchers, AuthorizeHttpRequestsConfigurer.this.authorizationManagerFactory);
}
/**
@@ -201,20 +220,31 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
private final List<? extends RequestMatcher> matchers;
private AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory;
private boolean not;
/**
* Creates an instance.
* @param matchers the {@link RequestMatcher} instances to map
* @param authorizationManagerFactory the {@link AuthorizationManagerFactory} for
* creating instances of {@link AuthorizationManager}
*/
AuthorizedUrl(List<? extends RequestMatcher> matchers) {
AuthorizedUrl(List<? extends RequestMatcher> matchers,
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory) {
this.matchers = matchers;
this.authorizationManagerFactory = authorizationManagerFactory;
}
protected List<? extends RequestMatcher> getMatchers() {
return this.matchers;
}
void setAuthorizationManagerFactory(
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory) {
this.authorizationManagerFactory = authorizationManagerFactory;
}
/**
* Negates the following authorization rule.
* @return the {@link AuthorizedUrl} for further customization
@@ -231,7 +261,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry permitAll() {
return access(SingleResultAuthorizationManager.permitAll());
return access(this.authorizationManagerFactory.permitAll());
}
/**
@@ -240,7 +270,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry denyAll() {
return access(SingleResultAuthorizationManager.denyAll());
return access(this.authorizationManagerFactory.denyAll());
}
/**
@@ -251,8 +281,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry hasRole(String role) {
return access(withRoleHierarchy(AuthorityAuthorizationManager
.hasAnyRole(AuthorizeHttpRequestsConfigurer.this.rolePrefix, new String[] { role })));
return access(this.authorizationManagerFactory.hasRole(role));
}
/**
@@ -264,8 +293,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry hasAnyRole(String... roles) {
return access(withRoleHierarchy(
AuthorityAuthorizationManager.hasAnyRole(AuthorizeHttpRequestsConfigurer.this.rolePrefix, roles)));
return access(this.authorizationManagerFactory.hasAnyRole(roles));
}
/**
@@ -275,7 +303,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry hasAuthority(String authority) {
return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority)));
return access(this.authorizationManagerFactory.hasAuthority(authority));
}
/**
@@ -286,13 +314,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry hasAnyAuthority(String... authorities) {
return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities)));
}
private AuthorityAuthorizationManager<RequestAuthorizationContext> withRoleHierarchy(
AuthorityAuthorizationManager<RequestAuthorizationContext> manager) {
manager.setRoleHierarchy(AuthorizeHttpRequestsConfigurer.this.roleHierarchy.get());
return manager;
return access(this.authorizationManagerFactory.hasAnyAuthority(authorities));
}
/**
@@ -301,7 +323,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry authenticated() {
return access(AuthenticatedAuthorizationManager.authenticated());
return access(this.authorizationManagerFactory.authenticated());
}
/**
@@ -313,7 +335,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* @see RememberMeConfigurer
*/
public AuthorizationManagerRequestMatcherRegistry fullyAuthenticated() {
return access(AuthenticatedAuthorizationManager.fullyAuthenticated());
return access(this.authorizationManagerFactory.fullyAuthenticated());
}
/**
@@ -324,7 +346,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* @see RememberMeConfigurer
*/
public AuthorizationManagerRequestMatcherRegistry rememberMe() {
return access(AuthenticatedAuthorizationManager.rememberMe());
return access(this.authorizationManagerFactory.rememberMe());
}
/**
@@ -334,7 +356,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
* @since 5.8
*/
public AuthorizationManagerRequestMatcherRegistry anonymous() {
return access(AuthenticatedAuthorizationManager.anonymous());
return access(this.authorizationManagerFactory.anonymous());
}
/**
@@ -16,6 +16,7 @@
package org.springframework.security.config.annotation.web.configurers;
import java.util.Set;
import java.util.function.Supplier;
import io.micrometer.observation.Observation;
@@ -36,14 +37,19 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationManagerFactory;
import org.springframework.security.authorization.AuthorizationObservationContext;
import org.springframework.security.authorization.SingleResultAuthorizationManager;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.config.ObjectPostProcessor;
@@ -82,13 +88,17 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
@@ -170,6 +180,26 @@ public class AuthorizeHttpRequestsConfigurerTests {
.withMessageContaining("manager cannot be null");
}
@Test
public void configureWhenCustomAuthorizationManagerFactoryRegisteredThenUsed() {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class).autowire();
verify(authorizationManagerFactory).permitAll();
verify(authorizationManagerFactory).denyAll();
verify(authorizationManagerFactory).hasRole("ADMIN");
verify(authorizationManagerFactory).hasAnyRole("USER", "ADMIN");
verify(authorizationManagerFactory).hasAuthority("write");
verify(authorizationManagerFactory).hasAnyAuthority("resource.read", "read");
verify(authorizationManagerFactory).authenticated();
verify(authorizationManagerFactory).fullyAuthenticated();
verify(authorizationManagerFactory).rememberMe();
verify(authorizationManagerFactory).anonymous();
verifyNoMoreInteractions(authorizationManagerFactory);
}
@Test
public void configureWhenObjectPostProcessorRegisteredThenInvokedOnAuthorizationManagerAndAuthorizationFilter() {
this.spring.register(ObjectPostProcessorConfig.class).autowire();
@@ -538,6 +568,205 @@ public class AuthorizeHttpRequestsConfigurerTests {
this.mvc.perform(requestWithAdmin).andExpect(status().isOk());
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndPermitAllThenRespondsWithOk() throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> permitAll = spy(SingleResultAuthorizationManager.permitAll());
given(authorizationManagerFactory.permitAll()).willReturn(permitAll);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/public").with(anonymous());
this.mvc.perform(request).andExpect(status().isOk());
verify(permitAll).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(permitAll);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndDenyAllThenRespondsWithForbidden()
throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> denyAll = spy(SingleResultAuthorizationManager.denyAll());
given(authorizationManagerFactory.denyAll()).willReturn(denyAll);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/private").with(user("user"));
this.mvc.perform(request).andExpect(status().isForbidden());
verify(denyAll).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(denyAll);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndHasRoleThenRespondsWithOk() throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> hasRole = spy(AuthorityAuthorizationManager.hasRole("ADMIN"));
given(authorizationManagerFactory.hasRole(anyString())).willReturn(hasRole);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/admin").with(user("admin").roles("ADMIN"));
this.mvc.perform(request).andExpect(status().isOk());
verify(hasRole).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(hasRole);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndHasAnyRoleThenRespondsWithOk() throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> hasAnyRole = spy(
AuthorityAuthorizationManager.hasAnyRole("USER", "ADMIN"));
given(authorizationManagerFactory.hasAnyRole(any(String[].class))).willReturn(hasAnyRole);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/user").with(user("user").roles("USER"));
this.mvc.perform(request).andExpect(status().isOk());
verify(hasAnyRole).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(hasAnyRole);
verifyNoInteractions(authorizationManager);
}
@Test
public void postWhenCustomAuthorizationManagerFactoryRegisteredAndHasAuthorityThenRespondsWithOk()
throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> hasAuthority = spy(
AuthorityAuthorizationManager.hasAuthority("write"));
given(authorizationManagerFactory.hasAuthority(anyString())).willReturn(hasAuthority);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = post("/resource")
.with(user("user").authorities(new SimpleGrantedAuthority("write")))
.with(csrf());
this.mvc.perform(request).andExpect(status().isOk());
verify(hasAuthority).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(hasAuthority);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndHasAnyAuthorityThenRespondsWithOk()
throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> hasAnyAuthority = spy(
AuthorityAuthorizationManager.hasAnyAuthority("resource.read", "read"));
given(authorizationManagerFactory.hasAnyAuthority(any(String[].class))).willReturn(hasAnyAuthority);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/resource")
.with(user("user").authorities(new SimpleGrantedAuthority("read")));
this.mvc.perform(request).andExpect(status().isOk());
verify(hasAnyAuthority).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(hasAnyAuthority);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndAuthenticatedThenRespondsWithOk()
throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> authenticated = spy(
AuthenticatedAuthorizationManager.authenticated());
given(authorizationManagerFactory.authenticated()).willReturn(authenticated);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/authenticated").with(user("user"));
this.mvc.perform(request).andExpect(status().isOk());
verify(authenticated).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(authenticated);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndFullyAuthenticatedThenRespondsWithOk()
throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> fullyAuthenticated = spy(
AuthenticatedAuthorizationManager.fullyAuthenticated());
given(authorizationManagerFactory.fullyAuthenticated()).willReturn(fullyAuthenticated);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/fully-authenticated").with(user("user"));
this.mvc.perform(request).andExpect(status().isOk());
verify(fullyAuthenticated).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(fullyAuthenticated);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndRememberMeThenRespondsWithOk() throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> rememberMe = spy(
AuthenticatedAuthorizationManager.rememberMe());
given(authorizationManagerFactory.rememberMe()).willReturn(rememberMe);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/remember-me")
.with(authentication(new RememberMeAuthenticationToken("test", "user", Set.of())));
this.mvc.perform(request).andExpect(status().isOk());
verify(rememberMe).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(rememberMe);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndAnonymousThenRespondsWithOk() throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
AuthorizationManager<RequestAuthorizationContext> anonymous = spy(
AuthenticatedAuthorizationManager.anonymous());
given(authorizationManagerFactory.anonymous()).willReturn(anonymous);
AuthorizationManagerFactoryConfig.authorizationManagerFactory = authorizationManagerFactory;
this.spring.register(AuthorizationManagerFactoryConfig.class, AccessTestController.class).autowire();
MockHttpServletRequestBuilder request = get("/anonymous").with(anonymous());
this.mvc.perform(request).andExpect(status().isOk());
verify(anonymous).authorize(any(), any(RequestAuthorizationContext.class));
verifyNoMoreInteractions(anonymous);
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenCustomAuthorizationManagerFactoryRegisteredAndAccessThenRespondsWithForbidden()
throws Exception {
AuthorizationManager<RequestAuthorizationContext> authorizationManager = mock();
AuthorizationManagerFactoryConfig.authorizationManagerFactory = mockAuthorizationManagerFactory(
authorizationManager);
this.spring.register(AuthorizationManagerFactoryConfig.class).autowire();
MockHttpServletRequestBuilder request = get("/").with(user("user"));
this.mvc.perform(request).andExpect(status().isForbidden());
verifyNoInteractions(authorizationManager);
}
@Test
public void getWhenExpressionHasIpAddressLocalhostConfiguredIpAddressIsLocalhostThenRespondsWithOk()
throws Exception {
@@ -587,6 +816,23 @@ public class AuthorizeHttpRequestsConfigurerTests {
};
}
private AuthorizationManagerFactory<RequestAuthorizationContext> mockAuthorizationManagerFactory(
AuthorizationManager<RequestAuthorizationContext> authorizationManager) {
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory = mock();
given(authorizationManagerFactory.permitAll()).willReturn(authorizationManager);
given(authorizationManagerFactory.denyAll()).willReturn(authorizationManager);
given(authorizationManagerFactory.hasRole(anyString())).willReturn(authorizationManager);
given(authorizationManagerFactory.hasAnyRole(any(String[].class))).willReturn(authorizationManager);
given(authorizationManagerFactory.hasAuthority(anyString())).willReturn(authorizationManager);
given(authorizationManagerFactory.hasAnyAuthority(any(String[].class))).willReturn(authorizationManager);
given(authorizationManagerFactory.authenticated()).willReturn(authorizationManager);
given(authorizationManagerFactory.fullyAuthenticated()).willReturn(authorizationManager);
given(authorizationManagerFactory.rememberMe()).willReturn(authorizationManager);
given(authorizationManagerFactory.anonymous()).willReturn(authorizationManager);
return authorizationManagerFactory;
}
@Test
public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception {
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
@@ -850,6 +1096,41 @@ public class AuthorizeHttpRequestsConfigurerTests {
}
@Configuration
@EnableWebSecurity
static class AuthorizationManagerFactoryConfig {
static AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory;
@Bean
AuthorizationManagerFactory<RequestAuthorizationContext> authorizationManagerFactory() {
return authorizationManagerFactory;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/public").permitAll()
.requestMatchers("/private").denyAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/user").hasAnyRole("USER", "ADMIN")
.requestMatchers(HttpMethod.POST, "/resource").hasAuthority("write")
.requestMatchers("/resource").hasAnyAuthority("resource.read", "read")
.requestMatchers("/authenticated").authenticated()
.requestMatchers("/fully-authenticated").fullyAuthenticated()
.requestMatchers("/remember-me").rememberMe()
.requestMatchers("/anonymous").anonymous()
.anyRequest().access((authentication, context) -> new AuthorizationDecision(false))
);
// @formatter:on
return http.build();
}
}
@Configuration
@EnableWebSecurity
static class ObjectPostProcessorConfig {
@@ -1295,6 +1576,47 @@ public class AuthorizeHttpRequestsConfigurerTests {
}
@RestController
static class AccessTestController {
@RequestMapping("/public")
void publicEndpoint() {
}
@RequestMapping("/private")
void privateEndpoint() {
}
@RequestMapping("/admin")
void adminEndpoint() {
}
@RequestMapping("/user")
void userEndpoint() {
}
@RequestMapping("/resource")
void resourceEndpoint() {
}
@RequestMapping("/authenticated")
void authenticatedEndpoint() {
}
@RequestMapping("/fully-authenticated")
void fullyAuthenticatedEndpoint() {
}
@RequestMapping("/remember-me")
void rememberMeEndpoint() {
}
@RequestMapping("/anonymous")
void anonymousEndpoint() {
}
}
@Configuration
static class ObservationRegistryConfig {