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

It is impossible to customize `ResourceServerTokenServices` when enables authorization server and resource server at the same time . #740

Open m11y opened 8 years ago

m11y commented 8 years ago

I dig into the code, and find code in ResourceServerConfiguration:

private ResourceServerTokenServices resolveTokenServices() {
        if (tokenServices == null || tokenServices.size() == 0) {
            return null;
        }
        if (tokenServices.size() == 1) {
            return tokenServices.values().iterator().next();
        }
        if (tokenServices.size() == 2) {
            // Maybe they are the ones provided natively
            Iterator<ResourceServerTokenServices> iter = tokenServices.values().iterator();
            ResourceServerTokenServices one = iter.next();
            ResourceServerTokenServices two = iter.next();
            if (elementsEqual(one, two)) {
                return one;
            }
        }
        return context.getBean(ResourceServerTokenServices.class);
    }

the code above limits that only one instance of ResourceServerTokenServices exists.

And code in AuthorizationServerEndpointsConfiguration:

        @Bean
    public AuthorizationServerTokenServices defaultAuthorizationServerTokenServices() {
        return endpoints.getDefaultAuthorizationServerTokenServices();
    }

always register defaultAuthorizationServerTokenServices which implments ResourceServerTokenServices.

when implements custom tokenServices, exceptions was thrown.

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.security.oauth2.provider.token.ResourceServerTokenServices] is defined: expected single matching bean but found 3: consumerTokenServices,myTokenServices,defaultAuthorizationServerTokenServices
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:366) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1066) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration.resolveTokenServices(ResourceServerConfiguration.java:188) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
stefanocke commented 6 years ago

I had the same issue. as a workaround, I defined my TokenServices as primary ones:

@Bean @Primary public ResourceServerTokenServices getResourceServerTokenServices() { return myTokenServices; }

OrangeDog commented 5 years ago

Another way to do it is to inject the AuthorizationServerEndpointsConfiguration bean:

@Autowired
private AuthorizationServerEndpointsConfiguration endpoints;

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
    resources.tokenServices(endpoints.getEndpointsConfigurer().getResourceServerTokenServices());
}

or use it to expose the services bean

@Bean
public ResourceServerTokenServices resourceServerTokenServices(AuthorizationServerEndpointsConfiguration endpoints) {
    return endpoints.getEndpointsConfigurer().getResourceServerTokenServices()
}

@dsyer is there a reason that resolveTokenServices() doesn't do this itself? It will get the token store from the endpoint config, but not the token services.