[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