[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