blob: e919769f2e7337c520f8fee8cc7a8951f5f87a6d [file]
[[securedAnnotations]]
=== Defining Secured Annotations
You can use an `@Secured` annotation (either the standard `org.springframework.security.access.annotation.Secured` or the plugin's `grails.plugin.springsecurity.annotation.Secured` which has the same attributes and features but also supports defining a closure as the config attribute to make authorization decisions) in your controllers to configure which roles are required for which actions. To use annotations, specify `securityConfigType="Annotation"`, or leave it unspecified because it's the default:
[source,groovy]
.Listing {counter:listing}. Specifying `securityConfigType` as "`Annotation`"
----
grails.plugin.springsecurity.securityConfigType = "Annotation"
----
You can define the annotation at the class level, meaning that the specified roles are required for all actions, or at the action level, or both. If the class and an action are annotated then the action annotation values will be used since they're more specific.
For example, given this controller:
[source,groovy]
.Listing {counter:listing}. An annotated controller
----
package com.mycompany.myapp
import grails.plugin.springsecurity.annotation.Secured
class SecureAnnotatedController {
@Secured('ROLE_ADMIN')
def index() {
render 'you have ROLE_ADMIN'
}
@Secured(['ROLE_ADMIN', 'ROLE_SUPERUSER'])
def adminEither() {
render 'you have ROLE_ADMIN or SUPERUSER'
}
def anybody() {
render 'anyone can see this' // assuming you're not using "strict" mode,
// otherwise the action is not viewable by anyone
}
}
----
you must be authenticated and have `ROLE_ADMIN` to see `/myapp/secureAnnotated` (or `/myapp/secureAnnotated/index`) and be authenticated and have `ROLE_ADMIN` or `ROLE_SUPERUSER` to see `/myapp/secureAnnotated/adminEither`. Any user can access `/myapp/secureAnnotated/anybody` if you have disabled "`strict`" mode (using `rejectIfNoRule`), and nobody can access the action by default since it has no access rule configured.
In addition, you can define a closure in the annotation which will be called during access checking. The closure must return `true` or `false` and has all of the methods and properties that are available when using SpEL expressions, since the closure's `delegate` is set to a subclass of `WebSecurityExpressionRoot`, and also the Spring `ApplicationContext` as the `ctx` property:
[source,groovy]
.Listing {counter:listing}. An example of using a Closure in with `@Secured`
----
@Secured(closure = {
assert request
assert ctx
authentication.name == 'admin1'
})
def someMethod() {
...
}
----
Often most actions in a controller require similar access rules, so you can also define annotations at the class level:
[source,groovy]
----
package com.mycompany.myapp
import grails.plugin.springsecurity.annotation.Secured
@Secured('ROLE_ADMIN')
class SecureClassAnnotatedController {
def index() {
render 'index: you have ROLE_ADMIN'
}
def otherAction() {
render 'otherAction: you have ROLE_ADMIN'
}
@Secured('ROLE_SUPERUSER')
def super() {
render 'super: you have ROLE_SUPERUSER'
}
}
----
Here you need to be authenticated and have `ROLE_ADMIN` to see `/myapp/secureClassAnnotated` (or `/myapp/secureClassAnnotated/index`) or `/myapp/secureClassAnnotated/otherAction`. However, you must have `ROLE_SUPERUSER` to access `/myapp/secureClassAnnotated/super`. The action-scope annotation overrides the class-scope annotation. Note that "`strict`" mode isn't applicable here since all actions have an access rule defined (either explicitly or inherited from the class-level annotation).
Additionally, you can specify the HTTP method that is required in each annotation for the access rule, e.g.
[source,groovy]
----
package com.mycompany.myapp
import grails.plugin.springsecurity.annotation.Secured
class SecureAnnotatedController {
@Secured(value = ['ROLE_ADMIN'], httpMethod = 'GET')
def create() {
...
}
@Secured(value = ['ROLE_ADMIN'], httpMethod = 'POST')
def save() {
...
}
}
----
Here you must have ROLE_ADMIN for both the `create` and `save` actions but `create` requires a GET request (since it renders the form to create a new instance) and `save` requires POST (since it's the action that the form posts to).
==== Securing RESTful domain classes
Since Grails 2.3, domain classes can be annotated with the `grails.rest.Resource` AST transformation, which will generate internally a controller with the default CRUD operations.
You can also use the `@Secured` annotation on such domain classes:
[source,groovy]
----
@Resource
@Secured('ROLE_ADMIN')
class Thing {
String name
}
----
==== controllerAnnotations.staticRules
You can also define "`static`" mappings that cannot be expressed in the controllers, such as '/pass:[**]' or for JavaScript, CSS, or image URLs. Use the `controllerAnnotations.staticRules` property, for example:
[source,groovy]
----
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
...
[pattern: '/js/admin/**', access: ['ROLE_ADMIN']],
[pattern: '/someplugin/**', access: ['ROLE_ADMIN']]
]
----
This example maps all URLs associated with `SomePluginController`, which has URLs of the form `/somePlugin/...`, to `ROLE_ADMIN`; annotations are not an option here because you would not edit plugin code for a change like this.
[NOTE]
====
When mapping URLs for controllers that are mapped in `UrlMappings.groovy`, you need to secure the un-url-mapped URLs. For example if you have a FooBarController that you map to `/foo/bar/$action`, you must register that in `controllerAnnotations.staticRules` as `/foobar/pass:[**]`. This is different than the mapping you would use for the other two approaches and is necessary because `controllerAnnotations.staticRules` entries are treated as if they were annotations on the corresponding controller.
====