User: stark
Date: 01/02/14 13:20:09
Modified: security/src/main/org/jboss/security/plugins
JaasSecurityManagerService.java
JaasSecurityManagerServiceMBean.java
Added: security/src/main/org/jboss/security/plugins
JaasSecurityManager.java
Removed: security/src/main/org/jboss/security/plugins
SubjectSecurityManager.java
Log:
Updated SecurityInterceptor to be independent of any JAAS classes
and refactored security proxy layer to simplify the model.
Revision Changes Path
1.2 +40 -24
contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManagerService.java
Index: JaasSecurityManagerService.java
===================================================================
RCS file:
/products/cvs/ejboss/contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManagerService.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JaasSecurityManagerService.java 2001/02/12 09:24:54 1.1
+++ JaasSecurityManagerService.java 2001/02/14 21:20:08 1.2
@@ -29,6 +29,7 @@
import javax.management.ObjectName;
import org.jboss.logging.Log;
+import org.jboss.security.SecurityProxyFactory;
import org.jboss.util.ServiceMBeanSupport;
import org.jnp.server.NamingServer;
@@ -46,28 +47,33 @@
* @see SubjectSecurityManager
* @author <a href="[EMAIL PROTECTED]">Oleg Nitz</a>
* @author <a href="[EMAIL PROTECTED]">Rickard Oberg</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Scott Stark</a>
*/
public class JaasSecurityManagerService
extends ServiceMBeanSupport
implements JaasSecurityManagerServiceMBean, ObjectFactory
{
- /** The class that provides the */
+ /** The class that provides the security manager implementation */
private static String securityMgrClassName;
/** The loaded securityMgrClassName */
private static Class securityMgrClass;
/** The security credential cache policy, shared by all security mgrs */
private static CachePolicy cachePolicy;
private static String cacheJndiName;
+ /** The class that provides the SecurityProxyFactory implementation */
+ private static String securityProxyFactoryClassName;
+ private static Class securityProxyFactoryClass;
static NamingServer srv;
static Hashtable jsmMap = new Hashtable();
public JaasSecurityManagerService()
{
-System.out.println("JaasSecurityManagerService()");
try
- { // Use SubjectSecurityManager as the default
-
setSecurityManagerClass("org.jboss.security.plugins.SubjectSecurityManager");
+ { // Use JaasSecurityManager as the default
+
setSecurityManagerClass("org.jboss.security.plugins.JaasSecurityManager");
+ // Use SubjectSecurityProxyFactory as the default
+
setSecurityProxyFactoryClassName("org.jboss.security.SubjectSecurityProxyFactory");
}
catch(ClassNotFoundException e)
{
@@ -84,6 +90,16 @@
ClassLoader loader = Thread.currentThread().getContextClassLoader();
securityMgrClass = loader.loadClass(securityMgrClassName);
}
+ public String setSecurityProxyFactoryClassName()
+ {
+ return securityProxyFactoryClassName;
+ }
+ public void setSecurityProxyFactoryClassName(String className) throws
ClassNotFoundException
+ {
+ securityProxyFactoryClassName = className;
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ securityProxyFactoryClass = loader.loadClass(securityProxyFactoryClassName);
+ }
/** Get the jndi name under which the authentication cache policy is found
*/
public String getAuthenticationCacheJndiName()
@@ -108,22 +124,26 @@
return new ObjectName(OBJECT_NAME);
}
- protected void startService() throws Exception
- {
- srv = new NamingServer();
-
- InitialContext ic = new InitialContext();
-
- // Bind reference to SM subcontext in JNDI
- // Uses JNDI federation to handle the "java:jaas" context ourselves
- RefAddr refAddr = new StringRefAddr("nns", "JSM");
- Reference jsmsRef = new Reference("javax.naming.Context",
refAddr,getClass().getName(), null);
- Context ctx = new InitialContext();
- ctx.rebind("java:/jaas", jsmsRef);
+ protected void startService() throws Exception
+ {
+ srv = new NamingServer();
- cachePolicy = (CachePolicy) ctx.lookup(cacheJndiName);
- System.out.println("JAAS.startService, cachePolicy="+cachePolicy);
- }
+ InitialContext ic = new InitialContext();
+
+ // Bind reference to SM subcontext in JNDI
+ // Uses JNDI federation to handle the "java:jaas" context ourselves
+ RefAddr refAddr = new StringRefAddr("nns", "JSM");
+ Reference jsmsRef = new Reference("javax.naming.Context",
refAddr,getClass().getName(), null);
+ Context ctx = new InitialContext();
+ ctx.rebind("java:/jaas", jsmsRef);
+
+ cachePolicy = (CachePolicy) ctx.lookup(cacheJndiName);
+ System.out.println("JAAS.startService, cachePolicy="+cachePolicy);
+ // Bind the default SecurityProxyFactory instance under
java:/SecurityProxyFactory
+ SecurityProxyFactory proxyFactory = (SecurityProxyFactory)
securityProxyFactoryClass.newInstance();
+ ctx.bind("java:/SecurityProxyFactory", proxyFactory);
+ System.out.println("JAAS.startService, SecurityProxyFactory="+proxyFactory);
+ }
protected void stopService()
{
@@ -168,13 +188,11 @@
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment)
throws Exception
{
-System.out.println("JAAS.getObjectInstance, "+name);
if (name != null)
{
// Handle securityManager lookup
if (name.size() == 0)
return nameCtx;
-System.out.println(" -> "+jsmMap.get(name));
return jsmMap.get(name);
}
else
@@ -184,7 +202,6 @@
Name remainingName = cpe.getRemainingName();
Context ctx = new NamingContext(environment, null, srv);
-System.out.println(" -> "+ctx);
// Make sure that JSM is available
try
{
@@ -195,7 +212,6 @@
// Not found - add reference to JNDI, and a real security mgr to a
map
Reference jsmRef = new Reference(securityMgrClass.getName(),
getClass().getName(), null);
ctx.rebind(remainingName, jsmRef);
-System.out.println("JAAS.rebind "+remainingName+", "+jsmRef);
String securityDomain = remainingName.toString();
try
{ // Create instance of securityMgrClass
@@ -210,7 +226,7 @@
parameterTypes[0] = CachePolicy.class;
Method m = securityMgrClass.getMethod("setCachePolicy",
parameterTypes);
args[0] = cachePolicy;
- System.out.println("JAAS.setCachePolicy, c="+args[0]);
+System.out.println("JAAS.setCachePolicy, c="+args[0]);
m.invoke(securityMgr, args);
}
catch(Exception e2)
1.2 +2 -0
contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManagerServiceMBean.java
Index: JaasSecurityManagerServiceMBean.java
===================================================================
RCS file:
/products/cvs/ejboss/contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManagerServiceMBean.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JaasSecurityManagerServiceMBean.java 2001/02/12 09:24:55 1.1
+++ JaasSecurityManagerServiceMBean.java 2001/02/14 21:20:09 1.2
@@ -20,6 +20,8 @@
/** Set the class that provides the security manager implementation.
*/
public void setSecurityManagerClass(String className) throws
ClassNotFoundException;
+ public String setSecurityProxyFactoryClassName();
+ public void setSecurityProxyFactoryClassName(String className) throws
ClassNotFoundException;
/** Get the jndi name under which the authentication cache policy is found
*/
public String getAuthenticationCacheJndiName();
1.1
contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManager.java
Index: JaasSecurityManager.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import java.io.Serializable;
import java.net.URL;
import java.util.Set;
import java.util.Arrays;
import java.util.Iterator;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.security.acl.Group;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Policy;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.jboss.logging.Log;
import org.jboss.security.AppPolicy;
import org.jboss.security.AuthenticationInfo;
import org.jboss.security.EJBSecurityManager;
import org.jboss.security.RealmMapping;
import org.jboss.security.SecurityPolicy;
import org.jboss.security.SubjectSecurityManager;
import org.jboss.util.CachePolicy;
/** The SubjectSecurityManager is responsible both for authenticating credentials
associated with principals and for role mapping. This implementation relies
on the JAAS LoginContext/LoginModules associated with a bean for authentication,
and the context JAAS Subject object for role mapping.
@see #isValid(Principal, Object)
@see #Principal getPrincipal(Principal)
@see #doesUserHaveRole(Principal, Set)
@author <a href="[EMAIL PROTECTED]">Oleg Nitz</a>
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class JaasSecurityManager implements SubjectSecurityManager, RealmMapping,
Serializable
{
private String securityDomain;
private CachePolicy authenticationCache;
private SecurityPolicy securityPolicy;
private static ThreadLocal activeSubject = new ThreadLocal();
public JaasSecurityManager()
{
this("other");
}
public JaasSecurityManager(String securityDomain)
{
this.securityDomain = securityDomain;
securityPolicy = (SecurityPolicy) Policy.getPolicy();
}
/** The authenticationCache is typically a shared object that is populated
by the login code(LoginModule, etc.) and read by us.
*/
public void setCachePolicy(CachePolicy authenticationCache)
{
this.authenticationCache = authenticationCache;
System.out.println("SubjectSecurityManager("+securityDomain+").setCachePolicy,
c="+authenticationCache);
}
public void setSecurityPolicyName(String jndiName) throws NamingException
{
InitialContext ctx = new InitialContext();
securityPolicy = (SecurityPolicy) ctx.lookup(jndiName);
}
public String getSecurityDomain()
{
return securityDomain;
}
public Subject getActiveSubject()
{
return (Subject) activeSubject.get();
}
/** Validate that the given credential is correct for principal.
@return true if the principal was authenticated, false otherwise.
*/
public boolean isValid(Principal principal, Object credential)
{
// Check the cache first
Object cacheCredential = null;
if( authenticationCache != null )
cacheCredential = authenticationCache.get(principal);
System.out.println("SubjectSecurityManager("+securityDomain+").isValid,
p="+principal);
boolean isValid = false;
if( cacheCredential != null )
isValid = validateCache(cacheCredential, credential);
if( isValid == false )
isValid = authenticate(principal, credential);
return isValid;
}
/** Map the argument principal from the deployment environment principal
to the developer environment. This is called by the EJB context
getCallerPrincipal() to return the Principal as described by
the EJB developer domain.
@return a Principal object that is valid in the deployment environment
if one exists. If no Subject exists or the Subject has
*/
public Principal getPrincipal(Principal principal)
{
Principal result = principal;
AccessControlContext context = AccessController.getContext();
Subject subject = Subject.getSubject(context);
if( subject != null )
{ // If there is only one Principal, use it
Set subjectPrincipals = subject.getPrincipals();
if( subjectPrincipals.size() == 1 )
{
result = (Principal) subjectPrincipals.iterator().next();
}
else
{ // Look for a Group called getCallerPrincipal
Set subjectGroups = subject.getPrincipals(Group.class);
Iterator iter = subjectGroups.iterator();
while( iter.hasNext() )
{
Group grp = (Group) iter.next();
if( grp.getName().equals("getCallerPrincipal") )
{
result = (Principal) grp.members().nextElement();
break;
}
}
}
}
return result;
}
/** Does the current Subject have a role(a Principal) that equates to one
of the role names.
@param principal, ignored. The current AccessControlContext Subject determines
the active user and user roles.
@param roleNames, a set of String names for the roles to check.
*/
public boolean doesUserHaveRole(Principal principal, Set roleNames)
{
boolean hasRole = false;
AccessControlContext context = AccessController.getContext();
Subject subject = Subject.getSubject(context);
if( subject != null )
{
Set subjectPrincipals = subject.getPrincipals();
hasRole = subjectPrincipals.contains(principal);
if( hasRole == false )
{ // Check for Groups and see if principal belongs to any
Set subjectGroups = subject.getPrincipals(Group.class);
Iterator iter = subjectGroups.iterator();
while( hasRole == false && iter.hasNext() )
{
Group grp = (Group) iter.next();
hasRole = grp.isMember(principal);
}
}
}
return hasRole;
}
/**
* @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)
{ // If credential is not a char[] we don't now what to do...
if( (credential instanceof char[]) == false )
return false;
LoginContext lc;
Subject subj;
final String userName = principal.getName();
final char[] password = (char[]) credential;
boolean authenticated = false;
try
{
AppPolicy policy = securityPolicy.getAppPolicy(securityDomain);
if( policy != null )
{
AuthenticationInfo loginInfo = policy.getLoginInfo();
CallbackHandler callbackHandler = loginInfo.getAppCallbackHandler();
if( callbackHandler != null )
lc = new LoginContext(securityDomain, callbackHandler);
else
lc = new LoginContext(securityDomain);
lc.login();
activeSubject.set(lc.getSubject());
authenticated = true;
}
else
{
System.out.println("Failed to find security policy for:
"+securityDomain);
}
}
catch(LoginException e)
{
e.printStackTrace();
}
return authenticated;
}
private boolean validateCache(Object cacheCredential, Object credential)
{ // The cache value is the Subject with the principal username
Subject subject = (Subject) cacheCredential;
// Get the subject PublicCredentials to compare the credentials
Set credentials = subject.getPublicCredentials(credential.getClass());
if( credentials.isEmpty() == true )
{
System.out.println("Subject("+subject+") has no PublicCredentials of
type: "+credential.getClass());
return false;
}
Object subjectCredential = credentials.iterator().next();
boolean isValid = false;
if( subjectCredential instanceof Comparable )
{
Comparable c = (Comparable) subjectCredential;
isValid = c.compareTo(credential) == 0;
}
else if( credential instanceof char[] )
{
char[] a1 = (char[]) subjectCredential;
char[] a2 = (char[]) credential;
isValid = Arrays.equals(a1, a2);
}
else if( credential instanceof byte[] )
{
byte[] a1 = (byte[]) subjectCredential;
byte[] a2 = (byte[]) credential;
System.out.println("comparing byte[] credentials a1["+a1.length+"],
a2["+a2.length+"]");
isValid = Arrays.equals(a1, a2);
}
else
{
isValid = subjectCredential.equals(credential);
}
// If the crendential is still valid return true
if( isValid )
{
isValid = restoreSubject(subject);
}
System.out.println("User has valid cache auth="+isValid);
return isValid;
}
/** Set the argument subject to be the AccessControlContext subject. This
is done by creating a LoginContext('RestoreSubjectFromCache') that loads
the no-op RestoreSubjectFromCacheLoginModule.
*/
private boolean restoreSubject(Subject subject)
{
try
{
LoginContext lc = new LoginContext("RestoreSubjectFromCache", subject);
lc.login();
activeSubject.set(lc.getSubject());
System.out.println("restoreSubject, s="+lc.getSubject());
}
catch(LoginException e)
{
e.printStackTrace();
return false;
}
return true;
}
}