Summary
In Spring Security, Authentication & Authorization are tightly coupled. Nowadays, Authentication is often performed by external systems before a request reaches the application. For such cases, Spring offers AbstractPreAuthenticatedProcessingFilter which can be extended to set principal & credentials. After setting principal & credentials it creates a PreAuthenticatedAuthenticationToken which takes the principal & credentials. However currently, we cannot set a list of GrantedAuthority with this token. Because of which this filter is less useful for Method level Authorization as we cannot use GrantedAuthority in @PreAuthorize & @PostAuthorize annotations.
Actual Behavior
//PreAuthenticatedAuthenticationToken.java
package org.springframework.security.web.authentication.preauth;
import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 520L;
private final Object principal;
private final Object credentials;
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials) {
super((Collection)null);
this.principal = aPrincipal;
this.credentials = aCredentials;
}
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials, Collection<? extends GrantedAuthority> anAuthorities) {
super(anAuthorities);
this.principal = aPrincipal;
this.credentials = aCredentials;
this.setAuthenticated(true);
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
}
Here PreAuthenticatedAuthenticationToken in one of its constructors has anAuthorities , a list of GrantedAuthority which can be used with @PreAuthorize, @PostAuthorize tokens for Method Level Authorization.
//AbstractPreAuthenticatedProcessingFilter.java
public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware
{
private void doAuthenticate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
Object principal = this.getPreAuthenticatedPrincipal(request);
Object credentials = this.getPreAuthenticatedCredentials(request);
if (principal == null) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("No pre-authenticated principal found in request");
}
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("preAuthenticatedPrincipal = " + principal + ", trying to authenticate");
}
try {
PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken(principal, credentials);
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
Authentication authResult = this.authenticationManager.authenticate(authRequest);
this.successfulAuthentication(request, response, authResult);
} catch (AuthenticationException var7) {
this.unsuccessfulAuthentication(request, response, var7);
if (!this.continueFilterChainOnUnsuccessfulAuthentication) {
throw var7;
}
}
}
}
}
For full code: AbstractPreAuthenticatedProcessingFilter.java
Expected Behavior
AbstractPreAuthenticatedProcessingFilter should define another method:
protected abstract Object getGrantedAuthorities(HttpServletRequest var1);
Once we have this method, this should be set in PreAuthenticatedAuthenticationToken inside doAuthenticate method of AbstractPreAuthenticatedProcessingFilter class
Comment From: jzheaux
Thanks for the suggestion, @rahul-gupta-1525. Granted authorities are typically granted in the AuthenticationManager, separating it from the servlet layer, so adding a getGrantedAuthorities to a Spring Security filter is unlikely to be a fit.
Is there something that you are needing from the request in order to determine what granted authorities to add?
Comment From: rahul-gupta-1525
Yes @jzheaux . Unlike traditional approach, we aren't saving User roles & privileges in database. Instead, we define all the privileges or authorities in a yaml/properties file, and every incoming request will contain user details along with the subset of privileges the user has access to. In such cases, we just need to set GrantedAuthorities for an User & make use of @PreAuthorizeannotation to achieve method level authorization.
I understand we use AuthenticationManager to set GrantedAuthorities, but if we could introduce setting it in the servlet/request layer, it would be pretty straightforward.
Comment From: jzheaux
The way that this filter is intended to be used is to gather what material you need from the request and return it via the getPreAuthenticatedPrincipal and getPreAuthenticatedCredentials methods as well as the AuthenticationDetailsSource.
For example, the reference guide details how the AuthenticationDetailsSource is used:
Like other Spring Security authentication filters, the pre-authentication filter has an authenticationDetailsSource property which by default will create a WebAuthenticationDetails object to store additional information such as the session-identifier and originating IP address in the details property of the Authentication object. In cases where user role information can be obtained from the pre-authentication mechanism, the data is also stored in this property, with the details implementing the GrantedAuthoritiesContainer interface.
Given what you've shared so far, it appears that the code base and reference docs are sufficient to address your use case. As such, I'll close this issue; however feel free to provide more information if you feel like there is more to discuss.