Grails With Spring Security
Learn how to use two most popular plugins for Spring Security and Grails.
Join the DZone community and get the full member experience.
Join For FreeSpring Security touts a number of authentication, authorization, instance-based, and various other features that make it so attractive to secure applications with.
With this in mind, due to Grails use of Spring’s Inversion of Control Framework and MVC setup, developers sought to use Spring Security to secure Grails.
This has resulted in two notable plugins: Spring Security Core Plugin and Spring Security ACL Plugin.
We will be reviewing the capabilities of these Spring Security plugins and making comparisons to using Spring Security for a plain old Spring application.
Spring Security Core Plugin
This plugin provides practical defaults with many configuration options for customization.
Domain Classes
The Spring Security Core Plugin uses the default Grails domain classes. In order to use the standard lookup for the plugin, we need at a minimum a Person and Authority domain class.
If we want to store URL <==> Role mappings in the database (which is one of several approaches for defining the mappings), we need a Requestmap
domain class. If we use the recommended approach for mapping the many-to-many relationship between Person
and Authority, we also need a domain class to map the join table.
To use the user/group lookup, we’ll also need a Group
domain class. If we are using the recommended approach for mapping many-to-many relationship between Person
and Group
, and between Group
and Authority
, we’ll need a domain class for each to map the join tables. We can still additionally use Requestmap
with this approach.
We can use the s2-quickstart to generate domain classes. The syntax is quite easy:
grails s2-quickstart DOMAIN_CLASS_PACKAGE USER_CLASS_NAME ROLE_CLASS_NAME [REQUESTMAP_CLASS_NAME] [--groupClassName=GROUP_CLASS_NAME]
An example with Person
, Authority
, and Requestmap
:
grails s2-quickstart com.ourapp Person Authority Requestmap
Configuring Request Mappings for Securing URLs
We can choose among the following approaches to configure request mappings for securing URLs:
- The
@Secured
annotation. This is considered the default approach. - A map in application.groovy. This is called a Static Map
Requestmap
domain class instances stored in the database
We can only use one method at a time.
For example, here is the use of the @Secured
annotation with Spring Expression Language (SpEL):
class SecureController {
@Secured("hasRole('ROLE_USER')")
def someRandomAction() {
...
}
Various Other Features
Some various features of the Spring Security Core Plugin include:
- Helper classes for dealing with lower levels of Spring Security, such as a
SecurityTagLib
that provides GSP tags to support conditional display based on whether the user is authenticated and/or has the required role to perform a particular action. - Events – including event notifications, event listeners, and callback closures.
- Filters, including the ability to define which filters are applied to different URL patterns.
Spring Security ACL Plugin
The Spring Security ACL Plugin adds Domain Object Security support to a Grails application that uses the aforementioned Spring Security Core Plugin. So, we need to have that other plugin already in our build.gradle.
What does it mean to add Domain Object Security support? The Spring Security Core plugin and other extension plugins support restricting access to URLs via rules that include checking a user’s authentication status, roles, etc. and the ACL plugin extends this by adding support for restricting access to individual domain class instances.
Method Security
The four annotations typically available in Spring Security are available for use with Spring Expression Language (SpEL) expressions to perform Expression-Based Access Control:
-
@PreAuthorize
-
@PreFilter
-
@PostAuthorize
-
@PostFilter
The above annotations are all documented in the Method Security Expressions portion of the Spring Security documentation.
The ability to use method security is a very significant difference between the Spring Security ACL Plugin and the Spring Security Core Plugin. If we are to implement fine-grained access control, the Spring Security ACL Plugin is a must have for this reason.
Thankfully, besides the syntax differences between Groovy and Java, the code really looks the same:
@PreAuthorize("hasRole('ROLE_USER')")
@PostFilter("hasPermission(filterObject, read) or " +
"hasPermission(filterObject, admin)")
List getAllDocs(params = [:]) {
Report.list(params)
}
Domain Classes
Like the Spring Security Core Plugin, the Spring Security ACL Plugin uses domain classes for appropriate structuring.
The domain classes, in this case, are used to manage database state. To be compatible with the typically JDBC-based Spring Security code, domain classes are created to generate the table and column names.
The classes in this plugin associated with persistence use these classes. However, they can be overridden by running the s2-create-acl-domains script:
grails s2-create-acl-domains
So, the script will generate the same domain classes in our application’s grails-app/domain
folder to allow some customization.
Various Other Features
Some various features of the Spring Security ACL Plugin include:
- Run-As-Authentication Replacement: this is a temporary authentication switch that only lasts for one method invocation.
- Custom permissions: There are five permissions available from the
BasePermission
class:READ
,WRITE
,CREATE
,DELETE
, andADMINISTRATION
. You can add your own permissions if you need. - Tag library (taglib) for permit and deny.
Conclusion
The Spring Security Core Plugin offers a number of very useful features for securing Grails with Spring Security, but in order to implement more sophisticated, fine-grained authorization, it is necessary to use the Spring Security ACL Plugin in conjunction.
Recommended reading: Authorizing Resources Based On Who Created Them (Spring Security) and my posts about the Spring Framework for general Spring knowledge.
Published at DZone with permission of Michael Good, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments