Question

I'm using Grails 2.2.3 and the Spring Security ACL plugin 1.1.1, and I'd like to have a URL that is open to the public and the service layer using the @PostAuthorize annotation secures the resource. We're doing it this way because to determine whether a user has access to a particular object we need to look at the object first.

What I'd like to be able to do is in the controller layer catch the AccessDeniedException, then have the browser ask for credentials and try again. I've tried the naive approach of setting the response status to 401 and redirecting back to itself to try again. The problem I ran into is that the browser never asked for credentials.

To put this into code what I'd like to do is in the controller layer:

@Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def controllerAction() {
   try {
      someService.action()
   } catch (AccessDeniedException ade) {
      // if logged in show FORBIDDEN, if not ask for credentials and try again
   }
}

And the service layer would simply have:

@PostAuthorize("""returnObject.availability == 'ALL'""")
def action() {
   PersistedObject.findById(1)
}

Thanks for any help!

Was it helpful?

Solution

I ended up solving the problem, and it turns out I was missing a header that I needed to send along with the 401 status code.

To correct what I have above what you want to do is:

@Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def controllerAction() {
   try {
      someService.action()
   } catch (AccessDeniedException ade) {
      if (!springSecurityService.isLoggedIn()) {
         response.setHeader 'WWW-Authenticate', 'Basic realm="Grails Realm"' // the missing line
         response.sendError HttpServletResponse.SC_UNAUTHORIZED 
   }
}

The "redirect" I was looking for happens automatically within the browser after credentials are submitted. I was mistaken about needing something specific for the redirect.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top