blob: e089085d9bf9a8001b46348e54ea9dc7f367e079 [file]
////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
////
The token validation filter looks for the token in the request and then tries to validate it using the configured
token storage implementation.
If the validation is successful, the principal object is stored in the security context. This allows you to use in
your application `@Secured`, `springSecurityService.principal` and so on.
[NOTE]
====
`springSecurityService.currentUser` expects a `grails.plugin.springsecurity.userdetails.GrailsUser` to perform a DB query.
However, this plugins stores in the security context just a principal `Object`, because it does not assume you are using
domain classes to store the users. Use `springSecurityService.principal` instead.
====
This plugin supports http://tools.ietf.org/html/rfc6750[RFC 6750 Bearer Token] specification out-of-the-box.
=== Sending tokens in the request
The token can be sent in the `Authorization` request header:
[source]
.Listing {counter:listing}. Accessing a protected resource using `Authorization` request header
----
GET /protectedResource HTTP/1.1
Host: server.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0MjI5OTU5MjIsInN1YiI6ImppbWkiLCJyb2xlcyI6WyJST0xFX0FETUlOIiwiUk9MRV9VU0VSIl0sImlhdCI6MTQyMjk5MjMyMn0.rA7A2Gwt14LaYMpxNRtrCdO24RGrfHtZXY9fIjV8x8o
----
Or using form-encoded body parameters:
[source]
.Listing {counter:listing}. Accessing a protected resource using body parameters
----
POST /protectedResource HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
access_token=eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0MjI5OTU5MjIsInN1YiI6ImppbWkiLCJyb2xlcyI6WyJST0xFX0FETUlOIiwiUk9MRV9VU0VSIl0sImlhdCI6MTQyMjk5MjMyMn0.rA7A2Gwt14LaYMpxNRtrCdO24RGrfHtZXY9fIjV8x8o
----
If you need to use the `GET` HTTP method (to render images in an `img` tag, for example), you can also send the access token
in a query string parameter named `access_token`:
If you disable the bearer token support, you can customise it further:
[source,groovy]
----
grails.plugin.springsecurity.rest.token.validation.useBearerToken = false
grails.plugin.springsecurity.rest.token.validation.headerName = 'X-Auth-Token'
----
If you still want to have full access and read the token from a different part of the request, you can implement a
include::{baseGroovyApiUrl}grails/plugin/springsecurity/rest/token/reader/TokenReader.html[TokenReader]
and register it in your `resources.groovy` as `tokenReader`.
[NOTE]
====
You must disable bearer token support to register your own `tokenReader` implementation.
====
=== Anonymous access
If you want to enable anonymous access to URL's where this plugin's filters are applied, you need to:
. Configure `enableAnonymousAccess = true` (see table below).
. Make sure that the `anonymousAuthenticationFilter` is applied before `restTokenValidationFilter`. See how to configure filters for more details.
For example, with this configuration:
[source,groovy]
.Sample configuration to allow anonymous access
----
grails {
plugin {
springsecurity {
filterChain {
chainMap = [
[pattern: '/api/guest/**', filters: 'anonymousAuthenticationFilter,restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor'],
[pattern: '/api/**', filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'],
[pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter']
]
}
//Other Spring Security settings
//...
rest {
token {
validation {
enableAnonymousAccess = true
}
}
}
}
}
}
----
The following chains are configured:
. `/api/guest/**` is a stateless chain that allows anonymous access when no token is sent. If however a token is on the request, it will be validated.
. `/api/**` is a stateless chain that doesn't allow anonymous access. Thus, the token will always be required, and if missing, a Bad Request reponse will be sent back to the client.
. `/**` (read: everything else) is a traditional stateful chain.
=== Validation Endpoint
There is also an endpoint available that you can call in case you want to know if a given token is valid. It looks for
the token in a HTTP header as well, and if the token is still valid, it renders guide:authentication[its JSON representation].
If the token does not exist, it will render a `grails.plugin.springsecurity.rest.login.failureStatusCode` response
(`401` by default).
The relevant configuration properties for the validation endpoint are:
.Validation endpoint configuration options
[cols="80,20"]
|===
|*Config key* |*Default value*
|`grails.plugin.springsecurity.rest.token.validation.active`
|`true`
|`grails.plugin.springsecurity.rest.token.validation.headerName`
|`X-Auth-Token`
|`grails.plugin.springsecurity.rest.token.validation.endpointUrl`
|`/api/validate`
|===
Note that `headerName` is only considered if `grails.plugin.springsecurity.rest.token.validation.useBearerToken` is set
to `false`. Otherwise (the default approach), as per RFC 6750, the header name will be `Authorization` and the value
will be `Bearer TOKEN_VALUE`.