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.rmi.RemoteException;
025: import java.rmi.AccessException;
026: import java.rmi.ServerException;
027: import java.util.HashSet;
028: import java.util.Set;
029: import javax.ejb.Handle;
030: import javax.management.MBeanServerInvocationHandler;
031: import javax.management.MBeanServerConnection;
032: import javax.management.ObjectName;
033: import javax.naming.InitialContext;
034: import javax.rmi.PortableRemoteObject;
035: import javax.jms.Message;
036: import javax.jms.Queue;
037: import javax.jms.QueueConnection;
038: import javax.jms.QueueConnectionFactory;
039: import javax.jms.QueueReceiver;
040: import javax.jms.QueueSender;
041: import javax.jms.QueueSession;
042: import javax.jms.Session;
043: import javax.security.auth.login.Configuration;
044: import javax.security.auth.login.LoginContext;
045:
046: import org.jboss.security.auth.login.XMLLoginConfigImpl;
047: import org.jboss.security.plugins.JaasSecurityManagerServiceMBean;
048: import org.jboss.security.SimplePrincipal;
049: import org.jboss.test.JBossTestCase;
050: import org.jboss.test.JBossTestSetup;
051: import org.jboss.test.security.interfaces.CalledSession;
052: import org.jboss.test.security.interfaces.CalledSessionHome;
053: import org.jboss.test.security.interfaces.StatefulSession;
054: import org.jboss.test.security.interfaces.StatefulSessionHome;
055: import org.jboss.test.security.interfaces.StatelessSession;
056: import org.jboss.test.security.interfaces.StatelessSessionHome;
057: import org.jboss.test.security.interfaces.SecurityContext;
058: import org.jboss.test.security.interfaces.SecurityContextHome;
059: import org.jboss.test.security.ejb.jbas1852.SessionFacade;
060: import org.jboss.test.security.ejb.jbas1852.SessionFacadeHome;
061: import org.jboss.test.util.AppCallbackHandler;
062: import org.apache.log4j.Logger;
063:
064: import junit.extensions.TestSetup;
065: import junit.framework.Test;
066: import junit.framework.TestSuite;
067:
068: /** Test of EJB spec conformace using the security-spec.jar
069: deployment unit. These test the basic role based access model.
070:
071: @author Scott.Stark@jboss.org
072: @version $Revision: 57211 $
073: */
074: public class EJBSpecUnitTestCase extends JBossTestCase {
075: static String username = "scott";
076: static char[] password = "echoman".toCharArray();
077: static String QUEUE_FACTORY = "ConnectionFactory";
078:
079: LoginContext lc;
080: boolean loggedIn;
081:
082: public EJBSpecUnitTestCase(String name) {
083: super (name);
084: }
085:
086: /** Validate that the users have the expected logins and roles.
087: *
088: * @throws Exception
089: */
090: public void testSecurityDomain() throws Exception {
091: log.info("+++ testSecurityDomain, domain=spec-test");
092: MBeanServerConnection conn = (MBeanServerConnection) getServer();
093: ObjectName secMgrName = new ObjectName(
094: "jboss.security:service=JaasSecurityManager");
095: JaasSecurityManagerServiceMBean secMgr = (JaasSecurityManagerServiceMBean) MBeanServerInvocationHandler
096: .newProxyInstance(conn, secMgrName,
097: JaasSecurityManagerServiceMBean.class, false);
098:
099: // Test the spec-test security domain
100: String domain = "spec-test";
101: SimplePrincipal user = new SimplePrincipal("scott");
102: boolean isValid = secMgr.isValid(domain, user, password);
103: assertTrue("scott password is echoman", isValid);
104: HashSet testRole = new HashSet();
105: testRole.add(new SimplePrincipal("Echo"));
106: boolean hasRole = secMgr.doesUserHaveRole(domain, user,
107: password, testRole);
108: assertTrue("scott has Echo role", hasRole);
109: testRole.clear();
110: testRole.add(new SimplePrincipal("EchoLocal"));
111: hasRole = secMgr.doesUserHaveRole(domain, user, password,
112: testRole);
113: assertTrue("scott has EchoLocal role", hasRole);
114: testRole.clear();
115: testRole.add(new SimplePrincipal("ProjectUser"));
116: hasRole = secMgr.doesUserHaveRole(domain, user, password,
117: testRole);
118: assertTrue("scott has ProjectUser role", hasRole);
119:
120: isValid = secMgr.isValid(domain, user, "badpass".toCharArray());
121: assertTrue("badpass is an invalid password for scott",
122: isValid == false);
123:
124: // Test the spec-test-domain security domain
125: log.info("+++ testSecurityDomain, domain=spec-test-domain");
126: domain = "spec-test-domain";
127: isValid = secMgr.isValid(domain, user, password);
128: assertTrue("scott password is echoman", isValid);
129: hasRole = secMgr.doesUserHaveRole(domain, user, password,
130: testRole);
131: assertTrue("scott has Echo role", hasRole);
132: testRole.clear();
133: SimplePrincipal echoLocal = new SimplePrincipal("EchoLocal");
134: testRole.add(echoLocal);
135: hasRole = secMgr.doesUserHaveRole(domain, user, password,
136: testRole);
137: assertTrue("scott has EchoLocal role", hasRole);
138: testRole.clear();
139: SimplePrincipal projectUser = new SimplePrincipal("ProjectUser");
140: testRole.add(projectUser);
141: hasRole = secMgr.doesUserHaveRole(domain, user, password,
142: testRole);
143: assertTrue("scott has ProjectUser role", hasRole);
144: Set roles = secMgr.getUserRoles(domain, user, password);
145: assertTrue(roles != null);
146: assertTrue("roles contains EchoLocal", roles
147: .contains(echoLocal));
148: assertTrue("roles contains ProjectUser", roles
149: .contains(projectUser));
150:
151: isValid = secMgr.isValid(domain, user, "badpass".toCharArray());
152: assertTrue("badpass is an invalid password for scott",
153: isValid == false);
154: }
155:
156: /** Test the use of getCallerPrincipal from within the ejbCreate
157: * in a stateful session bean
158: */
159: public void testStatefulCreateCaller() throws Exception {
160: log.debug("+++ testStatefulCreateCaller");
161: login();
162: InitialContext jndiContext = new InitialContext();
163: Object obj = jndiContext.lookup("spec.StatefulSession");
164: obj = PortableRemoteObject.narrow(obj,
165: StatefulSessionHome.class);
166: StatefulSessionHome home = (StatefulSessionHome) obj;
167: log.debug("Found StatefulSessionHome");
168: // The create should be allowed to call getCallerPrincipal
169: StatefulSession bean = home.create("testStatefulCreateCaller");
170: // Need to invoke a method to ensure an ejbCreate call
171: bean.echo("testStatefulCreateCaller");
172: log.debug("Bean.echo(), ok");
173:
174: logout();
175: }
176:
177: /** Test that:
178: 1. SecureBean returns a non-null principal when getCallerPrincipal
179: is called with a security context and that this is propagated
180: to its Entity bean ref.
181:
182: 2. UnsecureBean throws an IllegalStateException when getCallerPrincipal
183: is called without a security context.
184: */
185: public void testGetCallerPrincipal() throws Exception {
186: logout();
187: log.debug("+++ testGetCallerPrincipal()");
188: Object obj = getInitialContext().lookup(
189: "spec.UnsecureStatelessSession2");
190: obj = PortableRemoteObject.narrow(obj,
191: StatelessSessionHome.class);
192: StatelessSessionHome home = (StatelessSessionHome) obj;
193: log.debug("Found Unsecure StatelessSessionHome");
194: StatelessSession bean = home.create();
195: log.debug("Created spec.UnsecureStatelessSession2");
196:
197: try {
198: // This should fail because echo calls getCallerPrincipal()
199: bean.echo("Hello from nobody?");
200: fail("Was able to call StatelessSession.echo");
201: } catch (RemoteException e) {
202: log.debug("echo failed as expected");
203: }
204: bean.remove();
205:
206: login();
207: obj = getInitialContext().lookup("spec.StatelessSession2");
208: obj = PortableRemoteObject.narrow(obj,
209: StatelessSessionHome.class);
210: home = (StatelessSessionHome) obj;
211: log.debug("Found spec.StatelessSession2");
212: bean = home.create();
213: log.debug("Created spec.StatelessSession2");
214: // Test that the Entity bean sees username as its principal
215: String echo = bean.echo(username);
216: log.debug("bean.echo(username) = " + echo);
217: assertTrue("username == echo", echo.equals(username));
218: bean.remove();
219: }
220:
221: /**
222: * Test that a call interacting with different security domains does not
223: * change the
224: * @throws Exception
225: */
226: public void testDomainInteraction() throws Exception {
227: logout();
228: login("testDomainInteraction", "testDomainInteraction"
229: .toCharArray());
230: log.debug("+++ testDomainInteraction()");
231: Object obj = getInitialContext().lookup(
232: "spec.UserInRoleContextSession");
233: obj = PortableRemoteObject.narrow(obj,
234: SecurityContextHome.class);
235: SecurityContextHome home = (SecurityContextHome) obj;
236: log.debug("Found UserInRoleContextSession");
237: SecurityContext bean = home.create();
238: log.debug("Created spec.UserInRoleContextSession");
239: HashSet roles = new HashSet();
240: roles.add("Role1");
241: roles.add("Role2");
242: bean.testDomainInteraction(roles);
243: bean.remove();
244: }
245:
246: /** Test that the calling principal is propagated across bean calls.
247: */
248: public void testPrincipalPropagation() throws Exception {
249: log.debug("+++ testPrincipalPropagation");
250: logout();
251: login();
252: Object obj = getInitialContext().lookup(
253: "spec.UnsecureStatelessSession2");
254: obj = PortableRemoteObject.narrow(obj,
255: StatelessSessionHome.class);
256: StatelessSessionHome home = (StatelessSessionHome) obj;
257: log.debug("Found Unsecure StatelessSessionHome");
258: StatelessSession bean = home.create();
259: log.debug("Created spec.UnsecureStatelessSession2");
260: log.debug("Bean.forward('testPrincipalPropagation') -> "
261: + bean.forward("testPrincipalPropagation"));
262: bean.remove();
263: }
264:
265: /** Test that the echo method is accessible by an Echo
266: role. Since the noop() method of the StatelessSession
267: bean was not assigned any permissions it should be unchecked.
268: */
269: public void testMethodAccess() throws Exception {
270: log.debug("+++ testMethodAccess");
271: login();
272: Object obj = getInitialContext()
273: .lookup("spec.StatelessSession");
274: obj = PortableRemoteObject.narrow(obj,
275: StatelessSessionHome.class);
276: StatelessSessionHome home = (StatelessSessionHome) obj;
277: log.debug("Found StatelessSessionHome");
278: StatelessSession bean = home.create();
279: log.debug("Created spec.StatelessSession");
280: log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
281:
282: try {
283: // This should not be allowed
284: bean.noop();
285: fail("Was able to call StatelessSession.noop");
286: } catch (RemoteException e) {
287: log.debug("StatelessSession.noop failed as expected");
288: }
289: bean.remove();
290: }
291:
292: /** Test that the echo method is accessible by an Echo
293: role. Since the excluded() method of the StatelessSession
294: bean has been placed into the excluded set it should not
295: accessible by any user. This uses the security domain of the
296: JaasSecurityDomain service to test its use as an authentication mgr.
297: */
298: public void testDomainMethodAccess() throws Exception {
299: log.debug("+++ testDomainMethodAccess");
300: login();
301: Object obj = getInitialContext().lookup(
302: "spec.StatelessSessionInDomain");
303: obj = PortableRemoteObject.narrow(obj,
304: StatelessSessionHome.class);
305: StatelessSessionHome home = (StatelessSessionHome) obj;
306: log.debug("Found StatelessSessionInDomain home");
307: StatelessSession bean = home.create();
308: log.debug("Created spec.StatelessSessionInDomain");
309: log.debug("Bean.echo('testDomainMethodAccess') -> "
310: + bean.echo("testDomainMethodAccess"));
311:
312: try {
313: // This should not be allowed
314: bean.excluded();
315: fail("Was able to call StatelessSession.excluded");
316: } catch (RemoteException e) {
317: log.debug("StatelessSession.excluded failed as expected");
318: }
319: bean.remove();
320: }
321:
322: /** Test that the permissions assigned to the stateless session bean:
323: with ejb-name=org/jboss/test/security/ejb/StatelessSession_test
324: are read correctly.
325: */
326: public void testMethodAccess2() throws Exception {
327: log.debug("+++ testMethodAccess2");
328: login();
329: InitialContext jndiContext = new InitialContext();
330: Object obj = jndiContext.lookup("spec.StatelessSession_test");
331: obj = PortableRemoteObject.narrow(obj,
332: StatelessSessionHome.class);
333: StatelessSessionHome home = (StatelessSessionHome) obj;
334: log.debug("Found StatelessSessionHome");
335: StatelessSession bean = home.create();
336: log.debug("Created spec.StatelessSession_test");
337: log.debug("Bean.echo('testMethodAccess2') -> "
338: + bean.echo("testMethodAccess2"));
339: bean.remove();
340: }
341:
342: /** Test a user with Echo and EchoLocal roles can access the CalleeBean
343: through its local interface by calling the CallerBean and that a user
344: with only a EchoLocal cannot call the CallerBean.
345: */
346: public void testLocalMethodAccess() throws Exception {
347: log.debug("+++ testLocalMethodAccess");
348: login();
349: InitialContext jndiContext = new InitialContext();
350: Object obj = jndiContext.lookup("spec.CallerBean");
351: obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
352: CalledSessionHome home = (CalledSessionHome) obj;
353: log.debug("Found spec.CallerBean Home");
354: CalledSession bean = home.create();
355: log.debug("Created spec.CallerBean");
356: log.debug("Bean.invokeEcho('testLocalMethodAccess') -> "
357: + bean.invokeEcho("testLocalMethodAccess"));
358: bean.remove();
359: }
360:
361: /** Test access to a bean with a mix of remote interface permissions and
362: * unchecked permissions with the unchecked permissions declared first.
363: * @throws Exception
364: */
365: public void testUncheckedRemote() throws Exception {
366: log.debug("+++ testUncheckedRemote");
367: login();
368: Object obj = getInitialContext().lookup(
369: "spec.UncheckedSessionRemoteLast");
370: obj = PortableRemoteObject.narrow(obj,
371: StatelessSessionHome.class);
372: StatelessSessionHome home = (StatelessSessionHome) obj;
373: log.debug("Found UncheckedSessionRemoteLast");
374: StatelessSession bean = home.create();
375: log.debug("Created spec.UncheckedSessionRemoteLast");
376: log.debug("Bean.echo('testUncheckedRemote') -> "
377: + bean.echo("testUncheckedRemote"));
378: try {
379: bean.excluded();
380: fail("Was able to call UncheckedSessionRemoteLast.excluded");
381: } catch (RemoteException e) {
382: log
383: .debug("UncheckedSessionRemoteLast.excluded failed as expected");
384: }
385: bean.remove();
386: logout();
387: }
388:
389: /** Test access to a bean with a mix of remote interface permissions and
390: * unchecked permissions with the unchecked permissions declared last.
391: * @throws Exception
392: */
393: public void testRemoteUnchecked() throws Exception {
394: log.debug("+++ testRemoteUnchecked");
395: login();
396: Object obj = getInitialContext().lookup(
397: "spec.UncheckedSessionRemoteFirst");
398: obj = PortableRemoteObject.narrow(obj,
399: StatelessSessionHome.class);
400: StatelessSessionHome home = (StatelessSessionHome) obj;
401: log.debug("Found UncheckedSessionRemoteFirst");
402: StatelessSession bean = home.create();
403: log.debug("Created spec.UncheckedSessionRemoteFirst");
404: log.debug("Bean.echo('testRemoteUnchecked') -> "
405: + bean.echo("testRemoteUnchecked"));
406: try {
407: bean.excluded();
408: fail("Was able to call UncheckedSessionRemoteFirst.excluded");
409: } catch (RemoteException e) {
410: log
411: .debug("UncheckedSessionRemoteFirst.excluded failed as expected");
412: }
413: bean.remove();
414: logout();
415: }
416:
417: /** Test that a user with a role that has not been assigned any
418: method permissions in the ejb-jar descriptor is able to access a
419: method that has been marked as unchecked.
420: */
421: public void testUnchecked() throws Exception {
422: log.debug("+++ testUnchecked");
423: // Login as scott to create the bean
424: login();
425: Object obj = getInitialContext()
426: .lookup("spec.StatelessSession");
427: obj = PortableRemoteObject.narrow(obj,
428: StatelessSessionHome.class);
429: StatelessSessionHome home = (StatelessSessionHome) obj;
430: log.debug("Found spec.StatelessSession Home");
431: StatelessSession bean = home.create();
432: log.debug("Created spec.StatelessSession");
433: // Logout and login back in as stark to test access to the unchecked method
434: logout();
435: login("stark", "javaman".toCharArray());
436: bean.unchecked();
437: log.debug("Called Bean.unchecked()");
438: logout();
439: }
440:
441: /** Test that a user with a valid role is able to access a
442: bean for which all methods have been marked as unchecked.
443: */
444: public void testUncheckedWithLogin() throws Exception {
445: log.debug("+++ testUncheckedWithLogin");
446: // Login as scott to see that a user with roles is allowed access
447: login();
448: Object obj = getInitialContext()
449: .lookup("spec.UncheckedSession");
450: obj = PortableRemoteObject.narrow(obj,
451: StatelessSessionHome.class);
452: StatelessSessionHome home = (StatelessSessionHome) obj;
453: log.debug("Found spec.StatelessSession Home");
454: StatelessSession bean = home.create();
455: log.debug("Created spec.StatelessSession");
456: bean.unchecked();
457: log.debug("Called Bean.unchecked()");
458: logout();
459: }
460:
461: /** Test that user scott who has the Echo role is not able to
462: access the StatelessSession2.excluded method even though
463: the Echo role has been granted access to all methods of
464: StatelessSession2 to test that the excluded-list takes
465: precendence over the method-permissions.
466: */
467: public void testExcluded() throws Exception {
468: log.debug("+++ testExcluded");
469: login();
470: Object obj = getInitialContext().lookup(
471: "spec.StatelessSession2");
472: obj = PortableRemoteObject.narrow(obj,
473: StatelessSessionHome.class);
474: StatelessSessionHome home = (StatelessSessionHome) obj;
475: log.debug("Found spec.StatelessSession2 Home");
476: StatelessSession bean = home.create();
477: log.debug("Created spec.StatelessSession2");
478: try {
479: bean.excluded();
480: fail("Was able to call Bean.excluded()");
481: } catch (Exception e) {
482: log.debug("Bean.excluded() failed as expected");
483: // This is what we expect
484: }
485: logout();
486: }
487:
488: /** This method tests the following call chains:
489: 1. RunAsStatelessSession.echo() -> PrivateEntity.echo()
490: 2. RunAsStatelessSession.noop() -> RunAsStatelessSession.excluded()
491: 3. RunAsStatelessSession.forward() -> StatelessSession.echo()
492: 1. Should succeed because the run-as identity of RunAsStatelessSession
493: is valid for accessing PrivateEntity.
494: 2. Should succeed because the run-as identity of RunAsStatelessSession
495: is valid for accessing RunAsStatelessSession.excluded().
496: 3. Should fail because the run-as identity of RunAsStatelessSession
497: is not Echo.
498: */
499: public void testRunAs() throws Exception {
500: log.debug("+++ testRunAs");
501: login();
502: Object obj = getInitialContext().lookup(
503: "spec.RunAsStatelessSession");
504: obj = PortableRemoteObject.narrow(obj,
505: StatelessSessionHome.class);
506: StatelessSessionHome home = (StatelessSessionHome) obj;
507: log.debug("Found RunAsStatelessSession Home");
508: StatelessSession bean = home.create();
509: log.debug("Created spec.RunAsStatelessSession");
510: log
511: .debug("Bean.echo('testRunAs') -> "
512: + bean.echo("testRunAs"));
513: bean.noop();
514: log.debug("Bean.noop(), ok");
515:
516: try {
517: // This should not be allowed
518: bean.forward("Hello");
519: fail("Was able to call RunAsStatelessSession.forward");
520: } catch (RemoteException e) {
521: log.debug("StatelessSession.forward failed as expected");
522: }
523: bean.remove();
524: }
525:
526: /** This method tests the following call chain:
527: Level1CallerBean.callEcho() -> Level2CallerBean.invokeEcho()
528: -> Level3CalleeBean.echo()
529: The Level1CallerBean uses a run-as of InternalRole and the Level2CallerBean
530: and Level3CalleeBean are only accessible by InternalRole.
531: */
532: public void testDeepRunAs() throws Exception {
533: log.debug("+++ testDeepRunAs");
534: login();
535: Object obj = getInitialContext()
536: .lookup("spec.Level1CallerBean");
537: obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
538: CalledSessionHome home = (CalledSessionHome) obj;
539: log.debug("Found Level1CallerBean Home");
540: CalledSession bean = home.create();
541: log.debug("Created spec.Level1CallerBean");
542: bean.callEcho();
543: log.debug("Bean.callEcho() ok");
544: bean.remove();
545:
546: // Make sure we cannot access Level2CallerBean remotely
547: obj = getInitialContext().lookup("spec.Level2CallerBean");
548: obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
549: home = (CalledSessionHome) obj;
550: log.debug("Found Level2CallerBean Home");
551: try {
552: bean = home.create();
553: fail("Was able to create Level2CallerBean");
554: } catch (ServerException e) {
555: AccessException ae = (AccessException) e.detail;
556: log.debug("Caught AccessException as expected", ae);
557: } catch (AccessException e) {
558: log.debug("Caught AccessException as expected", e);
559: }
560: }
561:
562: public void testRunAsSFSB() throws Exception {
563: log.info("+++ testRunAsSFSB");
564: login();
565: Object obj = getInitialContext().lookup(
566: "spec.CallerFacadeBean-testRunAsSFSB");
567: obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
568: CalledSessionHome home = (CalledSessionHome) obj;
569: log.debug("Found CallerFacadeBean-testRunAsSFSB Home");
570: CalledSession bean = home.create();
571: log.debug("Created spec.CallerFacadeBean-testRunAsSFSB");
572: bean.invokeEcho("testRunAsSFSB");
573: log.debug("Bean.invokeEcho() ok");
574: bean.remove();
575: }
576:
577: /**
578: * Test the run-as side-effects raised in
579: * http://jira.jboss.com/jira/browse/JBAS-1852
580: *
581: * @throws Exception
582: */
583: public void testJBAS1852() throws Exception {
584: log.info("+++ testJBAS1852");
585: login();
586: Object obj = getInitialContext().lookup(
587: "spec.PublicSessionFacade");
588: obj = PortableRemoteObject.narrow(obj, SessionFacadeHome.class);
589: SessionFacadeHome home = (SessionFacadeHome) obj;
590: log.debug("Found PublicSessionFacade home");
591: SessionFacade bean = home.create();
592: log.debug("Created PublicSessionFacade");
593: log.debug("Bean.callEcho('testJBAS1852') -> "
594: + bean.callEcho("testJBAS1852"));
595: bean.remove();
596: }
597:
598: /** Test that an MDB with a run-as identity is able to access secure EJBs
599: that require the identity.
600: */
601: public void testMDBRunAs() throws Exception {
602: log.debug("+++ testMDBRunAs");
603: logout();
604: QueueConnectionFactory queueFactory = (QueueConnectionFactory) getInitialContext()
605: .lookup(QUEUE_FACTORY);
606: Queue queA = (Queue) getInitialContext().lookup("queue/QueueA");
607: Queue queB = (Queue) getInitialContext().lookup("queue/QueueB");
608: QueueConnection queueConn = queueFactory
609: .createQueueConnection();
610: QueueSession session = queueConn.createQueueSession(false,
611: Session.AUTO_ACKNOWLEDGE);
612: Message msg = session.createMessage();
613: msg.setStringProperty("arg", "testMDBRunAs");
614: msg.setJMSReplyTo(queB);
615: QueueSender sender = session.createSender(queA);
616: sender.send(msg);
617: sender.close();
618: log.debug("Sent msg to queue/QueueA");
619: queueConn.start();
620: QueueReceiver recv = session.createReceiver(queB);
621: msg = recv.receive(5000);
622: log.debug("Recv msg: " + msg);
623: String info = msg.getStringProperty("reply");
624: recv.close();
625: session.close();
626: queueConn.close();
627:
628: if (info == null || info.startsWith("Failed")) {
629: fail("Recevied exception reply, info=" + info);
630: }
631: }
632:
633: /** Test that an MDB with a run-as identity is able to access secure EJBs
634: that require the identity. DeepRunAsMDB -> Level1MDBCallerBean.callEcho() ->
635: Level2CallerBean.invokeEcho() -> Level3CalleeBean.echo()
636: The MDB uses a run-as of InternalRole and the Level2CallerBean
637: and Level3CalleeBean are only accessible by InternalRole.
638: */
639: public void testMDBDeepRunAs() throws Exception {
640: log.debug("+++ testMDBDeepRunAs");
641: logout();
642: QueueConnectionFactory queueFactory = (QueueConnectionFactory) getInitialContext()
643: .lookup(QUEUE_FACTORY);
644: Queue queD = (Queue) getInitialContext().lookup("queue/QueueD");
645: Queue queB = (Queue) getInitialContext().lookup("queue/QueueB");
646: QueueConnection queueConn = queueFactory
647: .createQueueConnection();
648: QueueSession session = queueConn.createQueueSession(false,
649: Session.AUTO_ACKNOWLEDGE);
650: Message msg = session.createMessage();
651: msg.setStringProperty("arg", "testMDBDeepRunAs");
652: msg.setJMSReplyTo(queB);
653: QueueSender sender = session.createSender(queD);
654: sender.send(msg);
655: sender.close();
656: log.debug("Sent msg to " + queD);
657: queueConn.start();
658: QueueReceiver recv = session.createReceiver(queB);
659: msg = recv.receive(5000);
660: log.debug("Recv msg: " + msg);
661: String info = msg.getStringProperty("reply");
662: recv.close();
663: session.close();
664: queueConn.close();
665:
666: if (info == null || info.startsWith("Failed")) {
667: fail("Recevied exception reply, info=" + info);
668: }
669: }
670:
671: /** This method tests that the RunAsWithRolesMDB is assigned multiple roles
672: * within its onMessage so that it can call into the ProjRepository session
673: * bean's methods that required ProjectAdmin, CreateFolder and DeleteFolder
674: * roles.
675: */
676: public void testRunAsWithRoles() throws Exception {
677: log.debug("+++ testRunAsWithRoles");
678: logout();
679: QueueConnectionFactory queueFactory = (QueueConnectionFactory) getInitialContext()
680: .lookup(QUEUE_FACTORY);
681: Queue queC = (Queue) getInitialContext().lookup("queue/QueueC");
682: Queue queB = (Queue) getInitialContext().lookup("queue/QueueB");
683: QueueConnection queueConn = queueFactory
684: .createQueueConnection();
685: QueueSession session = queueConn.createQueueSession(false,
686: Session.AUTO_ACKNOWLEDGE);
687: Message msg = session.createMessage();
688: msg.setStringProperty("name", "testRunAsWithRoles");
689: msg.setJMSReplyTo(queB);
690: QueueSender sender = session.createSender(queC);
691: sender.send(msg);
692: sender.close();
693: log.debug("Sent msg to queue/QueueC");
694: queueConn.start();
695: QueueReceiver recv = session.createReceiver(queB);
696: msg = recv.receive(5000);
697: log.debug("Recv msg: " + msg);
698: String info = msg.getStringProperty("reply");
699: recv.close();
700: session.close();
701: queueConn.close();
702:
703: if (info == null || info.startsWith("Failed")) {
704: fail("Recevied exception reply, info=" + info);
705: }
706: }
707:
708: /** Test the security behavior of handles. To obtain secured bean from
709: a handle that the handle be
710: */
711: public void testHandle() throws Exception {
712: log.debug("+++ testHandle");
713: login();
714: Object obj = getInitialContext()
715: .lookup("spec.StatelessSession");
716: obj = PortableRemoteObject.narrow(obj,
717: StatelessSessionHome.class);
718: StatelessSessionHome home = (StatelessSessionHome) obj;
719: log.debug("Found StatelessSessionHome");
720: StatelessSession bean = home.create();
721: log.debug("Created spec.StatelessSession");
722: Handle h = bean.getHandle();
723: log.debug("Obtained handle: " + h);
724: bean = (StatelessSession) h.getEJBObject();
725: log.debug("Obtained bean from handle: " + bean);
726: log.debug("Bean.echo('testHandle') -> "
727: + bean.echo("testHandle"));
728: logout();
729:
730: /* Attempting to obtain the EJB fron the handle without security
731: association present should fail
732: */
733: try {
734: bean = (StatelessSession) h.getEJBObject();
735: fail("Should not be able to obtain a bean without login info");
736: } catch (Exception e) {
737: log
738: .debug("Obtaining bean from handle failed as expected, e="
739: + e.getMessage());
740: }
741:
742: // One should be able to obtain a handle without a login
743: h = bean.getHandle();
744: login();
745: // Now we should be able to obtain and use the secure bean
746: bean = (StatelessSession) h.getEJBObject();
747: log.debug("Obtained bean from handle: " + bean);
748: log.debug("Bean.echo('testHandle2') -> "
749: + bean.echo("testHandle2"));
750: logout();
751: }
752:
753: /** Test the security behavior of stateful handles. To obtain secured bean
754: from a handle requires that there be a security context to obtain the ejb.
755: */
756: public void testStatefulHandle() throws Exception {
757: log.debug("+++ testStatefulHandle");
758: login();
759: Object obj = getInitialContext().lookup("spec.StatefulSession");
760: obj = PortableRemoteObject.narrow(obj,
761: StatefulSessionHome.class);
762: StatefulSessionHome home = (StatefulSessionHome) obj;
763: log.debug("Found StatefulSession");
764: StatefulSession bean = home.create("testStatefulHandle");
765: log.debug("Created spec.StatelessSession");
766: Handle h = bean.getHandle();
767: log.debug("Obtained handle: " + h);
768: bean = (StatefulSession) h.getEJBObject();
769: log.debug("Obtained bean from handle: " + bean);
770: log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
771: logout();
772:
773: /* Attempting to obtain the EJB fron the handle without security
774: association present should fail
775: */
776: try {
777: bean = (StatefulSession) h.getEJBObject();
778: fail("Should not be able to obtain a bean without login info");
779: } catch (Exception e) {
780: log
781: .debug("Obtaining bean from handle failed as expected, e="
782: + e.getMessage());
783: }
784:
785: // One should be able to obtain a handle without a login
786: h = bean.getHandle();
787: login();
788: // Now we should be able to obtain and use the secure bean
789: bean = (StatefulSession) h.getEJBObject();
790: log.debug("Obtained bean from handle: " + bean);
791: log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
792: logout();
793: }
794:
795: /** Stress test declarative security.
796: */
797: public void testStress() throws Exception {
798: log.debug("+++ testStress");
799: int count = Integer.getInteger("jbosstest.threadcount", 10)
800: .intValue();
801: int iterations = Integer.getInteger("jbosstest.iterationcount",
802: 5000).intValue();
803: // Use a minimum of 100 iterations
804: if (iterations < 100)
805: iterations = 100;
806: log.info("Creating " + count + " threads doing " + iterations
807: + " iterations");
808: Thread[] testThreads = new Thread[count];
809: StressTester[] testers = new StressTester[count];
810:
811: for (int t = 0; t < count; t++) {
812: StressTester test = new StressTester(getInitialContext(),
813: iterations);
814: testers[t] = test;
815: Thread thr = new Thread(test, "Tester#" + t);
816: thr.start();
817: testThreads[t] = thr;
818: }
819:
820: int errorCount = 0;
821: for (int t = 0; t < count; t++) {
822: Thread thr = testThreads[t];
823: thr.join();
824: StressTester test = testers[t];
825: if (test.error != null) {
826: errorCount++;
827: }
828: }
829: assertTrue("Thread error count == 0", errorCount == 0);
830: }
831:
832: /** Stress test declarative security with the JAAS cache disabled.
833: */
834: public void testStressNoJaasCache() throws Exception {
835: log.info("+++ testStressNoJaasCache, domain=spec-test");
836: // Disable caching for the spec-test domain
837: MBeanServerConnection conn = (MBeanServerConnection) getServer();
838: ObjectName secMgrName = new ObjectName(
839: "jboss.security:service=JaasSecurityManager");
840: JaasSecurityManagerServiceMBean secMgr = (JaasSecurityManagerServiceMBean) MBeanServerInvocationHandler
841: .newProxyInstance(conn, secMgrName,
842: JaasSecurityManagerServiceMBean.class, false);
843: secMgr.setCacheTimeout("spec-test", 0, 0);
844:
845: Exception failed = null;
846: try {
847: // Now execute the testStress access
848: testStress();
849: } catch (Exception e) {
850: failed = e;
851: }
852:
853: secMgr.setCacheTimeout("spec-test", 60, 60);
854: if (failed != null)
855: throw failed;
856: }
857:
858: private static class StressTester implements Runnable {
859: InitialContext ctx;
860: int iterations;
861: Throwable error;
862:
863: StressTester(InitialContext ctx, int iterations)
864: throws Exception {
865: this .ctx = ctx;
866: this .iterations = iterations;
867: }
868:
869: public void run() {
870: Thread t = Thread.currentThread();
871: Logger log = Logger.getLogger(t.getName());
872: log.info("Begin run, t=" + t);
873: try {
874: AppCallbackHandler handler = new AppCallbackHandler(
875: EJBSpecUnitTestCase.username,
876: EJBSpecUnitTestCase.password);
877: for (int i = 0; i < iterations; i++) {
878: LoginContext lc = new LoginContext(
879: "spec-test-multi-threaded", handler);
880: lc.login();
881: Object obj = ctx.lookup("spec.StatelessSession");
882: obj = PortableRemoteObject.narrow(obj,
883: StatelessSessionHome.class);
884: StatelessSessionHome home = (StatelessSessionHome) obj;
885: log.debug("Found StatelessSessionHome");
886: StatelessSession bean = home.create();
887: log.debug("Created spec.StatelessSession");
888: log.debug("Bean.echo('Hello') -> "
889: + bean.echo("Hello"));
890: bean.remove();
891: lc.logout();
892: }
893: } catch (Throwable e) {
894: error = e;
895: log.error("Security failure", e);
896: }
897: log.info("End run, t=" + Thread.currentThread());
898: }
899: }
900:
901: /** Login as user scott using the conf.name login config or
902: 'spec-test' if conf.name is not defined.
903: */
904: private void login() throws Exception {
905: login(username, password);
906: }
907:
908: private void login(String username, char[] password)
909: throws Exception {
910: if (loggedIn)
911: return;
912:
913: lc = null;
914: String confName = System.getProperty("conf.name", "spec-test");
915: AppCallbackHandler handler = new AppCallbackHandler(username,
916: password);
917: log.debug("Creating LoginContext(" + confName + ")");
918: lc = new LoginContext(confName, handler);
919: lc.login();
920: log.debug("Created LoginContext, subject=" + lc.getSubject());
921: loggedIn = true;
922: }
923:
924: private void logout() throws Exception {
925: if (loggedIn) {
926: loggedIn = false;
927: lc.logout();
928: }
929: }
930:
931: /**
932: * Setup the test suite.
933: */
934: public static Test suite() throws Exception {
935: TestSuite suite = new TestSuite();
936: suite.addTest(new TestSuite(EJBSpecUnitTestCase.class));
937:
938: // Create an initializer for the test suite
939: TestSetup wrapper = new JBossTestSetup(suite) {
940: protected void setUp() throws Exception {
941: super .setUp();
942: Configuration
943: .setConfiguration(new XMLLoginConfigImpl());
944: redeploy("security-spec.jar");
945: flushAuthCache();
946: }
947:
948: protected void tearDown() throws Exception {
949: undeploy("security-spec.jar");
950: super.tearDown();
951:
952: }
953: };
954: return wrapper;
955: }
956:
957: }
|