[
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