For further background, see http://grails.markmail.org/message/62w2xpbgneapmhpd
I'm trying to mock out the Shiro SecurityUtils.getSubject() method in my BootStrap.groovy. I decided on this approach because the Subject builder in the latest Shiro version isn't available in the current version of the Nimble plugin (which I'm using). I decided to try playing with the SecurityUtils.metaClass but I have a feeling I'm missing something very fundamental about how metaClasses work. For reference, here's my Trackable class:
abstract class Trackable {
User createdBy
Date dateCreated
User lastUpdatedBy
Date lastUpdated
static constraints = {
lastUpdated(nullable:true)
lastUpdatedBy(nullable:true)
createdBy(nullable:true)
}
def beforeInsert = {
def subject
try {
subject = SecurityUtils.subject
} catch (Exception e) {
log.error "Error obtaining the subject. Message is [${e.message}]"
}
createdBy = (subject ? User.get( subject.principal ) :
User.findByUsername("admin"))
}
def beforeUpdate = {
def subject
try {
subject = SecurityUtils.subject
} catch (Exception e) {
log.error "Error obtaining the subject. Message is [${e.message}]"
}
lastUpdatedBy = (subject ? User.get( subject.principal ) :
User.findByUsername("admin"))
}
}
In my BootStrap.groovy, I have this:
def suMetaClass = new ExpandoMetaClass(SecurityUtils)
suMetaClass.'static'.getSubject = {[getPrincipal:{2}, toString:{"Canned Subject"}] as Subject}
suMetaClass.initialize()
SecurityUtils.metaClass = suMetaClass
And that works... sort of. If I print out the subject from BootStrap.groovy I get "Canned Subject". If I try to create and save instances of subclasses of Trackable, I get:
No SecurityManager accessible to this method, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. See the org.apache.shiro.SecurityUtils.getSubject() method JavaDoc for an explanation of expected environment configuration.
Am I missing something integral about how metaClasses work?
I figured out what was happening. In my BootStrap I was doing something like this:
def init = { servletContext->
switch (Environment.current.name) {
case "local":
def suMetaClass = new ExpandoMetaClass(SecurityUtils)
suMetaClass.'static'.getSubject = {[getPrincipal:{2}, toString:{"Canned Subject"}] as Subject}
suMetaClass.initialize()
SecurityUtils.metaClass = suMetaClass
new TrackableSubClass().save()
//Create some other domain instances
SecurityUtils.metaClass = null
}
//Create a couple domain instances that aren't environment specific
}
I added some debug statements and saw that the errors I was seeing were happening at the end of the init closure. I did some googling to double check how to flush my Hibernate session. Then I made the following changes:
def sessionFactory
def init = { servletContext->
switch (Environment.current.name) {
case "local":
def suMetaClass = new ExpandoMetaClass(SecurityUtils)
suMetaClass.'static'.getSubject = {[getPrincipal:{2}, toString:{"Canned Subject"}] as Subject}
suMetaClass.initialize()
SecurityUtils.metaClass = suMetaClass
new TrackableSubClass().save()
//Create some other domain instances
sessionFactory.currentSession.flush()
SecurityUtils.metaClass = null
}
//Create a couple domain instances that aren't environment specific
}
That seems to have completely resolved the issue and now I should be able to remove the cumbersome try/catch blocks from Trackable. :-)