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