How to restrict editing to the user who created with Grails - grails

Any user can create his/her own robot. A robot should be edited only by the creator or an administrator.
The next code works perfectly and it is an easy and simple solution:
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
class RobotController {
def springSecurityService
def edit() {
if (Robot.get(params.id).usuario.username == springSecurityService.authentication.name
|| SpringSecurityUtils.ifAnyGranted("ROL_ADMIN,ROL_SUPERADMIN"))
println "editing allowed"
else
println "editing denied"
}
}
But my teacher recommended me to secure the web using Config.groovy. The next code does not work:
grails.plugins.springsecurity.interceptUrlMap = [
'/index.gsp': ["isAuthenticated()"],
'/robot/edit/**': ["Robot.get(params.id).usuario.username == springSecurityService.authentication.name
|| hasAnyRole('ROL_ADMIN','ROL_SUPERADMIN')"],
'/robot/**': ["isAuthenticated()"]
]
It does not work because different reasons:
It is not possible to call the domain class Robot in Config.groovy
params.id has no sense in this place
The Java "or" (||) is not valid here. I tried other ways with not luck. The Groovy documentation is not clear for me.
Is possible to do it in Config.groovy? If not, the correct way would be using <sec:access> ... </sec:access> somehow?

I don't think you can do that kind of thing with plain Spring Security core.
Your teacher is right in the sense that you probably shouldn't implement the security in an ad-hoc manner, but you don't necessarily should do it in the Config.groovy -- that is a bit limiting.
You probably want to use the Spring Security ACL plugin, it adds some more domain classes and allows you to set up the access control with much more fine grained detail.
Check out the official docs. It may take a little while for you to learn it, but it is much better than rolling out your own ACL mechanism.

Related

Proper way to handle GORM calls in TagLib

I started using Webflow on a Grails 2.2.4 project today and I immediately ran into the following exception:
could not initialize proxy - no Session
Doing some research I ran across this SO question which then led me to this JIRA issue that is marked as Won't Fix because making GORM calls in a TagLib is considered a bad idea.
Since this kind of stuff seems to work fine from regular actions, I've not run across the issue before. My question is, how should the following code be structured so that I'm following the right practice.
I have a template called _nav.gsp which handles my sites navigation bar. There are a lot of menu options that are shown and hidden depending on user's roles. I have the following in a TagLib:
def ifProjectGranted = { attr, body ->
def authenticatedUser = docRegService.authenticatedUser
if (authenticatedUser) {
def roles = UserRole.findAllByUser(authenticatedUser).collect { it.role.authority }
// here I check roles and manage my rendering to the output
}
}
I know I can solve the problem by wrapping my findAllByUser in a withTransaction block. But according to the JIRA, I shouldn't be doing this lookup at all here. So where would I do it?

Security impact of using constantize

I'm currently reviewing some Rails controller. That controller takes user input and based on that user input a new object is created like so:
clazz = params[:type].classify.constantize
clazz.new(some_method_which_returns_filtered_params)
I'm concerned with the security of this approach. Are there classes in Ruby which the 'new' method could be used with malicious intent?
For example it might be possible to flood the program with new Symbols causing a denial of service (see http://brakemanscanner.org/docs/warning_types/denial_of_service/).
I'd recommend limiting the values that this code will accept for params[:type], before executing it. Eg with an if block like
if %w(foos bars bazzes).include?(params[:type])
clazz = params[:type].classify.constantize
clazz.new(some_method_which_returns_filtered_params)
end
I don't think DOS attacks are a specific problem with doing classify.constantize here: if someone spams your server with requests then that's going to DOS attack you whatever you do in the actual controller.
Preventing DOS attacks is hard. Securing web apps is a massive subject, but in particular you seem to be talking about the area of "sanitizing parameters" here. Have a look at
http://guides.rubyonrails.org/security.html
I can't resist linking to this classic XKCD strip: http://xkcd.com/327/

Drive two different browsers in one GebReportingSpec?

I'm using geb and spock for functional tests in my Grails 2.3.7 app. The app allows real-time interaction between users, which I'd like to test automatically.
Does anyone know how, or if it's possible, to run two different browsers in one Spec? For example, see the pseudo code below for how I imagine this working in a perfect world.
#Stepwise
class ChatPageSpec extends GebReportingSpec {
def "login with chrome"() {
}
def "login with firefox"() {
}
def "send chat request with chrome"() {
}
def "accept chat request with firefox"() {
}
def "send hello with chrome"() {
}
def "receive hello with firefox"() {
}
}
Running the tests in parallel as Craig describes (http://www.objectpartners.com/2013/11/14/parallel-grails-functional-tests-with-geb-and-gradle/) looked promising, but if I understand it correctly, the parallel tests would use different app instances, which won't work. Plus, #Stepwise or something similar would have to keep the browsers in sync.
I also checked out the poly driver plugin (http://grails.org/plugin/poly-driver), but it looks like it's designed for one browser per Spec.
Ken
I'm afraid that you will need to handcraft something for this.
There is an example of achieving this which was once posted to Geb mailing list. I have never used it myself but the code looks reasonable. It feels like you'll want to use MultiBrowserGebSpec and override createBrowserMap().
You can create driver instances by hand and then set it on browsers instances using setDriver(). Another way would be to have different config files for different browsers which you would load using getConf() and pass to Browser constructor. Yet another one would be to have different environments for different browsers in one GebConfig.groovy and use different ConfifgurationLoaders created using the constructor that accepts environment name.

Grails Spring Security Custom UserDetailsService (goal of Email in place of Username)

I am using Grails Spring Security Plugin 1.2.7.3 and would like to have the User authenticate via Email Address and Password. I would like Email Address to be the primary Login ID.
I came across the following Nabble post regarding case insensitive usernames, where the original poster is attempting to do the same. However, I was a bit confused on a few points:
I understand that I need to write my own implementation of UserDetailsService and register it in grails-app/conf/spring/resources.groovy.
However, I wasn't sure which folder the custom implementation of UserDetailsService should go (best practices). My guesses are either /grails-app/services, /grails-app/utils, or /src/groovy. Has anyone done this before and where is the best place for the custom UserDetailsService?
I read this chapter in the Docs: http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/11%20Custom%20UserDetailsService.html but I didn't really see guidance on what Grails folder to put it in.
I created my User domain class via s2 command:
s2-quickstart com.philiptenn.security User Role Requestmap
If I were to rename the field User.username to User.email so that my code is clearer, will I be in for a world of hurt?
I did a Find Usages on this field, and one stuck out in DefaultSecurityConfig.groovy: userLookup.usernamePropertyName = 'username'
Could I just update this to read:
DefaultSecurityConfig.groovy: userLookup.usernamePropertyName = 'email'
Thank you.
As you pointed out, you can override the default security configs in your own Config.groovy, the options all start with grails.plugins.springsecurity, so it would be grails.plugins.springsecurity.userLookup.usernamePropertyName = 'email' (docs). That's the first thing I'd try. If you check out the source of the GormUserDetailsService, the default userDetailsService, you'll see it uses that property for the lookup.

current sessions in Grails

I am a beginner in Grails 2.0 framework and I am trying to follow this tutorial http://grails.org/Simple+Avatar+Uploader . I implemented this code but I am getting an error in UserController.groovy at this line 'def user = User.current(session)' as ' No such property: User for class: grailtwitter.PersonController' I assume that this line takes the user's current session. I am looking for an explanation of how this works ?
This code is incomplete. The controller presupposes that you have a way of identifying the currently logged in user. Implicitly the line def user = User.current(session) assumes that you have defined a current() method on the user class itself that takes in a session and presumably uses some field that you've set in it to retrieve a User. That would be kind of dumb.
A common way to do this would be to build your own authentication mechanism. Note that this is a naive practice and you are far better off using Spring Security Core unless you want to leave your application open for gaping security holes. But, for practice, something like:
def login = {
//if you're stupid enough to store your passwords in plain text and not sanitize user inputs, you deserve to be hacked
def user = User.findByPassword(params.password)
if(user){
session.user = user
}
}
You could then replace the offending line in the tutorial (--def user = User.current(session)--) with
def user = session.user ?: new User(userid:"I'm a little teapot")
Before you go much further, you probably want to walk through this free eBook on Grails before you get much further. Also highly recommend Grails in Action.
When I have run into this in the past it's because I didn't import the class and Grails/Groovy thinks I'm trying to access a variable called User rather than a method on the class.

Resources