That process does not actually work. When the bootstrap is called (not by me but by the framework) the thread is already loaded with much of the grails stuff. If I spin off a new thread as you suggest (In Grails/Groovy I have to use Thread.start) all of the grails loaded stuff on the thread is not there and none of my bootstrap stuff works. I don't control the entry to the bootstrap and I need the stuff that is on the thread when I enter the bootstrap. I was not able to use your Runnable strategy as groovy does not like the syntax. Also if I try to clear the thread when i am done threadState.clear(); it also unloads the other security managers from the thread which were already there and I get some errors. Most of the code works ok.

I will try to use your subject.execute strategy but I need to figure out how to run on the existing thread so i can keep the grails stuff.

If there a way to tie the subject to the existing thread? I know i can't use the manual thread stuff and keep a clean system but this is only for development.

I will continue to experiment with different strategies.

I assume the thread I am on is destroyed after the bootstrap process anyway so the risk is pretty minimal and this is only used in development.

Scott Ryan
President/CTO
Soaring Eagle L.L.C.
[email protected]
(303) 263-3044

On Oct 29, 2009, at 10:46 AM, Les Hazlewood wrote:

Just a note - you should not use the ThreadState stuff as shown in
your code sample.  Instead use my example that executes a Runnable and
calls the 'doBootstrap' method (that you implement).

As documented in the Subject wiki page, if you use ThreadState
objects, you _must_ ensure that a thread is cleaned up after use.
Just calling ThreadState.bind() is not good enough - you must also
clear() it at the end of the thread execution.

The Subject.execute* methods perform this cleanup automatically and
you don't need to worry about ThreadState objects - a cleaner
approach, and easier to use.  For your case, you should the
Subject.execute methods instead.  Manual ThreadState manipulation is
really best left to lower-level framework programming.

Best,

Les

On Thu, Oct 29, 2009 at 12:33 PM, Scott Ryan <[email protected]> wrote:
SUCCESS!!!

I had to attach to the current thread due to all the grailsy stuff going on in the bootstrap but here is my code that appears to work. I will clean it up quite a lot and publish a solution on the mailing list and on my blog.

import org.apache.shiro.subject.Subject
import org.apache.shiro.subject.PrincipalCollection
import org.apache.shiro.subject.SimplePrincipalCollection
import org.apache.shiro.util.ThreadState
import org.apache.shiro.subject.support.SubjectThreadState
import org.apache.shiro.mgt.DefaultSecurityManager
import org.apache.shiro.mgt.SecurityManager

class BootStrap
{

   def shiroSecurityManager
   def init =
   {servletContext ->

buildSubject()
// RUN ALL your bootstrap code here

void buildSubject()
   {
// TODO Clean this up and add all realms if requirred
       Object userIdentity = "admin";
       def realms = shiroSecurityManager.realms
       println "ralsm cont" + realms?.size()
       def realm
       realms.each()
       {
           realm = it
       }
       //  Realm localizedRealm = shiroSecurityManager.realms
       SecurityManager bootstrapSecurityManager = new
DefaultSecurityManager(realm);
       PrincipalCollection principals = new
SimplePrincipalCollection(userIdentity, realm.getName());
       Subject subject = new
Subject .Builder (bootstrapSecurityManager).principals(principals).buildSubject();
       ThreadState threadState = new SubjectThreadState(subject);
       threadState.bind();
   }
}

All of my domain objects extend the BaseDomain

public abstract class BaseDomain
{
   static constraints =
   {
       // TODO Set some to be required
       dateCreated(nullable: true)
       createUser(nullable: true)
       lastUpdated(nullable: true)
       updateUser(nullable: true)
   }
   /** The date this entry was created */
   Date dateCreated
   /** The username that created this entry */
   String createUser
   /** The date this entry was last updated */
   Date lastUpdated
   /** The username that last updated this entry */
   String updateUser
   /** Before insert the database should populate the username
    * on the createUser.  The timestamp will be taken care of by the
    * grails framework automatically.
    */
   transient beforeInsert =
   {
       try
       {
           createUser =  SecurityUtils?.getSubject()?.getPrincipal()
       }
       catch (Exception ex)
       {

            log.fatal ("Exception in before Insert ", ex)

       }
   }
   /** Before update the database should populate the username
    * on the updateUser.  The timestamp will be taken care of by the
    * framework automatically.
    */
   transient beforeUpdate =
   {
       try
       {
           updateUser = SecurityUtils?.getSubject()?.getPrincipal()
       }
       catch (Exception ex)
       {

           log.fatal ("Exception in before Update ", ex)

       }
   }
}


Thanks so much for all your assistance as I know a lot of people have been
trying to get this to work.


Scott Ryan
President/CTO
Soaring Eagle L.L.C.
[email protected]
(303) 263-3044

On Oct 29, 2009, at 9:35 AM, Peter Ledbrook wrote:

Yes I think it is not running in a request/response mode. Just a dumb question as i implement your solution. I tried this earlier but since
Runnable is an interface it does not let me create one so I must be
missing
a parenthesis or something?

Correct, BootStrap is executed during servlet context startup, so
there is not request or response.

I will try out your suggestions and offer feedback. I think it would be nice to have access to both security managers from the plugin so you
could
use the same code during both processes.

The BootStrap instances are auto-wired by Spring, so you have access
to the Spring application context. I would consider grabbing the
"shiroSecurityManager" bean and copying the realms from there into
your own temporary (non-web) security manager. I say copy the realms,
but I mean the references to them.

That's if you even need the realms.

Cheers,

Peter



Reply via email to