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
