[jboss-cvs] JBoss Messaging SVN: r2256 - in branches/Branch_1_0_1_SP: src/main/org/jboss/jms/server/container and 5 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sat Feb 10 20:05:41 EST 2007
Author: ovidiu.feodorov at jboss.com
Date: 2007-02-10 20:05:41 -0500 (Sat, 10 Feb 2007)
New Revision: 2256
Modified:
branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/SecurityManager.java
branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/container/SecurityAspect.java
branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/endpoint/ServerConnectionFactoryEndpoint.java
branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/security/SecurityMetadataStore.java
branches/Branch_1_0_1_SP/tests/build.xml
branches/Branch_1_0_1_SP/tests/src/org/jboss/test/messaging/tools/jmx/MockJBossSecurityManager.java
branches/Branch_1_0_1_SP/tests/src/org/jboss/test/thirdparty/jbosssx/SecurityAssociationTest.java
Log:
http://jira.jboss.org/jira/browse/JBMESSAGING-824
Modified: branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/SecurityManager.java
===================================================================
--- branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/SecurityManager.java 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/SecurityManager.java 2007-02-11 01:05:41 UTC (rev 2256)
@@ -49,6 +49,11 @@
* Authenticate the specified user with the given password. Implementations are most likely to
* delegates to a JBoss AuthenticationManager.
*
+ * Successful autentication will place a new SubjectContext on thread local, which will be used
+ * in the authorization process. However, we need to make sure we clean up thread local
+ * immediately after we used the information, otherwise some other people security my be screwed
+ * up, on account of thread local security stack being corrupted.
+ *
* @throws JMSSecurityException if the user is not authenticated
*/
Subject authenticate(String user, String password) throws JMSSecurityException;
Modified: branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/container/SecurityAspect.java
===================================================================
--- branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/container/SecurityAspect.java 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/container/SecurityAspect.java 2007-02-11 01:05:41 UTC (rev 2256)
@@ -39,6 +39,7 @@
import org.jboss.jms.server.endpoint.advised.SessionAdvised;
import org.jboss.jms.server.security.SecurityMetadata;
import org.jboss.logging.Logger;
+import org.jboss.security.SecurityAssociation;
/**
* This aspect enforces the JBossMessaging JMS security policy.
@@ -53,6 +54,7 @@
* milliseconds later.
*
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @author <a href="mailto:ovidiu at jboss.org">Ovidiu Feodorov</a>
* @version <tt>$Revision 1.1 $</tt>
*
* $Id$
@@ -64,138 +66,138 @@
private static final Logger log = Logger.getLogger(SecurityAspect.class);
// Static --------------------------------------------------------
-
+
// Attributes ----------------------------------------------------
-
+
private boolean trace = log.isTraceEnabled();
-
+
private Set readCache;
-
+
private Set writeCache;
-
+
private Set createCache;
-
+
//TODO Make this configurable
private static final long INVALIDATION_INTERVAL = 15000;
-
+
private long lastCheck;
-
+
// Constructors --------------------------------------------------
-
+
// Public --------------------------------------------------------
public SecurityAspect()
{
readCache = new HashSet();
-
+
writeCache = new HashSet();
-
+
createCache = new HashSet();
}
-
+
public Object handleCreateConsumerDelegate(Invocation invocation) throws Throwable
{
MethodInvocation mi = (MethodInvocation)invocation;
-
+
// read permission required on the destination
Destination dest = (Destination)mi.getArguments()[0];
-
+
SessionAdvised del = (SessionAdvised)invocation.getTargetObject();
ServerSessionEndpoint sess = (ServerSessionEndpoint)del.getEndpoint();
-
+
check(dest, CheckType.READ, sess.getConnectionEndpoint());
-
+
// if creating a durable subscription then need create permission
-
+
String subscriptionName = (String)mi.getArguments()[3];
if (subscriptionName != null)
{
// durable
check(dest, CheckType.CREATE, sess.getConnectionEndpoint());
}
-
+
return invocation.invokeNext();
- }
-
+ }
+
public Object handleCreateBrowserDelegate(Invocation invocation) throws Throwable
{
// read permission required on the destination
-
+
MethodInvocation mi = (MethodInvocation)invocation;
-
+
Destination dest = (Destination)mi.getArguments()[0];
-
+
SessionAdvised del = (SessionAdvised)invocation.getTargetObject();
ServerSessionEndpoint sess = (ServerSessionEndpoint)del.getEndpoint();
-
+
check(dest, CheckType.READ, sess.getConnectionEndpoint());
-
+
return invocation.invokeNext();
}
-
+
public Object handleSend(Invocation invocation) throws Throwable
{
// anonymous producer - if destination is not null then write permissions required
-
+
MethodInvocation mi = (MethodInvocation)invocation;
-
+
Message m = (Message)mi.getArguments()[0];
Destination dest = m.getJMSDestination();
SessionAdvised del = (SessionAdvised)invocation.getTargetObject();
ServerSessionEndpoint se = (ServerSessionEndpoint)del.getEndpoint();
ServerConnectionEndpoint ce = se.getConnectionEndpoint();
-
+
check(dest, CheckType.WRITE, ce);
-
+
return invocation.invokeNext();
- }
-
+ }
+
public Object handleGetMessageNow(Invocation invocation) throws Throwable
- {
+ {
checkConsumerAccess(invocation);
-
+
return invocation.invokeNext();
- }
-
+ }
+
public Object handleActivate(Invocation invocation) throws Throwable
- {
+ {
checkConsumerAccess(invocation);
-
+
return invocation.invokeNext();
- }
-
+ }
+
protected void checkConsumerAccess(Invocation invocation) throws Throwable
{
ConsumerAdvised del = (ConsumerAdvised)invocation.getTargetObject();
ServerConsumerEndpoint cons = (ServerConsumerEndpoint)del.getEndpoint();
ServerConnectionEndpoint conn = cons.getSessionEndpoint().getConnectionEndpoint();
JBossDestination dest = cons.getDestination();
-
+
check(dest, CheckType.READ, conn);
}
-
+
// Package protected ---------------------------------------------
-
+
// Protected -----------------------------------------------------
-
+
// Private -------------------------------------------------------
-
+
private boolean checkCached(Destination dest, CheckType checkType)
{
long now = System.currentTimeMillis();
-
+
boolean granted = false;
-
+
if (now - lastCheck > INVALIDATION_INTERVAL)
{
readCache.clear();
-
+
writeCache.clear();
-
- createCache.clear();
+
+ createCache.clear();
}
else
- {
+ {
switch (checkType.type)
{
case CheckType.TYPE_READ:
@@ -219,20 +221,20 @@
}
}
}
-
+
lastCheck = now;
-
+
return granted;
}
-
+
private void check(Destination dest, CheckType checkType, ServerConnectionEndpoint conn)
throws JMSSecurityException
{
if (trace) { log.trace("checking access permissions to " + dest); }
-
+
if (checkCached(dest, checkType))
{
- //Ok
+ // OK
return;
}
@@ -248,27 +250,38 @@
throw new JMSSecurityException("No security configuration avaliable for " + name);
}
- // Authenticate
+ // Authenticate. Successful autentication will place a new SubjectContext on thread local,
+ // which will be used in the authorization process. However, we need to make sure we clean up
+ // thread local immediately after we used the information, otherwise some other people
+ // security my be screwed up, on account of thread local security stack being corrupted.
+
sm.authenticate(conn.getUsername(), conn.getPassword());
// Authorize
Set principals = checkType == CheckType.READ ? securityMetadata.getReadPrincipals() :
checkType == CheckType.WRITE ? securityMetadata.getWritePrincipals() :
securityMetadata.getCreatePrincipals();
-
- if (!sm.authorize(conn.getUsername(), principals))
+ try
{
- String msg = "User: " + conn.getUsername() +
- " is not authorized to " +
- (checkType == CheckType.READ ? "read from" :
- checkType == CheckType.WRITE ? "write to" : "create durable sub on") +
- " destination " + name;
-
- throw new JMSSecurityException(msg);
+ if (!sm.authorize(conn.getUsername(), principals))
+ {
+ String msg = "User: " + conn.getUsername() +
+ " is not authorized to " +
+ (checkType == CheckType.READ ? "read from" :
+ checkType == CheckType.WRITE ? "write to" : "create durable sub on") +
+ " destination " + name;
+
+ throw new JMSSecurityException(msg);
+ }
}
-
+ finally
+ {
+ // pop the Messaging SecurityContext, it did its job
+ SecurityAssociation.popSubjectContext();
+ }
+
// if we get here we're granted, add to the cache
-
+
switch (checkType.type)
{
case CheckType.TYPE_READ:
@@ -290,31 +303,31 @@
{
throw new IllegalArgumentException("Invalid checkType:" + checkType);
}
- }
+ }
}
-
+
// Inner classes -------------------------------------------------
-
+
private static class CheckType
{
private int type;
private CheckType(int type)
{
this.type = type;
- }
+ }
public static final int TYPE_READ = 0;
public static final int TYPE_WRITE = 1;
public static final int TYPE_CREATE = 2;
public static CheckType READ = new CheckType(TYPE_READ);
public static CheckType WRITE = new CheckType(TYPE_WRITE);
- public static CheckType CREATE = new CheckType(TYPE_CREATE);
+ public static CheckType CREATE = new CheckType(TYPE_CREATE);
public boolean equals(Object other)
{
if (!(other instanceof CheckType)) return false;
CheckType ct = (CheckType)other;
return ct.type == this.type;
}
- public int hashCode()
+ public int hashCode()
{
return type;
}
Modified: branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/endpoint/ServerConnectionFactoryEndpoint.java
===================================================================
--- branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/endpoint/ServerConnectionFactoryEndpoint.java 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/endpoint/ServerConnectionFactoryEndpoint.java 2007-02-11 01:05:41 UTC (rev 2256)
@@ -33,6 +33,7 @@
import org.jboss.jms.util.ExceptionUtil;
import org.jboss.logging.Logger;
import org.jboss.messaging.core.plugin.IdBlock;
+import org.jboss.security.SecurityAssociation;
/**
* Concrete implementation of ConnectionFactoryEndpoint
@@ -50,26 +51,26 @@
private static final Logger log = Logger.getLogger(ServerConnectionFactoryEndpoint.class);
// Static --------------------------------------------------------
-
+
// Attributes ----------------------------------------------------
private ServerPeer serverPeer;
-
+
private String clientID;
-
+
private int id;
-
+
private JNDIBindings jndiBindings;
-
+
private int prefetchSize;
-
+
protected int defaultTempQueueFullSize;
-
+
protected int defaultTempQueuePageSize;
-
+
protected int defaultTempQueueDownCacheSize;
-
+
// Constructors --------------------------------------------------
/**
@@ -95,51 +96,58 @@
}
// ConnectionFactoryDelegate implementation ----------------------
-
+
public ConnectionDelegate createConnectionDelegate(String username, String password)
throws JMSException
{
try
{
log.debug("creating a new connection for user " + username);
-
- // authenticate the user
+
+ // Authenticate. Successful autentication will place a new SubjectContext on thread local,
+ // which will be used in the authorization process. However, we need to make sure we clean
+ // up thread local immediately after we used the information, otherwise some other people
+ // security my be screwed up, on account of thread local security stack being corrupted.
+
serverPeer.getSecurityManager().authenticate(username, password);
-
+
+ // We don't need the SubjectContext on thread local anymore, clean it up
+ SecurityAssociation.popSubjectContext();
+
// see if there is a preconfigured client id for the user
if (username != null)
{
String preconfClientID =
serverPeer.getChannelMapperDelegate().getPreConfiguredClientID(username);
-
+
if (preconfClientID != null)
{
clientID = preconfClientID;
- }
+ }
}
-
+
serverPeer.checkClientID(clientID);
-
+
// create the corresponding "server-side" connection endpoint and register it with the
// server peer's ClientManager
ServerConnectionEndpoint endpoint =
new ServerConnectionEndpoint(serverPeer, clientID, username, password, prefetchSize,
- defaultTempQueueFullSize, defaultTempQueuePageSize, defaultTempQueueDownCacheSize);
-
+ defaultTempQueueFullSize, defaultTempQueuePageSize, defaultTempQueueDownCacheSize);
+
int connectionID = endpoint.getConnectionID();
-
+
ConnectionAdvised advised;
-
+
// Need to synchronize due to http://jira.jboss.com/jira/browse/JBMESSAGING-797
synchronized (AspectManager.instance())
- {
+ {
advised = new ConnectionAdvised(endpoint);
- }
-
+ }
+
JMSDispatcher.instance.registerTarget(new Integer(connectionID), advised);
-
+
log.debug("created and registered " + endpoint);
-
+
return new ClientConnectionDelegate(connectionID);
}
catch (Throwable t)
@@ -147,7 +155,7 @@
throw ExceptionUtil.handleJMSInvocation(t, this + " createConnectionDelegate");
}
}
-
+
public byte[] getClientAOPConfig() throws JMSException
{
try
@@ -174,7 +182,7 @@
// Public --------------------------------------------------------
-
+
public int getID()
{
return id;
@@ -186,10 +194,10 @@
}
// Package protected ---------------------------------------------
-
+
// Protected -----------------------------------------------------
-
+
// Private -------------------------------------------------------
-
+
// Inner classes -------------------------------------------------
}
Modified: branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/security/SecurityMetadataStore.java
===================================================================
--- branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/security/SecurityMetadataStore.java 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/src/main/org/jboss/jms/server/security/SecurityMetadataStore.java 2007-02-11 01:05:41 UTC (rev 2256)
@@ -162,6 +162,9 @@
if (authenticationManager.isValid(principal, passwordChars, subject))
{
+ // Warning! This "taints" thread local. Make sure you pop it off the stack as soon as
+ // you're done with it.
+ SecurityActions.pushSubjectContext(principal, passwordChars, subject);
return subject;
}
else
Modified: branches/Branch_1_0_1_SP/tests/build.xml
===================================================================
--- branches/Branch_1_0_1_SP/tests/build.xml 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/tests/build.xml 2007-02-11 01:05:41 UTC (rev 2256)
@@ -548,6 +548,7 @@
<exclude name="org/jboss/test/messaging/jms/MemLeakTest.class"/>
<exclude name="org/jboss/test/messaging/jms/ManifestTest.class"/>
<exclude name="org/jboss/test/messaging/jms/JCAWrapperTest.class"/>
+ <exclude name="org/jboss/test/thirdparty/jbosssx/SecurityAssociationTest.class"/>
</fileset>
</batchtest>
</junit>
Modified: branches/Branch_1_0_1_SP/tests/src/org/jboss/test/messaging/tools/jmx/MockJBossSecurityManager.java
===================================================================
--- branches/Branch_1_0_1_SP/tests/src/org/jboss/test/messaging/tools/jmx/MockJBossSecurityManager.java 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/tests/src/org/jboss/test/messaging/tools/jmx/MockJBossSecurityManager.java 2007-02-11 01:05:41 UTC (rev 2256)
@@ -22,29 +22,39 @@
package org.jboss.test.messaging.tools.jmx;
import java.security.Principal;
+import java.security.acl.Group;
import java.util.Iterator;
import java.util.Set;
+import java.util.HashSet;
import javax.security.auth.Subject;
import org.jboss.logging.Logger;
import org.jboss.security.AuthenticationManager;
import org.jboss.security.RealmMapping;
+import org.jboss.security.SecurityAssociation;
+import org.jboss.security.NobodyPrincipal;
+import org.jboss.security.AnybodyPrincipal;
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
-/* Mock Security manager for testing JMS security.
- *
- *
+/**
+ * Mock Security manager for testing JMS security.
+ *
* @author <a href="tim.fox at jboss.com">Tim Fox</a>
+ * @author <a href="mailto:ovidiu at jboss.org">Ovidiu Feodorov</a>
*
*/
public class MockJBossSecurityManager implements AuthenticationManager, RealmMapping
{
public static final String TEST_SECURITY_DOMAIN = "messaging-securitydomain";
-
+
private static final Logger log = Logger.getLogger(MockJBossSecurityManager.class);
-
+
+ private boolean simulateJBossJaasSecurityManager;
+
//Authentication Manager Implementation
-
+
public String getSecurityDomain()
{
return TEST_SECURITY_DOMAIN;
@@ -55,50 +65,94 @@
throw new UnsupportedOperationException();
}
- public boolean isValid(Principal principal, Object credential,
- Subject activeSubject)
+ public boolean isValid(Principal principal, Object credential, Subject activeSubject)
{
if (log.isTraceEnabled()) { log.trace("principal:" + principal + " credential:" + credential); }
-
+
+ boolean isValid = false;
+
String username = principal == null ? null : principal.getName();
char[] passwordChars = (char[])credential;
String password = passwordChars == null ? null : new String(passwordChars);
-
+
if (username == null)
{
- return true;
- }
+ isValid = true;
+
+ if (isValid && simulateJBossJaasSecurityManager)
+ {
+ // modify the activeSubject, need to add to it its current roles
+ // TODO: this is currently impmented in a messy way, this and doesUserHaveRole()
+ // implementation must be coalesced
+ addRole(activeSubject, "guest");
+ }
+ }
else if ("guest".equals(username))
{
- return "guest".equals(password);
+ isValid = "guest".equals(password);
+
+ if (isValid && simulateJBossJaasSecurityManager)
+ {
+ // modify the activeSubject, need to add to it its current roles
+ // TODO: this is currently impmented in a messy way, this and doesUserHaveRole()
+ // implementation must be coalesced
+ addRole(activeSubject, "guest");
+ }
}
else if ("john".equals(username))
{
- return "needle".equals(password);
+ isValid = "needle".equals(password);
+
+ if (isValid && simulateJBossJaasSecurityManager)
+ {
+ // modify the activeSubject, need to add to it its current roles
+ // TODO: this is currently impmented in a messy way, this and doesUserHaveRole()
+ // implementation must be coalesced
+ addRole(activeSubject, "publisher");
+ addRole(activeSubject, "durpublisher");
+ addRole(activeSubject, "def");
+ }
}
else if ("nobody".equals(username))
{
- return "nobody".equals(password);
+ isValid = "nobody".equals(password);
+
+ if (isValid && simulateJBossJaasSecurityManager)
+ {
+ // modify the activeSubject, need to add to it its current roles
+ // TODO: this is currently impmented in a messy way, this and doesUserHaveRole()
+ // implementation must be coalesced
+ addRole(activeSubject, "noacc");
+ }
}
else if ("dynsub".equals(username))
{
- return "dynsub".equals(password);
+ isValid = "dynsub".equals(password);
+
+ if (isValid && simulateJBossJaasSecurityManager)
+ {
+ // modify the activeSubject, need to add to it its current roles
+ // TODO: this is currently impmented in a messy way, this and doesUserHaveRole()
+ // implementation must be coalesced
+ addRole(activeSubject, "publisher");
+ addRole(activeSubject, "durpublisher");
+ }
}
else
{
- return false;
+ isValid = false;
}
+
+ return isValid;
}
-
public Subject getActiveSubject()
{
throw new UnsupportedOperationException();
}
+ // RealmMapping implementation
- //RealmMapping implementation
-
public Principal getPrincipal(Principal principal)
{
throw new UnsupportedOperationException();
@@ -117,47 +171,163 @@
}
return false;
}
-
-
+
public boolean doesUserHaveRole(Principal principal, Set roles)
- {
- String username = principal == null ? "guest" : principal.getName();
-
- if (log.isTraceEnabled())
+ {
+ // introduced the possiblity to "simulate" JaasSecurityManager behavior, which is ingnoring
+ // the principal passed as argument and looking at thread context for active subject; this
+ // would allow us to catch some problems earlier at functional testsuite level, and not
+ // wait for integration or smoke test. However, the "correct" place for this kind of test
+ // is at integration testsuite level.
+
+ if (simulateJBossJaasSecurityManager)
{
- log.trace("doesUserHaveRole:" + username);
- }
-
- if ("guest".equals(username))
- {
- return containsRole("guest", roles);
+ boolean hasRole = false;
+ // check that the caller is authenticated to the current thread
+ Subject subject = SecurityAssociation.getSubject();
+
+ if (subject != null)
+ {
+ // Check the caller's roles
+ Group subjectRoles = getSubjectRoles(subject);
+ if (subjectRoles != null)
+ {
+ Iterator iter = roles.iterator();
+ while (!hasRole && iter.hasNext())
+ {
+ Principal role = (Principal)iter.next();
+ hasRole = doesRoleGroupHaveRole(role, subjectRoles);
+ }
+ }
+ }
+ return hasRole;
}
- else if ("john".equals(username))
+ else
{
- return containsRole("publisher", roles) ||
- containsRole("durpublisher", roles) ||
- containsRole("def", roles);
- }
- else if ("dynsub".equals(username))
- {
- return containsRole("publisher", roles)||
+ // "alternate" MockJBossSecurityManager behavior, we actually look at 'principal' passed as
+ // parameter
+
+ String username = principal == null ? "guest" : principal.getName();
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("doesUserHaveRole:" + username);
+ }
+
+ if ("guest".equals(username))
+ {
+ return containsRole("guest", roles);
+ }
+ else if ("john".equals(username))
+ {
+ return containsRole("publisher", roles) ||
+ containsRole("durpublisher", roles) ||
+ containsRole("def", roles);
+ }
+ else if ("dynsub".equals(username))
+ {
+ return containsRole("publisher", roles)||
containsRole("durpublisher", roles);
+ }
+ else if ("nobody".equals(username))
+ {
+ return containsRole("noacc", roles);
+ }
+ else
+ {
+ return false;
+ }
}
- else if ("nobody".equals(username))
+ }
+
+ public Set getUserRoles(Principal principal)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSimulateJBossJaasSecurityManager(boolean b)
+ {
+ simulateJBossJaasSecurityManager = b;
+ }
+
+ public boolean isSimulateJBossJaasSecurityManager()
+ {
+ return simulateJBossJaasSecurityManager;
+ }
+
+ /**
+ * Copied from JaasSecurityManager.
+ */
+ private Group getSubjectRoles(Subject subject)
+ {
+ Set subjectGroups = subject.getPrincipals(Group.class);
+ Iterator iter = subjectGroups.iterator();
+ Group roles = null;
+ while (iter.hasNext())
{
- return containsRole("noacc", roles);
+ Group grp = (Group)iter.next();
+ String name = grp.getName();
+ if (name.equals("Roles"))
+ {
+ roles = grp;
+ }
}
- else
+ return roles;
+ }
+
+ /**
+ * Copied from JaasSecurityManager.
+ */
+ private boolean doesRoleGroupHaveRole(Principal role, Group userRoles)
+ {
+ // First check that role is not a NobodyPrincipal
+ if (role instanceof NobodyPrincipal)
{
return false;
}
-
+
+ // Check for inclusion in the user's role set
+ boolean isMember = userRoles.isMember(role);
+ if (!isMember)
+ {
+ // Check the AnybodyPrincipal special cases
+ isMember = (role instanceof AnybodyPrincipal);
+ }
+
+ return isMember;
}
-
- public Set getUserRoles(Principal principal)
+ private void addRole(Subject subject, String role)
{
- throw new UnsupportedOperationException();
+ Set groups = subject.getPrincipals(Group.class);
+
+ if(groups == null || groups.isEmpty())
+ {
+ Group g = new SimpleGroup("Roles");
+ subject.getPrincipals().add(g);
+ groups = new HashSet();
+ groups.add(g);
+ }
+
+ Group roles = null;
+
+ for(Iterator i = groups.iterator(); i.hasNext(); )
+ {
+ Group g = (Group)i.next();
+ if ("Roles".equals(g.getName()))
+ {
+ roles = g;
+ }
+ }
+
+ if (roles == null)
+ {
+ roles = new SimpleGroup("Roles");
+ subject.getPrincipals().add(roles);
+ }
+
+ roles.addMember(new SimplePrincipal(role));
+
}
}
\ No newline at end of file
Modified: branches/Branch_1_0_1_SP/tests/src/org/jboss/test/thirdparty/jbosssx/SecurityAssociationTest.java
===================================================================
--- branches/Branch_1_0_1_SP/tests/src/org/jboss/test/thirdparty/jbosssx/SecurityAssociationTest.java 2007-02-11 01:00:04 UTC (rev 2255)
+++ branches/Branch_1_0_1_SP/tests/src/org/jboss/test/thirdparty/jbosssx/SecurityAssociationTest.java 2007-02-11 01:05:41 UTC (rev 2256)
@@ -23,6 +23,7 @@
import org.jboss.test.messaging.MessagingTestCase;
import org.jboss.test.messaging.tools.ServerManagement;
+import org.jboss.test.messaging.tools.jmx.MockJBossSecurityManager;
import org.jboss.security.SecurityAssociation;
import org.jboss.security.SimplePrincipal;
@@ -45,6 +46,8 @@
* This is just a safety layer, full fledged security tests should be present in the integration
* test suite.
*
+ * Tests contained by this class are supposed to run only in local environment.
+ *
* @author <a href="mailto:ovidiu at jboss.org">Ovidiu Feodorov</a>
* @version <tt>$Revision$</tt>
* $Id$
@@ -73,6 +76,11 @@
*/
public void testSecurityAssociation() throws Exception
{
+ if(ServerManagement.isRemote())
+ {
+ fail("This test is supposed to be run in a local configuration");
+ }
+
ConnectionFactory cf = (ConnectionFactory)ic.lookup("/ConnectionFactory");
Queue queue = (Queue)ic.lookup("/queue/TestQueue");
@@ -134,12 +142,176 @@
}
}
+ /**
+ * Test for http://jira.jboss.org/jira/browse/JBMESSAGING-824
+ *
+ * Send a message to a queue that requires write permissions, and make sure the thread local
+ * SecurityContext stack is correctly cleaned up after that. We're using a test security
+ * manager that simulates a JBoss JaasSecurityManager.
+ *
+ */
+ public void testGuestAuthorizedSend() throws Exception
+ {
+ if(ServerManagement.isRemote())
+ {
+ fail("This test is supposed to be run in a local configuration");
+ }
+
+ MockJBossSecurityManager sm =
+ (MockJBossSecurityManager)ic.lookup(MockJBossSecurityManager.TEST_SECURITY_DOMAIN);
+ assertTrue(sm.isSimulateJBossJaasSecurityManager());
+
+ ConnectionFactory cf = (ConnectionFactory)ic.lookup("/ConnectionFactory");
+ Queue queue = (Queue)ic.lookup("/queue/SecureTestQueue");
+
+ Principal nabopolassar = new SimplePrincipal("nabopolassar");
+ Set principals = new HashSet();
+ principals.add(nabopolassar);
+ Subject subject =
+ new Subject(false, principals, Collections.EMPTY_SET, Collections.EMPTY_SET);
+ Principal nebuchadrezzar = new SimplePrincipal("nebuchadrezzar");
+
+ SecurityAssociation.pushSubjectContext(subject, nebuchadrezzar, "xexe");
+
+ Connection conn = null;
+
+ try
+ {
+ conn = cf.createConnection();
+ conn.start();
+
+ Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer prod = session.createProducer(queue);
+ MessageConsumer cons = session.createConsumer(queue);
+
+ TextMessage m = session.createTextMessage("floccinaucinihilipilification");
+
+ prod.send(m);
+
+ TextMessage rm = (TextMessage)cons.receive(5000);
+
+ assertEquals("floccinaucinihilipilification", rm.getText());
+
+ SecurityAssociation.SubjectContext context = SecurityAssociation.popSubjectContext();
+
+ Subject s = context.getSubject();
+ assertNotNull(s);
+ Set ps = s.getPrincipals();
+ assertNotNull(ps);
+ assertEquals(1, ps.size());
+ Principal p = (Principal)ps.iterator().next();
+ assertTrue(p instanceof SimplePrincipal);
+ assertEquals("nabopolassar", ((SimplePrincipal)p).getName());
+
+ p = context.getPrincipal();
+ assertNotNull(p);
+ assertTrue(p instanceof SimplePrincipal);
+ assertEquals("nebuchadrezzar", ((SimplePrincipal)p).getName());
+
+ Object o = context.getCredential();
+ assertNotNull(o);
+ assertEquals("xexe", o);
+ }
+ finally
+ {
+ if (conn != null)
+ {
+ conn.close();
+ }
+ }
+ }
+
+ /**
+ * Test for http://jira.jboss.org/jira/browse/JBMESSAGING-824
+ *
+ * Send a message to a queue that requires write permissions, and make sure the thread local
+ * SecurityContext stack is correctly cleaned up after that. We're using a test security
+ * manager that simulates a JBoss JaasSecurityManager.
+ */
+ public void testAuthorizedSend() throws Exception
+ {
+ if(ServerManagement.isRemote())
+ {
+ fail("This test is supposed to be run in a local configuration");
+ }
+
+ MockJBossSecurityManager sm =
+ (MockJBossSecurityManager)ic.lookup(MockJBossSecurityManager.TEST_SECURITY_DOMAIN);
+ assertTrue(sm.isSimulateJBossJaasSecurityManager());
+
+ ConnectionFactory cf = (ConnectionFactory)ic.lookup("/ConnectionFactory");
+ Queue queue = (Queue)ic.lookup("/queue/SecureTestQueue");
+
+ Principal nabopolassar = new SimplePrincipal("nabopolassar");
+ Set principals = new HashSet();
+ principals.add(nabopolassar);
+ Subject subject =
+ new Subject(false, principals, Collections.EMPTY_SET, Collections.EMPTY_SET);
+ Principal nebuchadrezzar = new SimplePrincipal("nebuchadrezzar");
+
+ SecurityAssociation.pushSubjectContext(subject, nebuchadrezzar, "xexe");
+
+ Connection conn = null;
+
+ try
+ {
+ conn = cf.createConnection("john", "needle");
+ conn.start();
+
+ Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer prod = session.createProducer(queue);
+ MessageConsumer cons = session.createConsumer(queue);
+
+ TextMessage m = session.createTextMessage("floccinaucinihilipilification");
+
+ prod.send(m);
+
+ TextMessage rm = (TextMessage)cons.receive(5000);
+
+ assertEquals("floccinaucinihilipilification", rm.getText());
+
+ SecurityAssociation.SubjectContext context = SecurityAssociation.popSubjectContext();
+
+ Subject s = context.getSubject();
+ assertNotNull(s);
+ Set ps = s.getPrincipals();
+ assertNotNull(ps);
+ assertEquals(1, ps.size());
+ Principal p = (Principal)ps.iterator().next();
+ assertTrue(p instanceof SimplePrincipal);
+ assertEquals("nabopolassar", ((SimplePrincipal)p).getName());
+
+ p = context.getPrincipal();
+ assertNotNull(p);
+ assertTrue(p instanceof SimplePrincipal);
+ assertEquals("nebuchadrezzar", ((SimplePrincipal)p).getName());
+
+ Object o = context.getCredential();
+ assertNotNull(o);
+ assertEquals("xexe", o);
+ }
+ finally
+ {
+ if (conn != null)
+ {
+ conn.close();
+ }
+ }
+ }
+
// Package protected ----------------------------------------------------------------------------
// Protected ------------------------------------------------------------------------------------
protected void setUp() throws Exception
{
+ if(ServerManagement.isRemote())
+ {
+ fail("This test is supposed to be run in a local configuration");
+ }
+
super.setUp();
ServerManagement.start("all");
@@ -148,13 +320,38 @@
ServerManagement.deployQueue("TestQueue");
+ ServerManagement.deployQueue("SecureTestQueue");
+
+ final String secureQueueConfig =
+ "<security>" +
+ "<role name=\"publisher\" read=\"true\" write=\"true\" create=\"false\"/>" +
+ "<role name=\"guest\" read=\"true\" write=\"true\" create=\"false\"/>" +
+ "</security>";
+ ServerManagement.configureSecurityForDestination("SecureTestQueue", secureQueueConfig);
+
+ // make MockSecurityManager simulate JaasSecurityManager behavior. This is the whole point
+ // of this test, to catch JBoss AS integreation failure before the integration test suite
+ // does. However, this MUST NOT be a replacement for integration tests, it's just an
+ // additional safety layer.
+
+ MockJBossSecurityManager sm =
+ (MockJBossSecurityManager)ic.lookup(MockJBossSecurityManager.TEST_SECURITY_DOMAIN);
+
+ sm.setSimulateJBossJaasSecurityManager(true);
+
log.debug("setup done");
}
protected void tearDown() throws Exception
{
ServerManagement.undeployQueue("TestQueue");
+ ServerManagement.undeployQueue("SecureTestQueue");
+ MockJBossSecurityManager sm =
+ (MockJBossSecurityManager)ic.lookup(MockJBossSecurityManager.TEST_SECURITY_DOMAIN);
+
+ sm.setSimulateJBossJaasSecurityManager(false);
+
ic.close();
super.tearDown();
More information about the jboss-cvs-commits
mailing list