/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.security.test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.jacc.PolicyContext;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import org.jboss.logging.Logger;
import org.jboss.security.AuthorizationManager;
import org.jboss.security.SecurityConstants;
import org.jboss.security.SecurityContext;
import org.jboss.security.SecurityContextAssociation;
import org.jboss.security.SecurityContextFactory;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.callback.SecurityAssociationHandler;
import org.jboss.security.config.ApplicationPolicy;
import org.jboss.security.config.SecurityConfiguration;
import org.jboss.security.jacc.SubjectPolicyContextHandler;
import org.jboss.security.plugins.JBossAuthorizationManager;
import org.jboss.security.plugins.JaasSecurityManager;
import org.jboss.util.TimedCachePolicy;
/** Stress testing of the JaasSecurityManager
*
* @author Scott.Stark@jboss.org
* @version $Revision: 81036 $
*/
public class SecurityMgrStressTestCase extends TestCase
{
static final int Nusers = 10;
static final Logger log = Logger.getLogger(SecurityMgrStressTestCase.class);
/**
* Constructor for the SimpleUnitTestCase object
*
* @param name Test name
*/
public SecurityMgrStressTestCase(String name)
{
super(name);
}
/** Test concurrent access to the isValid and doesUserHaveRole security
* mgr methods.
*
* @exception Exception thrown on any failure
*/
public void testMTAuthentication() throws Exception
{
//SecurityAssociation.setServer();
int count = Integer.getInteger("jbosstest.threadcount", 10).intValue();
int iterations = Integer.getInteger("jbosstest.iterationcount", 5000).intValue();
log.info("Creating "+count+" threads doing "+iterations+" iterations");
PolicyContext.registerHandler(SecurityConstants.SUBJECT_CONTEXT_KEY,
new SubjectPolicyContextHandler(), false);
AuthorizationManager am = new JBossAuthorizationManager("testIdentity");
JaasSecurityManager secMgr = new JaasSecurityManager("testIdentity", new SecurityAssociationHandler());
TimedCachePolicy cache = new TimedCachePolicy(3, false, 100);
cache.create();
cache.start();
secMgr.setCachePolicy(cache);
Thread[] testThreads = new Thread[count];
AuthTester[] testers = new AuthTester[count];
for(int t = 0; t < count; t ++)
{
int userID = t % Nusers;
AuthTester test = new AuthTester(secMgr, am, iterations, userID);
if( t == count - 2 )
test.failAuthentication();
if( t == count - 1 )
test.failAuthorization();
testers[t] = test;
Thread thr = new Thread(test, "Tester#"+t);
thr.start();
testThreads[t] = thr;
}
for(int t = 0; t < count; t ++)
{
Thread thr = testThreads[t];
thr.join();
AuthTester test = testers[t];
if( test.failAuthentication == true || test.failAuthorization == true )
assertTrue("Failure test has an error", test.error != null);
else if( test.error != null )
fail("Unexpected error seen by : "+test.error.getLocalizedMessage());
}
}
protected void setUp()
{
// Install the custom JAAS configuration
Configuration.setConfiguration(new TestConfig());
}
/** Used to run the testcase from the command line
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
TestRunner.run(SecurityMgrStressTestCase.class);
}
/** Hard coded login configurations for the test cases. The configuration
name corresponds to the unit test function that uses the configuration.
*/
private static class TestConfig extends Configuration
{
private AppConfigurationEntry[] theEntry;
TestConfig()
{
String name = "org.jboss.security.auth.spi.MemoryUsersRolesLoginModule";
Properties users = new Properties();
Properties roles = new Properties();
for(int i = 0; i < Nusers; i ++)
{
String username = "jduke"+i;
users.setProperty(username, "theduke"+i);
StringBuffer roleNames = new StringBuffer();
for(int j = 0; j < 3; j ++)
{
if( j > 0 )
roleNames.append(',');
roleNames.append(username+"-Role"+j);
}
roles.setProperty(username, roleNames.toString());
}
HashMap options = new HashMap();
options.put("users", users);
options.put("roles", roles);
AppConfigurationEntry ace = new AppConfigurationEntry(name,
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
theEntry = new AppConfigurationEntry[]{ace};
}
public AppConfigurationEntry[] getAppConfigurationEntry(String name)
{
return theEntry;
}
public void refresh()
{
}
}
private static class AuthTester implements Runnable
{
JaasSecurityManager secMgr;
int iterations;
String username;
String password;
Throwable error;
boolean failAuthentication;
boolean failAuthorization;
AuthorizationManager am;
AuthTester(JaasSecurityManager secMgr, AuthorizationManager am, int iterations, int id)
{
this.iterations = iterations;
this.secMgr = secMgr;
this.am = am;
this.username = "jduke"+id;
this.password = "theduke"+id;
}
void failAuthentication()
{
failAuthentication = true;
}
void failAuthorization()
{
failAuthorization = true;
}
public void run()
{
log.info("Begin run, t="+Thread.currentThread());
String thePassword = password;
if( failAuthentication == true )
thePassword += "-fail";
SimplePrincipal user = new SimplePrincipal(username);
HashSet roleSet = new HashSet();
for(int j = 0; j < 3; j ++)
{
String role = username+"-Role"+j;
if( failAuthorization == true )
role += "-fail";
roleSet.add(new SimplePrincipal(role));
}
try
{
for(int i = 0; i < iterations; i ++)
{
String securityDomain = secMgr.getSecurityDomain();
Subject subject = new Subject();
boolean authenticated = secMgr.isValid(user, thePassword, subject);
if( authenticated == false )
throw new SecurityException("Failed to authenticate: "+user);
SecurityConfiguration.addApplicationPolicy(new ApplicationPolicy(securityDomain));
SecurityContext sc = SecurityContextFactory.createSecurityContext(user,
thePassword, subject, securityDomain);
SecurityContextAssociation.setSecurityContext(sc);
//SecurityAssociation.pushSubjectContext(subject, user, "any");
boolean authorized = am.doesUserHaveRole(user, roleSet);
SecurityContextAssociation.clearSecurityContext();
if( authorized == false )
{
Subject s = secMgr.getActiveSubject();
throw new SecurityException("Failed to authorize, subject="+s);
}
}
}
catch(Throwable t)
{
error = t;
if( failAuthentication == false && failAuthorization == false )
log.error("Security failure", t);
}
log.info("End run, t="+Thread.currentThread());
}
}
}