mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-10-21 09:48:46 +00:00
Add AuthorizationManagerFactory
Signed-off-by: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com>
This commit is contained in:
parent
a4f813ab29
commit
eeb4574bb3
@ -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 {
|
||||
|
||||
|
@ -28,6 +28,8 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@ -38,6 +40,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractSecurityExpressionHandler<T>
|
||||
@ -49,6 +52,8 @@ public abstract class AbstractSecurityExpressionHandler<T>
|
||||
|
||||
private @Nullable RoleHierarchy roleHierarchy;
|
||||
|
||||
private AuthorizationManagerFactory<T> authorizationManagerFactory = new DefaultAuthorizationManagerFactory<>();
|
||||
|
||||
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
||||
|
||||
@Override
|
||||
@ -106,11 +111,58 @@ public abstract class AbstractSecurityExpressionHandler<T>
|
||||
protected abstract SecurityExpressionOperations createSecurityExpressionRoot(
|
||||
@Nullable Authentication authentication, T invocation);
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthorizationManagerFactory} to be used. The default is
|
||||
* {@link DefaultAuthorizationManagerFactory}.
|
||||
* @param authorizationManagerFactory the {@link AuthorizationManagerFactory} to use.
|
||||
* Cannot be null.
|
||||
* @since 7.0
|
||||
*/
|
||||
public final void setAuthorizationManagerFactory(AuthorizationManagerFactory<T> authorizationManagerFactory) {
|
||||
Assert.notNull(authorizationManagerFactory, "authorizationManagerFactory cannot be null");
|
||||
this.authorizationManagerFactory = authorizationManagerFactory;
|
||||
}
|
||||
|
||||
protected final AuthorizationManagerFactory<T> getAuthorizationManagerFactory() {
|
||||
return this.authorizationManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows accessing the {@link DefaultAuthorizationManagerFactory} for getting and
|
||||
* setting defaults. This method will be removed in Spring Security 8.
|
||||
* @return the {@link DefaultAuthorizationManagerFactory}
|
||||
* @throws IllegalStateException if a different {@link AuthorizationManagerFactory}
|
||||
* was already set
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
protected final DefaultAuthorizationManagerFactory<T> getDefaultAuthorizationManagerFactory() {
|
||||
if (!(this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T> defaultAuthorizationManagerFactory)) {
|
||||
throw new IllegalStateException(
|
||||
"authorizationManagerFactory must be an instance of DefaultAuthorizationManagerFactory");
|
||||
}
|
||||
|
||||
return defaultAuthorizationManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getDefaultAuthorizationManagerFactory()} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
protected @Nullable RoleHierarchy getRoleHierarchy() {
|
||||
return this.roleHierarchy;
|
||||
}
|
||||
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
||||
/**
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setRoleHierarchy(@Nullable RoleHierarchy roleHierarchy) {
|
||||
if (roleHierarchy != null) {
|
||||
getDefaultAuthorizationManagerFactory().setRoleHierarchy(roleHierarchy);
|
||||
}
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,6 @@
|
||||
package org.springframework.security.access.expression;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@ -26,10 +24,11 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
@ -38,20 +37,19 @@ import org.springframework.util.function.SingletonSupplier;
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
|
||||
public abstract class SecurityExpressionRoot<T extends @Nullable Object> implements SecurityExpressionOperations {
|
||||
|
||||
private final Supplier<Authentication> authentication;
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
private @Nullable RoleHierarchy roleHierarchy;
|
||||
|
||||
private @Nullable Set<String> roles;
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
|
||||
private final T object;
|
||||
|
||||
private AuthorizationManagerFactory<T> authorizationManagerFactory = new DefaultAuthorizationManagerFactory<>();
|
||||
|
||||
/**
|
||||
* Allows "permitAll" expression
|
||||
*/
|
||||
@ -77,9 +75,12 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param authentication the {@link Authentication} to use. Cannot be null.
|
||||
* @deprecated Use {@link #SecurityExpressionRoot(Supplier, Object)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
@SuppressWarnings("NullAway")
|
||||
public SecurityExpressionRoot(@Nullable Authentication authentication) {
|
||||
this(() -> authentication);
|
||||
this(() -> authentication, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,44 +89,70 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to use.
|
||||
* Cannot be null.
|
||||
* @since 5.8
|
||||
* @deprecated Use {@link #SecurityExpressionRoot(Supplier, Object)} instead
|
||||
*/
|
||||
public SecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication) {
|
||||
@Deprecated(since = "7.0")
|
||||
@SuppressWarnings("NullAway")
|
||||
public SecurityExpressionRoot(Supplier<@Nullable Authentication> authentication) {
|
||||
this(authentication, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance that uses lazy initialization of the {@link Authentication}
|
||||
* object.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to use.
|
||||
* Cannot be null.
|
||||
* @param object the object being authorized
|
||||
* @since 7.0
|
||||
*/
|
||||
public SecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication, T object) {
|
||||
this.authentication = SingletonSupplier.of(() -> {
|
||||
Authentication value = authentication.get();
|
||||
Assert.notNull(value, "Authentication object cannot be null");
|
||||
return value;
|
||||
});
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasAuthority(String authority) {
|
||||
return hasAnyAuthority(authority);
|
||||
return isGranted(this.authorizationManagerFactory.hasAnyAuthority(authority));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasAnyAuthority(String... authorities) {
|
||||
return hasAnyAuthorityName(null, authorities);
|
||||
return isGranted(this.authorizationManagerFactory.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasRole(String role) {
|
||||
return hasAnyRole(role);
|
||||
if (this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T>) {
|
||||
// To provide passivity for old behavior where hasRole('ROLE_A') is allowed,
|
||||
// we strip the role prefix when found.
|
||||
// TODO: Remove in favor of fixing inconsistent behavior?
|
||||
String rolePrefix = this.defaultRolePrefix;
|
||||
if (role.startsWith(rolePrefix)) {
|
||||
role = role.substring(rolePrefix.length());
|
||||
}
|
||||
}
|
||||
return isGranted(this.authorizationManagerFactory.hasRole(role));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasAnyRole(String... roles) {
|
||||
return hasAnyAuthorityName(this.defaultRolePrefix, roles);
|
||||
}
|
||||
|
||||
private boolean hasAnyAuthorityName(@Nullable String prefix, String... roles) {
|
||||
Set<String> roleSet = getAuthoritySet();
|
||||
for (String role : roles) {
|
||||
String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
|
||||
if (roleSet.contains(defaultedRole)) {
|
||||
return true;
|
||||
if (this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T>) {
|
||||
// To provide passivity for old behavior where hasRole('ROLE_A') is allowed,
|
||||
// we strip the role prefix when found.
|
||||
// TODO: Remove in favor of fixing inconsistent behavior?
|
||||
String rolePrefix = this.defaultRolePrefix;
|
||||
for (int index = 0; index < roles.length; index++) {
|
||||
String role = roles[index];
|
||||
if (role.startsWith(rolePrefix)) {
|
||||
roles[index] = role.substring(rolePrefix.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return isGranted(this.authorizationManagerFactory.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,33 +162,37 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
|
||||
@Override
|
||||
public final boolean permitAll() {
|
||||
return true;
|
||||
return isGranted(this.authorizationManagerFactory.permitAll());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean denyAll() {
|
||||
return false;
|
||||
return isGranted(this.authorizationManagerFactory.denyAll());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAnonymous() {
|
||||
return this.trustResolver.isAnonymous(getAuthentication());
|
||||
return isGranted(this.authorizationManagerFactory.anonymous());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAuthenticated() {
|
||||
return this.trustResolver.isAuthenticated(getAuthentication());
|
||||
return isGranted(this.authorizationManagerFactory.authenticated());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isRememberMe() {
|
||||
return this.trustResolver.isRememberMe(getAuthentication());
|
||||
return isGranted(this.authorizationManagerFactory.rememberMe());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isFullyAuthenticated() {
|
||||
Authentication authentication = getAuthentication();
|
||||
return this.trustResolver.isFullyAuthenticated(authentication);
|
||||
return isGranted(this.authorizationManagerFactory.fullyAuthenticated());
|
||||
}
|
||||
|
||||
private boolean isGranted(AuthorizationManager<T> authorizationManager) {
|
||||
AuthorizationResult authorizationResult = authorizationManager.authorize(this.authentication, this.object);
|
||||
return (authorizationResult != null && authorizationResult.isGranted());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,12 +204,24 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
return getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
this.trustResolver = trustResolver;
|
||||
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setRoleHierarchy(@Nullable RoleHierarchy roleHierarchy) {
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
if (roleHierarchy != null) {
|
||||
getDefaultAuthorizationManagerFactory().setRoleHierarchy(roleHierarchy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,20 +236,46 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
* If null or empty, then no default role prefix is used.
|
||||
* </p>
|
||||
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
@Deprecated(since = "7.0")
|
||||
public void setDefaultRolePrefix(@Nullable String defaultRolePrefix) {
|
||||
if (defaultRolePrefix == null) {
|
||||
defaultRolePrefix = "";
|
||||
}
|
||||
getDefaultAuthorizationManagerFactory().setRolePrefix(defaultRolePrefix);
|
||||
this.defaultRolePrefix = defaultRolePrefix;
|
||||
}
|
||||
|
||||
private Set<String> getAuthoritySet() {
|
||||
if (this.roles == null) {
|
||||
Collection<? extends GrantedAuthority> userAuthorities = getAuthentication().getAuthorities();
|
||||
if (this.roleHierarchy != null) {
|
||||
userAuthorities = this.roleHierarchy.getReachableGrantedAuthorities(userAuthorities);
|
||||
}
|
||||
this.roles = AuthorityUtils.authorityListToSet(userAuthorities);
|
||||
/**
|
||||
* Sets the {@link AuthorizationManagerFactory} to use for creating instances of
|
||||
* {@link AuthorizationManager}.
|
||||
* @param authorizationManagerFactory the {@link AuthorizationManagerFactory} to use
|
||||
* @since 7.0
|
||||
*/
|
||||
public void setAuthorizationManagerFactory(AuthorizationManagerFactory<T> authorizationManagerFactory) {
|
||||
Assert.notNull(authorizationManagerFactory, "authorizationManagerFactory cannot be null");
|
||||
this.authorizationManagerFactory = authorizationManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows accessing the {@link DefaultAuthorizationManagerFactory} for getting and
|
||||
* setting defaults. This method will be removed in Spring Security 8.
|
||||
* @return the {@link DefaultAuthorizationManagerFactory}
|
||||
* @throws IllegalStateException if a different {@link AuthorizationManagerFactory}
|
||||
* was already set
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
private DefaultAuthorizationManagerFactory<T> getDefaultAuthorizationManagerFactory() {
|
||||
if (!(this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T> defaultAuthorizationManagerFactory)) {
|
||||
throw new IllegalStateException(
|
||||
"authorizationManagerFactory must be an instance of DefaultAuthorizationManagerFactory");
|
||||
}
|
||||
return this.roles;
|
||||
|
||||
return defaultAuthorizationManagerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -225,24 +294,4 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
this.permissionEvaluator = permissionEvaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefixes role with defaultRolePrefix if defaultRolePrefix is non-null and if role
|
||||
* does not already start with defaultRolePrefix.
|
||||
* @param defaultRolePrefix
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
private static String getRoleWithDefaultPrefix(@Nullable String defaultRolePrefix, String role) {
|
||||
if (role == null) {
|
||||
return role;
|
||||
}
|
||||
if (defaultRolePrefix == null || defaultRolePrefix.length() == 0) {
|
||||
return role;
|
||||
}
|
||||
if (role.startsWith(defaultRolePrefix)) {
|
||||
return role;
|
||||
}
|
||||
return defaultRolePrefix + role;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import org.springframework.security.access.expression.AbstractSecurityExpression
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.parameters.DefaultSecurityParameterNameDiscoverer;
|
||||
import org.springframework.util.Assert;
|
||||
@ -56,11 +57,14 @@ import org.springframework.util.Assert;
|
||||
* @author Luke Taylor
|
||||
* @author Evgeniy Cheban
|
||||
* @author Blagoja Stamatovski
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpressionHandler<MethodInvocation>
|
||||
implements MethodSecurityExpressionHandler {
|
||||
|
||||
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
@ -69,7 +73,7 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||
|
||||
private @Nullable PermissionCacheOptimizer permissionCacheOptimizer = null;
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
private String defaultRolePrefix = DEFAULT_ROLE_PREFIX;
|
||||
|
||||
public DefaultMethodSecurityExpressionHandler() {
|
||||
}
|
||||
@ -106,12 +110,14 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||
|
||||
private MethodSecurityExpressionOperations createSecurityExpressionRoot(
|
||||
Supplier<? extends @Nullable Authentication> authentication, MethodInvocation invocation) {
|
||||
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
|
||||
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication, invocation);
|
||||
root.setThis(invocation.getThis());
|
||||
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(getTrustResolver());
|
||||
Optional.ofNullable(getRoleHierarchy()).ifPresent(root::setRoleHierarchy);
|
||||
root.setDefaultRolePrefix(getDefaultRolePrefix());
|
||||
if (!DEFAULT_ROLE_PREFIX.equals(this.defaultRolePrefix)) {
|
||||
// Ensure SecurityExpressionRoot can strip the custom role prefix
|
||||
root.setDefaultRolePrefix(getDefaultRolePrefix());
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -232,15 +238,22 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||
* {@link AuthenticationTrustResolverImpl}.
|
||||
* @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
|
||||
* null.
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
Assert.notNull(trustResolver, "trustResolver cannot be null");
|
||||
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
|
||||
this.trustResolver = trustResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current {@link AuthenticationTrustResolver}
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
protected AuthenticationTrustResolver getTrustResolver() {
|
||||
return this.trustResolver;
|
||||
}
|
||||
@ -289,14 +302,24 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||
* If null or empty, then no default role prefix is used.
|
||||
* </p>
|
||||
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
@Deprecated(since = "7.0")
|
||||
public void setDefaultRolePrefix(@Nullable String defaultRolePrefix) {
|
||||
if (defaultRolePrefix == null) {
|
||||
defaultRolePrefix = "";
|
||||
}
|
||||
getDefaultAuthorizationManagerFactory().setRolePrefix(defaultRolePrefix);
|
||||
this.defaultRolePrefix = defaultRolePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The default role prefix
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
protected String getDefaultRolePrefix() {
|
||||
return this.defaultRolePrefix;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.security.access.expression.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
@ -28,9 +29,11 @@ import org.springframework.security.core.Authentication;
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.0
|
||||
*/
|
||||
class MethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
|
||||
class MethodSecurityExpressionRoot extends SecurityExpressionRoot<MethodInvocation>
|
||||
implements MethodSecurityExpressionOperations {
|
||||
|
||||
private @Nullable Object filterObject;
|
||||
|
||||
@ -38,12 +41,9 @@ class MethodSecurityExpressionRoot extends SecurityExpressionRoot implements Met
|
||||
|
||||
private @Nullable Object target;
|
||||
|
||||
MethodSecurityExpressionRoot(@Nullable Authentication a) {
|
||||
super(a);
|
||||
}
|
||||
|
||||
MethodSecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication) {
|
||||
super(authentication);
|
||||
MethodSecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication,
|
||||
MethodInvocation methodInvocation) {
|
||||
super(authentication, methodInvocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A factory for creating different kinds of {@link AuthorizationManager} instances.
|
||||
*
|
||||
* @param <T> the type of object that the authorization check is being done on
|
||||
* @author Steve Riesenberg
|
||||
* @since 7.0
|
||||
*/
|
||||
public interface AuthorizationManagerFactory<T extends @Nullable Object> {
|
||||
|
||||
/**
|
||||
* Create an {@link AuthorizationManager} that allows anyone.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> permitAll() {
|
||||
return SingleResultAuthorizationManager.permitAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that does not allow anyone.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> denyAll() {
|
||||
return SingleResultAuthorizationManager.denyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have the specified
|
||||
* role.
|
||||
* @param role the role (automatically prepended with ROLE_) that should be required
|
||||
* to allow access (i.e. USER, ADMIN, etc.)
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> hasRole(String role) {
|
||||
return AuthorityAuthorizationManager.hasRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have one of many
|
||||
* roles.
|
||||
* @param roles the roles (automatically prepended with ROLE_) that the user should
|
||||
* have at least one of to allow access (i.e. USER, ADMIN, etc.)
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> hasAnyRole(String... roles) {
|
||||
return AuthorityAuthorizationManager.hasAnyRole(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have the specified
|
||||
* authority.
|
||||
* @param authority the authority that should be required to allow access (i.e.
|
||||
* ROLE_USER, ROLE_ADMIN, etc.)
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> hasAuthority(String authority) {
|
||||
return AuthorityAuthorizationManager.hasAuthority(authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have one of many
|
||||
* authorities.
|
||||
* @param authorities the authorities that the user should have at least one of to
|
||||
* allow access (i.e. ROLE_USER, ROLE_ADMIN, etc.)
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> hasAnyAuthority(String... authorities) {
|
||||
return AuthorityAuthorizationManager.hasAnyAuthority(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that allows any authenticated user.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> authenticated() {
|
||||
return AuthenticatedAuthorizationManager.authenticated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that allows users who have authenticated
|
||||
* and were not remembered.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> fullyAuthenticated() {
|
||||
return AuthenticatedAuthorizationManager.fullyAuthenticated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that allows users that have been
|
||||
* remembered.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> rememberMe() {
|
||||
return AuthenticatedAuthorizationManager.rememberMe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that allows only anonymous users.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> anonymous() {
|
||||
return AuthenticatedAuthorizationManager.anonymous();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A factory for creating different kinds of {@link AuthorizationManager} instances.
|
||||
*
|
||||
* @param <T> the type of object that the authorization check is being done on
|
||||
* @author Steve Riesenberg
|
||||
* @since 7.0
|
||||
*/
|
||||
public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object>
|
||||
implements AuthorizationManagerFactory<T> {
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
||||
|
||||
private String rolePrefix = "ROLE_";
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationTrustResolver} used to check the user's
|
||||
* authentication.
|
||||
* @param trustResolver the {@link AuthenticationTrustResolver} to use
|
||||
*/
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
Assert.notNull(trustResolver, "trustResolver cannot be null");
|
||||
this.trustResolver = trustResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link RoleHierarchy} used to discover reachable authorities.
|
||||
* @param roleHierarchy the {@link RoleHierarchy} to use
|
||||
*/
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
||||
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix used to create an authority name from a role name. Can be an empty
|
||||
* string.
|
||||
* @param rolePrefix the role prefix to use
|
||||
*/
|
||||
public void setRolePrefix(String rolePrefix) {
|
||||
Assert.notNull(rolePrefix, "rolePrefix cannot be null");
|
||||
this.rolePrefix = rolePrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasRole(String role) {
|
||||
return hasAnyRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasAnyRole(String... roles) {
|
||||
return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasAuthority(String authority) {
|
||||
return withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasAnyAuthority(String... authorities) {
|
||||
return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> authenticated() {
|
||||
return withTrustResolver(AuthenticatedAuthorizationManager.authenticated());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> fullyAuthenticated() {
|
||||
return withTrustResolver(AuthenticatedAuthorizationManager.fullyAuthenticated());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> rememberMe() {
|
||||
return withTrustResolver(AuthenticatedAuthorizationManager.rememberMe());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> anonymous() {
|
||||
return withTrustResolver(AuthenticatedAuthorizationManager.anonymous());
|
||||
}
|
||||
|
||||
private AuthorityAuthorizationManager<T> withRoleHierarchy(AuthorityAuthorizationManager<T> authorizationManager) {
|
||||
authorizationManager.setRoleHierarchy(this.roleHierarchy);
|
||||
return authorizationManager;
|
||||
}
|
||||
|
||||
private AuthenticatedAuthorizationManager<T> withTrustResolver(
|
||||
AuthenticatedAuthorizationManager<T> authorizationManager) {
|
||||
authorizationManager.setTrustResolver(this.trustResolver);
|
||||
return authorizationManager;
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.access.expression.method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -53,7 +54,7 @@ public class MethodSecurityExpressionRootTests {
|
||||
@BeforeEach
|
||||
public void createContext() {
|
||||
this.user = mock(Authentication.class);
|
||||
this.root = new MethodSecurityExpressionRoot(this.user);
|
||||
this.root = new MethodSecurityExpressionRoot(() -> this.user, mock(MethodInvocation.class));
|
||||
this.ctx = new StandardEvaluationContext();
|
||||
this.ctx.setRootObject(this.root);
|
||||
this.trustResolver = mock(AuthenticationTrustResolver.class);
|
||||
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class AuthorizationManagerFactoryTests {
|
||||
|
||||
@Test
|
||||
public void permitAllReturnsSingleResultAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.permitAll();
|
||||
assertThat(authorizationManager).isInstanceOf(SingleResultAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void denyAllReturnsSingleResultAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.denyAll();
|
||||
assertThat(authorizationManager).isInstanceOf(SingleResultAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasRoleReturnsAuthorityAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.hasRole("USER");
|
||||
assertThat(authorizationManager).isInstanceOf(AuthorityAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAnyRoleReturnsAuthorityAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.hasAnyRole("USER", "ADMIN");
|
||||
assertThat(authorizationManager).isInstanceOf(AuthorityAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAuthorityReturnsAuthorityAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.hasAuthority("authority1");
|
||||
assertThat(authorizationManager).isInstanceOf(AuthorityAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAnyAuthorityReturnsAuthorityAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.hasAnyAuthority("authority1", "authority2");
|
||||
assertThat(authorizationManager).isInstanceOf(AuthorityAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedReturnsAuthenticatedAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.authenticated();
|
||||
assertThat(authorizationManager).isInstanceOf(AuthenticatedAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fullyAuthenticatedReturnsAuthenticatedAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.fullyAuthenticated();
|
||||
assertThat(authorizationManager).isInstanceOf(AuthenticatedAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeReturnsAuthenticatedAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.rememberMe();
|
||||
assertThat(authorizationManager).isInstanceOf(AuthenticatedAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void anonymousReturnsAuthenticatedAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.anonymous();
|
||||
assertThat(authorizationManager).isInstanceOf(AuthenticatedAuthorizationManager.class);
|
||||
}
|
||||
|
||||
}
|
@ -26,6 +26,8 @@ import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@ -92,18 +94,18 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class SecurityEvaluationContextExtension implements EvaluationContextExtension {
|
||||
|
||||
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
|
||||
|
||||
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
||||
.getContextHolderStrategy();
|
||||
|
||||
private @Nullable Authentication authentication;
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
||||
private AuthorizationManagerFactory<Object> authorizationManagerFactory = new DefaultAuthorizationManagerFactory<>();
|
||||
|
||||
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
private String defaultRolePrefix = DEFAULT_ROLE_PREFIX;
|
||||
|
||||
/**
|
||||
* Creates a new instance that uses the current {@link Authentication} found on the
|
||||
@ -126,14 +128,16 @@ public class SecurityEvaluationContextExtension implements EvaluationContextExte
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityExpressionRoot getRootObject() {
|
||||
public SecurityExpressionRoot<Object> getRootObject() {
|
||||
Authentication authentication = getAuthentication();
|
||||
SecurityExpressionRoot root = new SecurityExpressionRoot(authentication) {
|
||||
SecurityExpressionRoot<Object> root = new SecurityExpressionRoot<>(() -> authentication, new Object()) {
|
||||
};
|
||||
root.setTrustResolver(this.trustResolver);
|
||||
root.setRoleHierarchy(this.roleHierarchy);
|
||||
root.setAuthorizationManagerFactory(this.authorizationManagerFactory);
|
||||
root.setPermissionEvaluator(this.permissionEvaluator);
|
||||
root.setDefaultRolePrefix(this.defaultRolePrefix);
|
||||
if (!DEFAULT_ROLE_PREFIX.equals(this.defaultRolePrefix)) {
|
||||
// Ensure SecurityExpressionRoot can strip the custom role prefix
|
||||
root.setDefaultRolePrefix(this.defaultRolePrefix);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -156,15 +160,46 @@ public class SecurityEvaluationContextExtension implements EvaluationContextExte
|
||||
return context.getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthorizationManagerFactory} to be used. The default is
|
||||
* {@link DefaultAuthorizationManagerFactory}.
|
||||
* @param authorizationManagerFactory the {@link AuthorizationManagerFactory} to use.
|
||||
* Cannot be null.
|
||||
* @since 7.0
|
||||
*/
|
||||
public void setAuthorizationManagerFactory(AuthorizationManagerFactory<Object> authorizationManagerFactory) {
|
||||
Assert.notNull(authorizationManagerFactory, "authorizationManagerFactory cannot be null");
|
||||
this.authorizationManagerFactory = authorizationManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows accessing the {@link DefaultAuthorizationManagerFactory} for getting and
|
||||
* setting defaults. This method will be removed in Spring Security 8.
|
||||
* @return the {@link DefaultAuthorizationManagerFactory}
|
||||
* @throws IllegalStateException if a different {@link AuthorizationManagerFactory}
|
||||
* was already set
|
||||
*/
|
||||
private DefaultAuthorizationManagerFactory<Object> getDefaultAuthorizationManagerFactory() {
|
||||
if (!(this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<Object> defaultAuthorizationManagerFactory)) {
|
||||
throw new IllegalStateException(
|
||||
"authorizationManagerFactory must be an instance of DefaultAuthorizationManagerFactory");
|
||||
}
|
||||
|
||||
return defaultAuthorizationManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationTrustResolver} to be used. Default is
|
||||
* {@link AuthenticationTrustResolverImpl}. Cannot be null.
|
||||
* @param trustResolver the {@link AuthenticationTrustResolver} to use
|
||||
* @since 5.8
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
Assert.notNull(trustResolver, "trustResolver cannot be null");
|
||||
this.trustResolver = trustResolver;
|
||||
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,10 +207,13 @@ public class SecurityEvaluationContextExtension implements EvaluationContextExte
|
||||
* Cannot be null.
|
||||
* @param roleHierarchy the {@link RoleHierarchy} to use
|
||||
* @since 5.8
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
||||
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
getDefaultAuthorizationManagerFactory().setRoleHierarchy(roleHierarchy);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,8 +237,12 @@ public class SecurityEvaluationContextExtension implements EvaluationContextExte
|
||||
* @param defaultRolePrefix the default prefix to add to roles. The default is
|
||||
* "ROLE_".
|
||||
* @since 5.8
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
getDefaultAuthorizationManagerFactory().setRolePrefix(defaultRolePrefix);
|
||||
this.defaultRolePrefix = defaultRolePrefix;
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,9 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.expression.DenyAllPermissionEvaluator;
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
@ -102,9 +101,11 @@ public class SecurityEvaluationContextExtensionTests {
|
||||
public void setTrustResolverWhenNotNullThenVerifyRootObject() {
|
||||
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "ROLE_EXPLICIT");
|
||||
this.securityExtension = new SecurityEvaluationContextExtension(explicit);
|
||||
AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
AuthenticationTrustResolver trustResolver = mock(AuthenticationTrustResolver.class);
|
||||
given(trustResolver.isAuthenticated(explicit)).willReturn(true);
|
||||
this.securityExtension.setTrustResolver(trustResolver);
|
||||
assertThat(getRoot()).extracting("trustResolver").isEqualTo(trustResolver);
|
||||
assertThat(getRoot().isAuthenticated()).isTrue();
|
||||
verify(trustResolver).isAuthenticated(explicit);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -117,11 +118,11 @@ public class SecurityEvaluationContextExtensionTests {
|
||||
|
||||
@Test
|
||||
public void setRoleHierarchyWhenNotNullThenVerifyRootObject() {
|
||||
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "ROLE_EXPLICIT");
|
||||
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "ROLE_PARENT");
|
||||
this.securityExtension = new SecurityEvaluationContextExtension(explicit);
|
||||
RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
||||
RoleHierarchy roleHierarchy = RoleHierarchyImpl.fromHierarchy("ROLE_PARENT > ROLE_EXPLICIT");
|
||||
this.securityExtension.setRoleHierarchy(roleHierarchy);
|
||||
assertThat(getRoot()).extracting("roleHierarchy").isEqualTo(roleHierarchy);
|
||||
assertThat(getRoot().hasRole("EXPLICIT")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -143,25 +144,25 @@ public class SecurityEvaluationContextExtensionTests {
|
||||
|
||||
@Test
|
||||
public void setDefaultRolePrefixWhenCustomThenVerifyRootObject() {
|
||||
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "ROLE_EXPLICIT");
|
||||
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "CUSTOM_EXPLICIT");
|
||||
this.securityExtension = new SecurityEvaluationContextExtension(explicit);
|
||||
String defaultRolePrefix = "CUSTOM_";
|
||||
this.securityExtension.setDefaultRolePrefix(defaultRolePrefix);
|
||||
assertThat(getRoot()).extracting("defaultRolePrefix").isEqualTo(defaultRolePrefix);
|
||||
assertThat(getRoot().hasRole("EXPLICIT")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRootObjectWhenAdditionalFieldsNotSetThenVerifyDefaults() {
|
||||
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "ROLE_EXPLICIT");
|
||||
this.securityExtension = new SecurityEvaluationContextExtension(explicit);
|
||||
SecurityExpressionRoot root = getRoot();
|
||||
assertThat(root).extracting("trustResolver").isInstanceOf(AuthenticationTrustResolverImpl.class);
|
||||
assertThat(root).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
|
||||
assertThat(root).extracting("permissionEvaluator").isInstanceOf(DenyAllPermissionEvaluator.class);
|
||||
assertThat(root).extracting("defaultRolePrefix").isEqualTo("ROLE_");
|
||||
SecurityExpressionRoot<?> securityExpressionRoot = getRoot();
|
||||
assertThat(securityExpressionRoot.isAuthenticated()).isTrue();
|
||||
assertThat(securityExpressionRoot.hasRole("PARENT")).isFalse();
|
||||
assertThat(securityExpressionRoot.hasRole("EXPLICIT")).isTrue();
|
||||
assertThat(securityExpressionRoot.hasPermission(new Object(), "read")).isFalse();
|
||||
}
|
||||
|
||||
private SecurityExpressionRoot getRoot() {
|
||||
private SecurityExpressionRoot<?> getRoot() {
|
||||
return this.securityExtension.getRootObject();
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,43 @@ Another manager is the `AuthenticatedAuthorizationManager`.
|
||||
It can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
|
||||
Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
|
||||
|
||||
[[authz-authorization-manager-factory]]
|
||||
=== Creating AuthorizationManager instances
|
||||
|
||||
The javadoc:org.springframework.security.authorization.AuthorizationManagerFactory[] interface (introduced in Spring Security 7.0) is used to create generic ``AuthorizationManager``s in xref:servlet/authorization/authorize-http-requests.adoc[request-based] and xref:servlet/authorization/method-security.adoc[method-based] authorization components.
|
||||
The following is a sketch of the `AuthorizationManagerFactory` interface:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
public interface AuthorizationManagerFactory<T> {
|
||||
AuthorizationManager<T> permitAll();
|
||||
AuthorizationManager<T> denyAll();
|
||||
AuthorizationManager<T> hasRole(String role);
|
||||
AuthorizationManager<T> hasAnyRole(String... roles);
|
||||
AuthorizationManager<T> hasAuthority(String authority);
|
||||
AuthorizationManager<T> hasAnyAuthority(String... authorities);
|
||||
AuthorizationManager<T> authenticated();
|
||||
AuthorizationManager<T> fullyAuthenticated();
|
||||
AuthorizationManager<T> rememberMe();
|
||||
AuthorizationManager<T> anonymous();
|
||||
}
|
||||
----
|
||||
|
||||
The default implementation is javadoc:org.springframework.security.authorization.DefaultAuthorizationManagerFactory[], which allows for customizing the `rolePrefix` (defaults to `"ROLE_"`), `RoleHierarchy` and `AuthenticationTrustManager` that are provided to the ``AuthorizationManager``s created by the factory.
|
||||
|
||||
In order to customize the default instance used by Spring Security, simply publish a bean as in the following example:
|
||||
|
||||
include-code::./AuthorizationManagerFactoryConfiguration[tag=config,indent=0]
|
||||
|
||||
[TIP]
|
||||
It is also possible to target a specific usage of this factory within Spring Security by providing a concrete parameterized type instead of a generic type.
|
||||
See examples of each in the xref:servlet/authorization/authorize-http-requests.adoc#customizing-authorization-managers[request-based] and xref:servlet/authorization/method-security.adoc#customizing-authorization-managers[method-based] sections of the documentation.
|
||||
|
||||
In addition to simply customizing the default instance of `AuthorizationManagerFactory`, you can provide your own implementation to fully customize the instances created by the factory and provide your own implementations.
|
||||
|
||||
[NOTE]
|
||||
The {gh-url}/core/src/main/java/org/springframework/security/authorization/AuthorizationManagerFactory.java[actual interface] provides default implementations for all factory methods, which allows custom implementations to only implement the methods that need to be customized.
|
||||
|
||||
[[authz-authorization-managers]]
|
||||
==== AuthorizationManagers
|
||||
There are also helpful static factories in javadoc:org.springframework.security.authorization.AuthorizationManagers[] for composing individual ``AuthorizationManager``s into more sophisticated expressions.
|
||||
|
@ -57,6 +57,7 @@ In many cases, your authorization rules will be more sophisticated than that, so
|
||||
* I want to <<match-by-custom, match a request programmatically>>
|
||||
* I want to <<authorize-requests, authorize a request programmatically>>
|
||||
* I want to <<remote-authorization-manager, delegate request authorization>> to a policy agent
|
||||
* I want to <<customizing-authorization-managers,customize how authorization managers are created>>
|
||||
|
||||
[[request-authorization-architecture]]
|
||||
== Understanding How Request Authorization Components Work
|
||||
@ -765,6 +766,24 @@ You will notice that since we are using the `hasRole` expression we do not need
|
||||
<6> Any URL that has not already been matched on is denied access.
|
||||
This is a good strategy if you do not want to accidentally forget to update your authorization rules.
|
||||
|
||||
[[customizing-authorization-managers]]
|
||||
== Customizing Authorization Managers
|
||||
|
||||
When you use the `authorizeHttpRequests` DSL, Spring Security takes care of creating the appropriate `AuthorizationManager` instances for you.
|
||||
In certain cases, you may want to customize what is created in order to have complete control over how authorization decisions are made xref:servlet/authorization/architecture.adoc#authz-delegate-authorization-manager[at the framework level].
|
||||
|
||||
In order to take control of creating instances of `AuthorizationManager` for authorizing HTTP requests, you can create a custom xref:servlet/authorization/architecture.adoc#authz-authorization-manager-factory[`AuthorizationManagerFactory`].
|
||||
For example, let's say you want to create a convention that authenticated users must be authenticated _AND_ have the `USER` role.
|
||||
To do this, you can create a custom implementation for HTTP requests as in the following example:
|
||||
|
||||
include-code::./CustomHttpRequestsAuthorizationManagerFactory[tag=class,indent=0]
|
||||
|
||||
Now, whenever you <<activate-request-security,require authentication>>, Spring Security will automatically invoke your custom factory to create an instance of `AuthorizationManager` that requires authentication _AND_ the `USER` role.
|
||||
|
||||
[TIP]
|
||||
We use this as a simple example of creating a custom `AuthorizationManagerFactory`, though it is also possible (and often simpler) to replace a specific `AuthorizationManager` only for a particular request.
|
||||
See <<remote-authorization-manager>> for an example.
|
||||
|
||||
[[authorization-expressions]]
|
||||
== Expressing Authorization with SpEL
|
||||
|
||||
|
@ -1995,6 +1995,24 @@ This works on both classes and interfaces.
|
||||
This does not work for interfaces, since they do not have debug information about the parameter names.
|
||||
For interfaces, either annotations or the `-parameters` approach must be used.
|
||||
|
||||
[[customizing-authorization-managers]]
|
||||
== Customizing Authorization Managers
|
||||
|
||||
When you use SpEL expressions with <<use-preauthorize,`@PreAuthorize`>>, <<use-postauthorize,`@PostAuthorize`>>, <<use-prefilter,`@PreFilter`>> and <<use-postfilter,`@PostFilter`>>, Spring Security takes care of creating the appropriate `AuthorizationManager` instances for you.
|
||||
In certain cases, you may want to customize what is created in order to have complete control over how authorization decisions are made xref:servlet/authorization/architecture.adoc#authz-delegate-authorization-manager[at the framework level].
|
||||
|
||||
In order to take control of creating instances of `AuthorizationManager` for pre- and post-annotations, you can create a custom xref:servlet/authorization/architecture.adoc#authz-authorization-manager-factory[`AuthorizationManagerFactory`].
|
||||
For example, let's say you want to allow users with the `ADMIN` role whenever any other role is required.
|
||||
To do this, you can create a custom implementation for method security as in the following example:
|
||||
|
||||
include-code::./CustomMethodInvocationAuthorizationManagerFactory[tag=class,indent=0]
|
||||
|
||||
Now, whenever you <<use-preauthorize,use the `@PreAuthorize` annotation>> with `hasRole` or `hasAnyRole`, Spring Security will automatically invoke your custom factory to create an instance of `AuthorizationManager` that allows access for the given role(s) _OR_ the `ADMIN` role.
|
||||
|
||||
[TIP]
|
||||
We use this as a simple example of creating a custom `AuthorizationManagerFactory`, though the same outcome could be accomplished with <<favor-granting-authorities,a role hierarchy>>.
|
||||
Use whichever approach fits best in your situation.
|
||||
|
||||
[[authorize-object]]
|
||||
== Authorizing Arbitrary Objects
|
||||
|
||||
|
@ -12,6 +12,7 @@ Each section that follows will indicate the more notable removals as well as the
|
||||
== Core
|
||||
|
||||
* Removed `AuthorizationManager#check` in favor of `AuthorizationManager#authorize`
|
||||
* Added xref:servlet/authorization/architecture.adoc#authz-authorization-manager-factory[`AuthorizationManagerFactory`] for creating `AuthorizationManager` instances in xref:servlet/authorization/authorize-http-requests.adoc#customizing-authorization-managers[request-based] and xref:servlet/authorization/method-security.adoc#customizing-authorization-managers[method-based] authorization components
|
||||
|
||||
== Config
|
||||
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain clients copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.authorization.authzauthorizationmanagerfactory;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||
|
||||
/**
|
||||
* Documentation for {@link AuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class AuthorizationManagerFactoryConfiguration {
|
||||
|
||||
// tag::config[]
|
||||
@Bean
|
||||
<T> AuthorizationManagerFactory<T> authorizationManagerFactory() {
|
||||
DefaultAuthorizationManagerFactory<T> authorizationManagerFactory =
|
||||
new DefaultAuthorizationManagerFactory<>();
|
||||
authorizationManagerFactory.setTrustResolver(getAuthenticationTrustResolver());
|
||||
authorizationManagerFactory.setRoleHierarchy(getRoleHierarchy());
|
||||
authorizationManagerFactory.setRolePrefix("role_");
|
||||
|
||||
return authorizationManagerFactory;
|
||||
}
|
||||
// end::config[]
|
||||
|
||||
private static AuthenticationTrustResolverImpl getAuthenticationTrustResolver() {
|
||||
AuthenticationTrustResolverImpl authenticationTrustResolver =
|
||||
new AuthenticationTrustResolverImpl();
|
||||
authenticationTrustResolver.setAnonymousClass(Anonymous.class);
|
||||
authenticationTrustResolver.setRememberMeClass(RememberMe.class);
|
||||
|
||||
return authenticationTrustResolver;
|
||||
}
|
||||
|
||||
private static RoleHierarchyImpl getRoleHierarchy() {
|
||||
return RoleHierarchyImpl.fromHierarchy("role_admin > role_user");
|
||||
}
|
||||
|
||||
static class Anonymous extends TestingAuthenticationToken {
|
||||
|
||||
Anonymous(String principal) {
|
||||
super(principal, "", "role_anonymous");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class RememberMe extends TestingAuthenticationToken {
|
||||
|
||||
RememberMe(String principal) {
|
||||
super(principal, "", "role_rememberMe");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain clients copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.authorization.authzauthorizationmanagerfactory;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.docs.servlet.authorization.authzauthorizationmanagerfactory.AuthorizationManagerFactoryConfiguration.Anonymous;
|
||||
import org.springframework.security.docs.servlet.authorization.authzauthorizationmanagerfactory.AuthorizationManagerFactoryConfiguration.RememberMe;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
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.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationManagerFactoryConfiguration}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class AuthorizationManagerFactoryConfigurationTests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void getAnonymousWhenCustomAnonymousClassThenOk() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new Anonymous("anonymous");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/anonymous").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnonymousWhenAuthenticatedThenForbidden() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "role_user");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/anonymous").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRememberMeWhenCustomRememberMeClassThenOk() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new RememberMe("rememberMe");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/rememberMe").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRememberMeWhenAuthenticatedThenForbidden() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "role_user");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/rememberMe").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserWhenCustomUserRoleThenOk() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "role_user");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserWhenCustomAdminRoleThenOk() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("admin", "", "role_admin");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPreAuthorizeWhenCustomUserRoleThenOk() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "role_user");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/preAuthorize").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPreAuthorizeWhenCustomAdminRoleThenOk() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("admin", "", "role_admin");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/preAuthorize").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPreAuthorizeWhenOtherRoleThenForbidden() throws Exception {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration.class, SecurityConfiguration.class,
|
||||
TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("other", "", "role_other");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/preAuthorize").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@Configuration
|
||||
static class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers("/anonymous").anonymous()
|
||||
.requestMatchers("/rememberMe").rememberMe()
|
||||
.requestMatchers("/user").hasRole("user")
|
||||
.requestMatchers("/preAuthorize").permitAll()
|
||||
.anyRequest().denyAll()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping({ "/anonymous", "/rememberMe", "/user" })
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
void httpRequest() {
|
||||
}
|
||||
|
||||
@GetMapping("/preAuthorize")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@PreAuthorize("hasRole('user')")
|
||||
void preAuthorize() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain clients copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.authorization.customizingauthorizationmanagers;
|
||||
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.AuthorizationManagers;
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Documentation for {@link AuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Component
|
||||
public class CustomHttpRequestsAuthorizationManagerFactory
|
||||
implements AuthorizationManagerFactory<RequestAuthorizationContext> {
|
||||
|
||||
private final AuthorizationManagerFactory<RequestAuthorizationContext> delegate =
|
||||
new DefaultAuthorizationManagerFactory<>();
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<RequestAuthorizationContext> authenticated() {
|
||||
return AuthorizationManagers.allOf(
|
||||
this.delegate.authenticated(),
|
||||
this.delegate.hasRole("USER")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain clients copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.authorization.customizingauthorizationmanagers;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
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.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link CustomHttpRequestsAuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class CustomHttpRequestsAuthorizationManagerFactoryTests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void getHelloWhenAnonymousThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/hello").with(anonymous()))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(unauthenticated());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHelloWhenAuthenticatedWithNoRolesThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", Collections.emptyList());
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/hello").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHelloWhenAuthenticatedWithUserRoleThenOk() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "ROLE_USER");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/hello").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHelloWhenAuthenticatedWithOtherRoleThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "ROLE_OTHER");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/hello").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CustomHttpRequestsAuthorizationManagerFactory customHttpRequestsAuthorizationManagerFactory() {
|
||||
return new CustomHttpRequestsAuthorizationManagerFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/**")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
void ok() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain clients copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.authorization.customizingauthorizationmanagers;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.AuthorizationManagers;
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Documentation for {@link AuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Component
|
||||
public class CustomMethodInvocationAuthorizationManagerFactory
|
||||
implements AuthorizationManagerFactory<MethodInvocation> {
|
||||
|
||||
private final AuthorizationManagerFactory<MethodInvocation> delegate =
|
||||
new DefaultAuthorizationManagerFactory<>();
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<MethodInvocation> hasRole(String role) {
|
||||
return AuthorizationManagers.anyOf(
|
||||
this.delegate.hasRole(role),
|
||||
this.delegate.hasRole("ADMIN")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<MethodInvocation> hasAnyRole(String... roles) {
|
||||
return AuthorizationManagers.anyOf(
|
||||
this.delegate.hasAnyRole(roles),
|
||||
this.delegate.hasRole("ADMIN")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain clients copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.authorization.customizingauthorizationmanagers;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
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.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link CustomMethodInvocationAuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class CustomMethodInvocationAuthorizationManagerFactoryTests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void getUserWhenAnonymousThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(anonymous()))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(unauthenticated());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserWhenAuthenticatedWithNoRolesThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", Collections.emptyList());
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserWhenAuthenticatedWithUserRoleThenOk() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "ROLE_USER");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserWhenAuthenticatedWithAdminRoleThenOk() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("admin", "", "ROLE_ADMIN");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserWhenAuthenticatedWithOtherRoleThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "ROLE_OTHER");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRolesWhenAuthenticatedWithRole1RoleThenOk() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "ROLE_ROLE1");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/roles").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRolesWhenAuthenticatedWithAdminRoleThenOk() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("admin", "", "ROLE_ADMIN");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/roles").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRolesWhenAuthenticatedWithOtherRoleThenForbidden() throws Exception {
|
||||
this.spring.register(SecurityConfiguration.class, TestController.class).autowire();
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "", "ROLE_OTHER");
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/roles").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@Configuration
|
||||
static class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CustomMethodInvocationAuthorizationManagerFactory customMethodInvocationAuthorizationManagerFactory() {
|
||||
return new CustomMethodInvocationAuthorizationManagerFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/user")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
void user() {
|
||||
}
|
||||
|
||||
@GetMapping("/roles")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@PreAuthorize("hasAnyRole('ROLE1', 'ROLE2')")
|
||||
void roles() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.authorization.authzauthorizationmanagerfactory
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory
|
||||
|
||||
/**
|
||||
* Documentation for [org.springframework.security.authorization.AuthorizationManagerFactory].
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class AuthorizationManagerFactoryConfiguration {
|
||||
// tag::config[]
|
||||
@Bean
|
||||
fun <T> authorizationManagerFactory(): AuthorizationManagerFactory<T> {
|
||||
val authorizationManagerFactory = DefaultAuthorizationManagerFactory<T>()
|
||||
authorizationManagerFactory.setTrustResolver(getAuthenticationTrustResolver())
|
||||
authorizationManagerFactory.setRoleHierarchy(getRoleHierarchy())
|
||||
authorizationManagerFactory.setRolePrefix("role_")
|
||||
|
||||
return authorizationManagerFactory
|
||||
}
|
||||
// end::config[]
|
||||
|
||||
private fun getAuthenticationTrustResolver(): AuthenticationTrustResolverImpl {
|
||||
val authenticationTrustResolver = AuthenticationTrustResolverImpl()
|
||||
authenticationTrustResolver.setAnonymousClass(Anonymous::class.java)
|
||||
authenticationTrustResolver.setRememberMeClass(RememberMe::class.java)
|
||||
|
||||
return authenticationTrustResolver
|
||||
}
|
||||
|
||||
private fun getRoleHierarchy(): RoleHierarchyImpl {
|
||||
return RoleHierarchyImpl.fromHierarchy("role_admin > role_user")
|
||||
}
|
||||
|
||||
internal class Anonymous(principal: String) :
|
||||
TestingAuthenticationToken(principal, "", "role_anonymous")
|
||||
|
||||
internal class RememberMe(principal: String) :
|
||||
TestingAuthenticationToken(principal, "", "role_rememberMe")
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.authorization.authzauthorizationmanagerfactory
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.kt.docs.servlet.authorization.authzauthorizationmanagerfactory.AuthorizationManagerFactoryConfiguration.Anonymous
|
||||
import org.springframework.security.kt.docs.servlet.authorization.authzauthorizationmanagerfactory.AuthorizationManagerFactoryConfiguration.RememberMe
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [AuthorizationManagerFactoryConfiguration].
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class AuthorizationManagerFactoryConfigurationTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getAnonymousWhenCustomAnonymousClassThenOk() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = Anonymous("anonymous")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/anonymous").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getAnonymousWhenAuthenticatedThenForbidden() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "role_user")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/anonymous").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getRememberMeWhenCustomRememberMeClassThenOk() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = RememberMe("rememberMe")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/rememberMe").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getRememberMeWhenAuthenticatedThenForbidden() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val user = TestingAuthenticationToken("user", "", "role_user")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/rememberMe").with(authentication(user)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(user))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenCustomUserRoleThenOk() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "role_user")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenCustomAdminRoleThenOk() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val admin = TestingAuthenticationToken("admin", "", "role_admin")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(authentication(admin)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(admin))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getPreAuthorizeWhenCustomUserRoleThenOk() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "role_user")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/preAuthorize").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getPreAuthorizeWhenCustomAdminRoleThenOk() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = TestingAuthenticationToken("admin", "", "role_admin")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/preAuthorize").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getPreAuthorizeWhenOtherRoleThenForbidden() {
|
||||
this.spring.register(AuthorizationManagerFactoryConfiguration::class.java, SecurityConfiguration::class.java)
|
||||
.autowire()
|
||||
val authentication = TestingAuthenticationToken("other", "", "role_other")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/preAuthorize").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@Configuration
|
||||
internal open class SecurityConfiguration {
|
||||
@Bean
|
||||
@Throws(Exception::class)
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http.authorizeHttpRequests { authorize ->
|
||||
authorize
|
||||
.requestMatchers("/anonymous").anonymous()
|
||||
.requestMatchers("/rememberMe").rememberMe()
|
||||
.requestMatchers("/user").hasRole("user")
|
||||
.requestMatchers("/preAuthorize").permitAll()
|
||||
.anyRequest().denyAll()
|
||||
}
|
||||
// @formatter:on
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun testController(testService: TestService): TestController {
|
||||
return TestController(testService())
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun testService(): TestService {
|
||||
return TestServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal open class TestController(private val testService: TestService) {
|
||||
@GetMapping(value = ["/anonymous", "/rememberMe", "/user"])
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
fun httpRequest() {
|
||||
}
|
||||
|
||||
@GetMapping("/preAuthorize")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
fun preAuthorize() {
|
||||
testService.preAuthorize()
|
||||
}
|
||||
}
|
||||
|
||||
internal interface TestService {
|
||||
@PreAuthorize("hasRole('user')")
|
||||
fun preAuthorize()
|
||||
}
|
||||
|
||||
internal open class TestServiceImpl : TestService {
|
||||
override fun preAuthorize() {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.authorization.customizingauthorizationmanagers
|
||||
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory
|
||||
import org.springframework.security.authorization.AuthorizationManagers
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* Documentation for {@link AuthorizationManagerFactory}.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Component
|
||||
class CustomHttpRequestsAuthorizationManagerFactory : AuthorizationManagerFactory<RequestAuthorizationContext> {
|
||||
private val delegate = DefaultAuthorizationManagerFactory<RequestAuthorizationContext>()
|
||||
|
||||
override fun authenticated(): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorizationManagers.allOf(
|
||||
delegate.authenticated(),
|
||||
delegate.hasRole("USER")
|
||||
)
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.authorization.customizingauthorizationmanagers
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [CustomHttpRequestsAuthorizationManagerFactory].
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class CustomHttpRequestsAuthorizationManagerFactoryTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getHelloWhenAnonymousThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java, TestController::class.java).autowire()
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/hello").with(anonymous()))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(SecurityMockMvcResultMatchers.unauthenticated())
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getHelloWhenAuthenticatedWithUserRoleThenOk() {
|
||||
spring.register(SecurityConfiguration::class.java, TestController::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_USER")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/hello").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getHelloWhenAuthenticatedWithOtherRoleThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java, TestController::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_OTHER")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/hello").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getHelloWhenAuthenticatedWithNoRolesThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java, TestController::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", listOf())
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/hello").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
internal open class SecurityConfiguration {
|
||||
@Bean
|
||||
@Throws(Exception::class)
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests { authorize ->
|
||||
authorize.anyRequest().authenticated()
|
||||
}
|
||||
// @formatter:on
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun customHttpRequestsAuthorizationManagerFactory(): CustomHttpRequestsAuthorizationManagerFactory {
|
||||
return CustomHttpRequestsAuthorizationManagerFactory()
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class TestController {
|
||||
@GetMapping("/**")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
fun ok() {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.authorization.customizingauthorizationmanagers
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory
|
||||
import org.springframework.security.authorization.AuthorizationManagers
|
||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* Documentation for [AuthorizationManagerFactory].
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Component
|
||||
class CustomMethodInvocationAuthorizationManagerFactory : AuthorizationManagerFactory<MethodInvocation> {
|
||||
private val delegate = DefaultAuthorizationManagerFactory<MethodInvocation>()
|
||||
|
||||
override fun hasRole(role: String): AuthorizationManager<MethodInvocation> {
|
||||
return AuthorizationManagers.anyOf(
|
||||
delegate.hasRole(role),
|
||||
delegate.hasRole("ADMIN")
|
||||
)
|
||||
}
|
||||
|
||||
override fun hasAnyRole(vararg roles: String): AuthorizationManager<MethodInvocation> {
|
||||
return AuthorizationManagers.anyOf(
|
||||
delegate.hasAnyRole(*roles),
|
||||
delegate.hasRole("ADMIN")
|
||||
)
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
|
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.authorization.customizingauthorizationmanagers
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [CustomMethodInvocationAuthorizationManagerFactory].
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class CustomMethodInvocationAuthorizationManagerFactoryTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenAnonymousThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(anonymous()))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(unauthenticated())
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenAuthenticatedWithNoRolesThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", listOf())
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenAuthenticatedWithUserRoleThenOk() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_USER")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenAuthenticatedWithAdminRoleThenOk() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_ADMIN")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getUserWhenAuthenticatedWithOtherRoleThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_OTHER")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/user").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getRolesWhenAuthenticatedWithRole1RoleThenOk() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_ROLE1")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/roles").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getRolesWhenAuthenticatedWithAdminRoleThenOk() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_ADMIN")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/roles").with(authentication(authentication)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun getRolesWhenAuthenticatedWithOtherRoleThenForbidden() {
|
||||
spring.register(SecurityConfiguration::class.java).autowire()
|
||||
val authentication = TestingAuthenticationToken("user", "", "ROLE_OTHER")
|
||||
// @formatter:off
|
||||
mockMvc.perform(get("/roles").with(authentication(authentication)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(authenticated().withAuthentication(authentication))
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@Configuration
|
||||
internal open class SecurityConfiguration {
|
||||
@Bean
|
||||
@Throws(Exception::class)
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests { authorize ->
|
||||
authorize.anyRequest().authenticated()
|
||||
}
|
||||
// @formatter:on
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun customMethodInvocationAuthorizationManagerFactory(): CustomMethodInvocationAuthorizationManagerFactory {
|
||||
return CustomMethodInvocationAuthorizationManagerFactory()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun testController(testService: TestService): TestController {
|
||||
return TestController(testService())
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun testService(): TestService {
|
||||
return TestServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal open class TestController(private val testService: TestService) {
|
||||
@GetMapping("/user")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
fun user() {
|
||||
testService.user()
|
||||
}
|
||||
|
||||
@GetMapping("/roles")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
fun roles() {
|
||||
testService.roles()
|
||||
}
|
||||
}
|
||||
|
||||
internal interface TestService {
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
fun user()
|
||||
|
||||
@PreAuthorize("hasAnyRole('ROLE1', 'ROLE2')")
|
||||
fun roles()
|
||||
}
|
||||
|
||||
internal open class TestServiceImpl : TestService {
|
||||
override fun user() {
|
||||
}
|
||||
|
||||
override fun roles() {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2004-present the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ https://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<!-- tag::config[] -->
|
||||
<b:bean id="authorizationManagerFactory" class="org.springframework.security.authorization.DefaultAuthorizationManagerFactory">
|
||||
<b:property name="trustResolver" ref="authenticationTrustResolver"/>
|
||||
<b:property name="roleHierarchy" ref="roleHierarchy"/>
|
||||
<b:property name="rolePrefix" value="role_"/>
|
||||
</b:bean>
|
||||
<!-- end::config[] -->
|
||||
|
||||
<b:bean id="authenticationTrustResolver" class="org.springframework.security.authentication.AuthenticationTrustResolverImpl">
|
||||
<b:property name="anonymousClass" value="org.springframework.security.authentication.TestingAuthenticationToken"/>
|
||||
</b:bean>
|
||||
|
||||
<b:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl" factory-method="fromHierarchy">
|
||||
<b:constructor-arg name="hierarchy" value="role_admin > role_user"/>
|
||||
</b:bean>
|
||||
|
||||
</b:beans>
|
@ -36,6 +36,7 @@
|
||||
<suppress files="JoseHeader\.java" checks="SpringMethodVisibility"/>
|
||||
<suppress files="DefaultLoginPageGeneratingFilterTests\.java" checks="SpringLeadingWhitespace"/>
|
||||
<suppress files="AuthenticationException\.java" checks="MutableException"/>
|
||||
<suppress files="FilterInvocationExpressionRoot\.java" checks="SpringMethodVisibility"/>
|
||||
|
||||
<!-- Lambdas that we can't replace with a method reference because a closure is required -->
|
||||
<suppress files="BearerTokenAuthenticationFilter\.java" checks="SpringLambda"/>
|
||||
|
@ -28,9 +28,8 @@ import org.springframework.security.access.expression.AbstractSecurityExpression
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link SecurityExpressionHandler} which uses a
|
||||
@ -43,12 +42,10 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class DefaultMessageSecurityExpressionHandler<T> extends AbstractSecurityExpressionHandler<Message<T>> {
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
@Override
|
||||
public EvaluationContext createEvaluationContext(Supplier<? extends @Nullable Authentication> authentication,
|
||||
Message<T> message) {
|
||||
MessageSecurityExpressionRoot root = createSecurityExpressionRoot(authentication, message);
|
||||
MessageSecurityExpressionRoot<T> root = createSecurityExpressionRoot(authentication, message);
|
||||
StandardEvaluationContext ctx = new StandardEvaluationContext(root);
|
||||
BeanResolver beanResolver = getBeanResolver();
|
||||
if (beanResolver != null) {
|
||||
@ -64,18 +61,21 @@ public class DefaultMessageSecurityExpressionHandler<T> extends AbstractSecurity
|
||||
return createSecurityExpressionRoot(() -> authentication, invocation);
|
||||
}
|
||||
|
||||
private MessageSecurityExpressionRoot createSecurityExpressionRoot(
|
||||
private MessageSecurityExpressionRoot<T> createSecurityExpressionRoot(
|
||||
Supplier<? extends Authentication> authentication, Message<T> invocation) {
|
||||
MessageSecurityExpressionRoot root = new MessageSecurityExpressionRoot(authentication, invocation);
|
||||
MessageSecurityExpressionRoot<T> root = new MessageSecurityExpressionRoot<>(authentication, invocation);
|
||||
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(this.trustResolver);
|
||||
root.setRoleHierarchy(getRoleHierarchy());
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
Assert.notNull(trustResolver, "trustResolver cannot be null");
|
||||
this.trustResolver = trustResolver;
|
||||
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ package org.springframework.security.messaging.access.expression;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@ -27,13 +29,14 @@ import org.springframework.security.core.Authentication;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @since 4.0
|
||||
*/
|
||||
public class MessageSecurityExpressionRoot extends SecurityExpressionRoot {
|
||||
public class MessageSecurityExpressionRoot<T> extends SecurityExpressionRoot<Message<T>> {
|
||||
|
||||
public final Message<?> message;
|
||||
public final Message<T> message;
|
||||
|
||||
public MessageSecurityExpressionRoot(Authentication authentication, Message<?> message) {
|
||||
public MessageSecurityExpressionRoot(Authentication authentication, Message<T> message) {
|
||||
this(() -> authentication, message);
|
||||
}
|
||||
|
||||
@ -44,8 +47,9 @@ public class MessageSecurityExpressionRoot extends SecurityExpressionRoot {
|
||||
* @param message the {@link Message} to use
|
||||
* @since 5.8
|
||||
*/
|
||||
public MessageSecurityExpressionRoot(Supplier<? extends Authentication> authentication, Message<?> message) {
|
||||
super(authentication);
|
||||
public MessageSecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication,
|
||||
Message<T> message) {
|
||||
super(authentication, message);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||
import org.springframework.util.Assert;
|
||||
@ -36,14 +37,15 @@ import org.springframework.util.Assert;
|
||||
* create a {@link WebSecurityExpressionRoot}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @since 5.8
|
||||
*/
|
||||
public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpressionHandler<RequestAuthorizationContext>
|
||||
implements SecurityExpressionHandler<RequestAuthorizationContext> {
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
private String defaultRolePrefix = DEFAULT_ROLE_PREFIX;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway") // https://github.com/spring-projects/spring-framework/issues/35371
|
||||
@ -64,11 +66,13 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres
|
||||
|
||||
private WebSecurityExpressionRoot createSecurityExpressionRoot(
|
||||
Supplier<? extends @Nullable Authentication> authentication, RequestAuthorizationContext context) {
|
||||
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, context.getRequest());
|
||||
root.setRoleHierarchy(getRoleHierarchy());
|
||||
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, context);
|
||||
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(this.trustResolver);
|
||||
root.setDefaultRolePrefix(this.defaultRolePrefix);
|
||||
if (!DEFAULT_ROLE_PREFIX.equals(this.defaultRolePrefix)) {
|
||||
// Ensure SecurityExpressionRoot can strip the custom role prefix
|
||||
root.setDefaultRolePrefix(this.defaultRolePrefix);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -76,10 +80,12 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres
|
||||
* Sets the {@link AuthenticationTrustResolver} to be used. The default is
|
||||
* {@link AuthenticationTrustResolverImpl}.
|
||||
* @param trustResolver the {@link AuthenticationTrustResolver} to use
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
Assert.notNull(trustResolver, "trustResolver cannot be null");
|
||||
this.trustResolver = trustResolver;
|
||||
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,9 +97,13 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres
|
||||
* role ROLE_ADMIN will be used when the defaultRolePrefix is "ROLE_" (default).
|
||||
* @param defaultRolePrefix the default prefix to add to roles. The default is
|
||||
* "ROLE_".
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
Assert.notNull(defaultRolePrefix, "defaultRolePrefix cannot be null");
|
||||
getDefaultAuthorizationManagerFactory().setRolePrefix(defaultRolePrefix);
|
||||
this.defaultRolePrefix = defaultRolePrefix;
|
||||
}
|
||||
|
||||
|
@ -23,30 +23,33 @@ import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Eddú Meléndez
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation>
|
||||
implements SecurityExpressionHandler<FilterInvocation> {
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
private String defaultRolePrefix = DEFAULT_ROLE_PREFIX;
|
||||
|
||||
@Override
|
||||
protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication,
|
||||
FilterInvocation fi) {
|
||||
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
|
||||
FilterInvocationExpressionRoot root = new FilterInvocationExpressionRoot(() -> authentication, fi);
|
||||
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(this.trustResolver);
|
||||
root.setRoleHierarchy(getRoleHierarchy());
|
||||
root.setDefaultRolePrefix(this.defaultRolePrefix);
|
||||
if (!DEFAULT_ROLE_PREFIX.equals(this.defaultRolePrefix)) {
|
||||
// Ensure SecurityExpressionRoot can strip the custom role prefix
|
||||
root.setDefaultRolePrefix(this.defaultRolePrefix);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -55,10 +58,12 @@ public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpress
|
||||
* {@link AuthenticationTrustResolverImpl}.
|
||||
* @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
|
||||
* null.
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
Assert.notNull(trustResolver, "trustResolver cannot be null");
|
||||
this.trustResolver = trustResolver;
|
||||
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,8 +80,15 @@ public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpress
|
||||
* If null or empty, then no default role prefix is used.
|
||||
* </p>
|
||||
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
|
||||
* @deprecated Use
|
||||
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
|
||||
*/
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
@Deprecated(since = "7.0")
|
||||
public void setDefaultRolePrefix(@Nullable String defaultRolePrefix) {
|
||||
if (defaultRolePrefix == null) {
|
||||
defaultRolePrefix = "";
|
||||
}
|
||||
getDefaultAuthorizationManagerFactory().setRolePrefix(defaultRolePrefix);
|
||||
this.defaultRolePrefix = defaultRolePrefix;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.access.expression;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.util.matcher.IpAddressMatcher;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
* @since 7.0
|
||||
*/
|
||||
final class FilterInvocationExpressionRoot extends SecurityExpressionRoot<FilterInvocation> {
|
||||
|
||||
/**
|
||||
* Allows direct access to the request object
|
||||
*/
|
||||
public final HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* Creates an instance for the given {@link Supplier} of the {@link Authentication}
|
||||
* and {@link HttpServletRequest}.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to use
|
||||
* @param fi the {@link FilterInvocation} to use
|
||||
*/
|
||||
FilterInvocationExpressionRoot(Supplier<Authentication> authentication, FilterInvocation fi) {
|
||||
super(authentication, fi);
|
||||
this.request = fi.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a specific IP address or a range using the IP/Netmask (e.g. 192.168.1.0/24 or
|
||||
* 202.24.0.0/14).
|
||||
* @param ipAddress the address or range of addresses from which the request must
|
||||
* come.
|
||||
* @return true if the IP address of the current request is in the required range.
|
||||
*/
|
||||
public boolean hasIpAddress(String ipAddress) {
|
||||
IpAddressMatcher matcher = new IpAddressMatcher(ipAddress);
|
||||
return matcher.matches(this.request);
|
||||
}
|
||||
|
||||
}
|
@ -24,22 +24,29 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||
import org.springframework.security.web.util.matcher.IpAddressMatcher;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.0
|
||||
*/
|
||||
public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
|
||||
public class WebSecurityExpressionRoot extends SecurityExpressionRoot<RequestAuthorizationContext> {
|
||||
|
||||
/**
|
||||
* Allows direct access to the request object
|
||||
*/
|
||||
public final HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* @deprecated Use
|
||||
* {@link #WebSecurityExpressionRoot(Supplier, RequestAuthorizationContext)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
public WebSecurityExpressionRoot(@Nullable Authentication a, FilterInvocation fi) {
|
||||
this(() -> a, fi.getRequest());
|
||||
this(() -> a, new RequestAuthorizationContext(fi.getRequest()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,14 +55,30 @@ public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to use
|
||||
* @param request the {@link HttpServletRequest} to use
|
||||
* @since 5.8
|
||||
* @deprecated Use
|
||||
* {@link #WebSecurityExpressionRoot(Supplier, RequestAuthorizationContext)} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0")
|
||||
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1246
|
||||
public WebSecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication,
|
||||
HttpServletRequest request) {
|
||||
super(authentication);
|
||||
super(authentication, new RequestAuthorizationContext(request));
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for the given {@link Supplier} of the {@link Authentication}
|
||||
* and {@link HttpServletRequest}.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to use
|
||||
* @param context the {@link RequestAuthorizationContext} to use
|
||||
* @since 7.0
|
||||
*/
|
||||
public WebSecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication,
|
||||
RequestAuthorizationContext context) {
|
||||
super(authentication, context);
|
||||
this.request = context.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a specific IP address or a range using the IP/Netmask (e.g. 192.168.1.0/24 or
|
||||
* 202.24.0.0/14).
|
||||
|
Loading…
x
Reference in New Issue
Block a user