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