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<[email protected]> 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

Reply via email to