spring-attic / spring-security-oauth

Support for adding OAuth1(a) and OAuth2 features (consumer and provider) for Spring web applications.
http://github.com/spring-projects/spring-security-oauth
Apache License 2.0
4.69k stars 4.04k forks source link

RemoteTokenServices can't parse nested collections within the token's authentication details #560

Open vicmosin opened 9 years ago

vicmosin commented 9 years ago

There is an OAuth2 server based on spring-security-oauth2 2.0.7.RELEASE. All the configurations are default except of using JwtAccessTokenConverter as a token converter.

Resource server uses the same oauth library. In order to validate the token, it calls oauth server's /check_token endpoint which returns either JSON or XML representation of token. This call is made within the RemoteTokenServices.loadAuthentication method which uses a RestTemplate as a transport layer. The problem is that somewhere inside the template's implementation there is a code, which add a Accept: application/xml;... header. This behavior causes oauth server response with XML and RestTemplate can't parse correctly the nested collections (i.e. authorities and scope fields) within the response - they are always treated as String and not as Collection.

The solution is either override the RemoteTokenServices and add manually the Accept: application/json; header or change oauth server's behavior to ignore this header and return JSON by default.

dsyer commented 9 years ago

RemoteTokenServices uses a stock RestTemplate that it creates itself unless you inject one yourself. I suspect you have changed the default settings somehow if it is sending Accept: ... in any form.

vicmosin commented 9 years ago

Nope.. There is no any overrides from my side... Here is the bean:

@Bean
ResourceServerTokenServices remoteTokenService() {
     RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
     remoteTokenServices.setAccessTokenConverter(jwtAccessTokenConverter());
     remoteTokenServices.setCheckTokenEndpointUrl(authServerCheckTokenUrl);
     remoteTokenServices.setClientId(authServerClientId);
     remoteTokenServices.setClientSecret(authServerClientSecret);

     return remoteTokenServices;
}

RestTemplate.doExecute uses requestCallback instance which extends AcceptHeaderRequestCallback and adds the header

pdelagrave commented 5 years ago

Hi, This is still an issue.

The stock RestTemplate used by RemoteTokenServices will include MappingJackson2XmlHttpMessageConverter in its messageConverter list in front of the JSON one when that converter bean exists in the context.

The MappingJackson2XmlHttpMessageConverter bean is created when the XmlMapper class exists in the classpath, which is typically provided by the com.fasterxml.jackson.dataformat:jackson-dataformat-xml maven dependency: https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/JacksonHttpMessageConvertersConfiguration.java#L62

Basically, the Spring Security Authorization Server and Resource Server interaction is broken when letting Spring use the default RestTemplates for them when XmlMapper is in the classpath.

One main issue is that it silently "works" until it doesn't, for example if the user has more than one scope items and the one making it back to the RemoteTokenServices isn't the required one.

See the attached minimal app to reproduce the issue. The unmodified code doesn't work (Executing the tests in AppTest), then commenting out build.gradle:18 will fix it: removing the jackson-dataformat-xml dependency.

xmltest.tar.gz