There are three main pieces to be aware of in the Shiro authentication workflow: a Subject, the SecurityManager, and SecurityUtils. Creating a fake Subject is easy; the two things in Subject we need to worry about are the "principal" (more or less the user name) and whether or not that user is authenticated. We'll crate a Map with some simple closures and cast it as a Subject we can use:
import org.apache.shiro.subject.Subject
def subject = [ getPrincipal: { "iamauser" },
isAuthenticated: { true }
] as Subject
Now we can use that Subject wherever we need to return a subject for Shiro to act on.
The next step is making sure we have a SecurityManager in our Shiro ThreadContext object. With the SecurityManager, the only thing we need to worry about is that it returns our subject, so we'll again fake that with a Map and the "as" keyword:
import org.apache.shiro.util.ThreadContext
ThreadContext.put( ThreadContext.SECURITY_MANAGER_KEY,
[ getSubject: { subject } ] as SecurityManager )
Finally, since using Shiro's SecurityUtils makes it easy to deal with security objects in our controller code, we'll want to make sure it returns the values we want. In our case, all we really needed was the subject:
import org.apache.shiro.SecurityUtils
SecurityUtils.metaClass.static.getSubject = { subject }
That's it! In our controller test cases, we put that in our setUp() method, and we were then able to test our controllers that used Shiro's SecurityUtils to grab the current user like this:
def user
def subject = SecurityUtils.subject
if (subject.authenticated) {
user = ShiroUser.findByUsername( subject.principal )
} else {
// do something different
}
Putting together the pieces of the mock Shiro code looks like this:
import org.apache.shiro.subject.Subject
import org.apache.shiro.util.ThreadContext
import org.apache.shiro.SecurityUtils
def subject = [ getPrincipal: { "iamauser" },
isAuthenticated: { true }
] as Subject
ThreadContext.put( ThreadContext.SECURITY_MANAGER_KEY,
[ getSubject: { subject } ] as SecurityManager )
SecurityUtils.metaClass.static.getSubject = { subject }
5 comments:
This was very useful, thanks!
Fantastic, man. It didn't fix my code - but it made it testable.
!-Brandon
Really helpful.
Would've taken me a fair bit of time to figure this out.
You saved me hours.
Thanks!
'YourAdmin' ??? What's up with my view name?
Thank you very much for this detailed information about mocking Shiro in tests. That's really useful and it's missing from original Shiro Security grails plugin description.
Post a Comment