Unexpected observations using spring-security (acegi) plugin

3 messages Options
Embed this post
Permalink
jlo_gestalt

Unexpected observations using spring-security (acegi) plugin

Reply Threaded More More options
Print post
Permalink
I've recently started using grails (v1.1.1) at work and wanted to build security into my project from the beginning using spring-security/acegi (v0.5.2).

I have successfully followed the Basic Tutorial using Requestmap and so far everything has worked pretty well. However, I have come across some unexpected behaviours I would like to confirm work as designed or find existing workarounds.

Users without Roles are unable to login
I found it unusual that Users have to be associated with a Role before being able to login via the LoginController. When a User not associated with a Role attempts to login via the LoginController, the error in grails is "ERROR springsecurity.GrailsDaoImpl  - User [james] has no GrantedAuthority". I expected to define an admin role (ROLE_ADMIN), one admin user (admin), and associate the two; then define a bunch of users without having to associate them with any Role (less maintenance). Then I could use the 3 roles: IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED, and IS_AUTHENTICATED_ANONYMOUSLY to control access to areas of my system that don't require specific Roles.

The Requestmaps for this use case would be something like:
new Requestmap(url: "/admin/**", configAttribute: "ROLE_ADMIN").save()
new Requestmap(url: "/event/**", configAttribute: "IS_AUTHENTICATED_FULLY").save()

Given this scenario, Users without a Role are unable to login and go to /event. Seems like overkill to associate every User with a Role when I am using the IS_AUTHENTICATED* Roles.

Is this a valid use case or is it pretty much standard to require a User to have a Role? Seems to me the IS_AUTHENTICATED* Roles indicate the user provided a valid username/password and can access the system with extra defined Roles.

Spring-Security Allows Delete for Wrong User
I wanted to restrict Delete actions to only admins (as above I am using the Requestmap strategy) on one of my simple models (Event). I have 2 Roles (ROLE_ADMIN and ROLE_USER) and 2 Users (admin and james). User admin is ROLE_ADMIN and User james is ROLE_USER.

I have 1 Requestmap to only allow admins to delete Events:
new Requestmap(url: "/event/delete/**", configAttribute: "ROLE_ADMIN").save()

What I expect is only the admin user can delete Events, however what I observed was my james User was able to view the event (/event/show/1) and click the Delete button to delete the Event. When my james User goes directly to the URL, /event/delete/2, it correctly responds with "Sorry, you're not authorized to view this page.". This is what I would expect to see when clicking the Delete button. Perhaps I don't know enough about submitButtons and controllers (I have not changed the auto-generated views or controllers). I realize I can disabled the Delete button using the ifAnyGranted taglib. I just expected the Delete button would traverse the same path to the controller, thus allowing acegi to prevent access.

What is the Delete button doing that prevents acegi from preventing access?
burtbeckwith

Re: Unexpected observations using spring-security (acegi) plugin

Reply Threaded More More options
Print post
Permalink
To be honest, I'm not sure why there's a rule that a user has to have at least one role. You're right that 'regular' users who can't really do anything don't need one, but admins would. When I implemented security in a large app recently I cheated and used subclasses, where admins and users extended a common base class, and admins had regular mapped roles but the user class had a hard-coded getRoles() method that returned a singleton Set containing ROLE_USER.

The standard implementation of the user lookup is org.springframework.security.userdetails.jdbc.JdbcDaoImpl, and it enforces the rule, and I believe that the plugin's implementation was coded to use the same logic. The source for JdbcDaoImpl is here: http://static.springsource.org/spring-security/site/xref/org/springframework/security/userdetails/jdbc/JdbcDaoImpl.html

You could try writing your own and returning an empty array - I'm pretty sure the rest of the framework will work fine but I haven't tested it. See this writeup for how to do that: http://www.grails.org/AcegiSecurity+Plugin+-+Custom+UserDetailsService

The problem with delete is due to the actionSubmit in the generated GSPs. This is a way of putting multiple submit buttons in one form, each sending the action name as a parameter so the controller can figure out which to use. Unfortunately it posts to the 'index' action, so URL-based security doesn't work for this case. There are two options - rework the two buttons to be regular submit buttons each in its own <g:form> with 'action' set to the real action being used, or use annotations. The annotation mechanism looks at URL mappings and is aware of the controller and action, not just the URL.

Burt

On Thursday 29 October 2009 12:55:41 am james lorenzen wrote:

>
> I've recently started using grails (v1.1.1) at work and wanted to build
> security into my project from the beginning using spring-security/acegi
> (v0.5.2).
>
> I have successfully followed the
> http://www.grails.org/AcegiSecurity+Plugin+-+Basic+Tutorial Basic Tutorial
> using Requestmap  and so far everything has worked pretty well. However, I
> have come across some unexpected behaviours I would like to confirm work as
> designed or find existing workarounds.
>
> Users without Roles are unable to login
> I found it unusual that Users have to be associated with a Role before being
> able to login via the LoginController. When a User not associated with a
> Role attempts to login via the LoginController, the error in grails is
> "ERROR springsecurity.GrailsDaoImpl  - User [james] has no
> GrantedAuthority". I expected to define an admin role (ROLE_ADMIN), one
> admin user (admin), and associate the two; then define a bunch of users
> without having to associate them with any Role (less maintenance). Then I
> could use the 3 roles: IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED,
> and IS_AUTHENTICATED_ANONYMOUSLY to control access to areas of my system
> that don't require specific Roles.
>
> The Requestmaps for this use case would be something like:
> new Requestmap(url: "/admin/**", configAttribute: "ROLE_ADMIN").save()
> new Requestmap(url: "/event/**", configAttribute:
> "IS_AUTHENTICATED_FULLY").save()
>
> Given this scenario, Users without a Role are unable to login and go to
> /event. Seems like overkill to associate every User with a Role when I am
> using the IS_AUTHENTICATED* Roles.
>
> Is this a valid use case or is it pretty much standard to require a User to
> have a Role? Seems to me the IS_AUTHENTICATED* Roles indicate the user
> provided a valid username/password and can access the system with extra
> defined Roles.
>
> Spring-Security Allows Delete for Wrong User
> I wanted to restrict Delete actions to only admins (as above I am using the
> Requestmap strategy) on one of my simple models (Event). I have 2 Roles
> (ROLE_ADMIN and ROLE_USER) and 2 Users (admin and james). User admin is
> ROLE_ADMIN and User james is ROLE_USER.
>
> I have 1 Requestmap to only allow admins to delete Events:
> new Requestmap(url: "/event/delete/**", configAttribute:
> "ROLE_ADMIN").save()
>
> What I expect is only the admin user can delete Events, however what I
> observed was my james User was able to view the event (/event/show/1) and
> click the Delete button to delete the Event. When my james User goes
> directly to the URL, /event/delete/2, it correctly responds with "Sorry,
> you're not authorized to view this page.". This is what I would expect to
> see when clicking the Delete button. Perhaps I don't know enough about
> submitButtons and controllers (I have not changed the auto-generated views
> or controllers). I realize I can disabled the Delete button using the
> ifAnyGranted taglib. I just expected the Delete button would traverse the
> same path to the controller, thus allowing acegi to prevent access.
>
> What is the Delete button doing that prevents acegi from preventing access?


signature.asc (204 bytes) Download Attachment
jlo_gestalt

Re: Unexpected observations using spring-security (acegi) plugin

Reply Threaded More More options
Print post
Permalink
Thanks Burt. Kind of what I suspected.
Should I file an improvement for Users requiring to have a Role?

That makes sense how the GSP submits to the index action. I'll go ahead and update the wiki pages to indicate this behaviour so others don't run into this issue.

So, if I continued to use one form and Requestmaps, but disabled the Delete button using the g:ifAnyGranted taglib, a malicious user could still technically construct a POST request that performed a Delete by posting to the index action mimic'ing the Delete button? For that matter the same holds true even if I did use multiple forms (1 per admin action), since they could mimic the same behaviour as the Delete button. So I am guessing the most secure practice is to use annotations?