You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shiro.apache.org by Peter Ledbrook <pe...@cacoethes.co.uk> on 2009/09/03 12:50:49 UTC

Updating subject with new security manager

Hi,

The Shiro plugin for Grails tries to support automatic reloading of
realms. So when a user modifies a realm while the application is
running, the change takes effect almost immediately without the user
having to restart the servlet container. A side-effect of this feature
is that the security manager bean is reloaded. In other words, you get
a new instance of the security manager.

The problem I'm facing is that the subject never gets updated with the
new security manager, so the user's changes to his or her realm don't
take effect as they should. I was using a nasty hack via Groovy to
update the securityManager field on the subject directly, but it is a
hack. Are there any other ways of updating the subject? Maybe creating
a new delegating subject with the new security manager? If not, any
ideas for changes to Shiro that might aid this?

Thanks,

Peter

Re: Updating subject with new security manager

Posted by Peter Ledbrook <pe...@cacoethes.co.uk>.
> OK, got it. Thanks for the info. Hot-swappable proxy it is!

In case anyone else needs to do this, I had to come up with a nasty
hack. The problem is that the proxy ends up being reloaded because it
depends on the security manager bean. So, when defining the
hot-swappable target source, I specify a dummy security manager class
that does nothing. Once the bean definitions are all loaded, I swap
the real security manager into the target source.

Cheers,

Peter

Re: Updating subject with new security manager

Posted by Peter Ledbrook <pe...@cacoethes.co.uk>.
> But even if there was only ever the request thread, you still would
> have to be concerned about the SecurityManager reloading even during
> mid thread execution since the SM instance is a shared application
> singleton - a proxy with a hot swappable target source would probably
> safely handle this switch, even when concurrent requests are
> executing.  Add in the above associateWith mechanisms, and you'll need
> this safety for sure if you can dynamically substitute the SM at
> runtime.

OK, got it. Thanks for the info. Hot-swappable proxy it is!

Peter

Re: Updating subject with new security manager

Posted by Les Hazlewood <lh...@apache.org>.
Hi Peter (et. al.),

Any other framework developers wondering how to integrate Shiro with
their framework would do well to read this email - it explains a core
fundamental principal of how Shiro works in any environment.

On Thu, Sep 3, 2009 at 11:49 AM, Peter Ledbrook<pe...@cacoethes.co.uk> wrote:
>> One thought I have is that perhaps the SecurityManager instance with
>> which the DelegatingSubject is constructed could be a SecurityManager
>> proxy?  Then you could have control over how that proxy operates -
>> whether it uses a cached instance or, perhaps upon a reload, the proxy
>> knows to acquire the new SecurityManager?
>
> Does it need to be that complicated? I've taken a look at the code,
> but I'm struggling to understand when the subject is created and how
> long it survives. Is it re-created each request? Or is it bound to a
> session? If it's recreated each request, why would it be picking up
> the old security manager?

For all Shiro runtime environments, web or not, the executing thread
must create a Subject instance and bind it to that thread, and when
the thread's execution is done, that instance needs to be unbound from
the thread so it can be garbage collected.  Subject instances are
meant to be very short lived, while a Subject's state can be
long-lived (i.e. in a Session).

Almost always this required logic should occur in a try/finally block
for any thread's execution:

try {
     //1. Create a subject instance
     //2. bind the subject and any necessary associated data to the
currently running thread
     //3. do some work
} finally {
    //4. unbind the subject and any associated data from the
    //    currently running thread so they can be garbage collected
}

For web environments, the ShiroFilter does this logic (albeit in a
slightly more complex way) in the doFilterInternal implementation if
you're curious.

So, yes, the Subject instance is created for each web request.  But
the Subject instance is built using the SecurityManager instance that
the ShiroFilter acquires at startup (ShiroFilter.java, line 489).

Now that I think about it, I think we should just drop the
SpringShiroFilter entirely and show users how to configure the normal
ShiroFilter using Spring's DelegatingFilterProxy.  This is much more
convenient and a more powerful configuration for Spring users.  But I
guess that is another discussion...

>> This sounds like an ideal solution, especially with the latest
>> Callable/Runnable/RunAs supporting coming in 1.0.  These mechanisms
>> need to retain the SecurityManager instance in use so when transferred
>> to another thread, that same SM is available on the other thread.  If
>> the SM instance is a proxy, the DelegatingSubject running on the other
>> threads would be cleanly updated as well.
>
> I think this maybe done fairly easily with a Spring ProxyFactoryBean
> and a hot-swappable target. Alternatively, could the subject just pick
> up the security manager from the thread context whenever it needs it?

The ProxyFactoryBean sounds logical - it would be a good way to go I think.

As far as picking up the SecurityManager from the ThreadContext, sure,
this would work fine, but only for the request thread - it would fail
for the new Callable/Runnable/RunAs support for 1.0.

With the new Subject.associateWith methods and probably the upcoming
RunAs support, the DelegatingSubject's SecurityManager instance needs
to be 'passed around' to other threads.  In a web environment, the
SecurityManager accessible to the request-thread needs to be retained
for use on any other thread that might execute the Callable/Runnable
returned from the new Subject.associateWith methods.

That is, this needs to function properly:

Subject requestSubject = SecurityUtils.getSubject();
Runnable work = requestSubject.associateWith( new Runnable() {
    public void run() {
        //make sure this method is executed as 'requestSubject':
        doWorkThatTakesALongTime();
    }
});
//do the work on another thread, don't block the request thread:
executorService.submit(work);

The submit method above, while running on a different thread will
still run as 'requestSubject', even though the original request thread
has finished executing.  It is a very cool feature, and probably one
of the most often requested things for Shiro - particularly for daemon
or system-level work that needs to run as a particular user.

The Subject.associateWith methods in fact do the thread housekeeping
automatically of course, but the point is that once the other threads
are executing somewhere else (no longer the request thread), the
'requestSubject's internal SecurityManager instance still needs to
function.  It is passed from the originating request-thread to another
just by a simple object reference.

But even if there was only ever the request thread, you still would
have to be concerned about the SecurityManager reloading even during
mid thread execution since the SM instance is a shared application
singleton - a proxy with a hot swappable target source would probably
safely handle this switch, even when concurrent requests are
executing.  Add in the above associateWith mechanisms, and you'll need
this safety for sure if you can dynamically substitute the SM at
runtime.

HTH!

Cheers,

Les

Re: Updating subject with new security manager

Posted by Peter Ledbrook <pe...@cacoethes.co.uk>.
> One thought I have is that perhaps the SecurityManager instance with
> which the DelegatingSubject is constructed could be a SecurityManager
> proxy?  Then you could have control over how that proxy operates -
> whether it uses a cached instance or, perhaps upon a reload, the proxy
> knows to acquire the new SecurityManager?

Does it need to be that complicated? I've taken a look at the code,
but I'm struggling to understand when the subject is created and how
long it survives. Is it re-created each request? Or is it bound to a
session? If it's recreated each request, why would it be picking up
the old security manager?

> This sounds like an ideal solution, especially with the latest
> Callable/Runnable/RunAs supporting coming in 1.0.  These mechanisms
> need to retain the SecurityManager instance in use so when transferred
> to another thread, that same SM is available on the other thread.  If
> the SM instance is a proxy, the DelegatingSubject running on the other
> threads would be cleanly updated as well.

I think this maybe done fairly easily with a Spring ProxyFactoryBean
and a hot-swappable target. Alternatively, could the subject just pick
up the security manager from the thread context whenever it needs it?

Peter

Re: Updating subject with new security manager

Posted by Les Hazlewood <lh...@apache.org>.
Ah yes, this makes much more sense to me now - thanks for clarifying.

One thought I have is that perhaps the SecurityManager instance with
which the DelegatingSubject is constructed could be a SecurityManager
proxy?  Then you could have control over how that proxy operates -
whether it uses a cached instance or, perhaps upon a reload, the proxy
knows to acquire the new SecurityManager?

This sounds like an ideal solution, especially with the latest
Callable/Runnable/RunAs supporting coming in 1.0.  These mechanisms
need to retain the SecurityManager instance in use so when transferred
to another thread, that same SM is available on the other thread.  If
the SM instance is a proxy, the DelegatingSubject running on the other
threads would be cleanly updated as well.

Would this be an acceptable solution?  Or does anything else come to mind?

- Les

On Thu, Sep 3, 2009 at 10:31 AM, Peter Ledbrook<pe...@cacoethes.co.uk> wrote:
>> What do you mean exactly by modifying a realm?  I would guess that you
>> mean changing state/attributes on an existing Realm instance.  Is this
>> correct?  Or are you talking about adding or removing realm instances
>> on the SecurityManager at runtime?
>
> I mean changing the code in the realm, for example by adding a print
> statement, or modifying the behaviour of isPermitted().
>
>> The application SecurityManager instance shouldn't need to be swapped
>> at runtime.  Any changes to its configuration should be dynamically
>> applied, IMO.  But this might be a different discussion - I don't see
>> how modifying an existing realm instance's state would have any effect
>> on the security manager.
>
> Because the realm's class changes, Spring has to update everything
> that ultimately references it. In other words, all beans that directly
> or indirectly depend on the realm have to be reloaded, security
> manager included.
>
> Hope that clears things up,
>
> Peter
>

Re: Updating subject with new security manager

Posted by Peter Ledbrook <pe...@cacoethes.co.uk>.
> What do you mean exactly by modifying a realm?  I would guess that you
> mean changing state/attributes on an existing Realm instance.  Is this
> correct?  Or are you talking about adding or removing realm instances
> on the SecurityManager at runtime?

I mean changing the code in the realm, for example by adding a print
statement, or modifying the behaviour of isPermitted().

> The application SecurityManager instance shouldn't need to be swapped
> at runtime.  Any changes to its configuration should be dynamically
> applied, IMO.  But this might be a different discussion - I don't see
> how modifying an existing realm instance's state would have any effect
> on the security manager.

Because the realm's class changes, Spring has to update everything
that ultimately references it. In other words, all beans that directly
or indirectly depend on the realm have to be reloaded, security
manager included.

Hope that clears things up,

Peter

Re: Updating subject with new security manager

Posted by Les Hazlewood <lh...@apache.org>.
Hi Peter,

What do you mean exactly by modifying a realm?  I would guess that you
mean changing state/attributes on an existing Realm instance.  Is this
correct?  Or are you talking about adding or removing realm instances
on the SecurityManager at runtime?

The application SecurityManager instance shouldn't need to be swapped
at runtime.  Any changes to its configuration should be dynamically
applied, IMO.  But this might be a different discussion - I don't see
how modifying an existing realm instance's state would have any effect
on the security manager.

Confused,

Les

On Thu, Sep 3, 2009 at 6:50 AM, Peter Ledbrook<pe...@cacoethes.co.uk> wrote:
> Hi,
>
> The Shiro plugin for Grails tries to support automatic reloading of
> realms. So when a user modifies a realm while the application is
> running, the change takes effect almost immediately without the user
> having to restart the servlet container. A side-effect of this feature
> is that the security manager bean is reloaded. In other words, you get
> a new instance of the security manager.
>
> The problem I'm facing is that the subject never gets updated with the
> new security manager, so the user's changes to his or her realm don't
> take effect as they should. I was using a nasty hack via Groovy to
> update the securityManager field on the subject directly, but it is a
> hack. Are there any other ways of updating the subject? Maybe creating
> a new delegating subject with the new security manager? If not, any
> ideas for changes to Shiro that might aid this?
>
> Thanks,
>
> Peter
>