(Quick Reference)

7 Configuration - Reference Documentation

Authors: Brian Saville, Bobby Vandiver, Roy Willemse

Version: 3.0.0-RC2

7 Configuration

The plugin is pessimistic by default, locking down as much as possible to guard against accidental security breaches. However, these constraints can be modified if so desired in grails-app/conf/application.groovy. The properties below exist in the grails.plugin.springsecurity.oauthProvider namespace.

7.1 Plugin

The following properties define whether the plugin is active and where the required filters are registered in the Spring Security filter chain:

PropertyDefault ValueMeaning
activetrueWhether the plugin is enabled.
filterStartPositionSecurityFilterPosition.X509_FILTER.orderThe position in the filter chain of the OAuth2AuthenticationProcessingFilter, which handles authentication for resource access by extracting an access token from the incoming request.
clientFilterStartPositionSecurityFilterPosition.DIGEST_AUTH_FILTER.orderThe position in the filter chain of the ClientCredentialsTokenEndpointFilter, which handles client authentication.
statelessFilterStartPositionSecurityFilterPosition.SECURITY_CONTEXT_FILTER.orderThe position in the filter chain of the StatelessSecurityContextPersistenceFilter, which is used to ensure access to OAuth 2.0 resources and the token endpoint are stateless.
exceptionTranslationFilterStartPositionSecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.orderThe position in the filter chain of the ExceptionTranslationFilter configured with a NullRequestCache, which is used to ensure access to OAuth 2.0 resources and the token endpoint are stateless.
basicAuthenticationFilterStartPositionSecurityFilterPosition.BASIC_AUTH_FILTER.orderThe position in the filter chain of the BasicAuthenticationFilter configured with a NullRememberMeServices, which is used to ensure access to OAuth 2.0 resources and the token endpoint are stateless.
registerStatelessFiltertrueWhen this is true, the plugin will register the statelessSecurityContextPersistenceFilter in the filter chain after the securityContextPersistenceFilter provided by the Spring Security Core plugin. See below for additional configuration of the filter chain(s) required to properly secure access to OAuth 2.0 resources.
registerExceptionTranslationFiltertrueWhen this is true, the plugin will register the oauth2ExceptionTranslationFilter in the filter chain after the exceptionTranslationFilter provided by the Spring Security Core plugin. See below for additional configuration of the filter chain(s) required to properly secure access to OAuth 2.0 resources.
registerBasicAuthenticationFiltertrueWhen this is true, the plugin will register the oauth2BasicAuthenticationFilter in the filter chain after the basicAuthenticationFilter provided by the Spring Security Core plugin. See below for additional configuration of the filter chain(s) required to properly secure access to OAuth 2.0 resources.
realmNameGrails OAuth2 RealmRealm name included in the WWW-Authenticate header in a challenge response.

7.2 Endpoint URLs

The endpoint URLs used by the underlying Spring Security OAuth 2.0 implementation can be changed using the following properties:

PropertyDefault ValueMeaning
authorizationEndpointUrl'/oauth/authorize'Authorization endpoint URL.
tokenEndpointUrl'/oauth/token'Token endpoint URL.
userApprovalEndpointUrl'/oauth/confirm_access'URL of the view to display for confirming access to protected resources.
userApprovalParameter'user_oauth_approval'The name of the parameter submitted in the confirmation request. The value of this parameter is used to determine whether a user has confirmed (true) or denied (false) access.
errorEndpointUrl'/oauth/error'URL of the view to display if an error occurs while interacting with the authorization endpoint and the error cannot be returned as part of the query or fragment of the client's redirect URI. This is usually the case when there is a problem with the requesting client's redirect URI.

When changing the URL for the authorizationEndpointUrl or tokenEndpointUrl, you must update Spring Security Core's configuration. Using the staticRules configuration and the default configuration as an example, your grails-app/conf/Config.groovy will look like this:

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')"],
        ...

To change the authorizationEndpointUrl to /authorize, you will need to make the following changes in grails-app/conf/application.groovy:

grails.plugin.springsecurity.oauthProvider.authorizationEndpointUrl = '/authorize'

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

7.3 Token Services

The following properties apply to how tokens are issued and how long they are valid. If a client has defined a specific token validity length, the client's length will take priority over the values configured for the token services.

PropertyDefault ValueMeaning
tokenServices.registerTokenEnhancerstrueWhether registered TokenEnhancer instances should be used.
tokenServices.accessTokenValiditySeconds60 * 60 * 12The length of time that an access token will be valid after it has been issued.
tokenServices.refreshTokenValiditySeconds60 * 60 * 24 * 30The length of time that a refresh token will be valid after it has been issued.
tokenServices.reuseRefreshTokenfalseWhether a new refresh token should be generated if one is currently available.
tokenServices.supportRefreshTokentrueWhether a refresh token can be issued upon request.

7.4 Token Enhancers Configuration

By default, the plugin will register a TokenEnhancerChain with an empty list of TokenEnhancer delegates. When the tokenServices.registerTokenEnhancers option is true, the plugin will detect and use all registered Spring beans implementing the TokenEnhancer interface.

If more control over the ordering of the enhancers in the chain is desired, set the tokenServices.registerTokenEnhancers option to false. The TokenEnhancerChain bean is registered under the name tokenEnhancerChain, so the plugin consumer can get a handle to it for more fine grained configuration.

This bean is aliased under the name tokenEnhancer. This is the bean that is registered with the tokenServices bean. This is done to allow customization of the registered enhancer with minimal effort. Just override the tokenEnhancer bean.

7.5 Supported Grant Types

The following properties determine which of the standard grant types the application can support. Individual clients must declare which of the enabled grant types they support.

PropertyDefault ValueMeaning
grantTypes.authorizationCodetrueWhether the Authorization Code Grant is supported.
grantTypes.implicittrueWhether the Implicit Grant is supported.
grantTypes.clientCredentialstrueWhether the Client Credentials Grant is supported.
grantTypes.passwordtrueWhether the Resource Owner Password Credentials is supported.
grantTypes.refreshTokentrueWhether Refresh Token Grant is supported.

7.6 Additional Authorization Constraints

The plugin enforces the following restrictions on authorization request params:

PropertyDefault ValueMeaning
authorization.requireRegisteredRedirectUritrueWhether a client is required to have registered a redirect URI before performing an authorization request. This addresses RFC 6749 Section 10.6: Authorization Code Redirection URI Manipulation and RFC 6749 Section 10.15: Open Redirectors .
authorization.requireScopetrueWhether the scope for each access token requested is required.

7.7 User Approval Configuration

The plugin provides support for the three UserApprovalHandler implementations provided by the underlying Spring OAuth library. This only applies to the authorization endpoint and allows you to configure the method of auto-approval used by the application. The following properties determine which method of auto-approval to use and how it is configured:

PropertyDefault ValueMeaning
autoEXPLICITDetermines which method of auto-approval to use. The value is determined by grails.plugin.springsecurity.oauthprovider.approval.UserApprovalSupport and must be EXPLICIT, TOKEN_STORE or APPROVAL_STORE.
handleRevocationAsExpiryfalseWhen configured to use an approval store for auto-approval, this determines if approval revocation should expire the corresponding approval instance (true) or delete the approval (false) outright.
approvalValiditySeconds60 * 60 * 24 * 30When configured to use an approval store for auto-approval, the length of time that an approval will be valid after it has been granted.
scopePrefix'scope.'When configured to use an approval store for auto-approval, the prefix added to approved scopes as part of the auto-approval process.

The auto property determines which of the three UserApprovalHandler provided by Spring OAuth will be used.

The default option is to require explicit approval for every authorization and is equivalent to setting auto to EXPLICIT:

grails.plugin.springsecurity.oauthprovider.approval.auto = UserApproval.EXPLICIT

Auto-approval based on previously issued access tokens is supported via the TokenStoreUserApprovalHandler provided by Spring OAuth and can be configured by setting auto to TOKEN_STORE:

grails.plugin.springsecurity.oauthprovider.approval.auto = UserApproval.TOKEN_STORE

Auto-approval based on prior approvals is supported via the ApprovalStoreUserApprovalHandler provided by Spring OAuth and can be configured by setting auto to APPROVAL_STORE:

grails.plugin.springsecurity.oauthprovider.approval.auto = UserApproval.APPROVAL_STORE

The plugin will configure the TokenStoreUserApprovalHandler and ApprovalStoreUserApprovalHandler to use the GORM backed TokenStore and ApprovalStore respectively.

Please consult Spring OAuth directly for more information on the usage of the TokenStore and ApprovalStore methods of auto-approval.

7.8 Default Client Configuration

An application can use the following properties to define the default values that will be used when creating a ClientDetails instance if a client has not specified a value. The default configuration will not allow a client to retrieve an access token unless they have explicitly registered support for the requested grant type.

PropertyDefault ValueMeaning
defaultClientConfig.resourceIds[]Resources the client is authorized to access. This is currently unused as access to resources is controlled by Spring Security Core's rules.
defaultClientConfig.authorizedGrantTypes[]Grant types the client supports.
defaultClientConfig.scope[]Scope to use for each access token request.
defaultClientConfig.autoApproveScopes[]Scopes to auto-approve for authorization requests. Including a value of true in the list will auto-approve all scopes for clients using the default configuration.
defaultClientConfig.registeredRedirectUrinullURI to redirect the user-agent to during an authorization code or implicit grant.
defaultClientConfig.authorities[]Roles and authorities granted to the client.
defaultClientConfig.accessTokenValiditySecondsnullThe length of time that an access token will be valid after it has been issued. This is used instead of the length configured for token services if available.
defaultClientConfig.refreshTokenValiditySecondsnullThe length of time that a refresh token will be valid after it has been issued. This is used instead of the length configured for token services if available.
defaultClientConfig.additionalInformation[:]Additional information about the client. This is not required by OAuth 2.0 but is exposed in the underlying Spring library.

7.9 Filter Chain Configuration

Spring Security Core plugin's securityContextPersistenceFilter stores state in the HTTP session. Access to the token endpoint and OAuth 2.0 resources must be stateless.

By default, the OAuth2 plugin will register the statelessSecurityContextPersistenceFilter in the filter chain after the securityContextPersistenceFilter provided by the Spring Security Core plugin. This is provided as a convenience for the plugin consumer, so they can remove one filter or the other to easily achieve stateful or stateless request handling. See the example below. This automatic filter registration can be disabled by setting the registerStatelessFilter configuration option to false.

The plugin registers an OAuth2AuthenticationProcessingFilter under the bean name oauth2ProviderFilter. This filter provides token authentication using the underlying token store for resource access.

The plugin registers a ClientCredentialsTokenEndpointFilter under the bean name clientCredentialsTokenEndpointFilter. This filter is responsible for authenticating the client specified in any OAuth 2.0 requests. The plugin also registers a BasicAuthenticationFilter under the bean name oauth2BasicAuthenticationFilter. This filter is responsible for authenticating the client via HTTP Basic authentication, which is the recommended method in the OAuth 2.0 specification.

Finally, the plugin registers an ExceptionTranslationFilter under the bean name oauth2ExceptionTranslationFilter. This filter is created with a NullRequestCache instance rather than the HttpSessionRequestCache instance that the Spring Security Core plugin provided ExceptionTranslationFilter is created with. Similar to the statelessSecurityContextPersistenceFilter, this filter is registered automatically by the plugin but can be disabled by setting the registerExceptionTranslationFilter configuration option to false.

The following filter chain configuration is recommended:

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']
]

The oauth2ProviderFilter and stateful securityContextPersistenceFilter and exceptionTranslationFilter are removed from the token endpoint's filter chain. With the securityContextPersistenceFilter removed, the statelessSecurityContextPersistenceFilter will be used to ensure access token requests are stateless. Similarly, removing the exceptionTranslationFilter will allow the oauth2ExceptionTranslationFilter to take its place in the filter chain.

The securityContextPersistenceFilter and exceptionTranslationFilter are also removed from the filter chain for OAuth 2.0 resources. However, the oauth2ProviderFilter must not be removed, as this filter is responsible for authenticating the OAuth 2.0 access token included in the request.

It is recommend that filter chain(s) for non-OAuth 2.0 resources have all OAuth 2.0 specific filters removed. These include: statelessSecurityContextPersistenceFilter, oauth2ProviderFilter, clientCredentialsTokenEndpointFilter, basicAuthenticationFilter and oauth2ExceptionTranslationFilter. It is also recommended that any unnecessary filters such as the rememberMeAuthenticationFilter and authenticationProcessingFilter are removed from the filter chains for the token endpoint and OAuth 2.0 resources.

7.10 Domain Class Custom Serialization Configuration

The default behavior of the plugin is to serialize the additionalInformation and scope properties of the Client and AccessToken classes as a Map<String, Object> and Set<String> respectively. This is how the s2-init-oauth2-provider script will generate the domain classes. However, this might not be ideal for all plugin consumers who want more control over the serialization of these fields.

To accommodate these users, it is possible to override the default serialization method on a case-by-case basis. The plugin provides two interfaces to accomplish.

For the additionalInformation fields:

package grails.plugin.springsecurity.oauthprovider.serialization;

import java.util.Map;

public interface OAuth2AdditionalInformationSerializer {

Object serialize(Map<String, Object> additionalInformation);

Map<String, Object> deserialize(Object additionalInformation); }

For the scope field:

package grails.plugin.springsecurity.oauthprovider.serialization;

import java.util.Set;

public interface OAuth2ScopeSerializer {

Object serialize(Set<String> scopes);

Set<String> deserialize(Object scopes); }

By default, the plugin registers implementations that do little more than return the argument provided to each method. The following table shows which plugin provided Spring beans implement these interfaces and how they're used:

Bean NameInterface ImplementedDescription
clientAdditionalInformationSerializerOAuth2AdditionalInformationSerializerHandles deserialization of the additionalInformation property of the Client class into a Map<String, Object>. Only the deserialize method is used by the plugin at this time.
accessTokenAdditionalInformationSerializerOAuth2AdditionalInformationSerializerHandles serialization and deserialization of the additionalInformation property of the AccessToken class into a Map<String, Object>.
accessTokenScopeSerializerOAuth2ScopeSerializerHandles serialization and deserialization of the scope property of the AccessToken class into a Set<String>.

Overriding these beans in resources.groovy will allow the plugin consumer to customize how these fields are serialized. However, this will require the affected domain class to be modified to accommodate the change. For example, let's change the AccessToken to serialized its additionalInformation as JSON String and its scope as white space delimited String.

First, modify the AccessToken class to reflect the change in the storage of these fields:

package test.oauth2

class AccessToken {

String authenticationKey byte[] authentication

String username String clientId

String value String tokenType

Date expiration String additionalInformation

String scope

static hasOne = [refreshToken: String]

static constraints = { username nullable: true clientId nullable: false, blank: false value nullable: false, blank: false, unique: true tokenType nullable: false, blank: false expiration nullable: false scope nullable: false refreshToken nullable: true authenticationKey nullable: false, blank: false, unique: true authentication nullable: false, minSize: 1, maxSize: 1024 * 4 additionalInformation nullable: true }

static mapping = { version false scope lazy: false } }

Next, implement the earlier described interfaces:

package test

import grails.plugin.springsecurity.oauthprovider.serialization.OAuth2ScopeSerializer import org.springframework.security.oauth2.common.util.OAuth2Utils

class WhiteSpaceDelimitedStringScopeSerializer implements OAuth2ScopeSerializer {

@Override Object serialize(Set<String> scopes) { return OAuth2Utils.formatParameterList(scopes) }

@Override Set<String> deserialize(Object scopes) { return OAuth2Utils.parseParameterList(scopes) } }

And:

package test

import grails.plugin.springsecurity.oauthprovider.serialization.OAuth2AdditionalInformationSerializer import groovy.json.JsonOutput import groovy.json.JsonSlurper

class JsonAdditionalInformationSerializer implements OAuth2AdditionalInformationSerializer {

@Override Object serialize(Map<String, Object> additionalInformation) { JsonOutput.toJson(additionalInformation) }

@Override Map<String, Object> deserialize(Object additionalInformation) { new JsonSlurper().parseText(additionalInformation as String) } }

The serialize methods are guaranteed to receive a non-null argument, although they may be provided an empty collection. The deserialize methods are expected to return a non-null value.

Finally, in resources.groovy, override the appropriate beans:

import test.JsonAdditionalInformationSerializer
import test.WhiteSpaceDelimitedStringScopeSerializer

beans = { // Other beans here

accessTokenAdditionalInformationSerializer(JsonAdditionalInformationSerializer) accessTokenScopeSerializer(WhiteSpaceDelimitedStringScopeSerializer) }