[jboss-cvs] JBossAS SVN: r67657 - trunk/security/src/main/org/jboss/security/plugins.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Fri Nov 30 14:28:18 EST 2007


Author: anil.saldhana at jboss.com
Date: 2007-11-30 14:28:18 -0500 (Fri, 30 Nov 2007)
New Revision: 67657

Modified:
   trunk/security/src/main/org/jboss/security/plugins/JaasSecurityManager.java
Log:
JBAS-4599: JaasSecurityManager refactored to include a delegate

Modified: trunk/security/src/main/org/jboss/security/plugins/JaasSecurityManager.java
===================================================================
--- trunk/security/src/main/org/jboss/security/plugins/JaasSecurityManager.java	2007-11-30 13:36:23 UTC (rev 67656)
+++ trunk/security/src/main/org/jboss/security/plugins/JaasSecurityManager.java	2007-11-30 19:28:18 UTC (rev 67657)
@@ -21,34 +21,22 @@
 */
 package org.jboss.security.plugins;
 
-import java.lang.reflect.Method;
 import java.lang.reflect.UndeclaredThrowableException;
 import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
 import javax.security.auth.Subject;
 import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
 import javax.security.auth.message.MessageInfo;
 
-import org.jboss.logging.Logger;
 import org.jboss.security.AuthenticationManager;
-import org.jboss.security.AuthorizationManager;
 import org.jboss.security.RealmMapping;
-import org.jboss.security.SecurityConstants;
-import org.jboss.security.SecurityContext;
-import org.jboss.security.SecurityUtil;
 import org.jboss.security.SubjectSecurityManager;
 import org.jboss.security.auth.callback.SecurityAssociationHandler;
+import org.jboss.security.plugins.auth.JaasSecurityManagerBase;
 import org.jboss.system.ServiceMBeanSupport;
 import org.jboss.util.CachePolicy;
-import org.jboss.util.TimedCachePolicy;
 
 /** The JaasSecurityManager is responsible both for authenticating credentials
  associated with principals and for role mapping. This implementation relies
@@ -67,156 +55,9 @@
 */
 public class JaasSecurityManager extends ServiceMBeanSupport
    implements SubjectSecurityManager, RealmMapping
-{
-   /** The authentication cache object.
-    */
-   public static class DomainInfo implements TimedCachePolicy.TimedEntry
-   {
-      private static Logger log = Logger.getLogger(DomainInfo.class);
-      private static boolean trace = log.isTraceEnabled();
-      private LoginContext loginCtx;
-      private Subject subject;
-      private Object credential;
-      private Principal callerPrincipal;
-      private long expirationTime;
-      /** Is there an active authentication in process */
-      private boolean needsDestroy;
-      /** The number of users sharing this DomainInfo */
-      private int activeUsers;
-
-      /**
-       Create a cache entry with the given lifetime in seconds. Since this comes
-       from the TimedCachePolicy, its expected to be <= Integer.MAX_VALUE.
-       
-       @param lifetime - lifetime in seconds. A lifetime <= 0 means no caching
-         with the exception of -1 which indicates that the cache entry never
-         expires.
-       */
-      public DomainInfo(long lifetime)
-      {
-         expirationTime = lifetime;
-         if( expirationTime != -1 )
-            expirationTime *= 1000;
-      }
-
-      synchronized int acquire()
-      {
-         return activeUsers ++;
-      }
-      synchronized int release()
-      {
-         int users = activeUsers --;
-         if( needsDestroy == true && users == 0 )
-         {
-            if( trace )
-               log.trace("needsDestroy is true, doing logout");
-            logout();
-         }
-         return users;
-      }
-      synchronized void logout()
-      {
-         if( trace )
-            log.trace("logout, subject="+subject+", this="+this);
-         try
-         {
-            if( loginCtx != null )
-               loginCtx.logout();
-         }
-         catch(Throwable e)
-         {
-            if( trace )
-               log.trace("Cache entry logout failed", e);
-         }
-      }
-
-      public void init(long now)
-      {
-         expirationTime += now;
-      }
-      public boolean isCurrent(long now)
-      {
-         boolean isCurrent = expirationTime == -1;
-         if( isCurrent == false )
-            isCurrent = expirationTime > now;
-         return isCurrent;
-      }
-      public boolean refresh()
-      {
-         return false;
-      }
-      /**
-       * This 
-       */ 
-      public void destroy()
-      {
-         if( trace )
-         {
-            log.trace("destroy, subject="+subject+", this="+this
-               +", activeUsers="+activeUsers);
-         }
-
-         synchronized( this )
-         {
-            if( activeUsers == 0 )
-               logout();
-            else
-            {
-               if( trace )
-                  log.trace("destroy saw activeUsers="+activeUsers);
-               needsDestroy = true;
-            }
-         }
-      }
-      public Object getValue()
-      {
-         return this;
-      }
-      public String toString()
-      {
-         StringBuffer tmp = new StringBuffer(super.toString());
-         tmp.append('[');
-         tmp.append(SubjectActions.toString(subject));
-         tmp.append(",credential.class=");
-         if( credential != null )
-         {
-            Class c = credential.getClass();
-            tmp.append(c.getName());
-            tmp.append('@');
-            tmp.append(System.identityHashCode(c));
-         }
-         else
-         {
-            tmp.append("null");
-         }
-         tmp.append(",expirationTime=");
-         tmp.append(expirationTime);
-         tmp.append(']');
-
-         return tmp.toString();
-      }
-   }
-
-   /** The name of the domain this instance is securing. It is used as
-    the appName into the SecurityPolicy.
-    */
-   private String securityDomain;
-   /** A cache of DomainInfo objects keyd by Principal. This is now
-    always set externally by our security manager service.
-    */
-   private CachePolicy domainCache;
-   /** The JAAS callback handler to use in defaultLogin */
-   private CallbackHandler handler;
-   /** The setSecurityInfo(Principal, Object) method of the handler obj */
-   private transient Method setSecurityInfo;
-   /** The flag to indicate that the Subject sets need to be deep copied*/
-   private boolean deepCopySubjectOption = false; 
-   
-   /** The log4j category for the security manager domain
-    */
-   protected Logger log;
-   protected boolean trace;
-
+{ 
+   private JaasSecurityManagerBase delegate = null;
+      
    /** Creates a default JaasSecurityManager for with a securityDomain
     name of 'other'.
     */
@@ -233,24 +74,7 @@
     */
    public JaasSecurityManager(String securityDomain, CallbackHandler handler)
    {
-      this.securityDomain = securityDomain;
-      this.handler = handler;
-      String categoryName = getClass().getName()+'.'+securityDomain;
-      this.log = Logger.getLogger(categoryName);
-      this.trace = log.isTraceEnabled();
-
-      // Get the setSecurityInfo(Principal principal, Object credential) method
-      Class[] sig = {Principal.class, Object.class};
-      try
-      {
-         setSecurityInfo = handler.getClass().getMethod("setSecurityInfo", sig);
-      }
-      catch (Exception e)
-      {
-         String msg = "Failed to find setSecurityInfo(Princpal, Object) method in handler";
-         throw new UndeclaredThrowableException(e, msg);
-      } 
-      log.debug("CallbackHandler: "+handler);
+      delegate = new JaasSecurityManagerBase(securityDomain,handler); 
    }
 
    /** The domainCache is typically a shared object that is populated
@@ -260,8 +84,7 @@
     */
    public void setCachePolicy(CachePolicy domainCache)
    {
-      this.domainCache = domainCache;
-      log.debug("CachePolicy set to: "+domainCache);
+      delegate.setCachePolicy(domainCache); 
    }
 
    /**
@@ -272,8 +95,7 @@
     */
    public void setDeepCopySubjectOption(Boolean flag)
    {
-      log.debug("setDeepCopySubjectOption="+ flag);
-      this.deepCopySubjectOption = (flag == Boolean.TRUE) ;
+      delegate.setDeepCopySubjectOption(flag); 
    } 
    
    /** Not really used anymore as the security manager service manages the
@@ -281,8 +103,7 @@
     */
    public void flushCache()
    {
-      if( domainCache != null )
-         domainCache.flush();
+      delegate.flushCache(); 
    }
 
    /** Get the name of the security domain associated with this security mgr.
@@ -290,7 +111,7 @@
     */
    public String getSecurityDomain()
    {
-      return securityDomain;
+      return delegate.getSecurityDomain();
    }
 
    /** Get the currently authenticated Subject. This is a thread local
@@ -300,18 +121,7 @@
     */
    public Subject getActiveSubject()
    {
-      /* This does not use SubjectActions.getActiveSubject since the caller
-         must have the correct permissions to access the
-         SecurityAssociation.getSubject method.
-      */
-      //return SecurityAssociation.getSubject();
-      Subject subj = null;
-      SecurityContext sc = SecurityContextAssociation.getSecurityContext();
-      if(sc != null)
-      {
-         subj = sc.getUtil().getSubject();
-      }
-      return subj;
+      return delegate.getActiveSubject(); 
    }
 
    /** Validate that the given credential is correct for principal. This
@@ -322,7 +132,7 @@
     */
    public boolean isValid(Principal principal, Object credential)
    {
-      return isValid(principal, credential, null);
+      return delegate.isValid(principal, credential, null);
    }
 
    /** Validate that the given credential is correct for principal. This first
@@ -340,28 +150,12 @@
    public boolean isValid(Principal principal, Object credential,
       Subject activeSubject)
    {
-      // Check the cache first
-      DomainInfo cacheInfo = getCacheInfo(principal, true);
-      if( trace )
-         log.trace("Begin isValid, principal:"+principal+", cache info: "+cacheInfo);
-
-      boolean isValid = false;
-      if( cacheInfo != null )
-      {
-         isValid = validateCache(cacheInfo, credential, activeSubject);
-         if( cacheInfo != null )
-            cacheInfo.release();
-      }
-      if( isValid == false )
-         isValid = authenticate(principal, credential, activeSubject);
-      if( trace )
-         log.trace("End isValid, "+isValid); 
-      return isValid;
+      return delegate.isValid(principal, credential, activeSubject); 
    }
    
    public boolean isValid(MessageInfo requestMessage, Subject clientSubject, String layer)
    {
-      return false;
+      return delegate.isValid(requestMessage, clientSubject, layer);
    }
 
    /** Map the argument principal from the deployment environment principal
@@ -374,26 +168,7 @@
     */
    public Principal getPrincipal(Principal principal)
    {
-      if(domainCache == null)
-         return principal;
-      Principal result = principal; 
-      // Get the CallerPrincipal group member
-      synchronized( domainCache )
-      {
-         DomainInfo info = getCacheInfo(principal, false);
-         if( trace )
-            log.trace("getPrincipal, cache info: "+info);
-         if( info != null )
-         {
-            result = info.callerPrincipal;
-            // If the mapping did not have a callerPrincipal just use principal
-            if( result == null )
-               result = principal;
-            info.release();
-         }
-      }
-
-      return result;
+      return delegate.getPrincipal(principal); 
    }
 
    /** Does the current Subject have a role(a Principal) that equates to one
@@ -413,11 +188,9 @@
     @see java.security.acl.Group;
     @see Subject#getPrincipals()
     */
-   public boolean doesUserHaveRole(Principal principal, Set rolePrincipals)
-   { 
-      AuthorizationManager am = SecurityUtil.getAuthorizationManager(securityDomain, 
-            SecurityConstants.JAAS_CONTEXT_ROOT);
-      return am.doesUserHaveRole(principal, rolePrincipals); 
+   public boolean doesUserHaveRole(Principal principal, Set<Principal> rolePrincipals)
+   {
+      return delegate.doesUserHaveRole(principal, rolePrincipals); 
    } 
 
    /** Return the set of domain roles the current active Subject 'Roles' group
@@ -428,306 +201,16 @@
     @return The Set<Principal> for the application domain roles that the
     principal has been assigned.
    */
-   public Set getUserRoles(Principal principal)
+   public Set<Principal> getUserRoles(Principal principal)
    {
-      AuthorizationManager am = SecurityUtil.getAuthorizationManager(securityDomain,
-            SecurityConstants.JAAS_CONTEXT_ROOT);
-      return am.getUserRoles(principal);
+      return delegate.getUserRoles(principal); 
    } 
    
    /**
     * @see AuthenticationManager#getTargetPrincipal(Principal,Map)
     */
-   public Principal getTargetPrincipal(Principal anotherDomainPrincipal, Map contextMap)
+   public Principal getTargetPrincipal(Principal anotherDomainPrincipal, Map<String,Object> contextMap)
    {
-      throw new RuntimeException("Not implemented yet");
-   }
-
-   /** Currently this simply calls defaultLogin() to do a JAAS login using the
-    security domain name as the login module configuration name.
-    
-    * @param principal - the user id to authenticate
-    * @param credential - an opaque credential.
-    * @return false on failure, true on success.
-    */
-   private boolean authenticate(Principal principal, Object credential,
-      Subject theSubject)
-   {
-      Subject subject = null;
-      boolean authenticated = false;
-      LoginException authException = null;
-
-      try
-      {
-         // Validate the principal using the login configuration for this domain
-         LoginContext lc = defaultLogin(principal, credential);
-         subject = lc.getSubject();
-
-         // Set the current subject if login was successful
-         if( subject != null )
-         {
-            // Copy the current subject into theSubject
-            if( theSubject != null )
-            {
-               SubjectActions.copySubject(subject, theSubject, false,this.deepCopySubjectOption);
-            }
-            else
-            {
-               theSubject = subject;
-            }
-
-            authenticated = true;
-            // Build the Subject based DomainInfo cache value
-            updateCache(lc, subject, principal, credential);
-         }
-      }
-      catch(LoginException e)
-      {
-         // Don't log anonymous user failures unless trace level logging is on
-         if( principal != null && principal.getName() != null || trace )
-            log.trace("Login failure", e);
-         authException = e;
-      }
-      // Set the security association thread context info exception
-      SubjectActions.setContextInfo("org.jboss.security.exception", authException);
-
-      return authenticated;
-   }
-
-   /** Pass the security info to the login modules configured for
-    this security domain using our SecurityAssociationHandler.
-    @return The authenticated Subject if successful.
-    @exception LoginException throw if login fails for any reason.
-    */
-   private LoginContext defaultLogin(Principal principal, Object credential)
-      throws LoginException
-   {
-      /* We use our internal CallbackHandler to provide the security info. A
-      copy must be made to ensure there is a unique handler per active
-      login since there can be multiple active logins.
-      */
-      Object[] securityInfo = {principal, credential};
-      CallbackHandler theHandler = null;
-      try
-      {
-         theHandler = (CallbackHandler) handler.getClass().newInstance();
-         setSecurityInfo.invoke(theHandler, securityInfo);
-      }
-      catch (Throwable e)
-      {
-         if( trace )
-            log.trace("Failed to create/setSecurityInfo on handler", e);
-         LoginException le = new LoginException("Failed to setSecurityInfo on handler");
-         le.initCause(e);
-         throw le;
-      }
-      Subject subject = new Subject();
-      LoginContext lc = null;
-      if( trace )
-         log.trace("defaultLogin, principal="+principal);
-      lc = SubjectActions.createLoginContext(securityDomain, subject, theHandler);
-      lc.login();
-      if( trace )
-         log.trace("defaultLogin, lc="+lc+", subject="+SubjectActions.toString(subject));
-      return lc;
-   }
-
-   /** Validate the cache credential value against the provided credential
-    */
-   private boolean validateCache(DomainInfo info, Object credential,
-      Subject theSubject)
-   {
-      if( trace )
-      {
-         StringBuffer tmp = new StringBuffer("Begin validateCache, info=");
-         tmp.append(info.toString());
-         tmp.append(";credential.class=");
-         if( credential != null )
-         {
-            Class c = credential.getClass();
-            tmp.append(c.getName());
-            tmp.append('@');
-            tmp.append(System.identityHashCode(c));
-         }
-         else
-         {
-            tmp.append("null");
-         }
-         log.trace(tmp.toString());
-      }
-
-      Object subjectCredential = info.credential;
-      boolean isValid = false;
-      // Check for a null credential as can be the case for an anonymous user
-      if( credential == null || subjectCredential == null )
-      {
-         // Both credentials must be null
-         isValid = (credential == null) && (subjectCredential == null);
-      }
-      // See if the credential is assignable to the cache value
-      else if( subjectCredential.getClass().isAssignableFrom(credential.getClass()) )
-      {
-        /* Validate the credential by trying Comparable, char[], byte[],
-         Object[], and finally Object.equals()
-         */
-         if( subjectCredential instanceof Comparable )
-         {
-            Comparable c = (Comparable) subjectCredential;
-            isValid = c.compareTo(credential) == 0;
-         }
-         else if( subjectCredential instanceof char[] )
-         {
-            char[] a1 = (char[]) subjectCredential;
-            char[] a2 = (char[]) credential;
-            isValid = Arrays.equals(a1, a2);
-         }
-         else if( subjectCredential instanceof byte[] )
-         {
-            byte[] a1 = (byte[]) subjectCredential;
-            byte[] a2 = (byte[]) credential;
-            isValid = Arrays.equals(a1, a2);
-         }
-         else if( subjectCredential.getClass().isArray() )
-         {
-            Object[] a1 = (Object[]) subjectCredential;
-            Object[] a2 = (Object[]) credential;
-            isValid = Arrays.equals(a1, a2);
-         }
-         else
-         {
-            isValid = subjectCredential.equals(credential);
-         }
-      }
-      else if( subjectCredential instanceof char[] && credential instanceof String )
-      {
-         char[] a1 = (char[]) subjectCredential;
-         char[] a2 = ((String) credential).toCharArray();
-         isValid = Arrays.equals(a1, a2);
-      }
-      else if( subjectCredential instanceof String && credential instanceof char[] )
-      {
-         char[] a1 = ((String) subjectCredential).toCharArray();
-         char[] a2 = (char[]) credential;
-         isValid = Arrays.equals(a1, a2);         
-      }
-
-      // If the credentials match, set the thread's active Subject
-      if( isValid )
-      {
-         // Copy the current subject into theSubject
-         if( theSubject != null )
-         {
-            SubjectActions.copySubject(info.subject, theSubject, false,this.deepCopySubjectOption);
-         }
-      }
-      if( trace )
-         log.trace("End validateCache, isValid="+isValid);
-
-      return isValid;
-   }
- 
-   /** An accessor method that synchronizes access on the domainCache
-    to avoid a race condition that can occur when the cache entry expires
-    in the presence of multi-threaded access. The allowRefresh flag should
-    be true for authentication accesses and false for other accesses.
-    Previously the other accesses included authorization and caller principal
-    mapping. Now the only use of the 
-
-    @param principal - the caller identity whose cached credentials are to
-    be accessed.
-    @param allowRefresh - a flag indicating if the cache access should flush
-    any expired entries.
-    */
-   private DomainInfo getCacheInfo(Principal principal, boolean allowRefresh)
-   {
-      if( domainCache == null )
-         return null;
-
-      DomainInfo cacheInfo = null;
-      synchronized( domainCache )
-      {
-          if( allowRefresh == true )
-            cacheInfo = (DomainInfo) domainCache.get(principal);
-          else
-            cacheInfo = (DomainInfo) domainCache.peek(principal);
-         if( cacheInfo != null )
-            cacheInfo.acquire();
-      }
-      return cacheInfo;
-   }
-
-   private Subject updateCache(LoginContext lc, Subject subject,
-      Principal principal, Object credential)
-   {
-      // If we don't have a cache there is nothing to update
-      if( domainCache == null )
-         return subject;
-
-      long lifetime = 0;
-      if( domainCache instanceof TimedCachePolicy )
-      {
-         TimedCachePolicy cache = (TimedCachePolicy) domainCache;
-         lifetime = cache.getDefaultLifetime();
-      }
-      DomainInfo info = new DomainInfo(lifetime);
-      info.loginCtx = lc;
-      info.subject = new Subject();
-      SubjectActions.copySubject(subject, info.subject, true, this.deepCopySubjectOption);
-      info.credential = credential;
-
-      if( trace )
-      {
-         log.trace("updateCache, inputSubject="+SubjectActions.toString(subject)
-            +", cacheSubject="+SubjectActions.toString(info.subject));
-      }
-
-     /* Get the Subject callerPrincipal by looking for a Group called
-        'CallerPrincipal'
-      */
-      Set subjectGroups = subject.getPrincipals(Group.class);
-      Iterator iter = subjectGroups.iterator();
-      while( iter.hasNext() )
-      {
-         Group grp = (Group) iter.next();
-         String name = grp.getName();
-         if( name.equals("CallerPrincipal") )
-         {
-            Enumeration members = grp.members();
-            if( members.hasMoreElements() )
-               info.callerPrincipal = (Principal) members.nextElement();
-         }
-      }
-      
-     /* Handle null principals with no callerPrincipal. This is an indication
-        of an user that has not provided any authentication info, but
-        has been authenticated by the domain login module stack. Here we look
-        for the first non-Group Principal and use that.
-      */
-      if( principal == null && info.callerPrincipal == null )
-      {
-         Set subjectPrincipals = subject.getPrincipals(Principal.class);
-         iter = subjectPrincipals.iterator();
-         while( iter.hasNext() )
-         {
-            Principal p = (Principal) iter.next();
-            if( (p instanceof Group) == false )
-               info.callerPrincipal = p;
-         }
-      }
-
-     /* If the user already exists another login is active. Currently
-        only one is allowed so remove the old and insert the new. Synchronize
-        on the domainCache to ensure the removal and addition are an atomic
-        operation so that getCacheInfo cannot see stale data.
-      */
-      synchronized( domainCache )
-      {
-         if( domainCache.peek(principal) != null )
-            domainCache.remove(principal);
-         domainCache.insert(principal, info);
-         if( trace )
-            log.trace("Inserted cache info: "+info);
-      }
-      return info.subject;
+      return delegate.getTargetPrincipal(anotherDomainPrincipal, contextMap); 
    } 
-}
+}
\ No newline at end of file




More information about the jboss-cvs-commits mailing list