[Spring Security] Invoke @Secured service methods from background (Quartz) threads

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[Spring Security] Invoke @Secured service methods from background (Quartz) threads

Benjamin Wolff
Hi,

I have several Quartz background jobs in which I inject services. Most of the service methods I need to invoke are protected by @Secured annotations which check for required granted authorities (roles).

The problem is, that these annotations fail to evaluate because there is no Authentication in the background thread.

What would be the code I need to sucessfully invoke this methods? I looked at the docs for the Switch User or "doWithAuth()" mechanism, but somehow these don't directly support what I want to do. I don't use additional Filters or replace a current Authentication, I'd just need to either put the necessary roles in the current thread context or disable the annotation for the single method invocation.

I'd be grateful for your suggestions!

Cheers,
Ben
Cheers,
Ben
Reply | Threaded
Open this post in threaded view
|

Re: [Spring Security] Invoke @Secured service methods from background (Quartz) threads

a.shneyderman
You did not mention what security framework you are using but in cae
it is spring-security, you could use

SecurityContextHolder.context.setAuthentication()

construct authentication you want and make sure context has this
information before you crossed any of the @Secured boundaries.

Maybe there is a simpler method but that is what I do in tests and I
do not see why you could not do it in your BG jobs.

Cheers,
Alex.

On Fri, Mar 16, 2012 at 12:54 PM, Benjamin Wolff <[hidden email]> wrote:

> Hi,
>
> I have several Quartz background jobs in which I inject services. Most of
> the service methods I need to invoke are protected by @Secured annotations
> which check for required granted authorities (roles).
>
> The problem is, that these annotations fail to evaluate because there is no
> Authentication in the background thread.
>
> What would be the code I need to sucessfully invoke this methods? I looked
> at the docs for the Switch User or "doWithAuth()" mechanism, but somehow
> these don't directly support what I want to do. I don't use additional
> Filters or replace a current Authentication, I'd just need to either put the
> necessary roles in the current thread context or disable the annotation for
> the single method invocation.
>
> I'd be grateful for your suggestions!
>
> Cheers,
> Ben
>
>
> --
> View this message in context: http://grails.1312388.n4.nabble.com/Spring-Security-Invoke-Secured-service-methods-from-background-Quartz-threads-tp4477983p4477983.html
> Sent from the Grails - user mailing list archive at Nabble.com.
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>    http://xircles.codehaus.org/manage_email
>
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: [Spring Security] Invoke @Secured service methods from background (Quartz) threads

Benjamin Wolff
Hi Alex,

sorry, I thought the framework was apparent from the title of my topic ;).

Thanks for your insight. I have created two static helper methods in a utility class. They allow me now to write the following code in my background threads:

MyGrailsUtil.runWithRoles(["ROLE_1", "ROLE_2"]) {
    ... code to run with the given roles ...
}

For the archive, the code of the helper methods are as follows:
    static void runWithAuthentication(Authentication authentication, Closure clos) {
        // Cache the current authentication, if there is one.
        Authentication oldAuthentication = SecurityContextHolder.context.authentication

        // Set the new authentication to the thread SecurityContext and execute the closure. Make
        // sure that the old Authentication is restored afterwards, if one existed.
        try {
            SecurityContextHolder.context.authentication = authentication
            clos()
        } finally {
            if (oldAuthentication) {
                SecurityContextHolder.context.authentication = oldAuthentication
            } else {
                SecurityContextHolder.clearContext()
            }
        }
    }

    static void runWithRoles(List<String> roles, Closure clos) {
        // Transform the String roles to GrantedAuthorities.
        def authorities = roles.collect { new GrantedAuthorityImpl(it) }

        // Create the fake Authentication object with the authorities.
        Authentication authentication = new AnonymousAuthenticationToken("system", new Object(),
            authorities)

        // Run the closure with the fake authentication.
        runWithAuthentication(authentication, clos)
    }
Cheers,
Ben
Reply | Threaded
Open this post in threaded view
|

Re: [Spring Security] Invoke @Secured service methods from background (Quartz) threads

basejump (Josh)
You can also do
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
in either Bootstrap or in a plugins doWithApplicationContext
This will by default have any spun off child threads use the parents spring security context credentials.

If its kick off by a quartz job we have something along the lines of the following to do a login if none exists

import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.authority.AuthorityUtils
...
static void loginAsSystemUser() {
        def user = User.get(999) //the user that is dedicated to running jobs
        def authorities = AuthorityUtils.createAuthorityList('ROLE_XXX')
        def grailsUser = new GrailsUser(user.login, user.passwd, user.enabled,
                true, !user.mustChangePassword, true, authorities, user)
        SCH.context.authentication = new UsernamePasswordAuthenticationToken(grailsUser, user.passwd, authorities)
}


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: [Spring Security] Invoke @Secured service methods from background (Quartz) threads

Michael Campbell-2
I'm doing something similar, but the methods I'm using aren't secured with @SECURE. From my quartz jobs I'm calling a method which immediately tries to get the logged in user with the command

def user = User.get(springSecurityService.principal.id)

This works well when users are logging in, but when I use basejump's code fragment from my quartz job springSecurityService.principal.id does not hold an ID it holds an actual User object.

Any thoughts on what might be causing this?
Thanks
- Michael

On Fri, Mar 16, 2012 at 10:44 PM, Josh (basejump) <[hidden email]> wrote:
You can also do
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
in either Bootstrap or in a plugins doWithApplicationContext
This will by default have any spun off child threads use the parents spring security context credentials.

If its kick off by a quartz job we have something along the lines of the following to do a login if none exists

import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.authority.AuthorityUtils
...
static void loginAsSystemUser() {
       def user = User.get(999) //the user that is dedicated to running jobs
       def authorities = AuthorityUtils.createAuthorityList('ROLE_XXX')
       def grailsUser = new GrailsUser(user.login, user.passwd, user.enabled,
               true, !user.mustChangePassword, true, authorities, user)
       SCH.context.authentication = new UsernamePasswordAuthenticationToken(grailsUser, user.passwd, authorities)
}


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email



Reply | Threaded
Open this post in threaded view
|

Re: [Spring Security] Invoke @Secured service methods from background (Quartz) threads

Mike Powers
Did you ever find a solution to this problem?

On Tue, Mar 20, 2012 at 5:07 PM, Michael Campbell <[hidden email]> wrote:
I'm doing something similar, but the methods I'm using aren't secured with @SECURE. From my quartz jobs I'm calling a method which immediately tries to get the logged in user with the command

def user = User.get(springSecurityService.principal.id)

This works well when users are logging in, but when I use basejump's code fragment from my quartz job springSecurityService.principal.id does not hold an ID it holds an actual User object.

Any thoughts on what might be causing this?
Thanks
- Michael


On Fri, Mar 16, 2012 at 10:44 PM, Josh (basejump) <[hidden email]> wrote:
You can also do
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
in either Bootstrap or in a plugins doWithApplicationContext
This will by default have any spun off child threads use the parents spring security context credentials.

If its kick off by a quartz job we have something along the lines of the following to do a login if none exists

import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.authority.AuthorityUtils
...
static void loginAsSystemUser() {
       def user = User.get(999) //the user that is dedicated to running jobs
       def authorities = AuthorityUtils.createAuthorityList('ROLE_XXX')
       def grailsUser = new GrailsUser(user.login, user.passwd, user.enabled,
               true, !user.mustChangePassword, true, authorities, user)
       SCH.context.authentication = new UsernamePasswordAuthenticationToken(grailsUser, user.passwd, authorities)
}


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email