I need to extend the OAuth2AuthenticationProcessingFilter, and I can't
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http);
resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();
Could the OAuth2AuthenticationProcessingFilter instance be configurable from
@EnableResourceServer configuration ?
@Configuration
@EnableResourceServer
@EnableWebSecurity
public static class MyResourceServerConfigurer implements ResourceServerConfigurer {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceServerFilter(new OAuth2AuthenticationProcessingFilter())......;
}
It could. But since the main object of the @EnableResourceServer is to install a OAuth2AuthenticationProcessingFilter maybe it would be simpler to just forgo the use of @EnableResourceServer and inject the filter yourself? What is your use case anyway (why do you need to extend the filter - there are plenty of extension points in its components)?
When the access_token is invalid/expired.
I will recover with an alternative authentication scheme. (it's an internal company design). And for that i need access to request, response, and the filter chain.
authenticationEntryPoint would seem like a good choice, but the problem is that the chain.doFilter(request, response) doesn't get called and the resource will not get.
So for that I'd have to change the OAuth2AuthenticationProcessingFilter
in a way that the
chain.doFilter(request, response);
get executed.
and i'd hook with this logic in another place
Or extend the OAuth2AuthenticationProcessingFilter
catch (OAuth2Exception failed) {
// set the invalid authenticationToken or run my logic here
SecurityContextHolder.getContext().setAuthentication(authentication); // PreAuthenticatedAuthenticationToken invalid
//SecurityContextHolder.clearContext(); // comment this out
if (debug) {
logger.debug("Authentication request failed: " + failed);
}
authenticationEntryPoint.commence(request, response,
new InsufficientAuthenticationException(failed.getMessage(), failed));
// return; continue with the filterChain
}
chain.doFilter(request, response);
@EnableResourceServer does everything that it need
with this one exception of allowing to override the registered filter.
I would seem like a waste / lot more work to forgo it's use
Maybe you could inject a special AuthenticationManager into the OAuth2AuthenticationProcessingFilter and use it to handle your use case - if the token is valid, proceed as normal, otherwise return a special (unauthenticated) Authentication token that can be handled further down the filter chain. You only really need to prevent the AuthenticationManager from throwing an exception to get access to the filter chain.
it is a good choice, but i need access to the request and response
Then you can put a filter in the chain can't you?
configure(HttpSecurity http) from @EnableResourceServer is called before
configure(HttpSecurity http) from ResourceServerSecurityConfigurer
so if i hook in the same way ResourceServerSecurityConfigurer does
.addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.class)
OAuth2AuthenticationProcessingFilter is going to be called first
and any filter I register will not get called
because chain.doFilter(..) will not be called
I thought that's what you wanted - a filter that executes _after_ the OAuth2AuthenticationProcessingFilter? A custom AuthenticationManager was my suggestion to enable you to get access to the downstream filter. The AuthenticationManager would be added to the OAuth2AuthenticationProcessingFilter using ResourceServerSecurityConfigurer (so you don't have to give up @EnableResourceServer). Maybe I wasn't clear enough the first time?
BTW it's probably better to use .addFilterAfter(myFilter, AbstractPreAuthenticatedProcessingFilter.class) (so you know for sure it is after the OAuth2 filter).
I don't understand this: A custom AuthenticationManager was my suggestion to enable you to get access to the downstream filter.
How do create / register a custom AuthenticationManager that can access the filter chain and request, response?
I do want to execute after OAuth2AuthenticationProcessingFilter, but since i am expecting the access_token to be invalid, any filter that I register before or after AbstractPreAuthenticatedProcessingFilter will not be executed.
OAuth2AuthenticationProcessingFilter doesn't run the chain.doFilter(...) in case of an error.
I should have mentioned this before, I am new to spring security and I probably cannot see a lot of possible solutions that might be obvious to you.
Allowing to override the OAuth2AuthenticationProcessingFilter resourcesServerFilter in ResourceServerSecurityConfigurer seem like an good decision, that gives more flexibility
public final class ResourceServerSecurityConfigurer extends
SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private OAuth2AuthenticationProcessingFilter resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();
public ResourceServerSecurityConfigurer resourceServerFilter(OAuth2AuthenticationProcessingFilter resourceServerFilter) {
this.resourceServerFilter = resourceServerFilter;
return this;
}
This would be my a proposed change.
OAuth2AuthenticationProcessingFilter doesn't run the chain.doFilter(...) in case of an error.
That's why I suggested a custom AuthenticationManager - if there's no error you get a chance to precess the result downstream.
A custom OAuth2AuthenticationProcessingFilter implements doFilter which has access to request, response, filter chain, that is what I would need to give access to AuthenticationManager
But there is not way i can see to create a custom AuthenticationManager, and give access to those objects, with the current OAuth2AuthenticationProcessingFilter
final boolean debug = logger.isDebugEnabled();
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
try {
Authentication authentication = tokenExtractor.extract(request);
if (authentication == null) {
if (stateless && isAuthenticated()) {
if (debug) {
logger.debug("Clearing security context.");
}
SecurityContextHolder.clearContext();
}
if (debug) {
logger.debug("No token in request, will continue chain.");
}
}
else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
if (authentication instanceof AbstractAuthenticationToken) {
AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken) authentication;
needsDetails.setDetails(authenticationDetailsSource.buildDetails(request));
}
Authentication authResult = authenticationManager.authenticate(authentication);
if (debug) {
logger.debug("Authentication success: " + authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
}
}
If your AuthenticationManager creates an Authentication it will be in the SecurityContext when the chain calls your filter. That's often how downstream filters work.
If I create a custom AuthenticationManager an use it in OAuth2AuthenticationProcessingFilter I will not be able to access the HttpServletResponse response = (HttpServletResponse) res;
which I need to do
that is why i would like to create a custom OAuth2AuthenticationProcessingFilter
I don't think you are following my suggestion. Here's a complete project that explains it: https://github.com/scratches/custom-filter. If you don't like the way that works that's fine, but maybe it will help us to get on the same page at least.
THANK YOU, your solution works!
Now I understand what you meant, form the beginning.
Thank you for all your help.
Most helpful comment
I don't think you are following my suggestion. Here's a complete project that explains it: https://github.com/scratches/custom-filter. If you don't like the way that works that's fine, but maybe it will help us to get on the same page at least.