User: stark
Date: 01/02/12 01:24:57
Added: security/src/main/org/jboss/security/plugins
IdentityLoginModule.java
JaasSecurityManagerService.java
JaasSecurityManagerServiceMBean.java
RestoreSubjectFromCacheLoginModule.java
SRPServerProxy.java SRPService.java
SRPServiceMBean.java SRPVerifierStoreService.java
SRPVerifierStoreServiceMBean.java
SecurityPolicyService.java
SecurityPolicyServiceMBean.java
SubjectSecurityManager.java
Log:
Additions to the security framework to support JAAS based security
proxy layers
Revision Changes Path
1.1
contrib/security/src/main/org/jboss/security/plugins/IdentityLoginModule.java
Index: IdentityLoginModule.java
===================================================================
package org.jboss.security.plugins;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimplePrincipal;
/** A simple login module that simply associates the principal specified
in the module options with any subject authenticated against the module.
The type of Principal class used is org.jboss.security.SimplePrincipal.
If no principal option is specified a principal with the name of 'guest'
is used.
@see org.jboss.security.SimplePrincipal
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class IdentityLoginModule implements LoginModule
{
String principal;
Subject subject;
/** Creates new DigestLoginModule */
public IdentityLoginModule()
{
}
public void initialize(Subject subject, CallbackHandler handler, Map
sharedState, Map options)
{
this.subject = subject;
principal = (String) options.get("principal");
if( principal == null )
principal = "guest";
}
public boolean login() throws LoginException
{
subject.getPrincipals().add(new SimplePrincipal(principal));
return true;
}
public boolean commit() throws LoginException
{
return true;
}
public boolean abort() throws LoginException
{
return true;
}
public boolean logout() throws LoginException
{
return true;
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManagerService.java
Index: JaasSecurityManagerService.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Iterator;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.Reference;
import javax.naming.RefAddr;
import javax.naming.StringRefAddr;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import javax.naming.spi.NamingManager;
import javax.naming.CommunicationException;
import javax.naming.CannotProceedException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.jboss.logging.Log;
import org.jboss.util.ServiceMBeanSupport;
import org.jnp.server.NamingServer;
import org.jnp.interfaces.NamingContext;
import org.jboss.util.CachePolicy;
/**
* This is a JMX service which manages JAAS based SecurityManagers.
* JAAS SecurityManagers are responsible for validating credentials
* associated with principals. The service defaults to the
* org.jboss.security.plugins.SubjectSecurityManager implementation but
* this can be changed via the securityManagerClass property.
*
* @see JaasSecurityManager
* @see SubjectSecurityManager
* @author <a href="[EMAIL PROTECTED]">Oleg Nitz</a>
* @author <a href="[EMAIL PROTECTED]">Rickard Oberg</a>
*/
public class JaasSecurityManagerService
extends ServiceMBeanSupport
implements JaasSecurityManagerServiceMBean, ObjectFactory
{
/** The class that provides the */
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;
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");
}
catch(ClassNotFoundException e)
{
}
}
public String getSecurityManagerClass()
{
return securityMgrClassName;
}
public void setSecurityManagerClass(String className) throws
ClassNotFoundException
{
securityMgrClassName = className;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
securityMgrClass = loader.loadClass(securityMgrClassName);
}
/** Get the jndi name under which the authentication cache policy is found
*/
public String getAuthenticationCacheJndiName()
{
return cacheJndiName;
}
/** Set the jndi name under which the authentication cache policy is found
*/
public void setAuthenticationCacheJndiName(String jndiName)
{
this.cacheJndiName = jndiName;
}
public String getName()
{
return "JAAS Security Manager";
}
protected ObjectName getObjectName(MBeanServer server, ObjectName name)
throws javax.management.MalformedObjectNameException
{
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);
cachePolicy = (CachePolicy) ctx.lookup(cacheJndiName);
System.out.println("JAAS.startService, cachePolicy="+cachePolicy);
}
protected void stopService()
{
InitialContext ic;
try
{
ic = new InitialContext();
ic.unbind("java:/jaas");
}
catch (CommunicationException e)
{
// Do nothing, the naming services is already stopped
}
catch (Exception e)
{
log.exception(e);
}
}
// ObjectFactory implementation ----------------------------------
/**
* Object factory implementation. This method is a bit tricky as it is called
twice for each
* JSM lookup. Let's say the lookup is for "java:jaas/MySecurity". Then this will
first be
* called as JNDI starts the "jaas" federation. In that call we make sure that
the next call
* will go through, i.e. we check that the "MySecurity" binding is availble. Then
we return
* the implementation of the "jaas" context. Then, when the "MySecurity" is
dereferenced we
* look up the JSM from an internal static hash table.
*
* Note: it is possible to break this by doing the lookup in two phases: first
lookup "java:jaas"
* and then do a second lookup of "MySecurity". If that is done then the first
lookup has no way of
* knowing what name to check (i.e. it can't make sure that "MySecurity" is
available in the
* "java:jaas" context!
*
* @param obj
* @param name
* @param nameCtx
* @param environment
* @return
* @exception Exception
*/
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
{
// Handle "java:jaas" context
CannotProceedException cpe =
(CannotProceedException)environment.get(NamingManager.CPE);
Name remainingName = cpe.getRemainingName();
Context ctx = new NamingContext(environment, null, srv);
System.out.println(" -> "+ctx);
// Make sure that JSM is available
try
{
srv.lookup(remainingName);
}
catch(Exception e)
{
// 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
Class[] parameterTypes = {String.class};
Constructor ctor =
securityMgrClass.getConstructor(parameterTypes);
Object[] args = {securityDomain};
Object securityMgr = ctor.newInstance(args);
System.out.println("JAAS.Created securityMgr="+securityMgr);
// See if the security mgr supports an externalized cache policy
try
{
parameterTypes[0] = CachePolicy.class;
Method m = securityMgrClass.getMethod("setCachePolicy",
parameterTypes);
args[0] = cachePolicy;
System.out.println("JAAS.setCachePolicy, c="+args[0]);
m.invoke(securityMgr, args);
}
catch(Exception e2)
{ // No cache policy support, this is ok
}
System.out.println("JAAS.Added "+remainingName+", "+securityMgr+" to map");
jsmMap.put(remainingName, securityMgr);
}
catch(Exception e2)
{
e2.printStackTrace();
log.exception(e2);
throw e2;
}
}
return ctx;
}
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/JaasSecurityManagerServiceMBean.java
Index: JaasSecurityManagerServiceMBean.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
public interface JaasSecurityManagerServiceMBean
extends org.jboss.util.ServiceMBean
{
// Constants -----------------------------------------------------
public static final String OBJECT_NAME = ":service=JaasSecurityManager";
// Public --------------------------------------------------------
/** Get the class that provides the security manager implementation.
*/
public String getSecurityManagerClass();
/** Set the class that provides the security manager implementation.
*/
public void setSecurityManagerClass(String className) throws
ClassNotFoundException;
/** Get the jndi name under which the authentication cache policy is found
*/
public String getAuthenticationCacheJndiName();
/** Set the jndi name under which the authentication cache policy is found
*/
public void setAuthenticationCacheJndiName(String jndiName);
}
1.1
contrib/security/src/main/org/jboss/security/plugins/RestoreSubjectFromCacheLoginModule.java
Index: RestoreSubjectFromCacheLoginModule.java
===================================================================
package org.jboss.security.plugins;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimplePrincipal;
/** A pass through login module that simply returns true.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class RestoreSubjectFromCacheLoginModule implements LoginModule
{
/** Creates new DigestLoginModule */
public RestoreSubjectFromCacheLoginModule()
{
}
public boolean logout() throws LoginException
{
return true;
}
public void initialize(Subject subject, CallbackHandler handler, Map
sharedState, Map options)
{
}
public boolean login() throws LoginException
{
return true;
}
public boolean commit() throws LoginException
{
return true;
}
public boolean abort() throws LoginException
{
return true;
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SRPServerProxy.java
Index: SRPServerProxy.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.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import security.srp.protocol.SRPServerInterface;
/** A serializable proxy that is bound into JNDI with a reference to the
RMI implementation of a SRPServerInterface. This allows a client to lookup
the interface and not have the RMI stub for the server as it will be downloaded
to them when the SRPServerProxy is unserialized.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SRPServerProxy implements InvocationHandler, Serializable
{
private SRPServerInterface server;
/** Create a SRPServerProxy given the SRPServerInterface that method
invocations are to be delegated to.
*/
SRPServerProxy(SRPServerInterface server)
{
this.server = server;
}
/** The InvocationHandler invoke method. All calls are simply delegated to
the SRPServerInterface server object.
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object ret = null;
try
{
ret = method.invoke(server, args);
}
catch(InvocationTargetException e)
{
throw e.getTargetException();
}
catch(Throwable e)
{
e.printStackTrace();
throw e;
}
return ret;
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SRPService.java
Index: SRPService.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import java.lang.reflect.Proxy;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import org.jboss.naming.NonSerializableFactory;
import org.jboss.security.SimplePrincipal;
import org.jboss.util.ServiceMBeanSupport;
import org.jboss.util.TimedCachePolicy;
import security.srp.protocol.SRPRemoteServer;
import security.srp.protocol.SRPRemoteServer.SRPServerListener;
import security.srp.protocol.SRPServerInterface;
import security.srp.protocol.SRPServerSession;
import security.srp.protocol.SRPVerifierStore;
/** The JMX mbean interface for the SRP service. This mbean sets up an
RMI implementation of the 'Secure Remote Password' cryptographic authentication
system developed by Tom Wu ([EMAIL PROTECTED]). For more info on SRP
see http://www-cs-students.stanford.edu/~tjw/srp/.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SRPService extends ServiceMBeanSupport implements SRPServiceMBean,
SRPServerListener
{
private SRPRemoteServer server;
private int serverPort = 10099;
private SRPVerifierStore verifierStore;
private String verifierSourceJndiName = "srp:DefaultVerifierSource";
private String serverJndiName = "srp:SRPServerInterface";
private String cacheJndiName = "srp:AuthenticationCache";
private TimedCachePolicy cachePolicy;
// --- Begin SRPServiceMBean interface methods
/** Get the jndi name for the SRPVerifierSource implementation binding.
*/
public String getVerifierSourceJndiName()
{
return verifierSourceJndiName;
}
/** set the jndi name for the SRPVerifierSource implementation binding.
*/
public void setVerifierSourceJndiName(String jndiName)
{
this.verifierSourceJndiName = jndiName;
}
/** Get the jndi name under which the SRPServerInterface proxy should be bound
*/
public String getJndiName()
{
return serverJndiName;
}
/** Set the jndi name under which the SRPServerInterface proxy should be bound
*/
public void setJndiName(String jndiName)
{
this.serverJndiName = jndiName;
}
/** Get the jndi name under which the SRPServerInterface proxy should be bound
*/
public String getAuthenticationCacheJndiName()
{
return cacheJndiName;
}
/** Set the jndi name under which the SRPServerInterface proxy should be bound
*/
public void setAuthenticationCacheJndiName(String jndiName)
{
this.cacheJndiName = jndiName;
}
/** Get the RMI port for the SRPServerInterface
*/
public int getServerPort()
{
return serverPort;
}
/** Get the RMI port for the SRPServerInterface
*/
public void setServerPort(int serverPort)
{
this.serverPort = serverPort;
}
// --- End SRPServiceMBean interface methods
/** Called when username has sucessfully completed the SRP login.
*/
public void verifiedUser(String username, SRPServerSession session)
{
try
{
SimplePrincipal principal = new SimplePrincipal(username);
Subject subject = new Subject();
byte[] credential = session.getClientResponse();
subject.getPrincipals().add(principal);
subject.getPublicCredentials().add(credential);
synchronized( cachePolicy )
{ /* If the user already exists another login is active. Currently
only one is allowed so remove the old and insert the new.
*/
if( cachePolicy.peek(principal) != null )
cachePolicy.remove(principal);
cachePolicy.insert(principal, subject);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public String getName()
{
return "SRPService";
}
public void initService() throws Exception
{
}
public void startService() throws Exception
{
loadStore();
server = new SRPRemoteServer(verifierStore, serverPort);
server.addSRPServerListener(this);
// Bind a proxy into jndi
SRPServerProxy proxyHandler = new SRPServerProxy(server);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class[] interfaces = {SRPServerInterface.class};
Object proxy = Proxy.newProxyInstance(loader, interfaces, proxyHandler);
InitialContext ctx = new InitialContext();
ctx.rebind(serverJndiName, proxy);
System.out.println("Bound SRPServerProxy at "+serverJndiName);
// The type of cache needs to be externalized...
cachePolicy = new TimedCachePolicy(1800, false, 60);
cachePolicy.init();
cachePolicy.start();
// Bind a reference to store using NonSerializableFactory as the
ObjectFactory
NonSerializableFactory.rebind(ctx, cacheJndiName, cachePolicy);
System.out.println("Bound AuthenticationCache at "+cacheJndiName);
}
private void loadStore() throws NamingException
{
InitialContext ctx = new InitialContext();
// Get the SRPVerifierStore implementation
verifierStore = (SRPVerifierStore) ctx.lookup(verifierSourceJndiName);
if( server != null )
{
server.setVerifierStore(verifierStore);
}
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SRPServiceMBean.java
Index: SRPServiceMBean.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import javax.naming.NamingException;
/** The JMX mbean interface for the SRP service. This mbean sets up an
RMI implementation of the 'Secure Remote Password' cryptographic authentication
system developed by Tom Wu ([EMAIL PROTECTED]). For more info on SRP
see http://www-cs-students.stanford.edu/~tjw/srp/.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public interface SRPServiceMBean extends org.jboss.util.ServiceMBean
{
// Constants -----------------------------------------------------
public static final String OBJECT_NAME = ":service=SRPService";
/** Get the jndi name for the SRPVerifierSource implementation binding.
*/
public String getVerifierSourceJndiName();
/** set the jndi name for the SRPVerifierSource implementation binding.
*/
public void setVerifierSourceJndiName(String jndiName);
/** Get the jndi name under which the SRPServerInterface proxy should be bound
*/
public String getJndiName();
/** Set the jndi name under which the SRPServerInterface proxy should be bound
*/
public void setJndiName(String jndiName);
/** Get the jndi name under which the SRPServerInterface proxy should be bound
*/
public String getAuthenticationCacheJndiName();
/** Set the jndi name under which the SRPServerInterface proxy should be bound
*/
public void setAuthenticationCacheJndiName(String jndiName);
/** Get the RMI port for the SRPRemoteServerInterface
*/
public int getServerPort();
/** Set the RMI port for the SRPRemoteServerInterface
*/
public void setServerPort(int port);
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SRPVerifierStoreService.java
Index: SRPVerifierStoreService.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.File;
import java.io.IOException;
import java.net.URL;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import security.srp.protocol.SerialObjectStore;
import org.jboss.naming.NonSerializableFactory;
import org.jboss.util.ServiceMBeanSupport;
/** The JMX mbean interface for the SRP password verifier store. This
implementation uses the SerialObjectStore as a simple and yet secure
source of usernames and their password verifiers and verifier salts. It
also provides a simple interface for adding and deleting users from the
SerialObjectStore. The mbean stores a non-serializable reference to the
SRPVerifierStore interface in JNDI under the property.
@see security.srp.protocol.SerialObjectStore
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SRPVerifierStoreService extends ServiceMBeanSupport implements
SRPVerifierStoreServiceMBean
{
private SerialObjectStore store;
private String fileName = "SRPVerifierStore.ser";
private String jndiName = "srp:DefaultVerifierSource";
// --- Begin SRPVerifierStoreServiceMBean interface methods
/** Get the jndi name for the SRPVerifierSource implementation binding.
*/
public String getJndiName()
{
return jndiName;
}
/** set the jndi name for the SRPVerifierSource implementation binding.
*/
public void setJndiName(String jndiName)
{
this.jndiName = jndiName;
}
public void setStoreFile(String fileName) throws IOException
{
this.fileName = fileName;
if( store != null )
{
File storeFile = new File(fileName);
store.save(storeFile);
}
}
public void addUser(String username,String password) throws IOException
{
store.addUser(username, password);
System.out.println("Added username: "+username);
save();
}
public void delUser(String username) throws IOException
{
store.delUser(username);
System.out.println("Deleted username: "+username);
save();
}
// --- End SRPVerifierStoreServiceMBean interface methods
public String getName()
{
return "SRPVerifierStoreService";
}
public void initService() throws Exception
{
}
public void startService() throws Exception
{
File storeFile = new File(fileName);
store = new SerialObjectStore(storeFile);
System.out.println("Created SerialObjectStore at:
"+storeFile.getAbsolutePath());
InitialContext ctx = new InitialContext();
// Bind a reference to store using NonSerializableFactory as the
ObjectFactory
NonSerializableFactory.rebind(ctx, jndiName, store);
}
private void save() throws IOException
{
if( store != null )
{ // Try to locate the file on the classpath
File storeFile = new File(fileName);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
URL url = loader.getResource(fileName);
if( url == null )
{ // Try to locate the file's parent on the classpath
String parent = storeFile.getParent();
if( parent != null )
{
url = loader.getResource(parent);
if( url != null )
{
storeFile = new File(url.getFile(), storeFile.getName());
}
// else, just go with storeFile as a system file path
}
}
else
{
storeFile = new File(url.getFile());
}
store.save(storeFile);
}
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SRPVerifierStoreServiceMBean.java
Index: SRPVerifierStoreServiceMBean.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.IOException;
/** The JMX mbean interface for the SRP password verifier store.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public interface SRPVerifierStoreServiceMBean extends org.jboss.util.ServiceMBean
{
/** Get the jndi name for the SRPVerifierSource implementation binding.
*/
public String getJndiName();
/** set the jndi name for the SRPVerifierSource implementation binding.
*/
public void setJndiName(String jndiName);
/** Set the location of the user password verifier store
*/
public void setStoreFile(String fileName) throws IOException;
/** Add a user to the store.
*/
public void addUser(String username, String password) throws IOException;
/** Delete a user to the store.
*/
public void delUser(String username) throws IOException;
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SecurityPolicyService.java
Index: SecurityPolicyService.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.FileNotFoundException;
import java.net.URL;
import javax.naming.InitialContext;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.NamingException;
import javax.security.auth.Policy;
import org.jboss.naming.NonSerializableFactory;
import org.jboss.security.SecurityPolicy;
import org.jboss.security.SecurityPolicyParser;
import org.jboss.util.ServiceMBeanSupport;
/** The implementation class for the JMX SecurityPolicyServiceMBean. This
service creates a SecurityPolicy instance using a xml based policy store.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SecurityPolicyService extends ServiceMBeanSupport implements
SecurityPolicyServiceMBean
{
private String jndiName = "DefaultSecurityPolicy";
private SecurityPolicy securityPolicy;
private SecurityPolicyParser policySource;
private String policyFile;
/** Get the jndi name under which the SRPServerInterface proxy should be bound
*/
public String getJndiName()
{
return jndiName;
}
/** Set the jndi name under which the SRPServerInterface proxy should be bound
*/
public void setJndiName(String jndiName)
{
this.jndiName = jndiName;
}
public String getPolicyFile()
{
return policyFile;
}
public void setPolicyFile(String policyFile)
{
this.policyFile = policyFile;
}
public String getName()
{
return "SecurityPolicyService";
}
public void start() throws Exception
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
URL policyURL = loader.getResource(policyFile);
if( policyURL == null )
throw new FileNotFoundException("Failed to find URL for policy resource:
"+policyFile);
System.out.println("Loading policy file from: "+policyURL);
policySource = new SecurityPolicyParser(policyURL);
securityPolicy = new SecurityPolicy(policySource);
policySource.refresh();
InitialContext ctx = new InitialContext();
NonSerializableFactory.rebind(jndiName, securityPolicy);
// Bind a reference to securityPolicy using NonSerializableFactory as the
ObjectFactory
String className = securityPolicy.getClass().getName();
String factory = NonSerializableFactory.class.getName();
StringRefAddr addr = new StringRefAddr("nns", jndiName);
Reference memoryRef = new Reference(className, addr, factory, null);
ctx.rebind(jndiName, memoryRef);
// Install securityPolicy as the JAAS Policy
Policy.setPolicy(securityPolicy);
}
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SecurityPolicyServiceMBean.java
Index: SecurityPolicyServiceMBean.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import javax.naming.NamingException;
/** The JMX mbean interface for the
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public interface SecurityPolicyServiceMBean extends org.jboss.util.ServiceMBean
{
// Constants -----------------------------------------------------
public static final String OBJECT_NAME = ":service=SecurityPolicyService";
/** Get the jndi name under which the SRPServerInterface proxy should be bound
*/
public String getJndiName();
/** Set the jndi name under which the SRPServerInterface proxy should be bound
*/
public void setJndiName(String jndiName);
public String getPolicyFile();
public void setPolicyFile(String policyFile);
}
1.1
contrib/security/src/main/org/jboss/security/plugins/SubjectSecurityManager.java
Index: SubjectSecurityManager.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.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 [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SubjectSecurityManager implements EJBSecurityManager, RealmMapping,
Serializable
{
private String securityDomain;
private CachePolicy authenticationCache;
private SecurityPolicy securityPolicy;
private static ThreadLocal activeSubject = new ThreadLocal();
public SubjectSecurityManager()
{
this("other");
}
public SubjectSecurityManager(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;
}
}