/*
* 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.rmi.RemoteException;
import java.rmi.AccessException;
import java.rmi.ServerException;
import java.util.HashSet;
import java.util.Set;
import javax.ejb.Handle;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import org.jboss.security.auth.login.XMLLoginConfigImpl;
import org.jboss.security.plugins.JaasSecurityManagerServiceMBean;
import org.jboss.security.SimplePrincipal;
import org.jboss.test.JBossTestCase;
import org.jboss.test.JBossTestSetup;
import org.jboss.test.security.interfaces.CalledSession;
import org.jboss.test.security.interfaces.CalledSessionHome;
import org.jboss.test.security.interfaces.StatefulSession;
import org.jboss.test.security.interfaces.StatefulSessionHome;
import org.jboss.test.security.interfaces.StatelessSession;
import org.jboss.test.security.interfaces.StatelessSessionHome;
import org.jboss.test.security.interfaces.SecurityContext;
import org.jboss.test.security.interfaces.SecurityContextHome;
import org.jboss.test.security.ejb.jbas1852.SessionFacade;
import org.jboss.test.security.ejb.jbas1852.SessionFacadeHome;
import org.jboss.test.util.AppCallbackHandler;
import org.jboss.test.util.jms.JMSDestinationsUtil;
import org.jboss.logging.Logger;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* Test of EJB spec conformace using the security-spec.jar deployment unit. These test the basic role based access
* model.
*
* @author Scott.Stark@jboss.org
* @version $Revision: 105789 $
*/
public class EJBSpecUnitTestCase extends JBossTestCase
{
static String username = "scott";
static char[] password = "echoman".toCharArray();
static String QUEUE_FACTORY = "ConnectionFactory";
LoginContext lc;
boolean loggedIn;
public EJBSpecUnitTestCase(String name)
{
super(name);
}
/**
* Validate that the users have the expected logins and roles.
*
* @throws Exception
*/
public void testSecurityDomain() throws Exception
{
log.info("+++ testSecurityDomain, domain=spec-test");
MBeanServerConnection conn = getServer();
ObjectName secMgrName = new ObjectName("jboss.security:service=JaasSecurityManager");
JaasSecurityManagerServiceMBean secMgr = (JaasSecurityManagerServiceMBean) MBeanServerInvocationHandler
.newProxyInstance(conn, secMgrName, JaasSecurityManagerServiceMBean.class, false);
// Test the spec-test security domain
String domain = "spec-test";
SimplePrincipal user = new SimplePrincipal("scott");
boolean isValid = secMgr.isValid(domain, user, password);
assertTrue("scott password is echoman", isValid);
HashSet testRole = new HashSet();
testRole.add(new SimplePrincipal("Echo"));
boolean hasRole = secMgr.doesUserHaveRole(domain, user, password, testRole);
assertTrue("scott has Echo role", hasRole);
testRole.clear();
testRole.add(new SimplePrincipal("EchoLocal"));
hasRole = secMgr.doesUserHaveRole(domain, user, password, testRole);
assertTrue("scott has EchoLocal role", hasRole);
testRole.clear();
testRole.add(new SimplePrincipal("ProjectUser"));
hasRole = secMgr.doesUserHaveRole(domain, user, password, testRole);
assertTrue("scott has ProjectUser role", hasRole);
isValid = secMgr.isValid(domain, user, "badpass".toCharArray());
assertTrue("badpass is an invalid password for scott", isValid == false);
// Test the spec-test-domain security domain
log.info("+++ testSecurityDomain, domain=spec-test-domain");
domain = "spec-test-domain";
isValid = secMgr.isValid(domain, user, password);
assertTrue("scott password is echoman", isValid);
hasRole = secMgr.doesUserHaveRole(domain, user, password, testRole);
assertTrue("scott has Echo role", hasRole);
testRole.clear();
SimplePrincipal echoLocal = new SimplePrincipal("EchoLocal");
testRole.add(echoLocal);
hasRole = secMgr.doesUserHaveRole(domain, user, password, testRole);
assertTrue("scott has EchoLocal role", hasRole);
testRole.clear();
SimplePrincipal projectUser = new SimplePrincipal("ProjectUser");
testRole.add(projectUser);
hasRole = secMgr.doesUserHaveRole(domain, user, password, testRole);
assertTrue("scott has ProjectUser role", hasRole);
Set roles = secMgr.getUserRoles(domain, user, password);
assertTrue(roles != null);
assertTrue("roles contains EchoLocal", roles.contains(echoLocal));
assertTrue("roles contains ProjectUser", roles.contains(projectUser));
isValid = secMgr.isValid(domain, user, "badpass".toCharArray());
assertTrue("badpass is an invalid password for scott", isValid == false);
}
/**
* Test the use of getCallerPrincipal from within the ejbCreate in a stateful session bean
*/
public void testStatefulCreateCaller() throws Exception
{
log.debug("+++ testStatefulCreateCaller");
login();
InitialContext jndiContext = new InitialContext();
Object obj = jndiContext.lookup("spec.StatefulSession");
obj = PortableRemoteObject.narrow(obj, StatefulSessionHome.class);
StatefulSessionHome home = (StatefulSessionHome) obj;
log.debug("Found StatefulSessionHome");
// The create should be allowed to call getCallerPrincipal
StatefulSession bean = home.create("testStatefulCreateCaller");
// Need to invoke a method to ensure an ejbCreate call
bean.echo("testStatefulCreateCaller");
log.debug("Bean.echo(), ok");
logout();
}
/**
* Test that: 1. SecureBean returns a non-null principal when getCallerPrincipal is called with a security context
* and that this is propagated to its Entity bean ref.
*
* 2. UnsecureBean throws an IllegalStateException when getCallerPrincipal is called without a security context.
*/
public void testGetCallerPrincipal() throws Exception
{
logout();
log.debug("+++ testGetCallerPrincipal()");
Object obj = getInitialContext().lookup("spec.UnsecureStatelessSession2");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found Unsecure StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created spec.UnsecureStatelessSession2");
try
{
// This should fail because echo calls getCallerPrincipal()
bean.echo("Hello from nobody?");
fail("Was able to call StatelessSession.echo");
}
catch (RemoteException e)
{
log.debug("echo failed as expected");
}
bean.remove();
login();
obj = getInitialContext().lookup("spec.StatelessSession2");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
home = (StatelessSessionHome) obj;
log.debug("Found spec.StatelessSession2");
bean = home.create();
log.debug("Created spec.StatelessSession2");
// Test that the Entity bean sees username as its principal
String echo = bean.echo(username);
log.debug("bean.echo(username) = " + echo);
assertTrue("username == echo", echo.equals(username));
bean.remove();
}
/**
* Test that a call interacting with different security domains does not change the
*
* @throws Exception
*/
public void testDomainInteraction() throws Exception
{
logout();
login("testDomainInteraction", "testDomainInteraction".toCharArray());
log.debug("+++ testDomainInteraction()");
Object obj = getInitialContext().lookup("spec.UserInRoleContextSession");
obj = PortableRemoteObject.narrow(obj, SecurityContextHome.class);
SecurityContextHome home = (SecurityContextHome) obj;
log.debug("Found UserInRoleContextSession");
SecurityContext bean = home.create();
log.debug("Created spec.UserInRoleContextSession");
HashSet roles = new HashSet();
roles.add("Role1");
roles.add("Role2");
bean.testDomainInteraction(roles);
bean.remove();
}
/**
* Test that the calling principal is propagated across bean calls.
*/
public void testPrincipalPropagation() throws Exception
{
log.debug("+++ testPrincipalPropagation");
logout();
login();
Object obj = getInitialContext().lookup("spec.UnsecureStatelessSession2");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found Unsecure StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created spec.UnsecureStatelessSession2");
log.debug("Bean.forward('testPrincipalPropagation') -> " + bean.forward("testPrincipalPropagation"));
bean.remove();
}
/**
* Test that the echo method is accessible by an Echo role. Since the noop() method of the StatelessSession bean was
* not assigned any permissions it should be unchecked.
*/
public void testMethodAccess() throws Exception
{
log.debug("+++ testMethodAccess");
login();
Object obj = getInitialContext().lookup("spec.StatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession");
log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
try
{
// This should not be allowed
bean.noop();
fail("Was able to call StatelessSession.noop");
}
catch (RemoteException e)
{
log.debug("StatelessSession.noop failed as expected");
}
bean.remove();
}
/**
* Test that the echo method is accessible by an Echo role. Since the excluded() method of the StatelessSession bean
* has been placed into the excluded set it should not accessible by any user. This uses the security domain of the
* JaasSecurityDomain service to test its use as an authentication mgr.
*/
public void testDomainMethodAccess() throws Exception
{
log.debug("+++ testDomainMethodAccess");
login();
Object obj = getInitialContext().lookup("spec.StatelessSessionInDomain");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found StatelessSessionInDomain home");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSessionInDomain");
log.debug("Bean.echo('testDomainMethodAccess') -> " + bean.echo("testDomainMethodAccess"));
try
{
// This should not be allowed
bean.excluded();
fail("Was able to call StatelessSession.excluded");
}
catch (RemoteException e)
{
log.debug("StatelessSession.excluded failed as expected");
}
bean.remove();
}
/**
* Test that the permissions assigned to the stateless session bean: with
* ejb-name=org/jboss/test/security/ejb/StatelessSession_test are read correctly.
*/
public void testMethodAccess2() throws Exception
{
log.debug("+++ testMethodAccess2");
login();
InitialContext jndiContext = new InitialContext();
Object obj = jndiContext.lookup("spec.StatelessSession_test");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession_test");
log.debug("Bean.echo('testMethodAccess2') -> " + bean.echo("testMethodAccess2"));
bean.remove();
}
/**
* Test a user with Echo and EchoLocal roles can access the CalleeBean through its local interface by calling the
* CallerBean and that a user with only a EchoLocal cannot call the CallerBean.
*/
public void testLocalMethodAccess() throws Exception
{
log.debug("+++ testLocalMethodAccess");
login();
InitialContext jndiContext = new InitialContext();
Object obj = jndiContext.lookup("spec.CallerBean");
obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
CalledSessionHome home = (CalledSessionHome) obj;
log.debug("Found spec.CallerBean Home");
CalledSession bean = home.create();
log.debug("Created spec.CallerBean");
log.debug("Bean.invokeEcho('testLocalMethodAccess') -> " + bean.invokeEcho("testLocalMethodAccess"));
bean.remove();
}
/**
* Test access to a bean with a mix of remote interface permissions and unchecked permissions with the unchecked
* permissions declared first.
*
* @throws Exception
*/
public void testUncheckedRemote() throws Exception
{
log.debug("+++ testUncheckedRemote");
login();
Object obj = getInitialContext().lookup("spec.UncheckedSessionRemoteLast");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found UncheckedSessionRemoteLast");
StatelessSession bean = home.create();
log.debug("Created spec.UncheckedSessionRemoteLast");
log.debug("Bean.echo('testUncheckedRemote') -> " + bean.echo("testUncheckedRemote"));
try
{
bean.excluded();
fail("Was able to call UncheckedSessionRemoteLast.excluded");
}
catch (RemoteException e)
{
log.debug("UncheckedSessionRemoteLast.excluded failed as expected");
}
bean.remove();
logout();
}
/**
* Test access to a bean with a mix of remote interface permissions and unchecked permissions with the unchecked
* permissions declared last.
*
* @throws Exception
*/
public void testRemoteUnchecked() throws Exception
{
log.debug("+++ testRemoteUnchecked");
login();
Object obj = getInitialContext().lookup("spec.UncheckedSessionRemoteFirst");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found UncheckedSessionRemoteFirst");
StatelessSession bean = home.create();
log.debug("Created spec.UncheckedSessionRemoteFirst");
log.debug("Bean.echo('testRemoteUnchecked') -> " + bean.echo("testRemoteUnchecked"));
try
{
bean.excluded();
fail("Was able to call UncheckedSessionRemoteFirst.excluded");
}
catch (RemoteException e)
{
log.debug("UncheckedSessionRemoteFirst.excluded failed as expected");
}
bean.remove();
logout();
}
/**
* Test that a user with a role that has not been assigned any method permissions in the ejb-jar descriptor is able
* to access a method that has been marked as unchecked.
*/
public void testUnchecked() throws Exception
{
log.debug("+++ testUnchecked");
// Login as scott to create the bean
login();
Object obj = getInitialContext().lookup("spec.StatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found spec.StatelessSession Home");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession");
// Logout and login back in as stark to test access to the unchecked method
logout();
login("stark", "javaman".toCharArray());
bean.unchecked();
log.debug("Called Bean.unchecked()");
logout();
}
/**
* Test that a user with a valid role is able to access a bean for which all methods have been marked as unchecked.
*/
public void testUncheckedWithLogin() throws Exception
{
log.debug("+++ testUncheckedWithLogin");
// Login as scott to see that a user with roles is allowed access
login();
Object obj = getInitialContext().lookup("spec.UncheckedSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found spec.StatelessSession Home");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession");
bean.unchecked();
log.debug("Called Bean.unchecked()");
logout();
}
/**
* Test that user scott who has the Echo role is not able to access the StatelessSession2.excluded method even though
* the Echo role has been granted access to all methods of StatelessSession2 to test that the excluded-list takes
* precendence over the method-permissions.
*/
public void testExcluded() throws Exception
{
log.debug("+++ testExcluded");
login();
Object obj = getInitialContext().lookup("spec.StatelessSession2");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found spec.StatelessSession2 Home");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession2");
try
{
bean.excluded();
fail("Was able to call Bean.excluded()");
}
catch (Exception e)
{
log.debug("Bean.excluded() failed as expected");
// This is what we expect
}
logout();
}
/**
* This method tests the following call chains: 1. RunAsStatelessSession.echo() -> PrivateEntity.echo() 2.
* RunAsStatelessSession.noop() -> RunAsStatelessSession.excluded() 3. RunAsStatelessSession.forward() ->
* StatelessSession.echo() 1. Should succeed because the run-as identity of RunAsStatelessSession is valid for
* accessing PrivateEntity. 2. Should succeed because the run-as identity of RunAsStatelessSession is valid for
* accessing RunAsStatelessSession.excluded(). 3. Should fail because the run-as identity of RunAsStatelessSession is
* not Echo.
*/
public void testRunAs() throws Exception
{
log.debug("+++ testRunAs");
login();
Object obj = getInitialContext().lookup("spec.RunAsStatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found RunAsStatelessSession Home");
StatelessSession bean = home.create();
log.debug("Created spec.RunAsStatelessSession");
log.debug("Bean.echo('testRunAs') -> " + bean.echo("testRunAs"));
bean.noop();
log.debug("Bean.noop(), ok");
try
{
// This should not be allowed
bean.forward("Hello");
fail("Was able to call RunAsStatelessSession.forward");
}
catch (RemoteException e)
{
log.debug("StatelessSession.forward failed as expected");
}
bean.remove();
}
/**
* This method tests the following call chain: Level1CallerBean.callEcho() -> Level2CallerBean.invokeEcho() ->
* Level3CalleeBean.echo() The Level1CallerBean uses a run-as of InternalRole and the Level2CallerBean and
* Level3CalleeBean are only accessible by InternalRole.
*/
public void testDeepRunAs() throws Exception
{
log.debug("+++ testDeepRunAs");
login();
Object obj = getInitialContext().lookup("spec.Level1CallerBean");
obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
CalledSessionHome home = (CalledSessionHome) obj;
log.debug("Found Level1CallerBean Home");
CalledSession bean = home.create();
log.debug("Created spec.Level1CallerBean");
bean.callEcho();
log.debug("Bean.callEcho() ok");
bean.remove();
// Make sure we cannot access Level2CallerBean remotely
obj = getInitialContext().lookup("spec.Level2CallerBean");
obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
home = (CalledSessionHome) obj;
log.debug("Found Level2CallerBean Home");
try
{
bean = home.create();
fail("Was able to create Level2CallerBean");
}
catch (ServerException e)
{
AccessException ae = (AccessException) e.detail;
log.debug("Caught AccessException as expected", ae);
}
catch (AccessException e)
{
log.debug("Caught AccessException as expected", e);
}
}
public void testRunAsSFSB() throws Exception
{
log.info("+++ testRunAsSFSB");
login();
Object obj = getInitialContext().lookup("spec.CallerFacadeBean-testRunAsSFSB");
obj = PortableRemoteObject.narrow(obj, CalledSessionHome.class);
CalledSessionHome home = (CalledSessionHome) obj;
log.debug("Found CallerFacadeBean-testRunAsSFSB Home");
CalledSession bean = home.create();
log.debug("Created spec.CallerFacadeBean-testRunAsSFSB");
bean.invokeEcho("testRunAsSFSB");
log.debug("Bean.invokeEcho() ok");
bean.remove();
}
/**
* Test the run-as side-effects raised in http://jira.jboss.com/jira/browse/JBAS-1852
*
* @throws Exception
*/
public void testJBAS1852() throws Exception
{
log.info("+++ testJBAS1852");
login();
Object obj = getInitialContext().lookup("spec.PublicSessionFacade");
obj = PortableRemoteObject.narrow(obj, SessionFacadeHome.class);
SessionFacadeHome home = (SessionFacadeHome) obj;
log.debug("Found PublicSessionFacade home");
SessionFacade bean = home.create();
log.debug("Created PublicSessionFacade");
log.debug("Bean.callEcho('testJBAS1852') -> " + bean.callEcho("testJBAS1852"));
bean.remove();
}
/**
* Test that an MDB with a run-as identity is able to access secure EJBs that require the identity.
*/
public void testMDBRunAs() throws Exception
{
log.debug("Running test testMDBRunAs");
this.logout();
Thread.sleep(1000);
QueueConnectionFactory queueFactory = (QueueConnectionFactory) getInitialContext().lookup(QUEUE_FACTORY);
Queue queA = (Queue) getInitialContext().lookup("queue/QueueA");
Queue queB = (Queue) getInitialContext().lookup("queue/QueueB");
QueueConnection queueConn = null;
QueueSession session = null;
try
{
queueConn = queueFactory.createQueueConnection();
session = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueConn.start();
// create a JMS message.
Message msg = session.createMessage();
msg.setStringProperty("arg", "testMDBRunAs");
msg.setJMSReplyTo(queB);
// send the constructed message to queue A.
QueueSender sender = session.createSender(queA);
sender.send(msg);
sender.close();
log.debug("Sent msg to queue/QueueA");
// receive the message at queue B.
QueueReceiver recv = session.createReceiver(queB);
msg = recv.receive(15000);
recv.close();
log.debug("Recv msg: " + msg);
// get the message's content.
String info = msg.getStringProperty("reply");
if (info == null || info.startsWith("Failed"))
{
fail("Received exception reply, info=" + info);
}
}
finally
{
if (session != null)
session.close();
if (queueConn != null)
queueConn.close();
}
}
/**
* Test that an MDB with a run-as identity is able to access secure EJBs that require the identity. DeepRunAsMDB ->
* Level1MDBCallerBean.callEcho() -> Level2CallerBean.invokeEcho() -> Level3CalleeBean.echo() The MDB uses a run-as
* of InternalRole and the Level2CallerBean and Level3CalleeBean are only accessible by InternalRole.
*/
public void testMDBDeepRunAs() throws Exception
{
log.debug("Running test testMDBDeepRunAs");
this.logout();
Thread.sleep(1000);
QueueConnectionFactory queueFactory = (QueueConnectionFactory) getInitialContext().lookup(QUEUE_FACTORY);
Queue queD = (Queue) getInitialContext().lookup("queue/QueueD");
Queue queB = (Queue) getInitialContext().lookup("queue/QueueB");
QueueConnection queueConn = null;
QueueSession session = null;
try
{
queueConn = queueFactory.createQueueConnection();
session = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueConn.start();
// create a JMS message.
Message msg = session.createMessage();
msg.setStringProperty("arg", "testMDBDeepRunAs");
msg.setJMSReplyTo(queB);
// send the constructed message to queue D.
QueueSender sender = session.createSender(queD);
sender.send(msg);
sender.close();
log.debug("Sent msg to " + queD);
// receive the message at queue B
QueueReceiver recv = session.createReceiver(queB);
msg = recv.receive(15000);
recv.close();
log.debug("Recv msg: " + msg);
// get the message's content.
String info = msg.getStringProperty("reply");
if (info == null || info.startsWith("Failed"))
{
fail("Received exception reply, info=" + info);
}
}
finally
{
if (session != null)
session.close();
if (queueConn != null)
queueConn.close();
}
}
/**
* This method tests that the RunAsWithRolesMDB is assigned multiple roles within its onMessage so that it can call
* into the ProjRepository session bean's methods that required ProjectAdmin, CreateFolder and DeleteFolder roles.
*/
public void testRunAsWithRoles() throws Exception
{
log.debug("Running test testRunAsWithRoles");
this.logout();
QueueConnectionFactory queueFactory = (QueueConnectionFactory) getInitialContext().lookup(QUEUE_FACTORY);
Queue queC = (Queue) getInitialContext().lookup("queue/QueueC");
Queue queB = (Queue) getInitialContext().lookup("queue/QueueB");
QueueConnection queueConn = null;
QueueSession session = null;
try
{
queueConn = queueFactory.createQueueConnection();
session = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueConn.start();
// create a JMS message.
Message msg = session.createMessage();
msg.setStringProperty("name", "testRunAsWithRoles");
msg.setJMSReplyTo(queB);
// send the constructed message to queue C.
QueueSender sender = session.createSender(queC);
sender.send(msg);
sender.close();
log.debug("Sent msg to queue/QueueC");
// receive the message at queue B.
QueueReceiver recv = session.createReceiver(queB);
msg = recv.receive(5000);
log.debug("Recv msg: " + msg);
recv.close();
// get the message's content.
String info = msg.getStringProperty("reply");
if (info == null || info.startsWith("Failed"))
{
fail("Received exception reply, info=" + info);
}
}
finally
{
if (session != null)
session.close();
if (queueConn != null)
queueConn.close();
}
}
/**
* Test the security behavior of handles. To obtain secured bean from a handle that the handle be
*/
public void testHandle() throws Exception
{
log.debug("+++ testHandle");
login();
Object obj = getInitialContext().lookup("spec.StatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession");
Handle h = bean.getHandle();
log.debug("Obtained handle: " + h);
bean = (StatelessSession) h.getEJBObject();
log.debug("Obtained bean from handle: " + bean);
log.debug("Bean.echo('testHandle') -> " + bean.echo("testHandle"));
logout();
/*
* Attempting to obtain the EJB fron the handle without security association present should fail
*/
try
{
bean = (StatelessSession) h.getEJBObject();
fail("Should not be able to obtain a bean without login info");
}
catch (Exception e)
{
log.debug("Obtaining bean from handle failed as expected, e=" + e.getMessage());
}
// One should be able to obtain a handle without a login
h = bean.getHandle();
login();
// Now we should be able to obtain and use the secure bean
bean = (StatelessSession) h.getEJBObject();
log.debug("Obtained bean from handle: " + bean);
log.debug("Bean.echo('testHandle2') -> " + bean.echo("testHandle2"));
logout();
}
/**
* Test the security behavior of stateful handles. To obtain secured bean from a handle requires that there be a
* security context to obtain the ejb.
*/
public void testStatefulHandle() throws Exception
{
log.debug("+++ testStatefulHandle");
login();
Object obj = getInitialContext().lookup("spec.StatefulSession");
obj = PortableRemoteObject.narrow(obj, StatefulSessionHome.class);
StatefulSessionHome home = (StatefulSessionHome) obj;
log.debug("Found StatefulSession");
StatefulSession bean = home.create("testStatefulHandle");
log.debug("Created spec.StatelessSession");
Handle h = bean.getHandle();
log.debug("Obtained handle: " + h);
bean = (StatefulSession) h.getEJBObject();
log.debug("Obtained bean from handle: " + bean);
log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
logout();
/*
* Attempting to obtain the EJB fron the handle without security association present should fail
*/
try
{
bean = (StatefulSession) h.getEJBObject();
fail("Should not be able to obtain a bean without login info");
}
catch (Exception e)
{
log.debug("Obtaining bean from handle failed as expected, e=" + e.getMessage());
}
// One should be able to obtain a handle without a login
h = bean.getHandle();
login();
// Now we should be able to obtain and use the secure bean
bean = (StatefulSession) h.getEJBObject();
log.debug("Obtained bean from handle: " + bean);
log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
logout();
}
/**
* Stress test declarative security.
*/
public void testStress() throws Exception
{
log.debug("+++ testStress");
int count = Integer.getInteger("jbosstest.threadcount", 2).intValue();
int iterations = 10;
/*
* FIXME, Use a minimum of 100 iterations iterations = Integer.getInteger("jbosstest.iterationcount",
* 5).intValue(); if( iterations < 100 ) iterations = 100;
*/
log.info("Creating " + count + " threads doing " + iterations + " iterations");
Thread[] testThreads = new Thread[count];
StressTester[] testers = new StressTester[count];
for (int t = 0; t < count; t++)
{
StressTester test = new StressTester(getInitialContext(), iterations);
testers[t] = test;
Thread thr = new Thread(test, "Tester#" + t);
thr.start();
testThreads[t] = thr;
}
int errorCount = 0;
for (int t = 0; t < count; t++)
{
Thread thr = testThreads[t];
thr.join();
StressTester test = testers[t];
if (test.error != null)
{
errorCount++;
}
}
assertTrue("Thread error count == 0", errorCount == 0);
}
/**
* Stress test declarative security with the JAAS cache disabled.
*/
public void testStressNoJaasCache() throws Exception
{
log.info("+++ testStressNoJaasCache, domain=spec-test");
// Disable caching for the spec-test domain
MBeanServerConnection conn = getServer();
ObjectName secMgrName = new ObjectName("jboss.security:service=JaasSecurityManager");
JaasSecurityManagerServiceMBean secMgr = (JaasSecurityManagerServiceMBean) MBeanServerInvocationHandler
.newProxyInstance(conn, secMgrName, JaasSecurityManagerServiceMBean.class, false);
secMgr.setCacheTimeout("spec-test", 0, 0);
Exception failed = null;
try
{
// Now execute the testStress access
testStress();
}
catch (Exception e)
{
failed = e;
}
secMgr.setCacheTimeout("spec-test", 60, 60);
if (failed != null)
throw failed;
}
private static class StressTester implements Runnable
{
InitialContext ctx;
int iterations;
Throwable error;
StressTester(InitialContext ctx, int iterations) throws Exception
{
this.ctx = ctx;
this.iterations = iterations;
}
public void run()
{
Thread t = Thread.currentThread();
Logger log = Logger.getLogger(t.getName());
log.info("Begin run, t=" + t);
try
{
AppCallbackHandler handler = new AppCallbackHandler(EJBSpecUnitTestCase.username,
EJBSpecUnitTestCase.password);
for (int i = 0; i < iterations; i++)
{
LoginContext lc = new LoginContext("spec-test-multi-threaded", handler);
lc.login();
Object obj = ctx.lookup("spec.StatelessSession");
obj = PortableRemoteObject.narrow(obj, StatelessSessionHome.class);
StatelessSessionHome home = (StatelessSessionHome) obj;
log.debug("Found StatelessSessionHome");
StatelessSession bean = home.create();
log.debug("Created spec.StatelessSession");
log.debug("Bean.echo('Hello') -> " + bean.echo("Hello"));
bean.remove();
log.debug("Removed bean");
lc.logout();
}
}
catch (Throwable e)
{
error = e;
log.error("Security failure", e);
}
log.info("End run, t=" + Thread.currentThread());
}
}
/**
* Login as user scott using the conf.name login config or 'spec-test' if conf.name is not defined.
*/
private void login() throws Exception
{
login(username, password);
}
private void login(String username, char[] password) throws Exception
{
if (loggedIn)
return;
lc = null;
String confName = System.getProperty("conf.name", "spec-test");
AppCallbackHandler handler = new AppCallbackHandler(username, password);
log.debug("Creating LoginContext(" + confName + ")");
lc = new LoginContext(confName, handler);
lc.login();
log.debug("Created LoginContext, subject=" + lc.getSubject());
loggedIn = true;
}
private void logout() throws Exception
{
if (loggedIn)
{
loggedIn = false;
lc.logout();
}
}
@Override
protected void setUp() throws Exception
{
super.setUp();
if (System.getProperty("java.security.auth.login.config") == null)
{
System.setProperty("java.security.auth.login.config", "output/resources/security/auth.conf");
}
}
/**
* Setup the test suite.
*/
public static Test suite() throws Exception
{
TestSuite suite = new TestSuite();
suite.addTest(new TestSuite(EJBSpecUnitTestCase.class));
// Create an initializer for the test suite
TestSetup wrapper = new JBossTestSetup(suite)
{
@Override
protected void setUp() throws Exception
{
super.setUp();
Configuration.setConfiguration(XMLLoginConfigImpl.getInstance());
JMSDestinationsUtil.setupBasicDestinations();
JMSDestinationsUtil.deployQueue("QueueA");
JMSDestinationsUtil.deployQueue("QueueB");
JMSDestinationsUtil.deployQueue("QueueC");
JMSDestinationsUtil.deployQueue("QueueD");
redeploy("security-spec.jar");
flushAuthCache();
}
@Override
protected void tearDown() throws Exception
{
undeploy("security-spec.jar");
JMSDestinationsUtil.destroyDestinations();
super.tearDown();
}
};
return wrapper;
}
}