Archive for the Category 'security'

Hacking Delhi

Tuesday, January 19th, 2016

I did a talk at GR8Conf India on Saturday called “Fun With Spring Security” where I presented a few sample applications demonstrating various non-standard techniques for authentication, restricting access to URLs, etc. The test applications are available at GitHub and each has a README.adoc but I wanted to summarize the applications in a combined blog post.

All of the apps use Grails 3 and spring-security-core 3.x but would be easily converted to Grails 2 and version 2.x of the plugin since nothing depends on the newer versions.

Some items that are common to all or most of the apps:

  • when you start the app the index.gsp page has some links to test the various actions
  • debug/trace logging for the plugin and Spring Security is configured but commented out in logback.groovy
  • most of the applications are intentionally stripped-down:
    • no static resources
    • the GSPs are very minimal
    • unused attributes were removed from the grails.plugin.springsecurity block in application.groovy

autorole


The first example is the “autorole” application. It demonstrates how to infer one or more roles from persisted user information without explicitly storing roles in the traditional many-to-many format. In this example there isn’t even a Role or UserRole domain class, only the User class; all of the work is done in autorole.AutoRoleUserDetailsService, the custom UserDetailsService implementation.

A more realistic implementation would probably use a hybrid approach, storing some role information in the database and inferring the rest, with the UserDetailsService merging the “real” and “virtual” roles as needed.

Items of note:

  • test.User is the user domain class generated by the s2-quickstart script with one modification, adding a boolean admin property
  • the Role and UserRole classes generated by the s2-quickstart script were deleted since they’re not used
  • two users are created in BootStrap.groovy; user “admin” (password “password”) has the admin boolean set to true and will be auto-granted ROLE_ADMIN, and user “user” (password “password”) has the default value for admin (false) which will result in a grant of ROLE_USER
  • autorole.AutoRoleUserDetailsService is registered in grails-app/conf/spring/resources.groovy as the userDetailsService bean
  • secured.SecureController has two annotated actions; /secure requires ROLE_USER (or ROLE_ADMIN since hierarchical roles are configured) and /secure/admin requires ROLE_ADMIN

noroles


The next example is the “noroles” application. It shows how to use expressions to guard access when access rules are simple and roles aren’t required. In this example there isn’t even a Role or UserRole domain class, only the User class.

Items of note:

  • test.User is the user domain class generated by the s2-quickstart script with a few modifications:
    • a final authorities = [] property so GormUserDetailsService works correctly, but doesn’t grant any roles since there aren’t any (for demo purposes here, since there is a custom UserDetailsService)
    • a UserType userType property
    • a String businessUnit property
    • a boolean developer property
  • the Role and UserRole classes generated by the s2-quickstart script were deleted since they’re not used
  • four users are created in BootStrap.groovy, all with password “password”:
    • admin1 has UserType admin, businessUnit: ‘group1’
    • admin2 has UserType admin, businessUnit: ‘group2’
    • salesdude has UserType sales, businessUnit: ‘group1’
    • codemonkey has UserType other, businessUnit: ‘it’, developer true
  • secured.SecureController has several annotated actions using expressions to guard access
  • a custom UserDetailsService creates an extended UserDetails instance to cache nonstandard user properties for use in expressions

hacking_newdelhi


This is an update of the demo app from Greach 2015 (“hacking_madrid”) which was an update of the demo app from GGX 2011 (“hacking_london”). I updated it to Grails 3 and spring-security-core 3.0.3.

It adds an “organization” drop-down to the login page in addition to username and password, and a customized Authentication class, servlet filter, and AuthenticationProvider.

Items of note:

  • grails-app/views/login/auth.gsp is the same as auth.gsp from the core plugin, with the addition of a to select the user’s Organization during login
  • hacking.extralogin.OrganizationAuthentication extends UsernamePasswordAuthenticationToken to add a String organizationName property
  • hacking.extralogin.ui.OrganizationFilter extends the core plugin’s GrailsUsernamePasswordAuthenticationFilter and is registered as the authenticationProcessingFilter bean to process form logins; it creates OrganizationAuthentication instances from POST parameters for authentication
  • hacking.extralogin.auth.OrganizationAuthenticationProvider uses the data in OrganizationAuthentication to authenticate
    • It’s based on DaoAuthenticationProvider but directly accesses the database using GORM instead of delegating to a UserDetailsService
  • two new domain classes, Organization and OrgUser are used to persist the user/organization relationship
    • OrgUser is the many-to-many join class which uses two 1-to-many relationships instead of the traditional GORM static hasMany mapped collections
  • BootStrap.groovy creates test data:
    • two Organization instances, “Org1” and “Org2”
    • a user with ROLE_ADMIN (“admin”/”password”) in “Org1”
    • a user with ROLE_USER (“user”/”password”) in “Org2”
    • a user with ROLE_USER and enabled set to false (“disabled”/”password”) in “Org1”
  • rather than copying and pasting the entire bean definitions into resources.groovy to override the bean class for the authenticationProcessingFilter and daoAuthenticationProvider beans, hacking.HackingBeanFactoryPostProcessor is registered in resources.groovy and updates the bean class in the bean definition. This approach retains all of the dependency injections and configuration updates and helps prevent the app from breaking if updated to a newer version of the plugin that has different dependencies and/or config options for the beans
  • NoStackBadCredentialsException is thrown as needed instead of BadCredentialsException; it’s similar to the core plugin’s NoStackUsernameNotFoundException which avoids filling in the stack trace to reduce creation cost
  • secured.SecureController has two annotated actions; /secure requires ROLE_USER (or ROLE_ADMIN since hierarchical roles are configured) and /secure/admin requires ROLE_ADMIN

lockout


This application shows how to use events to lock a user account after a fixed number of failed login attempts.

Items of note:

  • lockout.FailureEventListener is registered to listen for AuthenticationFailureBadCredentialsEvent
  • lockout.SuccessEventListener is registered to listen for AuthenticationSuccessEvent
  • the User domain class has int badCredentialsCount to track failed logins
  • UserService increments badCredentialsCount for failures and resets to 0 on success
  • secured.SecureController has two annotated actions; /secure requires ROLE_USER (or ROLE_ADMIN since hierarchical roles are configured) and /secure/admin requires ROLE_ADMIN

x509


This application showing how to use X.509 browser certificates to authenticate.

Items of note:

  • X.509 is enabled by adding useX509 = true in application.groovy
  • two users (“dianne” and “scott”) are created in BootStrap.groovy, both with password “not_used” since it’s unused with certificate authentication
  • add the dianne.p12 and/or scott.p12 certificate to your browser to authenticate as that person
  • you must use SSL with X.509 authentication; I tested by building a WAR file and deploying it to Tomcat 8, and configuring run-app similarly is left as an exercise for the reader
    • To test, run `grails war` and copy build/libs/x509-0.1.war to the Tomcat webapps folder, renaming the war to ROOT.war so it uses the default context
    • be sure to access the application with SSL URLs, e.g. https://localhost:8443/secure/index
  • configure server.jks as the keystore and truststore; server.xml is an example Tomcat 8 config file that does this, expecting that server.jks is in the conf directory
  • secured.SecureController has two annotated actions; /secure requires ROLE_USER (or ROLE_ADMIN since hierarchical roles are configured) and /secure/admin requires ROLE_ADMIN

x509chained


This last application shows how to use X.509 browser certificates and a second authentication provider to authenticate.

Note that this has been only lightly tested and should be used with caution. I have no idea if there are gaps in the implementation. Test anything based on this approach and/or code extensively before using in a real application. If you find problems with the approach or code let me know so I can update the code.

Items of note:

  • X.509 is enabled by adding useX509 = true in application.groovy
  • two users (“dianne” and “scott”) are created in BootStrap.groovy, both with password “password” since the password is needed for the second form-auth phase
  • add the dianne.p12 and/or scott.p12 certificate to your browser to authenticate as that person
  • you must use SSL with X.509 authentication; I tested by building a WAR file and deploying it to Tomcat 8, and configuring run-app similarly is left as an exercise for the reader
    • To test, run `grails war` and copy build/libs/x509chained-0.1.war to the Tomcat webapps folder, renaming the war to ROOT.war so it uses the default context
    • be sure to access the application with SSL URLs, e.g. https://localhost:8443/secure/index
  • configure server.jks as the keystore and truststore; server.xml is an example Tomcat 8 config file that does this, expecting that server.jks is in the conf directory
  • x509chained.LoginController extends the plugin’s LoginController to not redirect to successHandler.defaultTargetUrl if authenticated. This is needed because the chained authentication happens in two requests with a redirect. If the first phase (X.509) succeeds, there will be an active authentication, but it’s incomplete and cannot be used yet. Filter chain processing must be allowed to happen to allow the second authentication phase to run.
  • x509chained.ChainedX509AuthenticationFilter extends the standard X509AuthenticationFilter to replace the Authentication in successfulAuthentication with one with all of the real roles replaced with ROLE_CHAINED_X509 as a marker to indicate that the first authentication phase succeeded. The second authentication phase will create a standard Authentication with the real roles.
  • x509chained.ChainedAuthenticationProcessingFilter extends the plugin’s form authentication filter (GrailsUsernamePasswordAuthenticationFilter). It detects that the X.509 phase has occurred and redirects to the login page, replacing the credentials (since they’re unused by X.509) with a marker string so downstream processing is aware of the current state in the workflow.
  • secured.SecureController has two annotated actions; /secure requires ROLE_USER (or ROLE_ADMIN since hierarchical roles are configured) and /secure/admin requires ROLE_ADMIN

One more approach for diagnosing spring-security-core login errors

Thursday, January 30th, 2014

I wrote up a few techniques to help determine what is happening when you are unable to authenticate with use the Grails spring-security-core plugin here and since then I’ve had to use them myself a couple of times. I have everything configured to easily debug the issues and often that ends up being the best approach, but not everyone is comfortable with a debugger, or not excited about the prospect of configuring their IDE with JAR sources and the other steps needed to properly debug. This and this Stack Overflow question prompted me to document another approach.

This one is a rather dangerous and should be removed as soon as the issue is resolved because it prints cleartext passwords to the console, which is a huge security risk.

There are a handful of places where the cleartext password is available, but I think the most convenient is in the additionalAuthenticationChecks method of DaoAuthenticationProvider. The arguments to the method are the UserDetails instance, which will have the hashed password from the database, and the UsernamePasswordAuthenticationToken which will have the cleartext password.

To access this, create a subclass of DaoAuthenticationProvider:

package deletethisasap

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken as UPAT
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.userdetails.UserDetails

class MyDaoAuthenticationProvider extends DaoAuthenticationProvider {

  protected void additionalAuthenticationChecks(UserDetails ud, UPAT auth) throws AuthenticationException {
    String hashedPassword = passwordEncoder.encodePassword(
         auth.credentials, null)
    boolean ok = passwordEncoder.isPasswordValid(
         ud.password, auth.credentials, null)
    println "Cleartext: '$auth.credentials' from DB: '$ud.password' hashed '$hashedPassword' Valid: $ok"
    super.additionalAuthenticationChecks ud, auth
  }
}

and register it with the same bean name in grails-app/conf/spring/resources.groovy:

import deletethisasap.MyDaoAuthenticationProvider

beans = {
  daoAuthenticationProvider(MyDaoAuthenticationProvider) {
    userDetailsService = ref('userDetailsService')
    passwordEncoder = ref('passwordEncoder')
    userCache = ref('userCache')
    saltSource = ref('saltSource')
    preAuthenticationChecks = ref('preAuthenticationChecks')
    postAuthenticationChecks = ref('postAuthenticationChecks')
    authoritiesMapper = ref('authoritiesMapper')
    hideUserNotFoundExceptions = true
  }
}

It prints the hashed password and the cleartext password, and the cleartext password hashed for comparison. This won’t necessarily be the same as the value from the database, for example when using bcrypt, but the encoder has an isPasswordValid method to verify that they’re equivalent, so that is also printed.

This code assumes that you’re using standard form-based authentication (i.e. DaoAuthenticationProvider) and that you’re not using a salt. If you are using salted passwords, dependency-inject the saltSource bean and use it in the encodePassword and isPasswordValid methods.

Automatically converting password hashes in Grails spring-security-core

Friday, December 20th, 2013

I was looking at this Stack Overflow question about converting password hashes and realized that it’s possible and rather convenient when using the spring-security-core plugin to automate the process.

To start, we’ll need a PasswordEncoder that can work with both algorithms. Here I’m assuming that you’ll be converting from SHA-256 (optionally with a salt) to bcrypt, but the general approach is mostly independent of the algorithms. Sha256ToBCryptPasswordEncoder will always hash new passwords using bcrypt, but can detect the difference between hashes from SHA-256 and bcrypt in isPasswordValid:

package com.burtbeckwith.grails.security;

import grails.plugin.springsecurity.authentication.encoding.BCryptPasswordEncoder;

import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder;

public class Sha256ToBCryptPasswordEncoder
       implements org.springframework.security.authentication.encoding.PasswordEncoder {

   protected MessageDigestPasswordEncoder sha256PasswordEncoder;
   protected BCryptPasswordEncoder bcryptPasswordEncoder;

   public String encodePassword(String rawPass, Object salt) {
      return bcryptPasswordEncoder.encodePassword(rawPass, null);
   }

   public boolean isPasswordValid(String encPass,
            String rawPass, Object salt) {
      if (encPass.startsWith("$2a$10$") && encPass.length() == 60) {
         // already bcrypt
         return bcryptPasswordEncoder.isPasswordValid(
                    encPass, rawPass, null);
      }

      if (encPass.length() == 64) {
         return sha256PasswordEncoder.isPasswordValid(
                    encPass, rawPass, salt);
      }

      // TODO
      return false;
   }

   /**
    * Dependency injection for the bcrypt password encoder
    * @param encoder the encoder
    */
   public void setBcryptPasswordEncoder(BCryptPasswordEncoder encoder) {
      bcryptPasswordEncoder = encoder;
   }

   /**
    * Dependency injection for the SHA-256 password encoder
    * @param encoder the encoder
    */
   public void setSha256PasswordEncoder(
           MessageDigestPasswordEncoder encoder) {
      sha256PasswordEncoder = encoder;
   }
}

This needs dependency injections for properly configured SHA-256 and bcrypt encoders, and we’ll see that in a bit.

Sha256ToBCryptPasswordEncoder cannot make any changes as only password information is available, so we’ll subclass DaoAuthenticationProvider and do this work in additionalAuthenticationChecks:

package com.burtbeckwith.grails.security

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.userdetails.GrailsUser

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.userdetails.UserDetails

class PasswordFixingDaoAuthenticationProvider
extends DaoAuthenticationProvider {

   def grailsApplication

   protected void additionalAuthenticationChecks(
         UserDetails userDetails,
         UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
      super.additionalAuthenticationChecks userDetails, authentication

      // if we got this far the password was ok

      String oldHashedPassword = userDetails.getPassword()
      if (oldHashedPassword.startsWith('$2a$10$') &&
            oldHashedPassword.length() == 60) {
         // already bcrypt
         return
      }

      if (oldHashedPassword.length() != 64) {
         // TODO
         return
      }

      String bcryptPassword = getPasswordEncoder().encodePassword(
               authentication.credentials, null) 

      // use HQL to update the password in the database directly

      def conf = SpringSecurityUtils.securityConfig
      String userClassName = conf.userLookup.userDomainClassName
      Class<?> User = grailsApplication.getDomainClass(userClassName).clazz

      def args = [p: bcryptPassword]
      String hql = 'update ' + User.name + ' u set u.password=:p where '
      if (userDetails instanceof GrailsUser) {
         hql += 'u.id=:id'
         args.id = userDetails.id
      }
      else {
         hql += 'u.' + conf.userLookup.usernamePropertyName + '=:un'
         args.un = userDetails.username
      }

      User.withNewSession {
         User.withTransaction {
            User.executeUpdate hql, args
         }
      }
   }
}

Calling super.additionalAuthenticationChecks() will ensure that a password was provided and it will be verified using either SHA-256 or bcrypt by Sha256ToBCryptPasswordEncoder, so if there is no exception thrown it’s safe to update the password. Note that the update code is generic and can be made more compact by hard-coding your class and property names.

We register Sha256ToBCryptPasswordEncoder as the passwordEncoder bean, and create bcryptPasswordEncoder and sha256PasswordEncoder beans, configured with the SHA-256 settings that were being used, and the bcrypt settings that will be used (configure those in Config.groovy as described in the docs). Also configure the bean override of daoAuthenticationProvider to be a PasswordFixingDaoAuthenticationProvider with the same configuration as is done in SpringSecurityCoreGrailsPlugin.groovy with the addition of the grailsApplication reference:

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.authentication.encoding.BCryptPasswordEncoder

import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder

import com.burtbeckwith.grails.security.PasswordFixingDaoAuthenticationProvider
import com.burtbeckwith.grails.security.Sha256ToBCryptPasswordEncoder

beans = {

   def conf = SpringSecurityUtils.securityConfig

   bcryptPasswordEncoder(BCryptPasswordEncoder, conf.password.bcrypt.logrounds) // 10

   sha256PasswordEncoder(MessageDigestPasswordEncoder, conf.password.algorithm) {
      encodeHashAsBase64 = conf.password.encodeHashAsBase64 // false
      iterations = conf.password.hash.iterations // 10000
   }

   passwordEncoder(Sha256ToBCryptPasswordEncoder) {
      bcryptPasswordEncoder = ref('bcryptPasswordEncoder')
      sha256PasswordEncoder = ref('sha256PasswordEncoder')
   }

   daoAuthenticationProvider(PasswordFixingDaoAuthenticationProvider) {
      userDetailsService = ref('userDetailsService')
      passwordEncoder = ref('passwordEncoder')
      userCache = ref('userCache')
      saltSource = ref('saltSource')
      preAuthenticationChecks = ref('preAuthenticationChecks')
      postAuthenticationChecks = ref('postAuthenticationChecks')
      authoritiesMapper = ref('authoritiesMapper')
      hideUserNotFoundExceptions = conf.dao.hideUserNotFoundExceptions // true
      grailsApplication = ref('grailsApplication')
   }
}

With this configuration, new users’ passwords will be hashed with bcrypt, and valid existing users’ passwords will be converted to bcrypt using the plaintext passwords used during login. Once your users are converted, back out these changes and convert to the standard bcrypt approach. This would involve deleting the grails.plugin.springsecurity.password.algorithm attribute and all salt configuration since bcrypt doesn’t support a salt, deleting Sha256ToBCryptPasswordEncoder and PasswordFixingDaoAuthenticationProvider, and removing the bcryptPasswordEncoder and sha256PasswordEncoder bean definitions and passwordEncoder and daoAuthenticationProvider overrides from resources.groovy since the beans configured by the plugin using Config.groovy settings will be sufficient. Also if you had added salt to the User class encodePassword method, e.g.

protected void encodePassword() {
   password = springSecurityService.encodePassword(password, username)
}

convert it back to the default without a salt:

protected void encodePassword() {
   password = springSecurityService.encodePassword(password)
}

Some approaches for diagnosing spring-security-core login errors

Wednesday, December 11th, 2013

If you use the Grails spring-security-core plugin and you’re unable to authenticate, it can be hard to know where to start looking for the cause. Often it’s due to confusion from older blog posts that tell you to explicitly hash the password when creating a user, e.g.

def user = new User(username: 'me', enabled: true,
     password: springSecurityService.encodePassword('password')).save()

But the generated User domain class auto-hashes your password for you, so you would just do this (I omitted setting enabled since in 2.0 it defaults to true):

def user = new User(username: 'me', password: 'password').save()

If that isn’t the problem, Spring Security logs a lot at the debug level, so enable that in the log4j block in Config.groovy:

log4j = {
   ...
   debug 'org.springframework.security'
}

With any luck there will be a useful signal in the noise and it’ll point you in the right direction.

If that doesn’t do it, you can configure a debugger and set a breakpoint in org.springframework.security.authentication.ProviderManager in the authenticate method. That’s where each registered AuthenticationProvider gets a chance to attempt an authentication if it supports the current Authentication.

Not everyone likes to use a debugger though. Another option is to register an event listener and look at the failure events. This is described in the plugin docs here. Here’s a simple configuration that will print information to the console for all failure events:

grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.onAbstractAuthenticationFailureEvent = { e, appCtx ->
   println "\nERROR auth failed for user $e.authentication.name: $e.exception.message\n"
}

Using MongoDB With Version 2.x of the Grails Spring Security Core Plugin

Sunday, December 01st, 2013

With a few customization steps it’s easy to use MongoDB to store user and role information for the spring-security-core plugin instead of using Hibernate, and after seeing this Stack Overflow question I thought I’d write up some notes on how to do this with the current plugins. Note that much of this is based on this blog post.

I created a demo application using Grails 2.3.3; it’s available on GitHub. The general steps were:

  • $ grails create-app mongoSpringSecurity
  • add the plugins to BuildConfig.groovy
  • $ grails s2-quickstart auth User Role
  • update DataSource.groovy to use MongoDB
  • create a custom UserDetailsService and register it in resources.groovy
  • create a test role and a user in BootStrap.groovy
  • customize the domain classes to use MongoDB
  • add tags to index.gsp to add a login link if you’re not logged in, and show that you’re logged in if you are

One difference between what I do here and what was done in the original blog post is that the custom UserDetailsService is not a Grails service – it’s in src/groovy and not in grails-app/services. It wasn’t necessary to be a real service then and isn’t now; it’s a coincidence that the Spring Security interface name ends in “Service”. See the plugin documentation for general information about customizing this bean.

You can see the source for the custom bean here. By embedding the authorities in the user domain class, the many-to-many relationship is not needed and the model is a lot simpler, so the class implementation is also – for example there’s no need for a withTransaction block to avoid lazy loading exceptions.

The changes for the User class are fairly minor. You need static mapWith = 'mongo' if you have both the Hibernate and MongoDB plugins; in this case it’s unnecessary but harmless to leave it in. The id field should be an ObjectId, and I retained the other customizations from the earlier blog post (the embedded roles, the addition of the email field, extra constraints, etc.). The Role class changes are similar.

Since we’re using a custom UserDetailsService, we can delete the userLookup.userDomainClassName, userLookup.authorityJoinClassName, and authority.className properties from Config.groovy, and since the roles are embedded in the user class we can delete the generated UserRole class.

You should be able to clone the repo and start the application (assuming you have MongoDB and Grails 2.3.3 already). Click the login link on the start page and after you successfully authenticate, the link should be replaced by a message.

A Grails plugin to bridge Spring Security and Shiro

Sunday, January 06th, 2013

I started using Spring Security in 2007 when I was tasked with adding security to a Spring/Hibernate application at the company I was working for. There were a few options to choose from, none of them particularly friendly to work with, and we chose Acegi Security because it was the most popular option for Spring applications. My experience was like that of many others – it was confusing and frustrating, and required a ton of XML. The next major release was renamed Spring Security 2.0 and it was officially brought in as a Spring subproject, and fortunately it made configuration dramatically simpler by using Spring XML namespaces.

When I started using Grails and found that it supported plugins one of the first I looked at was the acegi plugin, and I eventually became the plugin maintainer and later wrote most of the newer Spring Security plugins. I keep working with Spring Security because it’s very powerful and because I know it well, having struggled with learning Acegi 1.0.x, and then moving on to Spring Security 2.x and 3.x.

Grails has another popular security plugin, the shiro plugin. I haven’t used it but it has the reputation that it’s easier to use than Spring Security. I think that’s less the case with the plugins since spring-security-core and its dependent plugins are quite user-friendly, but more so when you’re not using the plugins or are working directly with the underlying APIs. For the most part the feature set of Spring Security and Shiro overlap with Spring Security having a few more features (but Shiro is catching up quickly). But one feature that is strangely implemented and hard to use in Spring Security but easy to use in Shiro is ACLs and permissions.

It took me a long time to get the spring-security-acl plugin finished, in large part because the Spring Security ACL implementation is overly complicated and hard to use. It works, but it’s far from user-friendly. But looking at the Shiro plugin’s documentation I was jealous to see that you can do simple things like grant the “printer:print:*” permission to a user, and the wildcard implies the “printer:print:lp7200” and “printer:print:epsoncolor” permissions. Then you can guard a service method with @RequiresPermissions('printer:print:*) and a user granted “printer:print:*” (or a more specific permission like “printer:print:lp7200”) can call the method, and others will be denied.

A while back I thought it would be cool to be able to use Shiro’s permission support in addition to Spring Security. I started working on it a few months ago and picked it up again this weekend and got it working. Basically it just adds a filter that runs after the Spring Security SecurityContextPersistenceFilter which populates the SecurityContext (typically from the HTTP session) with your current Authentication, and creates a Shiro Subject with the same information and registers it in the ThreadContext. In addition it adds support for storing permission information. This is done by default with a domain class that has a many-to-one relationship with the existing user class, but this is customizable.

So now you can install the spring-security-shiro alongside the spring-security-core and any of its dependent plugins and use both approaches. You can even use Spring Security ACLs and Shiro ACLs at the same time.

Check out the plugin page and the documentation for more information.

Make your Spring Security @Secured annotations more DRY

Wednesday, May 30th, 2012

Recently a user on the Grails User mailing list wanted to know how to reduce repetition when defining @Secured annotations. The rules for specifying attributes in Java annotations are pretty restrictive, so I couldn’t see a direct way to do what he was asking.

Using Groovy doesn’t really help here since for the most part annotations in a Groovy class are pretty much the same as in Java (except for the syntax for array values). Of course Groovy now supports closures in annotations, but this would require a code change in the plugin. But then I thought about some work Jeff Brown did recently in the cache plugin.

Spring’s cache abstraction API includes three annotations; @Cacheable, @CacheEvict, and @CachePut. We were thinking ahead about supporting more configuration options than these annotations allow, but since you can’t subclass annotations we decided to use an AST transformation to find our versions of these annotations (currently with the same attributes as the Spring annotations) and convert them to valid Spring annotations. So I looked at Jeff’s code and it ended up being the basis for a fix for this problem.


It’s not possible to use code to externalize the authority lists because you can’t control the compilation order. So I ended up with a solution that isn’t perfect but works – I look for a properties file in the project root (roles.properties). The format is simple – the keys are names for each authority list and the values are the lists of authority names, comma-delimited. Here’s an example:

admins=ROLE_ADMIN, ROLE_SUPERADMIN
switchUser=ROLE_SWITCH_USER
editors=ROLE_EDITOR, ROLE_ADMIN

These keys are the values you use for the new @Authorities annotation:

package grails.plugins.springsecurity.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.codehaus.groovy.transform.GroovyASTTransformationClass;

/**
 * @author Burt Beckwith
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@GroovyASTTransformationClass(
    "grails.plugins.springsecurity.annotation.AuthoritiesTransformation")
public @interface Authorities {
   /**
    * The property file key; the property value will be a
    * comma-delimited list of role names.
    * @return the key
    */
   String value();
}

For example here’s a controller using the new annotation:

@Authorities('admins')
class SecureController {

   @Authorities('editors')
   def someAction() {
      ...
   }
}

This is the equivalent of this controller (and if you decompile the one with @Authorities you’ll see both annotations):

@Secured(['ROLE_ADMIN', 'ROLE_SUPERADMIN'])
class SecureController {

   @Secured(['ROLE_EDITOR', 'ROLE_ADMIN'])
   def someAction() {
      ...
   }
}

The AST transformation class looks for @Authorities annotations, loads the properties file, and adds a new @Secured annotation (the @Authorities annotation isn’t removed) using the role names specified in the properties file:

package grails.plugins.springsecurity.annotation;

import grails.plugins.springsecurity.Secured;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;
import org.springframework.util.StringUtils;

/**
 * @author Burt Beckwith
 */
@GroovyASTTransformation(phase=CompilePhase.CANONICALIZATION)
public class AuthoritiesTransformation implements ASTTransformation {

  protected static final ClassNode SECURED =
       new ClassNode(Secured.class);

  public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
    try {
      ASTNode firstNode = astNodes[0];
      ASTNode secondNode = astNodes[1];
      if (!(firstNode instanceof AnnotationNode) ||
          !(secondNode instanceof AnnotatedNode)) {
        throw new RuntimeException("Internal error: wrong types: " +
            firstNode.getClass().getName() +
            " / " + secondNode.getClass().getName());
      }

      AnnotationNode rolesAnnotationNode = (AnnotationNode) firstNode;
      AnnotatedNode annotatedNode = (AnnotatedNode) secondNode;

      AnnotationNode secured = createAnnotation(rolesAnnotationNode);
      if (secured != null) {
        annotatedNode.addAnnotation(secured);
      }
    }
    catch (Exception e) {
      // TODO
      e.printStackTrace();
    }
  }

  protected AnnotationNode createAnnotation(AnnotationNode rolesNode)
        throws IOException {
    Expression value = rolesNode.getMembers().get("value");
    if (!(value instanceof ConstantExpression)) {
      // TODO
      System.out.println(
         "annotation @Authorities value isn't a ConstantExpression: " +
         value);
      return null;
    }

    String fieldName = value.getText();
    String[] authorityNames = getAuthorityNames(fieldName);
    if (authorityNames == null) {
      return null;
    }

    return buildAnnotationNode(authorityNames);
  }

  protected AnnotationNode buildAnnotationNode(String[] names) {
    AnnotationNode securedAnnotationNode = new AnnotationNode(SECURED);
    List<Expression> nameExpressions = new ArrayList<Expression>();
    for (String authorityName : names) {
      nameExpressions.add(new ConstantExpression(authorityName));
    }
    securedAnnotationNode.addMember("value",
              new ListExpression(nameExpressions));
    return securedAnnotationNode;
  }

  protected String[] getAuthorityNames(String fieldName)
       throws IOException {

    Properties properties = new Properties();
    File propertyFile = new File("roles.properties");
    if (!propertyFile.exists()) {
      // TODO
      System.out.println("Property file roles.properties not found");
      return null;
    }

    properties.load(new FileReader(propertyFile));

    Object value = properties.getProperty(fieldName);
    if (value == null) {
      // TODO
      System.out.println("No value for property '" + fieldName + "'");
      return null;
    }

    List<String> names = new ArrayList<String>();
    String[] nameArray = StringUtils.commaDelimitedListToStringArray(
        value.toString())
    for (String auth : nameArray) {
      auth = auth.trim();
      if (auth.length() > 0) {
        names.add(auth);
      }
    }

    return names.toArray(new String[names.size()]);
  }
}

I’ll probably include this in the plugin at some point – I created a JIRA issue as a reminder – but for now you can just copy these two classes into your application’s src/java folder and create a roles.properties file in the project root. Any time you want to add or remove an entry or add or remove a role name from an entry, update the properties file, run grails clean and grails compile to be sure that the latest values are used.

“Hacking the Grails Spring Security Plugin” at Groovy & Grails Exchange

Friday, December 09th, 2011

I gave a talk at the Groovy & Grails Exchange in London called “Hacking the Grails Spring Security Plugin”. I didn’t want to spend a lot of time discussing the sample app code since there was a lot of material to cover, so I’m making the code available here with a brief discussion of the implementation.


To support a custom login where the user’s organization must be specified in addition to the standard username and password, there’s a custom AuthenticationProvider (hacking.extralogin.auth.OrganizationAuthenticationProvider) which processes a subclass of UsernamePasswordAuthenticationToken (hacking.extralogin.OrganizationAuthentication) that adds an organizationName property, and a filter (hacking.extralogin.ui.OrganizationFilter) that creates the authentication from the request and initiates authentication.

In this example all authentication uses this approach, so the filter replaces the standard "authenticationProcessingFilter" bean (and subclasses the plugin’s RequestHolderAuthenticationFilter to maintain its functionality) and the provider replaces the "daoAuthenticationProvider" bean. The provider directly implements the AuthenticationProvider interface since using GORM directly is simple enough to not need to delegate to a UserDetailsService or other helper classes.

You can see the bean registrations for the filter and provider in grails-app/conf/spring/resources.groovy.

Note that the auth provider and filter are in separate packages to reinforce the idea that auth providers shouldn’t be aware of the UI. The filters that call the auth providers create an Authentication instance with all of the information that’s needed to authenticate, getting most or all of the data from the HTTP request. This keeps the auth providers modular and reusable outside of a web application.

No changes are required for the generated User, Role, or UserRole classes, but a new domain class Organization is needed to store the organization names, and OrgUser is needed to provide a link between users and organizations. auth.gsp has an extra input, a <select> box with all available Organization names.

If you request http://localhost:8080/hacking_london/secure you should see the text “not secured” since the index action is not guarded. But navigating to http://localhost:8080/hacking_london/secure/admin requires a user with ROLE_ADMIN, http://localhost:8080/hacking_london/secure/user requires a user with ROLE_USER, and http://localhost:8080/hacking_london/secure/adminOrUser requires a user with either ROLE_ADMIN or ROLE_USER. You can use one of the users created in BootStrap.groovy:

username Organization name password Role
admin Org1 password ROLE_ADMIN
user Org2 password ROLE_USER
disabled Org1 password ROLE_USER

There’s an extra user (“disabled”) with a disabled account to test that login fails with a correct username, org name, and password.

We also need to tweak an error message. The plugin’s i18n message bundle will display the error “Sorry, we were not able to find a user with that username and password” if the username, password, or organization are wrong. But we should include the organization in the message to indicate that it might have been wrong. To fix this, add this line to your application’s grails-app/i18n/messages.properties: springSecurity.errors.login.fail=Sorry, we were not able to find a user with that username, organization, and password.

To test this, log in as user ‘user’ with password ‘password’ but leave the organization name selected as ‘Org1’.

Note that since we’re not using the plugin’s UserDetailsService or Spring Security’s DaoAuthenticationProvider we don’t need the grails.plugins.springsecurity.userLookup.userDomainClassName, grails.plugins.springsecurity.userLookup.authorityJoinClassName, or
grails.plugins.springsecurity.authority.className properties added to Config.groovy by the s2-quickstart script. They’re commented out so you can switch back to the standard authentication approach by removing or commenting out the bean overrides in resources.groovy and the organization select box in auth.gsp.


The other significant customization I discussed was doing a custom post-logout redirect. It is possible to specify a spring-security-redirect request parameter when logging out, but this is too coarse an approach in general. If you need to use logic specific to the user, or something about the current authentication state, you need more control. So the sample application subclasses the default implementation of LogoutSuccessHandler, SimpleUrlLogoutSuccessHandler with hacking.logout.CustomLogoutSuccessHandler and registers it as the logoutSuccessHandler bean in resources.groovy.

The logic is contrived; if you’re in Organization ‘Org1’ you’re redirected to ‘http://yahoo.com’ and if you’re in Organization ‘Org2’ you’re redirected to ‘http://google.com’. Otherwise you’re redirected to the default location (‘/’ unless you’ve customized it with the grails.plugins.springsecurity.successHandler.defaultTargetUrl config attribute). But it shows an example of how you could use your own business logic to make a similar decision.

There’s one wrinkle here though; the only parameters for the overridden determineTargetUrl method are the HttpServletRequest and HttpServletResponse, but not the Authentication. And since this is the last step of the logout process, the user has already been logged out and the Authentication isn’t available from the request, springSecurityService, SecurityContextHolder, etc. But the public method (onLogoutSuccess) that calls this method has a parameter for the Authentication, so we save it in a ThreadLocal so it’s available for our override.


You can get the PDF of the presentation here, and the zip of the sample project here.

Updated Grails Console Plugin

Friday, December 10th, 2010

I’ve released an update to the Grails Console Plugin, version 1.0.1 (there was a bug affecting Grails 1.1 in the 1.0 release). The original authors (Siegfried Puchbauer and Mingfai Ma) aren’t working on it anymore and allowed me to do a release with some changes I had made.

I had been using a modified version of the plugin for a while and finally got around to contributing the changes back. The version I was using was storing the Groovy shell in the user’s HTTP session but this caused problems when clustering since it’s not serializable. This had been fixed in a more recent release however, so the changes I ended up making were mostly cosmetic.

I reworked the GSP, controller and service to be more modular, and split out the Javascript from the GSP into a .js file. In addition I upgraded CodeMirror to the latest version, and switched from Prototype to jQuery (and removed unreleased YUI-based code and other unused files). To customize the console view you can copy the plugin’s GSP (grails-app/views/console/index.gsp) to your application and it’ll be used instead.


Having a console like this available in a running Grails application is very useful. Since it’s running in the same process as your Grails app, it has access to GORM domain classes, services, and everything else in your application. So doing a quick database query, calling a service method or just testing some code is possible without restarting the application or running the standard Swing-based console.

It’s even useful in production, although since this is a very dangerous feature to have in a live web site it’s important to restrict access to it. My preference would be the Spring Security Core plugin since you can restrict it by role (e.g. ROLE_ADMIN) but also by IP address.

I wrote a while back about using a similar console to patch a bug in a running server.

If you have any questions or suggestions send a note to the Grails User mailing list, and report bugs in JIRA under the Grails-Console component.

ACLs in the Grails Spring Security Plugin

Sunday, December 27th, 2009

Update: If you’re interested in using ACLs with Spring Security and Grails, you can use the Spring Security ACL plugin


It has taken way too long, but the Grails Spring Security plugin finally has ACL support. It’s not officially available yet, but people have offered to beta test an early version of the plugin with ACLs, so you can download that here and report any issues back. Once it’s stable I’ll do an official release.

History

Stephan February did the first work adding ACL support to the plugin. Unfortunately at the time the plugin was based on Acegi 1.0.x and I had just converted it to use Spring Security 2.0. No one did the work to convert the ACL support to the new package layout and approach, so this wasn’t used.

This is a frequently requested feature, so I created a feature request as a TODO item for myself. I found some time to work on this over the summer and created an initial GORM-based implementation (the standard Spring Security implementation uses JDBC). I was fortunate to be able to use this at a client project at InnoCentive which helped to flesh out the ideas and identify a few issues.

Around the same time, Phillip Merensky mentioned on the mailing list that he was working on an implementation. He wrote about his approach here and attached his version of the plugin to the JIRA issue. Phillip’s work was very helpful; I’ve merged his version with mine for the current implementation.
(more…)

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.