Describe the bug
@AuthenticationPrincipal doesn't work when using Interface parameters.
To Reproduce
Given a User interface and a UserImplementation class that extends `User:
- Set an instance of the user into the Security context as follows:
SecurityContextHolder.getContext().setAuthentication(new CustomAuthentication(user));
public class CustomAuthentication implements Authentication {
private final User principal;
CustomAuthentication(User principal) {
this.principal = principal;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getDetails() {
return null;
}
@Override
public User getPrincipal() {
return principal;
}
@Override
public boolean isAuthenticated() {
return true;
}
@Override
public void setAuthenticated(boolean isAuthenticated) {
}
@Override
public String getName() {
return null;
}
}
- Inject that user into a RestController's method using:
@AuthenticationPrincipal User user
Expected behavior user is the same object set into the Security Context.
Instead, the User injected is an empty proxy that doesn't resolve correctly any of the methods defined in the interface.
Note: @AuthenticationPrincipal UserImplementation user Does not inject a proxy but the actual object so it works as expected.
Sample
I don't have a Github Project but I feel like I've done enough research on this so hopefully you don't need one.
What happens is that in HandlerMethodArgumentResolverComposite, there's a list of argumentResolvers.
getArgumentResolver traverses to this one to find a resolver that supports the given parameter.
There's a couple of ProxyingHandlerMethodArgumentResolver instances in that list that are before the AuthenticationPrincipalArgumentResolver. The first of these 2 instances of ProxyingHandlerMethodArgumentResolver have annotationNotRequired property set to false and the second one set to true.
The supportsParameter method of the second instance of ProxyingHandlerMethodArgumentResolver resolves successfully since the parameter uses an interface and the annotationNotRequired parameter is set to true so this resolver gets selected before we get to the AuthenticationPrincipalArgumentResolver one:
Reports that include a sample will take priority over reports that do not. At times, we may require a sample, so it is good to try and include a sample up front.
Comment From: eleftherias
Thanks for reaching out @agarcia-te.
This doesn't seem to be a problem with interfaces, since both UserDetails and OAuth2User, which are interfaces, work as expected when injected as the AuthenticationPrincipal argument.
I think we need to understand more about your use case to determine the cause of the issue. A minimal working sample would be the fastest way for us to start investigating.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: leonidv
Possible, https://github.com/spring-projects/spring-security/issues/11459 duplicated of this