(Quick Reference)

2 Getting Started - Reference Documentation

Authors:

Version: 2.0-SNAPSHOT

2 Getting Started

The following assumes that the Spring Security Core plugin has been installed and its required domain class created.

2.1 Install Plugin

Install the OAuth2 plugin by adding a dependency in grails-app/conf/BuildConfig.groovy:

plugins {
    compile ":spring-security-oauth2-provider:2.0-RC3"
}

This has a dependency on the Spring Security Core plugin, which will be installed if necessary.

2.2 Create Domain Classes

Run the s2-init-oauth2-provider script to generate the required domain classes.

2.3 Secure Authorization and Token Endpoints

Update the Core plugin's rules for the authorization and token endpoints so they are protected by Spring Security. If you're using the Core plugin's staticRules, you'll want to add the following in grails-app/conf/Config.groovy:

grails.plugin.springsecurity.controllerAnnotations.staticRules = [
        '/oauth/authorize.dispatch':      ["isFullyAuthenticated() and (request.getMethod().equals('GET') or request.getMethod().equals('POST'))"],
        '/oauth/token.dispatch':          ["isFullyAuthenticated() and request.getMethod().equals('POST')"],
        ...

The endpoints are standard Spring MVC controllers in the underlying Spring Security OAuth2 implementations and the URLs must be mapped with .dispatch.

The additional restrictions on the allowed HTTP methods are to ensure compliance with the OAuth 2.0 spec as defined in RFC 6749.

2.4 Exclude client_secret From Logs

Update the params exclusion list in grails-app/conf/Config.groovy so client secrets are not logged in the clear:

grails.exceptionresolver.params.exclude = ['password', 'client_secret']

2.5 (Optional) Customize Error and Confirm Access Views

When the plugin is installed, two views are copied for the error and confirm access pages. They are located under grails-app/views/oauth/. Customize these to fit your needs.

2.6 Client Registration

At this point your application is a proper OAuth 2.0 provider. You can now register clients in what ever method is appropriate for your application. For example, you can register a client in grails-app/conf/Bootstrap.groovy as follows:

def init = { servletContext ->
        new Client(
                clientId: 'my-client',
                authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'],
                authorities: ['ROLE_CLIENT'],
                scopes: ['read', 'write'],
                redirectUris: ['http://myredirect.com']
        ).save(flush: true)
    }

2.7 Controlling Access to Resources

Access to resources is controlled by the Spring Security Core plugin's access control mechanisms. Additionally, the plugin has full support for the OAuth 2.0 SPeL extensions provided by the underlying Spring library. Refer to the methods in OAuth2SecurityExpressionMethods for what is available in the plugin.

Using SPeL is the only tested and confirmed way to enforce OAuth 2.0 specific restrictions on resource access.

The following controller illustrates the use of OAuth 2.0 SPeL:

class SecuredOAuth2ResourcesController {

@Secured(["#oauth2.clientHasRole('ROLE_CLIENT')"]) def clientRoleExpression() { render "client role expression" }

@Secured(["ROLE_CLIENT"]) def clientRole() { render "client role" }

@Secured(["#oauth2.clientHasAnyRole('ROLE_CLIENT', 'ROLE_TRUSTED_CLIENT')"]) def clientHasAnyRole() { render "client has any role" }

@Secured(["#oauth2.isClient()"]) def client() { render "is client" }

@Secured(["#oauth2.isUser()"]) def user() { render "is user" }

@Secured(["#oauth2.denyOAuthClient()"]) def denyClient() { render "no client can see" }

@Secured(["permitAll"]) def anyone() { render "anyone can see" }

def nobody() { render "nobody can see" }

@Secured(["#oauth2.clientHasRole('ROLE_TRUSTED_CLIENT') and #oauth2.isClient() and #oauth2.hasScope('trust')"]) def trustedClient() { render "trusted client" }

@Secured(["hasRole('ROLE_USER') and #oauth2.isUser() and #oauth2.hasScope('trust')"]) def trustedUser() { render "trusted user" }

@Secured(["hasRole('ROLE_USER') or #oauth2.hasScope('read')"]) def userRoleOrReadScope() { render "user role or read scope" } }

The filter chains must be configured to ensure stateless access to the token endpoint and any OAuth 2.0 resources:

grails.plugin.springsecurity.filterChain.chainMap = [
        '/oauth/token': 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter',
        '/securedOAuth2Resources/**': 'JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-oauth2BasicAuthenticationFilter,-exceptionTranslationFilter',
        '/**': 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter,-oauth2BasicAuthenticationFilter,-oauth2ExceptionTranslationFilter'
]

Please consult the section on Filter Chain Configuration for more information.

2.8 Trouble Shooting

If you encounter a NullPointerException while using the OAuth2 plugin, you might have run into GPCACHE-25. This will occur when using the OAuth2 plugin with earlier versions of the Cache Plugin. However, the latest version at the time of this writing (1.1.6) seems to have fixed this issue. To resolve the NullPointerException issue, either upgrade the Cache plugin or uninstall it.

If an instance of one of the GORM backed classes that the plugin uses cannot be saved, an OAuth2ValidationException will be thrown. This is a subclass of the standard Grails ValidationException so the plugin consumer has the flexibility to determine how to deal with this type of error. The typical reason for this exception being thrown will likely be related to the max size allotted to the serialized OAuth2Authentication fields. The thrown exception can be inspected for further information about the Errors.