1

Please see below for the spring servlet file configuration. It used to work and now after upgrading dependencies to Spring core 4.0 and Spring sec oauth 2.0, it doesn't work. I mean, i'm not able to get the token. Please see below error messages and the problem :

When I try to get the token using following URL, it gives 406 with error:

url: /oauth2/oauth/token

"Error": The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.

Am I missing any configuration that is new in Spring 4.0 and Spring security 3.2 or Spring security oauth 2.0.0

Here are the details :

It's a REST based api, there's no client. I was testing this with Postman on chrome browser. Explicitly I didn't send anything in accept header. With older version of spring oauth2, it does work with application/json in accept header.

With below mentioned dependency versions, I get this response and it works fine. But, it fails and gives 406 as soon as I upgrade to new dependency versions :

{ "access_token": "f9287b1d-243b-453d-9d3e-f5ed67e974f6", "token_type": "bearer", "refresh_token": "c6a45534-7c20-4dda-b6f1-9a231cb649ed", "expires_in": 299999, "scope": "read write" }

I got that to working using following dependencies. :

<properties>
        <springsec.version>3.1.0.RELEASE</springsec.version>
        <spring.version>3.1.0.RELEASE</spring.version>
        <jersey-version>1.18.1</jersey-version>
        <springoauth2-version>1.0.0.RELEASE</springoauth2-version>      
</properties>

New dependencies I changed to when it started to fail: 

<properties>
        <springsec.version>3.2.5.RELEASE</springsec.version>
        <spring.version>4.1.1.RELEASE</spring.version>
        <jersey-version>1.18.1</jersey-version>
        <springoauth2-version>2.0.3.RELEASE</springoauth2-version>      
</properties>

The initial one was implemented using InMemoryTokenStore. But, now we want to use JDBCTokenStore. I read, that Spring oauth2 2.0 has better features, So I started changing the dependencies and along with that I had to change some package references in my code as they're changed now in the 2.0.

Here's the spring servlet context file:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
    xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">

    <http pattern="/oauth/token" create-session="stateless"
        authentication-manager-ref="authenticationManager"
        xmlns="http://www.springframework.org/schema/security" > 
        <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
        <anonymous enabled="false" />
        <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
        <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" /> 
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <http pattern="/resources/**" create-session="never"
        entry-point-ref="oauthAuthenticationEntryPoint"
        xmlns="http://www.springframework.org/schema/security">
        <anonymous enabled="false" />
        <intercept-url pattern="/resources/**" method="GET" />
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <http pattern="/logout" create-session="never" 
        entry-point-ref="oauthAuthenticationEntryPoint"
        xmlns="http://www.springframework.org/schema/security">
        <anonymous enabled="false" />
        <intercept-url pattern="/logout" method="GET" />
        <sec:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler"   />
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <bean id="logoutSuccessHandler" class="prototype.oauth2.authentication.security.LogoutImpl" >
        <property name="tokenstore" ref="tokenStore"></property>
    </bean>

    <bean id="oauthAuthenticationEntryPoint"
        class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    </bean>

    <bean id="clientAuthenticationEntryPoint"
        class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="springsec/client" />
        <property name="typeName" value="Basic" />
    </bean>

    <bean id="oauthAccessDeniedHandler"
        class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
    </bean>

    <bean id="clientCredentialsTokenEndpointFilter"
        class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    <authentication-manager alias="authenticationManager"
        xmlns="http://www.springframework.org/schema/security">
        <authentication-provider user-service-ref="clientDetailsUserService" />
    </authentication-manager>

    <bean id="clientDetailsUserService"
        class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
        <constructor-arg ref="clientDetails" />
    </bean>

    <bean id="clientDetails" class="prototype.oauth2.authentication.security.ClientDetailsServiceImpl"/>

    <authentication-manager id="userAuthenticationManager" 
        xmlns="http://www.springframework.org/schema/security">
        <authentication-provider  ref="customUserAuthenticationProvider">
        </authentication-provider>
    </authentication-manager>

    <bean id="customUserAuthenticationProvider"
        class="prototype.oauth2.authentication.security.CustomUserAuthenticationProvider">
    </bean>

    <oauth:authorization-server
        client-details-service-ref="clientDetails" token-services-ref="tokenServices">
        <oauth:authorization-code />
        <oauth:implicit/>
        <oauth:refresh-token/>
        <oauth:client-credentials />
        <oauth:password authentication-manager-ref="userAuthenticationManager"/>
    </oauth:authorization-server>

    <oauth:resource-server id="resourceServerFilter"
        resource-id="springsec" token-services-ref="tokenServices" />

    <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />      

    <bean id="tokenServices" 
        class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
        <property name="tokenStore" ref="tokenStore" />
        <property name="supportRefreshToken" value="true" />
        <property name="accessTokenValiditySeconds" value="300000"></property>
        <property name="clientDetailsService" ref="clientDetails" />
    </bean>


    <mvc:annotation-driven />   <!-- Declares explicit support for annotation-driven MVC controllers  @RequestMapping, @Controller -->

    <mvc:default-servlet-handler />

    <bean id="sampleResource" class="prototype.oauth2.authentication.resources.Resource"></bean>

</beans>

Here are the curl responses for both implementations:

This is new implementation Spring 4 and Spring oauth 2.0.3

curl -v -X POST -d "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -H "Accept:application/json" [url1]

It fails with :

> Accept:application/json
> Content-Length: 89
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 89 out of 89 bytes
* STATE: DO => DO_DONE handle 0x60002de40; line 1263 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x60002de40; line 1384 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x60002de40; line 1395 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 406 Not Acceptable
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Content-Type: text/html;charset=utf-8
< Content-Language: en
< Content-Length: 1108
< Date: Mon, 06 Oct 2014 18:16:23 GMT

This is with old implementaion with Spring 3 and Spring oauth 1.0 - it gives proper response back

curl -v -X POST -d "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -H "Accept:application/json" [url2]

> Host: localhost:8088
> Accept:application/json
> Content-Length: 89
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 89 out of 89 bytes
* STATE: DO => DO_DONE handle 0x60002de40; line 1263 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x60002de40; line 1384 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x60002de40; line 1395 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Cache-Control: no-store
< Pragma: no-cache
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Mon, 06 Oct 2014 18:16:55 GMT
<
* STATE: PERFORM => DONE handle 0x60002de40; line 1565 (connection #0)
* Connection #0 to host localhost left intact
* Expire cleared
{"access_token":"5a626e3f-8ef5-425f-945d-02f15abc7c2d","token_type":"bearer","refresh_token":"bc841c6c-7c44-42c0-811b-228526b43989","expires_in":292343,"scope":"read write"}
Madhu
  • 31
  • 1
  • 8
  • I don't think it's anything to do with Spring Security so the config you posted is irrelevant. What are you sending in your accept header? Where is the client? How is it implemented? – Dave Syer Oct 04 '14 at 07:32
  • Thanks Dave for the reply. – Madhu Oct 06 '14 at 14:25
  • Sorry, I was trying to reply you with more details, and got submitted. Let me post more details in a separate post. In comments, it's not allowing add all the details. – Madhu Oct 06 '14 at 15:28
  • You can propose an edit for your original post if your rep isn't high enough. A separate post will just get closed as a duplicate. – Dave Syer Oct 06 '14 at 15:41
  • Thanks again. I just edited and posted the spring-servlet config xml and other details about the implementation. – Madhu Oct 06 '14 at 15:43
  • I guess Spring 4.1 might have changed the default behaviour for an empty Accept header. Does it work with a proper Accept header? – Dave Syer Oct 06 '14 at 15:48
  • Nope. I just tried. I added Accept application/json and it still gives 406 wtih :The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers. I'm thinking - is something changed in clientCredentialsTokenEndpointFilter. Is that the one that's giving us back json response back in older version ? – Madhu Oct 06 '14 at 16:08
  • This is the online post I used to implement my protoype: [link]http://www.e-zest.net/blog/rest-authentication-using-oauth-2-0-resource-owner-password-flow-protocol/ and it worked with older version. I thought, it may give some insight into this implementation. – Madhu Oct 06 '14 at 16:14
  • Well it's not that (or any other) filter sending a 406. Normally it's a Spring MVC dispatcher. Are you sure you are sending a proper Accept header? How about trying with `curl` and pasting the actual command you are using? – Dave Syer Oct 06 '14 at 17:37
  • Thanks for reply. Added details with curl command used by editing original post. – Madhu Oct 06 '14 at 18:27
  • I was reading some other post. It was talking about MessageConverter. If you look at my current spring servlet xml, it didn't configure anything. Do you think it has anything to do with that ? Here's the link for other post. [link]http://stackoverflow.com/questions/7462202/spring-json-request-getting-406-not-acceptable – Madhu Oct 06 '14 at 18:40
  • It could just be a change in the transitive dependencies. Did you make sure Jackson is on the classpath (and no conflicts)? – Dave Syer Oct 06 '14 at 20:45
  • Yes, I added this dependency on the project and I do see this jar file/web-inf/LIB, Do we need to configure jackson in servlet anywhere ? org.codehaus.jackson jackson-mapper-asl 1.9.13 – Madhu Oct 06 '14 at 20:49
  • Well it works for me (and all the samples in Spring OAuth). Maybe you need to share a complete project? – Dave Syer Oct 07 '14 at 05:58
  • thanks for the reply again. I can share. But, how to share on stackoverflow ? – Madhu Oct 07 '14 at 14:31
  • Link to a project on github is great. – Dave Syer Oct 07 '14 at 16:47
  • Thanks again. I never used git before. But, I managed to commit. Here's the link [link]https://github.com/madhumm/TestSpringOauth2. Excuse me, if I didn't checkin as per git conventions. Thanks for all your help. – Madhu Oct 07 '14 at 17:42
  • You were right, I think, on the dependency. It worked after adding the following dependency: com.fasterxml.jackson.core jackson-databind 2.3.3 – Madhu Oct 07 '14 at 19:03

1 Answers1

1

This resolved the problem:

<dependency> 
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId> 
  <version>2.3.3</version> 
</dependency>

The error was not straight forward. It was giving 406 and complaining about accept headers. Based on Dave Syer's suggestion that it could be related to dependency issue, I started looking at jackson dependencies.

Madhu
  • 31
  • 1
  • 8