shiro-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Janne Jalkanen <Janne.Jalka...@ecyrd.com>
Subject Re: Weird unit testing problem
Date Sun, 21 Nov 2010 16:03:48 GMT

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 <janne.jalkanen@ecyrd.com> 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("test@thinglink.com","foobar")
);
>>  
>> The failure is 
>> 
>> org.apache.shiro.authc.IncorrectCredentialsException: The credentials provided for
account [org.apache.shiro.authc.UsernamePasswordToken - jj@thinglink.com, 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


Mime
View raw message