Add SecurityContextHolderStrategy XML Configuration for Method Security

Issue gh-11061
This commit is contained in:
Josh Cummings
2022-06-23 16:26:40 -06:00
parent da57bac061
commit 9cd7c7b046
8 changed files with 256 additions and 55 deletions

View File

@@ -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 javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.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")

View File

@@ -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;

View File

@@ -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() {