SecurityMockMvcRequestPostProcessors is a class that simplifies creating RequestPostProcessors for the purposes of testing. In large part, each RequestPostProcessor is responsible for creating an Authentication and populating the SecurityContextHolder.
The builders that SecurityMockMvcRequestPostProcessors exposes are actually quite convenient to use since they provide reasonable testing defaults. For example, oidcLogin() simplifies creating an OAuth2AuthenticationToken by defaulting certain claims and authorities:
RequestPostProcessor requestPostProcessor = oidcLogin().idToken(id -> id
.subject("test-subject"));
this.mvc.perform(get("/").with(requestPostProcessor));
As noted in a related ticket, these builders are designed to support MockMvc testing; however, since many of them are largely responsible for creating an Authentication, such behavior could reasonably be extracted out into a separate class:
public final class TestAuthentications {
public static OidcLoginAuthenticationBuilder oidcLogin() {
return new OidcLoginAuthenticationBuilder();
}
// ...
public static class OidcLoginAuthenticationBuilder {
// ... similar support as OidcLoginRequestPostProcessor
public Authentication build() {
return new OAuth2AuthenticationToken(...);
}
}
}
By doing so, testers could easily build the appropriate Authentication for service-level testing, where MockMvc is not being used:
@Test
public void testMyService() {
Authentication authentication = oidcLogin().idToken(id -> id
.subject("test-subject")).build();
SecurityContextHolder.getContext().setAuthentication(authentication);
// ... rest of test
}
The nice thing about this is that exposing a builder is a great deal more powerful than Spring Security's annotation support that's used in simpler authentication scenarios.
Comment From: ch4mpy
exposing a builder is a great deal more powerful than Spring Security's annotation support that's used in simpler authentication scenarios
Why would exposing a builder necessarily be an alternative to providing annotation support?
I do use common builders in annotations WithSecurityContextFactory, MockMvc post-processors and WebTestClient configurers. Samples are:
* KeycloakAuthenticationTokenTestingBuilder used in both @WithMockKeycloakAuth and KeycloakAuthRequestPostProcessor
* OidcIdAuthenticationTokenTestingBuilder used in @WithMockOidcId, OidcIdAuthenticationTokenRequestPostProcessor and OidcIdAuthenticationTokenWebTestClientConfigurer
Comment From: jzheaux
Good question, @ch4mpy, I probably could have worded that a bit better.
This ticket isn't intended to compare the builder approach against the annotation approach. Instead, it's intended to explore extracting the authentication builders from SecurityMockMvcRequestPostProcessors so that they can address additional use cases than they do today.
a great deal more powerful than Spring Security's annotation support that's used in simpler authentication scenarios.
This simply alludes to the fact that Spring Security's annotation support by design addresses simpler authentication scenarios than Spring Security's RequestPostProcessor builders.
Comment From: ch4mpy
IMO, annotations can "by design" address as many scenarios as RequestPostProcessor, WebTestClientConfigurer and MockServerConfigurer builders. @WithMockKeycloakAuth and @WithMockOidcId referenced above tend to prove it. You (I mean Spring-security team) just chose to limit annotation to simple cases.
I won't develop too much as this isn't this request topic, but tickets I got on the libs in which those two annotations lie, show that spring-security users tend to prefer annotations over MockMvc post-processors or WebTestClient configurers: I had zero feedback on any of the later when quite a few users have shown interest for @WithMockKeycloakAuth. Maybe because security rules are mostly defined on @Components with annotations too, or it moves security scenario definition out of test body, or it works with any kind of @Component (as this ticket builders would), or bit of all of this.
Comment From: jzheaux
IMO, annotations can "by design" address as many scenarios as RequestPostProcessor, WebTestClientConfigurer and MockServerConfigurer builders. @WithMockKeycloakAuth and @WithMockOidcId referenced above tend to prove it. You (I mean Spring-security team) just chose to limit annotation to simple cases.
Agreed.