7

I'm currently working on a spring app for an Oauth2 authentication but I got some issue implementing a custom ClientDetailsService.

I can't use the common inMemory ou jdbc clientDetailsService because clients information arn't stored in my app, I get them from an external webservice. But when I set a custom ClientDetailService I don't get the access_confirmation page anymore (I get a blank page).

To show you my issue I don't use my app but the the vanilla test from the official spring--security-oauth project spring-security-oauth

Here's the application code:

@SpringBootApplication
@EnableResourceServer
@RestController
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @RequestMapping("/")
    public String home() {
        return "Hello World";
    }

    @RequestMapping(value = "/", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public String create(@RequestBody MultiValueMap<String, String> map) {
        return "OK";
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(authenticationManager);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.checkTokenAccess("isAuthenticated()");
        }

        public ClientDetailsService clientDetailsService() {
            return new ClientDetailsService() {
                @Override
                public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
                    BaseClientDetails details = new BaseClientDetails();
                    details.setClientId(clientId);
                    details.setAuthorizedGrantTypes(Arrays.asList("authorization_code") );
                    details.setScope(Arrays.asList("read, trust"));
                    details.setResourceIds(Arrays.asList("oauth2-resource"));
                    Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
                    authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT"));
                    details.setAuthorities(authorities);
                    return details;
                }
            };
        }  //*/


        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off

            clients.withClientDetails(clientDetailsService());

            /*clients.inMemory()
                .withClient("test")
                    .authorizedGrantTypes("authorization_code")
                    .authorities("ROLE_CLIENT")
                    .scopes("read", "trust")
                    .resourceIds("oauth2-resource");
            //*/
            // @formatter:on
        }
    }

}

As you can see I add my custom clientDetailsService and change the ClientDetailsServiceconfigurer configuration to set it instead of the in memory clientDetailsService.

My problem is that when try to get my token I don't get my access_confirmation page anymore after I logged the user.

I found my problem, my definition of the scopes in my clientDetails was false. I had Arrays.asList("read, trust") instead of Arrays.asList("read", "trust")

Did I missed something? do I have to set my custom clientDetailsService somewhere else?

benedick steve
  • 81
  • 1
  • 1
  • 6
  • 1
    Do you have additional informations like stacktrace or log that are showing more about your problem? – sven.kwiotek Nov 29 '16 at 16:22
  • I don't get any error on my test. If i try to get the token with postman setting - localhost:8080/oauth/authorize as authorisation url - localhost:8080/oauth/token as token url - test as client id - authorization_code as grant type I get a empty screen after the user authentification (he didn't go on confirm_access page) – benedick steve Nov 29 '16 at 18:22
  • If i test it on my browser with this url: http://localhost:8080/oauth/authorize?client_id=test&redirect_uri=http://localhost:8080/&response_type=code I'm redirected to the redirect-uri without getting the confirm_access page to (for the browser url I know the url isn't ok to get my token but it should be enuogh to test the authorization ) – benedick steve Nov 29 '16 at 18:23
  • What if you define the redirect uri in your ClientDetails like details.setRegisteredRedirectUri(...) ? – sven.kwiotek Nov 30 '16 at 09:26
  • I tried but it doesn't change, registeredRedirectUris wasn't defined in the inMemory clientDetailsService definition that was working – benedick steve Nov 30 '16 at 09:54
  • You have to annotate the ClientDetailsService as @Bean. – sven.kwiotek Nov 30 '16 at 12:37
  • Could you post here your full Request with parameters, headers etc. – sven.kwiotek Nov 30 '16 at 17:42
  • Thanks for the help, I found my bug it was my definition of the scope in my clients details that was false. I had Arrays.asList("read, trust") instead of Arrays.asList("read", "trust"). Don't know why I don't get any error about it but seems to work fine now. – benedick steve Dec 01 '16 at 13:37

2 Answers2

7

Try changing your ClientDetails impl like so:

public ClientDetailsService clientDetailsService() {
        return new ClientDetailsService() {
            @Override
            public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
                BaseClientDetails details = new BaseClientDetails();
                details.setClientId(clientId);
                details.setAuthorizedGrantTypes(Arrays.asList("authorization_code") );
                details.setScope(Arrays.asList("read, trust"));
                details.setRegisteredRedirectUri(Collections.singleton("http://anywhere.com"));
                details.setResourceIds(Arrays.asList("oauth2-resource"));
                Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
                authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT"));
                details.setAuthorities(authorities);
                return details;
            }
        };
    }  //*/
vmarusic
  • 186
  • 1
  • 6
  • 1
    Thanks for the help, I found my bug it was my definition of the scope in my clients details that was false. I had Arrays.asList("read, trust") instead of Arrays.asList("read", "trust") – benedick steve Dec 01 '16 at 13:41
  • 1
    Nice! Did not notice the typo which i c/p as well :) – vmarusic Dec 01 '16 at 15:29
0

I am trying to do something similar but I have some different issue. Hope you guys can help me here .

I have a class below

@Entity
@Table(name = "oauth_client_details")
public class CustomOAuthClientDetails extends BaseClientDetails{
    
    
    
    /**
     * 
     */
    private static final long serialVersionUID = -2792747663814219416L;

    @Id
    @Override
    public String getClientId() {
        return super.getClientId();
    }
    
    
    @Override
    public String getClientSecret() {
        return super.getClientSecret();
    }
    
    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return super.getAuthorities();
    }

}

A repository class declared like below

Optional<CustomOAuthClientDetails> customOAuthClientDetails = authClientDetailsRepository.findByClientId(clientId);

When I try to do like below

details.setAuthorizedGrantTypes(customOAuthClientDetails.get().getAuthorizedGrantTypes());

I am getting below error

Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: oauth_client_details, for columns: [org.hibernate.mapping.Column(authorities)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:499) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:466) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.Property.isValid(Property.java:227) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:624) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.RootClass.validate(RootClass.java:267) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:354) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.2.jar:5.3.2]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.2.jar:5.3.2]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.2.jar:5.3.2]
    ... 21 common frames omitted


  • Problem which I could analyse is I am not able to parse data from oauth_client_details table to my Entity class. How can I do this ? – Abhishek Bansal Dec 21 '20 at 10:58
  • Welcome to SO. Please use answer section only for actual answering. If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. – Doj Dec 21 '20 at 11:18