3
votes

I installed Spring Security Core in my Grails application and set it up using s2-quickstart. I want '/' to handle login and logout actions. It means for me that user which is not logged in is able to access only root page and nothing else. Practically, everything except '/' should be blocket for users without role 'ROLE_ADMIN'.

I added login form on root page and set following configuration in Config.groovy:

grails.plugin.springsecurity.auth.loginFormUrl = '/'
grails.plugin.springsecurity.auth.ajaxLoginFormUrl = '/'
grails.plugin.springsecurity.failureHandler.defaultFailureUrl = '/'
grails.plugin.springsecurity.failureHandler.ajaxAuthFailUrl = '/'
grails.plugin.springsecurity.logout.postOnly = false
grails.plugin.springsecurity.userLookup.userDomainClassName = 'adminpanel.security.SecUser'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'adminpanel.security.SecUserSecRole'
grails.plugin.springsecurity.authority.className = 'adminpanel.security.SecRole'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    '/':                              ['permitAll'],
    '/index':                         ['permitAll'],
    '/index.gsp':                     ['permitAll'],
    '/**/js/**':                      ['permitAll'],
    '/**/css/**':                     ['permitAll'],
    '/**/images/**':                  ['permitAll'],
    '/**/favicon.ico':                ['permitAll']
]

I set @Secured(['ROLE_ADMIN']) on every controller of mine and added something like this to my index.gsp:

<head>
    <sec:ifAllGranted roles="ROLE_ADMIN">
        <meta name="layout" content="main"/>
    </sec:ifAllGranted>
    <sec:ifNotGranted roles="ROLE_ADMIN">
        <meta name="layout" content="login"/>
    </sec:ifNotGranted>
    <title>Home Page - Admin Panel</title>
</head>

There are two problems:

  1. The configuration works as I expected, but when I type in the browser: localhost:8080/AdminPanel/login/auth the page still exists and I can access it even being logged out user. I want to remove this URL completely, either logged in or logged out user shouldn't be able to access it.

  2. Even if the user is logged out, /login/auth view is rendered using "main" layout, despite the fact that I have the code I mentiond above in my index.gsp, which should change layout to "login". Why?

Thanks in advance!

1
Not immediately sure how best to disable the default /login/auth mapping, but to map / to the login page, you can add this line to UrlMappings: "/"(controller: "login", action: "auth") For #2, the default SpringSec login/auth.gsp view applies the main layout.Andrew
@Andrew Addin UrlMappings changed nothing for me. I change the URL, but it does not redirect me to the index at all. It is still rendered /login/auth/ page. Everything starts to look like I have to change the LoginController...kmb
Finally, I removed the additional URL Mappings and I changed auth.gsp. Now it looks like: <html> <head> <meta name='layout' content='login' /> </head> <body> </body> </html> Everything seems to work well, but I cannot access ${flash.messages} in my layout, but maybe I just do something wrong.kmb
Spring Security uses flash.message (no "s") by default.Andrew

1 Answers

3
votes

/login/auth works because of the "/$controller/$action?/$id?" mapping in UrlMappings. All controllers are auto-mapped because of this. One option is to remove this, but that means that you have to then explicitly map all controllers. There are benefits to this, and the grails.org app uses this approach.

You can't un-map an auto-mapped controller, but you can re-map it to something that sends a 404, and this looks the same to the user. One way is with a Grails filter, e.g. run grails create-filters site and put this in SiteFilters.groovy:

package com.foo.bar

class SiteFilters {

   def filters = {
      loginUnmap(uri: '/login/**') {
         before = {
            response.status = 404
            false
         }
      }
   }
}

I'm not 100% sure about the layout issue, but I think that the problem is that meta tags are handled specially by SiteMesh. The page is parsed to determine which layout to use, and then parts of your GSP are merged into the layout, so it's not surprising to me that using runtime tags like <g:if> don't work like you might want.