Hi Janne, I threw this together today:
http://shiro.apache.org/testing.html Feedback is welcome. I hope it helps! Best, Les On Sun, Nov 21, 2010 at 8:03 AM, Janne Jalkanen <[email protected]> wrote: > > Yup, this answers quite a few of my questions. Any chance this could be put > somewhere as a part of the official documentation as well? > Thanks heaps, tests are now running perfectly :-) > /Janne > On Nov 9, 2010, at 21:02 , Les Hazlewood wrote: > > Shiro can be configured dynamically in a single JVM - I do it all the time > on a product I'm working on. I guess it means what you mean by 'configure > dynamically'. I'm not swapping out the security manager entirely however. > I re-configure the same instance (maybe swap out its AuthorizationStrategy, > etc). > When a Subject instance is created (a DelegatingSubject specifically), it > accepts a SecurityManager instance at that time. It holds on to that > instance throughout it's lifetime. In other words, you can call > SecurityUtils.setSecurityManager at any time after that point (which sets a > VM-static singleton) and the previously instantiated Subject instance(s) > will not 'see' the new static SecurityManager instance. > Subject object instances themselves are intended to have a very short VM > lifetime - typically instantiated at the beginning of a thread's execution > and removed/garbage collected at the end of its execution. Swapping out a > SecurityManager entirely during a thread's execution is not something that > people have requested in the past, so we haven't built it. I'm not sure how > often this would occur in practice for running applications to be honest. > So to sidestep this for unit testing scenarios, there are two good > approaches that I can think of: > 1) Use a Subject.Builder and pass in the SecurityManager instance you want > it to use during the test. The constructed instance is used to 'execute' a > method under test: > Subject subject = new Subject.Builder(mySecurityManager).buildSubject(); > subject.execute( new Runnable() { > executeMethodUnderTest(); > }); > When 'executeMethodUnderTest' executes, the subject.execute method will > guarantee thread set-up and clean-up before and after the method's > execution, respectively. Also, any call to SecurityUtils.getSubject() > within that method (or any methods it calls) will work correctly. > 2) Set up and tear down the Shiro thread state before and after a test > methods's execution. This is the exact same thing as #1, but requires you > to do a little more work. See > the http://shiro.apache.org/subject.html page, "Manual Association" section > for more detail. You would do this in @Before and @After methods in JUnit: > private ThreadState shiroThreadState; > @Before > public void setUpSubject() { > Subject testSubject = Subject.Builder(securityManagerForTheTest). ... > .buildSubject(); > shiroThreadState = new SubjectThreadState(testSubject); > shiroThreadState.bind(); > } > @After > public void tearDownSubject() { > shiroThreadState.restore(); //or clear(); either is fine. > } > #1 is easier, but it might make your test cases look a little ugly. #2 is a > little more time consuming, but more flexible and arguably nicer when > keeping your tests clean. You can have this in a test superclass and your > subclasses wouldn't ever have to worry about it. They could call > SecurityUtils.getSubject() at any time and it would all work out. > Note that the Subject.Builder constructor doesn't require a securityManager > instance - if you don't provide one, it will call > SecurityUtils.getSecurityManager() and use that one instead. I typically > like to specify the instance myself because I personally don't like using > static singletons if I can avoid them, and at least in testing, I find it to > be a bit more deterministic. > Anyway, I hope this helps. Does this all make sense? > Best, > -- > Les Hazlewood > Founder, Katasoft, Inc. > Application Security Products & Professional Apache Shiro Support and > Training: > http://www.katasoft.com > On Tue, Nov 9, 2010 at 12:47 AM, Janne Jalkanen <[email protected]> > wrote: >> >> And to respond to myself - the problem turns out to be that I had one >> instance where Shiro was configured implicitly and not using the >> SHIRO_CONFIG below. Turns out that this causes a conflict if you configure >> Shiro twice with different settings within the same JVM. >> It would be good if there was some sort of a check for this - the >> exception message is not exactly helping here. >> /Janne >> On 8 Nov 2010, at 22:20, Janne Jalkanen wrote: >> >> Folks, >> I'm rather stymied at the following problem: Whenever I run my unit tests >> one at a time, everything works. But when I run the entire suite, the tests >> fail due to >> SecurityUtils.getSubject().logout(); // Ensure we are logged out >> SecurityUtils.getSubject().login( new >> UsernamePasswordToken("[email protected]","foobar") ); >> >> The failure is >> org.apache.shiro.authc.IncorrectCredentialsException: The credentials >> provided for account [org.apache.shiro.authc.UsernamePasswordToken - >> [email protected], rememberMe=false] did not match the expected credentials. >> at >> org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:191) >> at >> org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:179) >> at >> org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:264) >> at >> org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198) >> at >> org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106) >> at >> org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:269) >> at >> org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:247) >> at >> com.thinglink.site.stripes.AccountActionBeanTest.setup(AccountActionBeanTest.java:43) >> <rest is snipped away> >> I've tried different kinds of Shiro configurations, and the one that seems >> to work best right now looks like >> /** Configuration that we use in tests. */ >> private static final String SHIRO_CONFIG = >> "[main]\n"+ >> "credentialsMatcher = >> org.apache.shiro.authc.credential.Sha256CredentialsMatcher\n"+ >> "credentialsMatcher.storedCredentialsHexEncoded = false\n"+ >> "credentialsMatcher.hashSalted = true\n"+ >> "cacheManager = >> org.apache.shiro.cache.MemoryConstrainedCacheManager\n"+ >> "myRealm = com.thinglink.site.shiro.CassandraRealm\n"+ >> "myRealm.credentialsMatcher = $credentialsMatcher\n"+ >> "myRealm.cacheManager = $cacheManager\n"+ >> "securityManager = org.apache.shiro.mgt.DefaultSecurityManager\n"+ >> "securityManager.realm = $myRealm\n"; >> // For shiro we use our internal configuration, not the one that's found >> from classpath >> Ini ini = new Ini(); >> ini.load( SHIRO_CONFIG ); >> IniSecurityManagerFactory smf = new IniSecurityManagerFactory( ini >> ); >> SecurityUtils.setSecurityManager( smf.getInstance() ); >> I've tried using a WebIniSecurityManagerFactory, but the test framework >> I'm using does not fully implement the Servlet spec, so it's not that >> useful; it fails in interesting ways and getting cookies is a pain. So I >> figured I should try just simply the basic DefaultSecurityManager as >> everything runs in a single thread anyway. >> This is with 1.1.0 release. >> Any ideas as to what could explain why the tests aren't running if I run >> all the tests? The fun thing is that this is the *only* test currently which >> actively tries to log in. >> /Janne
