-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
In Test @AuthenticationPrincipal is null because ServerWebExchange is not wrapped #6598
Comments
Proposed patch in PR, I tried a few things this seems to be the easiest and least intrusive. |
@Dav1dde the behaviour you are seeing is the expected behaviour. If you start up your application and make a request that does not include the HTTP basic In order to include the required header in your request, you would create a custom It would be nice to have an |
@elefeint thanks for the great response. So I cannot use I am aware that none of my security matchers (I actually have 3, Basic Auth, JWT and SAML2) matches the request in the test, I was hoping I can skip the authentication with To summarize: In order to mock a principal, I have to mutate the request with |
@Dav1dde can you clarify how you are using the
I expected the Regarding the principal only being populated when it matches a security configuration, I would argue that this is reasonable behaviour. |
@eleftherias sorry, you're obviously correct. I didn't proof read what I wrote and got confused with
The problem now is that if you skip the chains (as you noted) the principal doesn't get attached to the "exchange" ( So if I understood you correctly in order to have a principal attached I need to go through at least one websecurity filter chain? But then what is the purpose of The implementation of public <T extends Principal> Mono<T> getPrincipal() {
return this.context.map(c -> (T) c.getAuthentication());
} The only reason |
The purpose of
Because you have custom matchers, you will need to create custom
As a side note, regarding |
But if the request goes through the security chain, shouldn't the security chain also take care of setting the correct principal?
Sure I can make a utility method somewhere that sets up everything so it passes through the security chain and sets the correct user, I was just hoping
Yeah this is what would be adressed with my PR.
No Where as @Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext,
ServerWebExchange exchange) {
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
return exchange.getPrincipal()
.ofType(Authentication.class)
.flatMap( a -> {
Object p = resolvePrincipal(parameter, a.getPrincipal());
Mono<Object> principal = Mono.justOrEmpty(p);
return adapter == null ? principal : Mono.just(adapter.fromPublisher(principal));
});
} Which comes down to Also a big thank you @eleftherias for your input and this discussion! |
Yes, exactly, the security chain will set the correct principal. The requests in your tests are not going through any of the spring security filter chain because they do not match any of your custom matchers.
No, your PR would change the behaviour of
As an alternative, you can create an additional filter chain that will process any requests that do not match your original filter chains, and allow anonymous users.
|
What I wanted to explain here is, if the security chain is meant to set the principal, then way does Maybe the right thing here is to not use
But that sounds like an issue with Imo the thing where you really have to be careful here is to not break |
Thank you for all of your input @Dav1dde.
As you mentioned in the comment above, Would you be interested in submitting a PR to update |
@eleftherias yeah I can make a PR for this! The change to |
@Dav1dde The |
gh #6598 Signed-off-by: David Herberth <[email protected]>
@eleftherias once again, thanks for the great discussion and the time you invested into this issue and I am glad, we together, could make Spring (Security) a tiny bit better :) |
I came here after googling why a WebClient mutated with mockUser() still resulted in request.principal() to be null. I'm unit testing a reactive router function, so security testing would be outside of the scope. The test is about the route returning a response depending on what kind of principal is there, but not how that would be inserted into the request (that is tested in a more integrating test). I will try a custom mutator for my case. |
Summary
Using
@WithMockUser
ororg.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers#mockAuthentication
directly in combination with@AuthenticationPrincipal
in a WebFlux controller leaves the principal empty while things like@PreAuthorize('isAuthenticated()')
work as expected.Actual Behavior
Mocking the principal in a test does not work with
@AuthenticaitonPrincipal
.Because my SecurityFilterChain does not match the request of the web test client (see below, only matches Requests that contain an Authorization: Basic header), the
org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter
gets never called (which is part of the SecurityFilterChain), meaning the request is never wrapped with aorg.springframework.security.web.server.context.SecurityContextServerWebExchange
.org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver#resolveArgument
usesexchange.getPrincipal()
to resolve the principal, which returns an empty Mono because the exchange is still theDefaultServerWebExchange
(not security!).Now the principal set in
org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.MutatorFilter
is not considered.The
org.springframework.security.access.prepost.PrePostAdviceReactiveMethodInterceptor
usesorg.springframework.security.core.context.ReactiveSecurityContextHolder#getContext
which would work for the resolver as well.Expected Behavior
The mocked principal should be resolved correctly for the
@AuthenticationPrincipal
argument.The exchange should be wrapped correctly.
Configuration
WebTestClient (minimal)
Security (minimal):
The important part here is the security matcher, which makes it so my Security chain does not match, nor does any other!
Version
Spring Security 5.1.4
Sample
Company code.
The text was updated successfully, but these errors were encountered: