(Quick Reference)

2 Getting Started - Reference Documentation

Authors: Brian Saville, Bobby Vandiver, Roy Willemse

Version: 3.0.0-RC2

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 build.gradle:

dependencies {
    compile 'org.grails.plugins:spring-security-oauth2-provider:3.0.0-SNAPSHOT'
}

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/application.groovy:

grails.plugin.springsecurity.controllerAnnotations.staticRules = [
        [pattern: '/oauth/authorize',           access: "isFullyAuthenticated() and (request.getMethod().equals('GET') or request.getMethod().equals('POST'))"],
        [pattern: '/oauth/token',               access: "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 (Optional) Customize Error and Confirm Access Views

The plugin provides views for the error and confirm access pages. These can be overridden by providing your own grails-app/views/oauth/error.gsp and grails-app/views/oauth/confirm_access.gsp files, respectively.

2.5 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/init/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.6 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 = [
        [pattern: '/oauth/token',               filters: 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter'],
        [pattern: '/securedOAuth2Resources/**', filters: 'JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-oauth2BasicAuthenticationFilter,-exceptionTranslationFilter'],
        [pattern: '/**',                        filters: 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter,-oauth2BasicAuthenticationFilter,-oauth2ExceptionTranslationFilter']
]

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

2.7 Trouble Shooting

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.