1

I'm trying to create a sample authorization server using the spring security oauth2 framework. The tutorials are confusing compared to any other spring related examples.

Update: If you are looking for a working solution, go to my answer. Ignore the code below.

When I invoked the token issue endpoint, the following error was thrown

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}

Here's my setup (using Groovy). I'm using spring-security-oauth2:2.3.4.RELEASE, spring-cloud-security:2.0.1.RELEASE, and boot:2.1.1.RELEASE.

@Configuration
@CompileStatic
class OAuth2ClientSpringConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    AuthenticationManager authenticationManager

    @Autowired
    UserDetailsService userDetailsService

    // register clients
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient('clientone')
                .secret('secret')
                .authorizedGrantTypes('password')
                .scopes('one', 'two')
    }

    //use default auth manager and user details service
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients()
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients()  //<--- update
    }
}

Static user credentials

@Configuration
@CompileStatic
class UserCredentialsSpringConfig extends WebSecurityConfigurerAdapter {

    @Bean
    AuthenticationManager authenticationManagerBean() {
        super.authenticationManagerBean()
    }

    @Bean
    UserDetailsService userDetailsServiceBean() {
        super.userDetailsServiceBean()
    }

    protected void configure(AuthenticationManagerBuilder auth) {
        auth.inMemoryAuthentication()
                .withUser('user1').password('pwd1').roles('USER')
                .and()
                .withUser('admin').password('pwd1').roles('ADMIN')
    }

    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth/token").permitAll()
                .anyRequest().authenticated()
    }
}

Postman setup

  • Added the client credentials in both places - Authorization header and in a normal header.

enter image description here


enter image description here

  • Used the body form params to send user credentials

enter image description here


Ran into the following error when I hit http://localhost:8080/auth/oauth/token

enter image description here

I've looked into different tutorials and not figured it out. Any inputs would be helpful.

phanin
  • 5,327
  • 5
  • 32
  • 50
  • Possible duplicate of https://stackoverflow.com/questions/52413820/java-spring-security-oauth2-accept-client-credentials-via-post – dur Jan 09 '19 at 15:04
  • Thanks for the response. I added `allowFormAuthenticationForClients()` and still the same error. – phanin Jan 09 '19 at 19:25
  • You also have to add `client_id` to your body (instead of a header). – dur Jan 09 '19 at 20:08
  • Thanks. Yep, tried that too. Didn't help. Right now, client_id and client_secret are added to body form data, headers, and authorization header. – phanin Jan 09 '19 at 21:46
  • I'm following the example in Spring Microservices in Action. No passwordEncoder is mentioned. Interesting. – phanin Jan 09 '19 at 22:49

2 Answers2

4

There are several tutorials online but some of them fail to mention that they are using Boot 1.x. That's what I ran into when I combined those instructions with Boot 2.x. Those tutorials might be valid with Boot 2.x but things were already confusing enough that I could not figure out a working model.

Here's a working solution for Boot 2.x. I started afresh with the code example at https://github.com/spring-projects/spring-security-oauth2-boot/tree/master/samples/spring-boot-sample-secure-oauth2-provider .

Import the spring-security-oauth2-autoconfigure dependency. Add @EnableAuthorizationServer to your main class. That's all you need for a simplest working model. No need to add a AuthorizationServerConfigurerAdapter, etc because it's auto configured with the data from application.yml. Take a look at the application.yml in the above github link.

Here's the Postman configuration

Copy the sample client id and secret from the application.yml and supply them as Auth headers.

enter image description here

Copy the generated password from boot log and put it in Body form data along with other attributes as shown in the picture.

enter image description here

That's it. Hit http://localhost:8080/oauth/token and you should see something like below

enter image description here

phanin
  • 5,327
  • 5
  • 32
  • 50
2

By specification, the token issue endpoint must be protected.

You have to provide client_id and client_secret as parameters (form) or as an http-basic authorization header

Taken directly from spec

 POST /token HTTP/1.1
 Host: server.example.com
 Content-Type: application/x-www-form-urlencoded

 grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
 &client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw

Please review

https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1

Why don't we remove the client out of your equation for a bit, and just focus on your Token Endpoint

curl is your friend, here is a FORM example (verified working example against Cloud Foundry UAA local where client secret is an empty string)

curl -v \
    -H "Content-Type=application/x-www-form-urlencoded" \
    -H "Accept=application/json" \
    -d "grant_type=password" \
    -d "client_id=cf" \
    -d "response_type=token" \
    -d "username=marissa" \
    -d "password=koala" \
    -d "client_secret=" \
    http://localhost:8080/uaa/oauth/token

and using http-basic

curl -v \
    -H "Content-Type=application/x-www-form-urlencoded" \
    -H "Accept=application/json" \
    -d "grant_type=password" \
    -d "client_id=cf" \
    -d "response_type=token" \
    -d "username=marissa" \
    -d "password=koala" \
    -u "cf:" \
    http://localhost:8080/uaa/oauth/token

Can you run these commands with your actual data and let us know the commands (perhaps update your question) and let us know the results. You see, we don't know what your UI app is actually doing, and using curl, will let us eliminate that from the question.

Community
  • 1
  • 1
Filip Hanik VMware
  • 1,484
  • 6
  • 8
  • Thanks for the response. I'm sending client_id and client_secret in multiple places (to find out which one works) - authorization header, form parameters. It doesn't work. Please check the postman images in the question. Let me know if you find anything, – phanin Jan 10 '19 at 23:41
  • @phani where are you allowing the client ID and Secret access to the token ID endpoint in your configuration? i.e. that client ID / Secret login is to provide access to the token endpoint, where is that configured – Darren Forsythe Jan 11 '19 at 00:32
  • @phani let's eliminate the requesting app until we figure out what is going on with the authorization server. I have updated the answer, perhaps you can let us know how that works – Filip Hanik VMware Jan 11 '19 at 17:53
  • @phani also do a sanity check - http://localhost:8080/auth/oauth/token is the URL (the /auth/oauth/token path prefix) the correct one? – Filip Hanik VMware Jan 11 '19 at 18:02
  • Thanks. doing some sanity check based on ^ inputs. – phanin Jan 11 '19 at 19:27
  • Apparently Spring MicroServices In Action (is old and) uses Boot 1.x but I'm using Boot 2. No matter what I will try above suggestions. Ref - https://github.com/carnellj/spmia-chapter7/blob/master/authentication-service/pom.xml#L16 – phanin Jan 11 '19 at 19:48
  • I've ditched my code (temporarily) and cloned https://github.com/spring-projects/spring-security-oauth2-boot/tree/master/samples/spring-boot-sample-secure-oauth2-provider. That seems to work. I will have to figure out the documentation to do what I need to productionalize our use case. – phanin Jan 12 '19 at 00:02