Add SecurityContextHolderStrategy XML Configuration for Method Security
Issue gh-11061
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.List;
|
||||
|
||||
import jakarta.annotation.security.DenyAll;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
@@ -49,6 +50,9 @@ public interface MethodSecurityService {
|
||||
@PermitAll
|
||||
String jsr250PermitAll();
|
||||
|
||||
@RolesAllowed("ADMIN")
|
||||
String jsr250RolesAllowed();
|
||||
|
||||
@Secured({ "ROLE_USER", "RUN_AS_SUPER" })
|
||||
Authentication runAs();
|
||||
|
||||
@@ -73,6 +77,12 @@ public interface MethodSecurityService {
|
||||
@PostAuthorize("#o?.contains('grant')")
|
||||
String postAnnotation(@P("o") String object);
|
||||
|
||||
@PreFilter("filterObject == authentication.name")
|
||||
List<String> preFilterByUsername(List<String> array);
|
||||
|
||||
@PostFilter("filterObject == authentication.name")
|
||||
List<String> postFilterByUsername(List<String> array);
|
||||
|
||||
@PreFilter("filterObject.length > 3")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
@Secured("ROLE_USER")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -51,6 +51,11 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsr250RolesAllowed() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication runAs() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
@@ -88,6 +93,16 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> preFilterByUsername(List<String> array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> postFilterByUsername(List<String> array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> manyAnnotations(List<String> object) {
|
||||
return object;
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.annotation.BusinessService;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
@@ -41,7 +42,10 @@ import org.springframework.security.config.annotation.method.configuration.Metho
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
@@ -49,6 +53,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Josh Cummings
|
||||
@@ -117,6 +122,17 @@ public class MethodSecurityBeanDefinitionParserTests {
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securedWhenCustomSecurityContextHolderStrategyThenUses() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabledCustomSecurityContextHolderStrategy")).autowire();
|
||||
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "pass"));
|
||||
strategy.setContext(context);
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::secured)
|
||||
.withMessage("Access Denied");
|
||||
verify(strategy).getContext();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void securedUserWhenRoleAdminThenAccessDeniedException() {
|
||||
@@ -148,6 +164,17 @@ public class MethodSecurityBeanDefinitionParserTests {
|
||||
this.methodSecurityService.preAuthorizeAdmin();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preAuthorizeWhenCustomSecurityContextHolderStrategyThenUses() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabledCustomSecurityContextHolderStrategy")).autowire();
|
||||
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "pass"));
|
||||
strategy.setContext(context);
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::preAuthorizeAdmin)
|
||||
.withMessage("Access Denied");
|
||||
verify(strategy).getContext();
|
||||
}
|
||||
|
||||
@WithMockUser(authorities = "PREFIX_ADMIN")
|
||||
@Test
|
||||
public void preAuthorizeAdminWhenRoleAdminAndCustomPrefixThenPasses() {
|
||||
@@ -187,6 +214,30 @@ public class MethodSecurityBeanDefinitionParserTests {
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preFilterWhenCustomSecurityContextHolderStrategyThenUses() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabledCustomSecurityContextHolderStrategy")).autowire();
|
||||
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "pass"));
|
||||
strategy.setContext(context);
|
||||
List<String> result = this.methodSecurityService
|
||||
.preFilterByUsername(new ArrayList<>(Arrays.asList("user", "bob", "joe")));
|
||||
assertThat(result).containsExactly("user");
|
||||
verify(strategy).getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postFilterWhenCustomSecurityContextHolderStrategyThenUses() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabledCustomSecurityContextHolderStrategy")).autowire();
|
||||
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "pass"));
|
||||
strategy.setContext(context);
|
||||
List<String> result = this.methodSecurityService
|
||||
.postFilterByUsername(new ArrayList<>(Arrays.asList("user", "bob", "joe")));
|
||||
assertThat(result).containsExactly("user");
|
||||
verify(strategy).getContext();
|
||||
}
|
||||
|
||||
@WithMockUser("bob")
|
||||
@Test
|
||||
public void methodReturningAListWhenPrePostFiltersConfiguredThenFiltersList() {
|
||||
@@ -253,6 +304,17 @@ public class MethodSecurityBeanDefinitionParserTests {
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsr250WhenCustomSecurityContextHolderStrategyThenUses() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabledCustomSecurityContextHolderStrategy")).autowire();
|
||||
SecurityContextHolderStrategy strategy = this.spring.getContext().getBean(SecurityContextHolderStrategy.class);
|
||||
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "pass"));
|
||||
strategy.setContext(context);
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(this.methodSecurityService::jsr250RolesAllowed).withMessage("Access Denied");
|
||||
verify(strategy).getContext();
|
||||
}
|
||||
|
||||
@WithAnonymousUser
|
||||
@Test
|
||||
public void jsr250PermitAllWhenRoleAnonymousThenPasses() {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2002-2022 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"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<method-security secured-enabled="true" jsr250-enabled="true" security-context-holder-strategy-ref="ref"/>
|
||||
|
||||
<b:bean id="ref" class="org.mockito.Mockito" factory-method="spy">
|
||||
<b:constructor-arg>
|
||||
<b:bean class="org.springframework.security.config.MockSecurityContextHolderStrategy"/>
|
||||
</b:constructor-arg>
|
||||
</b:bean>
|
||||
|
||||
<b:bean class="org.springframework.security.config.annotation.method.configuration.MethodSecurityServiceImpl"/>
|
||||
|
||||
</b:beans>
|
||||
Reference in New Issue
Block a user