[jboss-cvs] jbosssx/src/main/org/jboss/security/plugins ...
Anil Saldhana
anil.saldhana at jboss.com
Fri Jul 14 14:40:36 EDT 2006
User: asaldhana
Date: 06/07/14 14:40:36
Modified: src/main/org/jboss/security/plugins Tag:
JBoss_4_0_2_JBAS-977 JaasSecurityManager.java
SubjectActions.java
Log:
JBAS-3397: Remove the synchronization on the isValid method
Revision Changes Path
No revision
No revision
1.41.2.4.42.1 +122 -45 jbosssx/src/main/org/jboss/security/plugins/JaasSecurityManager.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: JaasSecurityManager.java
===================================================================
RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/plugins/JaasSecurityManager.java,v
retrieving revision 1.41.2.4
retrieving revision 1.41.2.4.42.1
diff -u -b -r1.41.2.4 -r1.41.2.4.42.1
--- JaasSecurityManager.java 17 Feb 2005 00:14:07 -0000 1.41.2.4
+++ JaasSecurityManager.java 14 Jul 2006 18:40:36 -0000 1.41.2.4.42.1
@@ -1,5 +1,5 @@
/*
- * JBoss, the OpenSource EJB server
+ * JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
@@ -37,13 +37,13 @@
domain name associated with the class for authentication,
and the context JAAS Subject object for role mapping.
- @see #isValid(Principal, Object)
+ @see #isValid(Principal, Object, Subject)
@see #getPrincipal(Principal)
@see #doesUserHaveRole(Principal, Set)
@author <a href="on at ibis.odessa.ua">Oleg Nitz</a>
@author Scott.Stark at jboss.org
- @version $Revision: 1.41.2.4 $
+ @version $Revision: 1.41.2.4.42.1 $
*/
public class JaasSecurityManager extends ServiceMBeanSupport
implements SubjectSecurityManager, RealmMapping
@@ -59,11 +59,47 @@
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;
public DomainInfo(int lifetime)
{
expirationTime = 1000 * lifetime;
}
+
+ 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;
@@ -79,15 +115,18 @@
public void destroy()
{
if( trace )
- log.trace("destroy, subject="+subject+", this="+this);
- try
+ log.trace("destroy, subject="+subject+", this="+this
+ +", activeUsers="+activeUsers);
+ synchronized( this )
{
- loginCtx.logout();
- }
- catch(Exception e)
+ if( activeUsers == 0 )
+ logout();
+ else
{
if( trace )
- log.trace("Cache entry logout failed", e);
+ log.trace("destroy saw activeUsers="+activeUsers);
+ needsDestroy = true;
+ }
}
}
public Object getValue()
@@ -98,10 +137,7 @@
{
StringBuffer tmp = new StringBuffer(super.toString());
tmp.append('[');
- tmp.append("Subject(");
- tmp.append(System.identityHashCode(subject));
- tmp.append(").principals=");
- tmp.append(subject.getPrincipals());
+ tmp.append(SubjectActions.toString(subject));
tmp.append(",credential.class=");
if( credential != null )
{
@@ -173,12 +209,13 @@
String msg = "Failed to find setSecurityInfo(Princpal, Object) method in handler";
throw new UndeclaredThrowableException(e, msg);
}
+ log.debug("CallbackHandler: "+handler);
}
/** The domainCache is typically a shared object that is populated
by the login code(LoginModule, etc.) and read by this class in the
isValid() method.
- @see #isValid(Principal, Object)
+ @see #isValid(Principal, Object, Subject)
*/
public void setCachePolicy(CachePolicy domainCache)
{
@@ -210,6 +247,10 @@
*/
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();
}
@@ -236,17 +277,22 @@
the state of the authenticated Subject.
@return true if the principal was authenticated, false otherwise.
*/
- public synchronized boolean isValid(Principal principal, Object credential,
+ public boolean isValid(Principal principal, Object credential,
Subject activeSubject)
{
// Check the cache first
DomainInfo cacheInfo = getCacheInfo(principal, true);
if( trace )
- log.trace("Begin isValid, cache info: "+cacheInfo);
+ 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 )
@@ -277,6 +323,7 @@
// If the mapping did not have a callerPrincipal just use principal
if( result == null )
result = principal;
+ info.release();
}
}
@@ -285,9 +332,13 @@
/** Does the current Subject have a role(a Principal) that equates to one
of the role names. This method obtains the Group named 'Roles' from
- the principal set of the currently authenticated Subject and then
- creates a SimplePrincipal for each name in roleNames. If the role is
- a member of the Roles group, then the user has the role.
+ the principal set of the currently authenticated Subject as determined
+ by the SecurityAssociation.getSubject() method and then creates a
+ SimplePrincipal for each name in roleNames. If the role is a member of the
+ Roles group, then the user has the role. This requires that the caller
+ establish the correct SecurityAssociation subject prior to calling this
+ method. In the past this was done as a side-effect of an isValid() call,
+ but this is no longer the case.
@param principal - ignored. The current authenticated Subject determines
the active user and assigned user roles.
@param rolePrincipals - a Set of Principals for the roles to check.
@@ -316,6 +367,8 @@
{
Principal role = (Principal) iter.next();
hasRole = doesRoleGroupHaveRole(role, roles);
+ if( trace )
+ log.trace("hasRole("+role+")="+hasRole);
}
}
if( trace )
@@ -324,11 +377,16 @@
return hasRole;
}
- /** Validates operational environment Principal against the specified
- application domain role.
- @param principal - the caller principal as known in the operation environment.
- @param role - the application domain role that the principal is to be validated against.
- @return true if the principal has the role, false otherwise.
+ /** Does the current Subject have a role(a Principal) that equates to one
+ of the role names.
+
+ @see #doesUserHaveRole(Principal, Set)
+
+ @param principal - ignored. The current authenticated Subject determines
+ the active user and assigned user roles.
+ @param role - the application domain role that the principal is to be
+ validated against.
+ @return true if the active principal has the role, false otherwise.
*/
public boolean doesUserHaveRole(Principal principal, Principal role)
{
@@ -350,7 +408,11 @@
return hasRole;
}
- /** Return the set of domain roles the principal has been assigned.
+ /** Return the set of domain roles the current active Subject 'Roles' group
+ found in the subject Principals set.
+
+ @param principal - ignored. The current authenticated Subject determines
+ the active user and assigned user roles.
@return The Set<Principal> for the application domain roles that the
principal has been assigned.
*/
@@ -464,23 +526,34 @@
private LoginContext defaultLogin(Principal principal, Object credential)
throws LoginException
{
- // We use our internal CallbackHandler to provide the security info
+ /* 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
{
- setSecurityInfo.invoke(handler, securityInfo);
+ theHandler = (CallbackHandler) handler.getClass().newInstance();
+ setSecurityInfo.invoke(theHandler, securityInfo);
}
- catch (Exception e)
+ catch (Throwable e)
{
if( trace )
log.trace("Failed to setSecurityInfo on handler", e);
- throw new LoginException("Failed to setSecurityInfo on handler, msg="
- + e.getMessage());
+ 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;
- lc = SubjectActions.createLoginContext(securityDomain, subject, handler);
+ 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;
}
@@ -569,10 +642,9 @@
/** 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 authorization accesses.
- If it were to be true for an authorization access a previously authenticated
- user could be seen to not have their expected permissions due to a cache
- expiration.
+ 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.
@@ -591,6 +663,8 @@
cacheInfo = (DomainInfo) domainCache.get(principal);
else
cacheInfo = (DomainInfo) domainCache.peek(principal);
+ if( cacheInfo != null )
+ cacheInfo.acquire();
}
return cacheInfo;
}
@@ -615,7 +689,10 @@
info.credential = credential;
if( trace )
- log.trace("updateCache, subject="+subject);
+ {
+ log.trace("updateCache, inputSubject="+SubjectActions.toString(subject)
+ +", cacheSubject="+SubjectActions.toString(info.subject));
+ }
/* Get the Subject callerPrincipal by looking for a Group called
'CallerPrincipal'
1.3.2.4.42.1 +40 -1 jbosssx/src/main/org/jboss/security/plugins/SubjectActions.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: SubjectActions.java
===================================================================
RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/plugins/SubjectActions.java,v
retrieving revision 1.3.2.4
retrieving revision 1.3.2.4.42.1
diff -u -b -r1.3.2.4 -r1.3.2.4.42.1
--- SubjectActions.java 6 Apr 2005 21:16:55 -0000 1.3.2.4
+++ SubjectActions.java 14 Jul 2006 18:40:36 -0000 1.3.2.4.42.1
@@ -27,6 +27,35 @@
*/
class SubjectActions
{
+ private static class ToStringSubjectAction implements PrivilegedAction
+ {
+ Subject subject;
+ ToStringSubjectAction(Subject subject)
+ {
+ this.subject = subject;
+ }
+ public Object run()
+ {
+ StringBuffer tmp = new StringBuffer();
+ tmp.append("Subject(");
+ tmp.append(System.identityHashCode(subject));
+ tmp.append(").principals=");
+ Iterator principals = subject.getPrincipals().iterator();
+ while( principals.hasNext() )
+ {
+ Object p = principals.next();
+ Class c = p.getClass();
+ tmp.append(c.getName());
+ tmp.append('@');
+ tmp.append(System.identityHashCode(c));
+ tmp.append('(');
+ tmp.append(p);
+ tmp.append(')');
+ }
+ return tmp.toString();
+ }
+ }
+
private static class GetSubjectAction implements PrivilegedAction
{
static PrivilegedAction ACTION = new GetSubjectAction();
@@ -176,7 +205,10 @@
static void copySubject(Subject fromSubject, Subject toSubject, boolean setReadOnly)
{
CopySubjectAction action = new CopySubjectAction(fromSubject, toSubject, setReadOnly);
+ if( System.getSecurityManager() != null )
AccessController.doPrivileged(action);
+ else
+ action.run();
}
static LoginContext createLoginContext(String securityDomain, Subject subject,
@@ -236,5 +268,12 @@
}
}
+ static String toString(Subject subject)
+ {
+ ToStringSubjectAction action = new ToStringSubjectAction(subject);
+ String info = (String) AccessController.doPrivileged(action);
+ return info;
+ }
+
}
More information about the jboss-cvs-commits
mailing list