This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

AnnouncementAnnouncement Module

Collapse

No announcement yet.

Oauth1: User authentication is skipped for Token AuthorizationPage Title Module

Oauth1: User authentication is skipped for Token Authorization

Apr 4th, 2012, 04:20 AM

Hi all,

I've got a OAuth1 provider configuration, based on Spring Security 3.1.0 and Spring security Oauth 1.0.0.M6, that works partly:
The requestToken endpoint does function.
Then however, if the client calls the authorize endpoint directly with the request token, the provider just authorizes the request (returning a verifier code), without challenging the user to prove its mandatory role ("ROLE_USER")
Only if I hit the confirm_access endpoint manually, user authentication kicks in.

As you can see, I rely on a 'pre authenticated' request: an external Shibboleth apache module that puts a REMOTE_USER header on the request. This is triggered by the "shibbolethEntryPoint" which basically redirects the user to an external URL. Only after successful login the request will come back with the REMOTE_USER header set.

What it looks like to me at this point is:
the <intercept-url pattern="/oauth/**" access="ROLE_USER" /> seems only to be active for requests to /oauth/confirm_access and not for /oauth/authorize, because a request for the latter is handled by UserAuthorizationProcessingFilter (filter 9 of 12) (therefore not hitting FilterSecurityInterceptor, filter 12 of 12).

Although there is some authentication check, at UserAuthorizationProcessingFilter:92

Code:

if (authentication == null || !authentication.isAuthenticated()) {
throw new InsufficientAuthenticationException("User must be authenticated before authorizing a request token.");
}

this is not hit because the authentication object is an anonymous authentication here, which seems to be enough, as you can see in the log below.

Your pre-authentication filter does not seem to have found the REMOTE_USER. How would you expect the authenticated principal to pick up the required ROLE_USER (the pre-auth filter presumably has no knowledge of roles)? Maybe you need to switch off anonymous authentication anyway, since you clearly don't want anonymous users to be obtaining access tokens?

Comment

Your pre-authentication filter does not seem to have found the REMOTE_USER. How would you expect the authenticated principal to pick up the required ROLE_USER (the pre-auth filter presumably has no knowledge of roles)?

I would expect that in this case the user should be pointed to the authenticationEntryPoint which will trigger the setting of the REMOTE_USER header...
By the way: I would say that on the requestToken-request for example the authentication is not yet done, so that request should not fail because of the missing REMOTE_USER header..

Maybe you need to switch off anonymous authentication anyway, since you clearly don't want anonymous users to be obtaining access tokens?

Good point; I did not try this.
Now I've disabled anonymous, indeed authorization fails because of missing user authentication. Then the UserAuthorizationProcessingFilter uses its failureHandler to redirect to the failure url.

Which leads me to a new problem; according to the log, the failure-url is not set:

Comment

That looks like a bug in the parser - it creates a bean definition for a AuthenticationFailureHandler and then never uses it. Your guess is as good as mine though. If you want to fix it and send a pull request that would be great (see instructions on README).

oauth server returns a token, without performing authentication of the end user

client requests /oauth/authorize to authorize the request token

server sees that no end user consent has been given yet and redirects to 'authentication-failed-url' (/oauth/confirm_access in my case)

/oauth/confirm_access handling sees that end user is not authenticated yet and redirects to the entry point (shibbolethEntryPoint in my case)

shibbolethEntryPoint authenticates and redirects to /oauth/confirm_access which serves a consent form (confirmationController yada)

This is how I would expect it to work.
In practice however, the server in step 5 says "An Authentication object was not found in the SecurityContext" and returns a HTTP 401 with "Authorize: OAuth" response header. (instead of redirecting to shibboleth entry point)
The log says:

Another question arises by the way: why is the attribute called 'authentication-failed-url'?
Because it's not actually a matter of authentication failure but rather that of authorization failure: the oauth client has not yet been authorized by the end user.

Comment

I will rephrase my question more concisely.
Perhaps this makes it easier for someone to stand up and enlighten me :-)

Using sparklr/tonr as inspiration, I expect that this config:

<oauth: provider authentication-failed-url="/confirm_access">

will use the /confirm_access as an 'user consent' form, first redirecting the end user to his authentication entrypoint to authenticate, before actually prompting the consent form.
Is this correct?

What part of the configuration ensures that authentication takes place?
(because in my case, the user gets a 401 - "An Authentication object was not found in the SecurityContext", instead of a redirection to an entry point)

Thanks!

Regards,
Geert

Comment

It turns out that to disable anonymous (<anonymous enabled="false" />) was a bad move after all.
This actually breaks the filter chain.
Normally, an anonymous authentication present in the security context would eventually trigger the decisionmanager (with AffirmativeBased voters) which throws a proper access-denied-exception that in turn is translated into a redirection to the authentication entry point. See this log:

The sparklr example, by the way, also breaks when disabling anonymous, in exactly the same way.

The point for my particular case was to let the client call /oauth/confirm_access url instead of /oauth/authorize directly, to authorize the request token.
The sparklr case and in the spring-sec-oauth1 configuration got me off on the wrong foot on this: the attribute in <oauth: provider> is called authentication-failed-url even though it's actually an authorization-endpoint to be used by clients.