Securing your Grails application:
A survey/layout of the security plugin space
Colin Harrington
G3 Summit US 2016
whoami > Colin Harrington
- Grails team at OCI
- @ColinHarrington
- harringtonc@ociweb.com
Title Text
Grails is a powerful web framework, for the Java platform aimed at multiplying developers’ productivity thanks to a Convention-over-Configuration, sensible defaults and opinionated APIs. It integrates smoothly with the JVM, allowing you to be immediately productive whilst providing powerful features, including integrated ORM, Domain-Specific Languages, runtime and compile-time meta-programming and Asynchronous programming.
Spring Security
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
History
- Acegi
- Spring-security-core
- Grails 3
Burt Beckwith
Spring Security Core
The Spring Security plugin simplifies the integration of Spring Security into Grails applications. The plugin provides sensible defaults with many configuration options for customization. Nearly everything is configurable or replaceable in the plugin and in Spring Security itself, which makes extensive use of interfaces.
grails-spring-security-core
- https://bintray.com/grails/plugins/spring-security-core
- https://github.com/grails-plugins/grails-spring-security-core
- https://grails-plugins.github.io/grails-spring-security-core/
Grails Artefacts
- SpringSecurityService
- SecurityTagLib
- LoginController & LogoutController
Highly Configurable
Sensible defaults
@Secured annotation
@Secured(value=["hasRole('ROLE_ADMIN')"], httpMethod='POST')
def someMethod() { ... }
WebSecurityExpressionRoot delegate...
@Secured(closure = {
assert request
assert ctx
authentication.name == 'admin1'
})
def someMethod() { ... }
Authentication Mechanisms
- Basic & Digest
- Cert - X.509
- Remember-me cookies
- Username/Password
FilterChain
grails.plugin.springsecurity.filterChain.filterNames = [
'securityContextPersistenceFilter', 'logoutFilter',
'authenticationProcessingFilter', 'myCustomProcessingFilter',
'rememberMeAuthenticationFilter', 'anonymousAuthenticationFilter',
'exceptionTranslationFilter', 'filterInvocationInterceptor'
]
chainMap
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/urlpattern1/**', filters: 'filter1,filter2,filter3,filter4'],
[pattern: '/urlpattern2/**', filters: 'filter1,filter3,filter5'],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
grails-spring-security-core
Plugins
- grails-security-bridge
- grails-spring-security-acl
- grails-spring-security-appinfo
- grails-spring-security-cas
- grails-spring-security-core
- grails-spring-security-facebook
- grails-spring-security-jaxrs
- grails-spring-security-kerberos
- grails-spring-security-ldap
- grails-spring-security-oauth2
- grails-spring-security-oauth2-facebook
- grails-spring-security-oauth2-google
- grails-spring-security-oauth2-provider
- grails-spring-security-rest
- grails-spring-security-shiro
- grails-spring-security-ui
Authentication Providers
- LDAP
- CAS
- Kerberos
Tools
- appinfo
- ui
Enhancement
- acl
- jaxrs
- enforcer
Token/Stateless
- rest
Adapter
- shiro
- security-bridge
oauth2
- oauth2-provider
- oath2
- oauth2-facebook
- oauth2-google
UserDetails
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
UserDetailsService
public interface UserDetailsService {
UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException;
}
AuthenticationProvider
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
boolean supports(Class<?> authentication);
}
AuthenticationProvider
- DaoAuthenticationProvider
- GrailsAnonymousAuthenticationProvider
- RunAsImplAuthenticationProvider
- KerberosServiceAuthenticationProvider
- CasAuthenticationProvider
- FacebookAuthProvider
- ...
Authentication
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated)
throws IllegalArgumentException;
}
Authentication Filter
public abstract class AbstractAuthenticationProcessingFilter
extends GenericFilterBean
implements ApplicationEventPublisherAware,
MessageSourceAware {
...
}
AuthenticationManager
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
Spring Security Rest
Restful Auth
Token Based
Stateful/Stateless
JWT
RFC6750
Stateful
- memcached
- GORM
- Redis
- Grails Cache
Stateless
JWT Signatures
Encryption
Authentication Provider
- Internal Auth
- Delegation
- CAS
spring-security-facebook
- https://github.com/splix/grails-spring-security-facebook
- http://splix.github.io/grails-spring-security-facebook/
Grails plugin for Facebook Authentication, extension to Grails Spring Security Core plugin
Approaches
- Server-Side authentication (FacebookAuthRedirectFilter)
- Transparent cookie based authorization (FacebookAuthCookieTransparentFilter)
- Manual cookie based authentication (FacebookAuthCookieDirectFilter)
- JSON or Android/iOS/desktop authorization (FacebookAuthJsonFilter)
ACL
- http://grails-plugins.github.io/grails-spring-security-acl/
- https://github.com/grails-plugins/grails-spring-security-acl
Access Control List
The ACL plugin adds Domain Object Security support to a Grails application that uses Spring Security. It depends on the Spring Security Core plugin.
The 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. The access can be very fine-grained and can define which actions can be taken on an object - these typically include Read, Create, Write, Delete, and Administer but you’re free to define whatever actions you like.
ACLs
- GORM
- Customizable
- Services
- Taglib
@PreAuthorize
@PreFilter
@PostAuthorize
@PostFilter
class ReportService {
@PreAuthorize("hasPermission(#id, 'com.yourapp.Report', read) or " +
"hasPermission(#id, 'com.yourapp.Report', admin)")
Report getReport(long id) {
Report.get(id)
}
@PreAuthorize("hasRole('ROLE_USER')")
@PostFilter("hasPermission(filterObject, read) or " +
"hasPermission(filterObject, admin)")
List getAllReports(params = [:]) {
Report.list(params)
}
@PreAuthorize("hasPermission(#report, write) or " +
"hasPermission(#report, admin)")
Report updateReport(Report report, params) {
report.properties = params
report.save()
report
}
@PreAuthorize("hasPermission(#report, delete) or " +
"hasPermission(#report, admin)")
void deleteReport(Report report) {
report.delete()
}
}
class AclUtilService {
void addPermission(Class<?> domainClass, Serializable id,
recipient, Permission permission) { ... }
void addPermission(domainObject, recipient, Permission permission) { ... }
void addPermission(ObjectIdentity oid, recipient,
Permission permission) { ... }
void changeOwner(domainObject, String newUsername) { ... }
void deletePermission(domainObject, recipient, Permission permission) { ... }
void deletePermission(Class<?> domainClass, long id,
recipient, Permission permission) { ... }
boolean hasPermission(Authentication authentication,
domainObject, Permission... permissions) { ... }
boolean hasPermission(Authentication authentication,
domainObject, List<Permission> permissions) { ... }
Acl readAcl(domainObject) { ... }
Acl readAcl(Class<?> domainClass, id) { ... }
void deleteAcl(domainObject) { ... }
protected Sid createSid(recipient) { ... }
}
Enforcer
- https://virtualdogbert.github.io/Enforcer/
- https://github.com/virtualdogbert/Enforcer
Enforcer
The Enforcer Plugin, gives you the tools to enforce business rules, and or permissions. Enforcer is light weight, easy to maintain, extend and, use. The plugin works off of a EnforcerService in conjunction with the Enforce, Reinforce, and ReinforceFilter Annotations(AST transforms).
def enforcerService
enforcerService.enforce({ hasRole('ROLE_USER', testUser) })
enforcerService.enforce({ hasDomainRole('owner', sprocket, testUser) })
@Enforce({hasRole('ROLE_USER', testUser)
&& hasDomainRole('owner', sprocket, testUser)})
def someMethod(){
//some logic
}
@Reinforce({hasRole('ROLE_USER', testUser)
&& hasDomainRole('owner', sprocket, testUser)})
def someMethod(){
//some logic
}
@ReinforceFilter({ Object o ->
(o as List).findResults { it % 2 == 0 ? it : null } })
List<Integer> reinforceFilter() {
[1, 2, 3, 4, 5, 6, 7, 8, 9]
}
Spring Security Shiro
Spring Security Shiro
The Spring Security Shiro plugin adds some support for using a hybrid approach combining Spring Security and Shiro. It currently only supports Shiro ACLs, since Spring Security ACLs are very powerful but can be very cumbersome to use, and the Shiro approach is straightforward and simple.
The majority of the authentication and authorization work is still done by Spring Security. This plugin listens for Spring Security authentication events and uses the Spring Security Authentication instance to build and register a ShiroSubject instance. It also removes the Shiro credentials when you explicitly logout.
grails.plugin.springsecurity.shiro.permissionDomainClassName =
'com.mycompany.myapp.Permission'
class Permission {
User user
String permission
static constraints = {
permission unique: 'user'
}
}
import com.mycompany.myapp.MyShiroPermissionResolver
beans = {
shiroPermissionResolver(MyShiroPermissionResolver)
}
Permissions
import org.apache.shiro.SecurityUtils
import org.apache.shiro.subject.Subject
...
Subject subject = SecurityUtils.getSubject()
subject.checkPermission('printer:print:lp7200')
subject.isPermitted('printer:print:lp7200')
subject.checkRole('ROLE_ADMIN')
subject.hasRole('ROLE_ADMIN')
subject.isAuthenticated()
... etc
grails-security-bridge
Grails Security Bridge
- https://bintray.com/bertramlabs/grails3-plugins/security-bridge
- https://github.com/bertramdev/grails-security-bridge
The Grails Security Bridge plugin is used for providing a decoupled, cross-plugin security interface. This allows you to keep the majority of authentication logic in one plugin, while other plugins can reference a public API interface to retrieve the information needed.
grails-security-bridge
@Secure Annotation
...
interface SecurityBridge {
def getCurrentUser()
def getUserIdentity()
def getCurrentAccount()
def getAccountIdentity()
def getCurrentUserDisplayName()
boolean isLoggedIn()
boolean isAuthorized(object, action)
boolean hasRole(role)
boolean hasPermission(permission, opts)
boolean hasPermission(permission)
def storeLocation(request)
def withUser(identity, Closure code)
Map createLink(String action)
}
Oauth2
(set of plugins)
spring-security-oauth2
- authenticate via oauth2
- multiple providers
- spring-security-oauth2-google
- spring-security-oauth2-facebook
application.yml
grails:
plugin:
springsecurity:
oauth2:
active: true
registration:
askToLinkOrCreateAccountUri: '/oauth2/ask'
roleNames: ['ROLE_USER']
-
askToLinkOrCreateAccountUri: The URI that is called to aks the user to either create a new account or link to an existing account
- roleNames: A list of role names that should be automatically granted to an OAuth User. The roles will be created if they do not exist
class MyGrailsUser {
...
static hasMany = [oAuthIDs: OAuthID]
}
Add the oAuthIDs to your user object
oauth2-provider
The OAuth2 plugin adds OAuth 2.0 support to a Grails application that uses Spring Security.
It depends on Spring Security Core plugin.
Authentication Providers
- LDAP
- CAS
- Kerberos
Tools
- appinfo
- ui
Enhancement
- acl
- jaxrs
- enforcer
Token/Stateless
- rest
Adapter
- shiro
- security-bridge
oauth2
- oauth2-provider
- oath2
- oauth2-facebook
- oauth2-google
Resources
-
grails.org
-
User Guide
(RTFM: Read The Fantastic Manual) -
Stack Overflow
-
Slack
-
Github!
-
twitter
Connect with Us
grails.org
groovy-community.grails.org
grailsblog.objectcomputing.com
objectcomputing.com/grails
@grailsframework
@objectcomputing
Thank you for attending!
Please visit our table for giveaways
and to meet the team!
ociweb.com/grails
info@ociweb.com
Securing your Grails application: A survey/layout of the security plugin space
By Colin Harrington
Securing your Grails application: A survey/layout of the security plugin space
Presentation at G3 Summit US 2016 https://g3summit.com/conference/fort_lauderdale/2016/11/session?id=36855 Securing your application with Spring Security has been the defacto standard in Grails. There is a suite of plugins at your disposal that give us a great start when securing our applications. We’ll cover the suite of spring-security related plugins, how they plug into Spring Security and how they interact with each other. We’ll dive into the underpinnings of AuthenticationProviders, Stateless authentication, ACLs and more.
- 2,710