This is a real head-scratcher. At least, for me.
I'm using OAuth 1.0. If I hit a URL that I have protected one-at-a-time, there is no issue. But if make a bunch of concurrent HTTP requests to that URL (~50), then I intermittently see this error:
HTML Code:java.lang.ClassCastException: com.me.CustomAuthentication cannot be cast to org.springframework.security.oauth.provider.ConsumerAuthentication at org.springframework.security.oauth.provider.ProtectedResourceProcessingFilter.onValidSignature(ProtectedResourceProcessingFilter.java:58) [spring-security-oauth-3.17.SS3.jar:na] at org.springframework.security.oauth.provider.OAuthProviderProcessingFilter.doFilter(OAuthProviderProcessingFilter.java:158) [spring-security-oauth-3.17.SS3.jar:na]
So the only background I think I need to explain is the com.me.CustomAuthentication -- it's a custom Authentication implementation I use in different parts of the code, but as I think you'll see, it's irrelevant; here's why.
If you look at the stack trace, we start in OAuthProviderProcessFilter, a base class. Here's what leads up to the exception:
From the stack trace, you can see that onValidSignature() is executed. Here's the code for that (only the 1st line because that's where the ClassCastException occurs)Code://create an authentication request. ConsumerAuthentication authentication = new ConsumerAuthentication(consumerDetails, credentials, oauthParams); authentication.setDetails(createDetails(request, consumerDetails)); Authentication previousAuthentication = SecurityContextHolder.getContext().getAuthentication(); try { ### ADDED BY sethcall: TAKE NOTE--HERE AUTH IS BEING SET INTO SECURITY CONTEXT HOLDER //set the authentication request (unauthenticated) into the context. SecurityContextHolder.getContext().setAuthentication(authentication); //validate the signature. validateSignature(authentication); //mark the authentication request as validated. authentication.setSignatureValidated(true); //mark that processing has been handled. request.setAttribute(OAUTH_PROCESSING_HANDLED, Boolean.TRUE); if (log.isDebugEnabled()) { log.debug("Signature validated."); } //go. onValidSignature(request, response, chain); } finally { //clear out the consumer authentication to make sure it doesn't get cached. resetPreviousAuthentication(previousAuthentication); }
So let's recap:Code:ConsumerAuthentication authentication = (ConsumerAuthentication) SecurityContextHolder.getContext().getAuthentication();
In the first block of code, SecurityContextHolder.getContext().setAuthenticati on(<consumer auth>) is called, and then in onValidSignature, SecurityContextHolder.getContext().getAuthenticati on() is called -- but now it's not of type ConsumerAuthentication ??
This seems outright impossible. If you look at SecurityContextHolder, you'll notice that it has various strategies; by default, it uses a ThreadLocal strategy (and I've verified multiple times--I'm using the default). So it's as if the ThreadLocal data is getting mixed up for various threads coming into the system. It's extremely odd.
Does anyone have any ideas? I'm just now beginning debugging, but I thought perhaps someone has seen something similiar. I haven't opened up a bug because I feel it's somehow something I've done or otherwise not really the fault of the OAuth library...
Anyway, thanks for your help...
Regards,
Seth


Reply With Quote