I'm having problems with OAuth2 error handling.
After I upgraded to the very latest snapshot BUILD-20120406.070018-90, the error handling behavior changed.
I believe the Spring security XML configuration changes required by the latest changes, are properly constructed, but
I'm attaching my xml config files here so that you can help me verify that I got it right.
If I pass invalid client credentials using the Basic Authorization header for example:
POST /exerciser-api/oauth/token HTTP/1.1
Accept: application/json
Authorization: Basic OTk5OTk5OlByZXZhU2VjcmV0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
grant_type=client_credentials
Then I get:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Preva"
Content-Type: text/html;charset=utf-8
<html>…something generated by Tomcat for a 401 error…</html>
1. According to the OAuth2 spec, section 5.2, the WWW-Authenticate response header should contain error=”invalid_client”.
2. The response body (which is optional) should be json not html.
http://tools.ietf.org/pdf/draft-ietf-oauth-v2-25.pdf
The BasicAuthenticationFilter is being triggered instead of the ClientCredentialsTokenEndpointFilter.
The client credentials error results in an Oauth2Exception being thrown by ClientDetailsService at loadUserByUsername
at ClientDetailsUserDetailsService. This isn't being handled by the oauthAccessDeniedHandler, instead it's being handled
by Spring basic security (not the Oauth2 extension), which obviously does not know anything about the Oauth2 spec.
Question is, how can we properly wire this to eliminate the problems described above... or is a fix already in progress?
Thank you
I have two xml config files:
security-context.xml:
oauth2-context.xml:Code:<?xml version="1.0" encoding="UTF-8" ?> <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schem...curity-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <http realm="Preva" pattern="/oauth/token" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="clientAuthenticationManager"> <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/> <anonymous enabled="false"/> <http-basic/> <!-- This needs to be anonymous so that the auth endpoint can handle oauth errors itself --> <!-- This allows you to put client_id=[value]&client_secret=value in the request body --> <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/> <access-denied-handler ref="oauthAccessDeniedHandler"/> </http> <beans:bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/> <beans:bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"> <beans:property name="realmName" value="Preva"/> </beans:bean> <http pattern="/version" security="none"/> <!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling separately. This isn't mandatory, but it makes it easier to control the behaviour. --> <http realm="Preva" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security"> <anonymous enabled="false"/> <intercept-url pattern="/**" access="ROLE_USER,ROLE_TRUSTED_CLIENT"/> <!--<custom-filter ref="resourceServerFilter" before="EXCEPTION_TRANSLATION_FILTER" />--> <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/> <access-denied-handler ref="oauthAccessDeniedHandler"/> </http> <beans:bean id="passwordEncoder" class="org.jasypt.spring.security3.PasswordEncoder"> <beans:property name="passwordEncryptor"> <beans:bean class="org.jasypt.util.password.StrongPasswordEncryptor"/> </beans:property> </beans:bean> <beans:bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService"> <beans:constructor-arg ref="clientDetailsService"/> </beans:bean> <authentication-manager id="clientAuthenticationManager" alias="clientAuthenticationManager"> <authentication-provider user-service-ref="clientDetailsUserService"> <password-encoder ref="passwordEncoder"/> </authentication-provider> </authentication-manager> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="exerciserAccountAuthenticationService"> <password-encoder ref="passwordEncoder"/> </authentication-provider> <authentication-provider ref="easyGymUserAuthenticationProvider"/> </authentication-manager> <global-method-security proxy-target-class="true" pre-post-annotations="enabled" secured-annotations="enabled" jsr250-annotations="enabled"> <expression-handler ref="oauthExpressionHandler"/> </global-method-security> </beans:beans>
Code:<?xml version="1.0" encoding="UTF-8" ?> <beans:beans xmlns="http://www.springframework.org/schema/security/oauth2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schem...oauth2-1.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schem...pring-util.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <beans:bean id="customCompositeTokenGranter" class="org.springframework.security.oauth2.provider.CompositeTokenGranter"> <beans:constructor-arg> <util:list> <beans:bean class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter" autowire="constructor"/> <beans:bean class="org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter" autowire="constructor"/> <beans:bean class="org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter" autowire="constructor"/> <beans:bean class="com.precor.preva.external.security.MemberManagementSystemTokenGranter" autowire="constructor"/> </util:list> </beans:constructor-arg> </beans:bean> <authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices" token-granter-ref="customCompositeTokenGranter"> </authorization-server> <resource-server id="resourceServerFilter" resource-id="preva-api" token-services-ref="tokenServices"/> <expression-handler id="oauthExpressionHandler"/> </beans:beans>


Reply With Quote
