[ 
https://issues.apache.org/jira/browse/CXF-4309?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jordi Torrente updated CXF-4309:
--------------------------------

    Component/s:     (was: JAX-RS)
                 JAX-RS Security
    
> OAuth2 Access Token Service: returned ClientAccessToken is not JAXB compliant
> -----------------------------------------------------------------------------
>
>                 Key: CXF-4309
>                 URL: https://issues.apache.org/jira/browse/CXF-4309
>             Project: CXF
>          Issue Type: Bug
>          Components: JAX-RS Security
>    Affects Versions: 2.6
>            Reporter: Jordi Torrente
>              Labels: jax-rs, jaxb, oauth2
>
> The OAuth2 Access Token Service current implementation (class 
> org.apache.cxf.rs.security.oauth2.services.AccessTokenService) processes a 
> request inside "handleTokenRequest()" and this method returns the 
> successfully generated token using an instance of ClientAccessToken.
> But that class has two problems or limitations:
> 1) It is not a JAXB-annotated bean so the error "No message body writer has 
> been found for response class ClientAccessToken" is raised. This can be 
> solved adding the "jaxbElementClassMap" property to the default JSON provider 
> (jettison):
> <bean id="jsonProvider" 
> class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
>   <property name="jaxbElementClassMap" ref="myElementClassMap"/>
> </bean>
> <util:map id="myElementClassMap">
>   <entry key="org.apache.cxf.rs.security.oauth2.common.ClientAccessToken" 
> value="ClientAccessToken"/>
> </util:map>
> <jaxrs:server id="oauth2Server" address="/oauth2">
>   <jaxrs:serviceBeans>
>     <ref bean="accessTokenService2"/>
>   </jaxrs:serviceBeans>
>   <jaxrs:providers>
>       <ref bean="jsonProvider"/>
>   </jaxrs:providers>    
> </jaxrs:server>
> Unluckily, after doing that change we find out the second problem:
>  
> 2) ClientAccessToken does not have a no-arg default constructor, so it's not 
> JAXB compliant, and the default JSON provider is unable to serialize the data:
> org.apache.cxf.rs.security.oauth2.common.AccessToken does not have a no-arg 
> default constructor.
>       this problem is related to the following location:
>               at org.apache.cxf.rs.security.oauth2.common.AccessToken
>               at org.apache.cxf.rs.security.oauth2.common.ClientAccessToken
>               
> The only way I've found to overcome both limitations is changing the JSON 
> provider to Codehaus jackson:
> <bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
> <bean id="jsonProvider" 
> class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider">
>   <property name="mapper" ref="jacksonObjectMapper" />
> </bean>
> <jaxrs:server id="oauth2Server" address="/oauth2">
>   <jaxrs:serviceBeans>
>     <ref bean="accessTokenService2"/>
>   </jaxrs:serviceBeans>
>   <jaxrs:providers>
>     <ref bean="jsonProvider"/>
>   </jaxrs:providers>    
> </jaxrs:server>
> Here you can see a response generated using this new provider:
> Response-Code: 200
> Content-Type: application/json
> Headers: {Cache-Control=[no-store], Pragma=[no-cache], Date=[Fri, 11 May 2012 
> 11:11:29 GMT]}
> Payload: 
> {"tokenKey":"e91ffcefb133de5eb7ebd02c25e7886e","tokenType":"bearer","parameters":{},"approvedScope":null,"refreshToken":null}
> So far all the work is done at the server side, but what about the client 
> side?
> If we try to de-serialize an access token response using CXF client 
> capabilities (org.apache.cxf.jaxrs.client.WebClient), we will find the same 
> already known problems: 
> a) With jettison: 
> No message body reader has been found for class : class 
> org.apache.cxf.rs.security.oauth2.common.ClientAccessToken, ContentType : 
> application/json
> Adding the "jaxbElementClassMap" property to the provider, will stop us at 
> the no-arg default constructor problem:
> JSONProvider<?> provider = new JSONProvider<Object>();
> provider.setJaxbElementClassMap(Collections.singletonMap("org.apache.cxf.rs.security.oauth2.common.ClientAccessToken",
>  "ClientAccessToken"));
> WebClient client = 
> WebClient.create("http://localhost:8080/fwmobisecurity2/services/oauth2";, 
> Collections.singletonList(provider));
> [...]
> ClientAccessToken obj = client.post(formData, ClientAccessToken.class);
>       
> b) With jackson:
> No suitable constructor found for type [simple type, class 
> org.apache.cxf.rs.security.oauth2.common.ClientAccessToken]: can not 
> instantiate from JSON object (need to add/enable type information?)
> Luckily, jackson offers "Mix-in Annotations" that allow us to define which 
> constructor to use, and its parameter binding:
> First we must create a class with the following content:
> import org.codehaus.jackson.annotate.JsonCreator;
> import org.codehaus.jackson.annotate.JsonProperty;
> public abstract class ClientAccessTokenDeserializeInfo {
>       @JsonCreator
>       ClientAccessTokenDeserializeInfo(
>                       @JsonProperty(value="tokenType") String tokenType, 
>                       @JsonProperty(value="tokenKey") String tokenKey) { }
> }
> And then we map it to the ClientAccessToken class:
> JacksonJsonProvider provider = new JacksonJsonProvider();
> ObjectMapper mapper = new ObjectMapper();
> mapper.getDeserializationConfig().addMixInAnnotations(ClientAccessToken.class,
>  ClientAccessTokenDeserializeInfo.class);
> provider.setMapper(mapper);
> WebClient client = 
> WebClient.create("http://localhost:8080/fwmobisecurity2/services/oauth2";, 
> Collections.singletonList(provider));
> [...]
> ClientAccessToken obj = client.post(formData, ClientAccessToken.class);
> Conclusion: Without changing ClientAccessToken source code, jackson JSON 
> provider MUST be used at server and client sides

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to