I am using @PreAuthorize
on methods in service interfaces. Theses services are used by @RestController
classes
With Spring Boot 2.x I enabled method security in a AutoConfiguration with @EnableGlobalMethodSecurity(prePostEnabled = true)
In some @SpringBootTest
s we concentrate on testing the functional logic and don't care about method security. Theses tests do no call a rest service or controller class. They directly call method from above mentioned service classes which are annotated with @PreAuthorize
. In these tests we disabled the method security by
@EnableAspectJAutoProxy
class MyTestApplication extends MySringBootApplication {
@Bean
public GeFaJwtInterceptorTestAspect jwtInterceptorTestAspect() {
return new GeFaJwtInterceptorTestAspect();
}
@Bean
@Primary
SecurityMetadataSource disableMethodSecurityForUnitTest() {
return new DefaultFilterInvocationSecurityMetadataSource(Maps.newLinkedHashMap());
}
}
That works fine.
After migration to Spring Boot 3 I am using @EnableMethodSecurity
now.
How can I disable Spring's security method in unit tests?
I read the article https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html#enable-annotation but did not find a solution there.
I tried out
@EnableMethodSecurity(prePostEnabled = false)
at MyTestApplication
@Bean
@Primary
@Order(Ordered.HIGHEST_PRECEDENCE)
AuthorizationManager<MethodInvocation> disableMethodSecurityForUnitTest1() {
return (authentication, object) -> new AuthorizationDecision(true);
}
But that did not work. Each try end up with one of the following exceptions
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
org.springframework.security.access.AccessDeniedException: Access Denied
Currently my only fix is to add @WithMockUser
on each test method which is not what I want as I want to test the functional logic only. (Method security is tested, too, but on another layer in our application.)
Thank's to Mar-Z answer I came to the clue to disable it by excluding the AutoConfiguration which activates the MethodSecurity.
Currently I only had one AutoConfigration in my maven module. That holds a couple of different Beans/ aspects. So at first I had to separate that AutoConfiguration into two parts. A second AutoConfiguration which only holds the configuration for activating the method security
As exclude
does only works for AutoConfiguration it must be an AutoConfiguration - Configuration only does not work
@AutoConfiguration
@EnableMethodSecurity
public class MyServiceSecurityAutoConfiguration {
// you could add any Beans here relevant for Authorization / method security etc.
}
Of course the class has to be added to src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
In my SpringBootTest
I excluded this AutoConfiguration like this
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {MyIntegrationTestApplication.class})
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY)
@ActiveProfiles({"dev", "console", "test"})
public class MyIntegrationTest {
// any tests here
}
@EnableAutoConfiguration(exclude = {MyServiceSecurityAutoConfiguration .class})
class MyIntegrationTestApplication extends MySpringBootApplication {
// Maybe you need to define some mandatory beans here if they are not loaded by AutoConfiguration
}
If you do not need to extend the SpringBootApplication (here MySpringBootApplication) by any additional bean you can also do this to exclude the MethodeSecurity-Configuration in your test:
@SpringBootTest(classes = {MySpringBootApplication .class})
@EnableAutoConfiguration(exclude = {MyServiceSecurityAutoConfiguration .class})
class MyIntegrationTest {
// any tests here
}
May be that helps other members, too.