001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.security.test;
023:
024: import java.util.HashSet;
025: import java.util.HashMap;
026: import java.util.Properties;
027: import java.util.Iterator;
028: import javax.security.auth.login.Configuration;
029: import javax.security.auth.login.AppConfigurationEntry;
030: import javax.security.auth.Subject;
031:
032: import junit.framework.TestCase;
033: import junit.textui.TestRunner;
034:
035: import org.apache.log4j.Logger;
036: import org.jboss.security.plugins.JaasSecurityManager;
037: import org.jboss.security.SimplePrincipal;
038: import org.jboss.security.SecurityAssociation;
039: import org.jboss.security.auth.callback.SecurityAssociationHandler;
040: import org.jboss.util.TimedCachePolicy;
041:
042: /** Stress testing of the JaasSecurityManager
043: *
044: * @author Scott.Stark@jboss.org
045: * @version $Revision: 57211 $
046: */
047: public class SecurityMgrStressTestCase extends TestCase {
048: static final int Nusers = 10;
049: static final Logger log = Logger
050: .getLogger(SecurityMgrStressTestCase.class);
051:
052: /**
053: * Constructor for the SimpleUnitTestCase object
054: *
055: * @param name Test name
056: */
057: public SecurityMgrStressTestCase(String name) {
058: super (name);
059: }
060:
061: /** Test concurrent access to the isValid and doesUserHaveRole security
062: * mgr methods.
063: *
064: * @exception Exception thrown on any failure
065: */
066: public void testMTAuthentication() throws Exception {
067: SecurityAssociation.setServer();
068: int count = Integer.getInteger("jbosstest.threadcount", 10)
069: .intValue();
070: int iterations = Integer.getInteger("jbosstest.iterationcount",
071: 5000).intValue();
072: log.info("Creating " + count + " threads doing " + iterations
073: + " iterations");
074: JaasSecurityManager secMgr = new JaasSecurityManager(
075: "testIdentity", new SecurityAssociationHandler());
076: TimedCachePolicy cache = new TimedCachePolicy(3, false, 100);
077: cache.create();
078: cache.start();
079: secMgr.setCachePolicy(cache);
080: Thread[] testThreads = new Thread[count];
081: AuthTester[] testers = new AuthTester[count];
082: for (int t = 0; t < count; t++) {
083: AuthTester test = new AuthTester(secMgr, iterations, t);
084: if (t == count - 2)
085: test.failAuthentication();
086: if (t == count - 1)
087: test.failAuthorization();
088: testers[t] = test;
089: Thread thr = new Thread(test, "Tester#" + t);
090: thr.start();
091: testThreads[t] = thr;
092: }
093:
094: for (int t = 0; t < count; t++) {
095: Thread thr = testThreads[t];
096: thr.join();
097: AuthTester test = testers[t];
098: if (test.failAuthentication == true
099: || test.failAuthorization == true)
100: assertTrue("Failure test has an error",
101: test.error != null);
102: else if (test.error != null)
103: fail("Unexpected error seen by : " + test);
104: }
105: }
106:
107: protected void setUp() {
108: // Install the custom JAAS configuration
109: Configuration.setConfiguration(new TestConfig());
110: }
111:
112: /** Used to run the testcase from the command line
113: *
114: * @param args The command line arguments
115: */
116: public static void main(String[] args) {
117: TestRunner.run(SecurityMgrStressTestCase.class);
118: }
119:
120: /** Hard coded login configurations for the test cases. The configuration
121: name corresponds to the unit test function that uses the configuration.
122: */
123: private static class TestConfig extends Configuration {
124: private AppConfigurationEntry[] theEntry;
125:
126: TestConfig() {
127: String name = "org.jboss.security.auth.spi.MemoryUsersRolesLoginModule";
128: Properties users = new Properties();
129: Properties roles = new Properties();
130: for (int i = 0; i < Nusers; i++) {
131: String username = "jduke" + i;
132: users.setProperty(username, "theduke" + i);
133: StringBuffer roleNames = new StringBuffer();
134: for (int j = 0; j < 3; j++) {
135: if (j > 0)
136: roleNames.append(',');
137: roleNames.append(username + "-Role" + j);
138: }
139: roles.setProperty(username, roleNames.toString());
140: }
141:
142: HashMap options = new HashMap();
143: options.put("users", users);
144: options.put("roles", roles);
145: AppConfigurationEntry ace = new AppConfigurationEntry(
146: name,
147: AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
148: options);
149: theEntry = new AppConfigurationEntry[] { ace };
150: }
151:
152: public AppConfigurationEntry[] getAppConfigurationEntry(
153: String name) {
154: return theEntry;
155: }
156:
157: public void refresh() {
158: }
159: }
160:
161: private static class AuthTester implements Runnable {
162: JaasSecurityManager secMgr;
163: int iterations;
164: int id;
165: int userID;
166: String username;
167: String password;
168: Throwable error;
169: boolean failAuthentication;
170: boolean failAuthorization;
171:
172: AuthTester(JaasSecurityManager secMgr, int iterations, int id) {
173: this .iterations = iterations;
174: this .id = id;
175: this .userID = id % Nusers;
176: this .secMgr = secMgr;
177: this .username = "jduke" + userID;
178: this .password = "theduke" + userID;
179: }
180:
181: void failAuthentication() {
182: failAuthentication = true;
183: }
184:
185: void failAuthorization() {
186: failAuthorization = true;
187: }
188:
189: public void run() {
190: log.info("Begin run, t=" + Thread.currentThread());
191: String thePassword = password;
192: if (failAuthentication == true)
193: thePassword += "-fail";
194: SimplePrincipal user = new SimplePrincipal(username);
195: HashSet roleSet = new HashSet();
196: for (int j = 0; j < 3; j++) {
197: String role = username + "-Role" + j;
198: if (failAuthorization == true)
199: role += "-fail";
200: roleSet.add(new SimplePrincipal(role));
201: }
202:
203: try {
204: Subject subject = new Subject();
205: for (int i = 0; i < iterations; i++) {
206: if (id == 0)
207: log.debug("Begin iter#" + i);
208: subject.getPrincipals().clear();
209: subject.getPrivateCredentials().clear();
210:
211: boolean authenticated = secMgr.isValid(user,
212: thePassword, subject);
213: if (authenticated == false)
214: throw new SecurityException(
215: "Failed to authenticate: " + user);
216: SecurityAssociation.pushSubjectContext(subject,
217: user, "any");
218: boolean authorized = secMgr.doesUserHaveRole(user,
219: roleSet);
220: if (authorized == false) {
221: Subject s = secMgr.getActiveSubject();
222: SecurityAssociation.popSubjectContext();
223: throw new SecurityException(
224: "Failed to authorize, user=" + user
225: + ", subject=" + toString(s));
226: }
227: SecurityAssociation.popSubjectContext();
228: if (id == 0)
229: log.debug("End iter#" + i);
230: }
231: } catch (Throwable t) {
232: error = t;
233: if (failAuthentication == false
234: && failAuthorization == false)
235: log.error("Security failure", t);
236: }
237: log.info("End run, t=" + Thread.currentThread());
238: }
239:
240: public String toString(Subject subject) {
241: StringBuffer tmp = new StringBuffer();
242: tmp.append("Subject(");
243: tmp.append(System.identityHashCode(subject));
244: tmp.append(").principals=");
245: Iterator principals = subject.getPrincipals().iterator();
246: while (principals.hasNext()) {
247: Object p = principals.next();
248: Class c = p.getClass();
249: tmp.append(c.getName());
250: tmp.append('@');
251: tmp.append(System.identityHashCode(c));
252: tmp.append('(');
253: tmp.append(p);
254: tmp.append(')');
255: }
256: return tmp.toString();
257: }
258:
259: }
260:
261: }
|