3
votes

I have an ios app which communicates with a REST API developed on Grails. In order to secure the REST API, I decided to use oAuth 2.0 'Resource Owner Password' flow. For the grails app to act as an oAuth 2.0 provider I am using the following http://grails.org/plugin/spring-security-oauth2-provider For Client with id as 'client' ,secret as '1234' and User with username as 'user' and password as 'password',the request for token is as follows

POST /oauth2-test/oauth/token HTTP/1.1
Host: 192.168.1.113:8080
Authorization: Basic Y2xpZW50OjEyMzQ=
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded

grant_type=password&scope=read&username=user&password=password

The response received is

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

My config.groovy edits for Spring Security and oAuth 2.0 provider plugin looks like this

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'test.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'test.UserRole'
grails.plugin.springsecurity.authority.className = 'test.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    '/':                              ['permitAll'],
    '/index':                         ['permitAll'],
    '/index.gsp':                     ['permitAll'],
    '/assets/**':                     ['permitAll'],
    '/**/js/**':                      ['permitAll'],
    '/**/css/**':                     ['permitAll'],
    '/**/images/**':                  ['permitAll'],
    '/**/favicon.ico':                ['permitAll'],
    '/oauth/authorize.dispatch': ["isFullyAuthenticated() and (request.getMethod().equals('GET') or request.getMethod().equals('POST'))"],
    '/oauth/token.dispatch'    : ["isFullyAuthenticated() and request.getMethod().equals('POST')"]
]

// Added by the Spring Security OAuth2 Provider plugin:
grails.plugin.springsecurity.oauthProvider.clientLookup.className = 'test.Client'
grails.plugin.springsecurity.oauthProvider.authorizationCodeLookup.className = 'test.AuthorizationCode'
grails.plugin.springsecurity.oauthProvider.accessTokenLookup.className = 'test.AccessToken'
grails.plugin.springsecurity.oauthProvider.refreshTokenLookup.className = 'test.RefreshToken'

grails.plugin.springsecurity.providerNames = [
        'clientCredentialsAuthenticationProvider',
        'daoAuthenticationProvider',
        'anonymousAuthenticationProvider',
        'rememberMeAuthenticationProvider'
]
grails.exceptionresolver.params.exclude = ['password', 'client_secret']
grails.plugin.springsecurity.filterChain.chainMap = [
        '/oauth/token': 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-rememberMeAuthenticationFilter',
        '/api/**': 'JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-rememberMeAuthenticationFilter',
        '/**': 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter'
]
  • What am i doing wrong? I understand oAuth 2.0 is primarily for authorization and not authentication. So do I have to explicitly add a filter for authentication?I started with Grails without any experience on Springs and any help is appreciated as to how to do it?
  • Does grant_type 'password' require client authentication? For grant
    type 'password' should user authentication not suffice?Even if it needs to authenticate the client it would use Basic Authentication according to my understanding. So do I need to explicitly add a basic authentication filter?
1
Are you passing client_id and client_secret in the Authorization header? Did you try passing them in the request instead? - Dan Fischer
Yes I am passing the client_id and client_secret in the Authorization header. Yes, tried passing them in the request as x-www-form-urlencoded and got the same result.. No change. - user559668
How did you resolve this please? - JohnTheBeloved
There's a discussion on Github on how to support HTTP Basic Authentication properly in the Spring Security OAuth2 Provider plugin: github.com/bluesliverx/grails-spring-security-oauth2-provider/… - Roy Willemse

1 Answers

2
votes

Basic Authentication is not enabled by default in Spring Security Core, so you can't put your client_id and client_secret in the Authorization header; in this case just add them to the request parameters (like grant_type)

The following CURL example should work:

curl -v -X POST \
-d "grant_type=password" \
-d "client_id=client" \
-d "client_secret=1234" \
-d "scope=read" \
-d "username=user" \
-d "password=password" http://localhost:8080/oauth2-test/oauth/token

{"access_token":"d3eb1c1c-9922-4cfc-87e3-7efca9a8a2f2","token_type":"bearer","refresh_token":"e790efc2-e708-4391-9a7b-e4d86dc70816","expires_in":42545,"scope":"read"}

Note that OAuth2 requires HTTPS. If you're running Grails with the -https option (grails run-app -https), the command is this:

curl -v --insecure -X POST \
-d "grant_type=password" \
-d "client_id=client" \
-d "client_secret=1234" \
-d "scope=read" \
-d "username=user" \
-d "password=password" https://localhost:8443/oauth2-test/oauth/token

When I omit the request parameter client_id, I get the following reply:

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

Update

If you want to be able to use HTTP Basic Authentication for the client_id, just enabling Basic Authentication in Spring Security Core (in Config.groovy) is not the solution since the BasicAuthenticationFilter is not initialised in a way suitable for oauth2. When the credentials are correct or omitted everything works as expected, but when the credentials are provided but wrong, you'll get a HTML response.

There is currently an issue on the project's Github page where the proper way of handling Basic Authentication is discussed:

https://github.com/bluesliverx/grails-spring-security-oauth2-provider/issues/65