Subject.execute* runs in the existing thread. It does not dispatch to
another thread.
Per Peter's last suggestion (about Closures automatically implementing
Runnable), try this:
subject.execute { doBootstrap(); }
Nice and short. Gotta love Groovy ;)
- Les
On Thu, Oct 29, 2009 at 12:57 PM, Scott Ryan <[email protected]> wrote:
> 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
>>>
>>>
>
>