User: stark
Date: 01/03/05 01:53:34
Added: src/main/org/jboss/security/plugins
AbstractServerLoginModule.java
JaasSecurityManager.java ProxyLoginModule.java
SRPServerProxy.java SRPService.java
SRPServiceMBean.java SRPVerifierStoreService.java
SRPVerifierStoreServiceMBean.java
SecurityAssociationCallback.java
SecurityAssociationHandler.java
SecurityPolicyService.java
SecurityPolicyServiceMBean.java
UsernamePasswordHandler.java
Log:
Initial version of the JBossSX module
Revision Changes Path
1.1
jbosssx/src/main/org/jboss/security/plugins/AbstractServerLoginModule.java
Index: AbstractServerLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import java.util.*;
import java.io.*;
import java.security.Principal;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
/**
* AbstractServerLoginModule
* written by: Edward Kenworthy 12th Dec 2000
*
* This class implements the common functionality required for a JAAS
ServerLoginModule.
* To implement your own implementation you need to add just the user/password/roles
lookup
* functionality.
*
* It attaches the roles to the subject as public credentials.
* According to the JAAS spec it requires privileged access to do this, and as I
don't
* explicilty code that privilege I assume I must have it by virtue of being a
ServerLoginModule.
*
* As a minimum you must implement:
*
* protected String getUsersRoles(); // returns a csv list of the users roles
* protected String getUsersPassword(); // returns the users password
*
* You may also wish to override
*
* public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
*
* In which case the first line of your initialize() method should be
super.initialize(subject, callbackHandler, sharedState, options);
*
* You may also wish to override
*
* public boolean login() throws LoginException
*
* In which case the last line of your login() method should be return super.login();
*
* @author <a href="[EMAIL PROTECTED]">Edward Kenworthy</a>
*/
public abstract class AbstractServerLoginModule implements LoginModule
{
private Subject _subject;
private CallbackHandler _callbackHandler;
// username and password
private String _username;
protected String getUsername() {return _username;}
private char[] _password;
abstract protected Enumeration getUsersRoles();
abstract protected String getUsersPassword();
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
_subject = subject;
_callbackHandler = callbackHandler;
}
public boolean login() throws LoginException
{
Callback[] callbacks = new Callback[2];
// prompt for a username and password
if (_callbackHandler == null)
{
throw new LoginException("Error: no CallbackHandler available " +
"to garner authentication information from the
user");
}
callbacks[0] = new NameCallback("User name: ", "guest");
callbacks[1] = new PasswordCallback("Password: ", false);
try
{
_callbackHandler.handle(callbacks);
_username = ((NameCallback)callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
if (tmpPassword != null)
{
_password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, _password, 0, tmpPassword.length);
((PasswordCallback)callbacks[1]).clearPassword();
}
}
catch (java.io.IOException ioe)
{
throw new LoginException(ioe.toString());
}
catch (UnsupportedCallbackException uce)
{
throw new LoginException("Error: " + uce.getCallback().toString() +
" not available to garner authentication information " +
"from the user");
}
String userPassword = getUsersPassword();
if (_password == null || userPassword == null || !(new
String(_password)).equals(userPassword))
{
System.out.print("[JAASSecurity] Bad password.\n");
throw new FailedLoginException("Password Incorrect/Password Required");
}
System.out.print("[JAASSecurity] User '" + _username + "' authenticated.\n");
return true;
}
/** Method to commit the authentication process (phase 2).
It associates the username as a SimplePrincipal in the
subject getPrincipals() Set and also adds a SimpleGroup
by the name of 'roles' to contain the
@see org.jboss.security.SimpleGroup;
@see org.jboss.security.SimplePrincipal;
@see java.security.acl.Group;
*/
public boolean commit() throws LoginException
{
// Add the username as a SimplePrincipal
Set roles = _subject.getPrincipals();
roles.add(new SimplePrincipal(_username));
// Add the user roles as Principals or SimplePrincipal
Enumeration roleList = getUsersRoles();
if (roleList != null)
{
SimpleGroup userRoles = new SimpleGroup("Roles");
while (roleList.hasMoreElements())
{
Object next = roleList.nextElement();
if( next instanceof Principal )
userRoles.addMember((Principal) next);
else
{
String roleName = next.toString();
userRoles.addMember(new SimplePrincipal(roleName));
}
}
roles.add(userRoles);
}
return true;
}
/**
* Method to abort the authentication process (phase 2).
*/
public boolean abort() throws LoginException
{
_username = null;
if (_password != null)
{
for (int i = 0; i < _password.length; i++)
_password[i] = ' ';
_password = null;
}
return true;
}
public boolean logout() throws LoginException
{
return true;
}
}
1.1
jbosssx/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.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;
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.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.SimplePrincipal;
import org.jboss.security.SubjectSecurityManager;
import org.jboss.security.plugins.SecurityAssociationHandler;
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
on the JAAS LoginContext/LoginModules associated with the security
domain name associated with the class 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
{
public static class DomainInfo
{
Subject subject;
Object credential;
Principal callerPrincipal;
Group roles;
}
/** The current authenticate()d subject.
*/
private static ThreadLocal activeSubject = new ThreadLocal();
/** 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.
*/
private CachePolicy domainCache;
/** The custom JAAS policy. This may be null if a custom
policy is not being used.
*/
private SecurityPolicy securityPolicy;
/** Used in the absence of a SecurityPolicy specific CallbackHandler
to pass credential info to the LoginModule associated with the
securityDomain name.
*/
private SecurityAssociationHandler handler = new SecurityAssociationHandler();
public JaasSecurityManager()
{
this("other");
}
public JaasSecurityManager(String securityDomain)
{
this.securityDomain = securityDomain;
try
{ // Try to get the SecurityPolicy from the JAAS Policy class
securityPolicy = (SecurityPolicy) Policy.getPolicy();
}
catch(ClassCastException e)
{ // The installed Policy is not a SecurityPolicy
}
}
/** 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)
*/
public void setCachePolicy(CachePolicy domainCache)
{
this.domainCache = domainCache;
}
public void setSecurityPolicyName(String jndiName) throws NamingException
{
InitialContext ctx = new InitialContext();
securityPolicy = (SecurityPolicy) ctx.lookup(jndiName);
}
/** Get the name of the security domain associated with this security mgr.
@return Name of the security manager security domain.
*/
public String getSecurityDomain()
{
return securityDomain;
}
/** Get the currently authenticated Subject. This is a thread local
property shared across all JaasSecurityManager instances.
@return The Subject authenticated in the current thread if one
exists, null otherwise.
*/
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
DomainInfo cacheInfo = null;
if( domainCache != null )
cacheInfo = (DomainInfo) domainCache.get(principal);
boolean isValid = false;
if( cacheInfo != null )
isValid = validateCache(cacheInfo, 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 no principals
then the argument principal is returned.
*/
public Principal getPrincipal(Principal principal)
{
Principal result = principal;
if( domainCache != null )
{
// Get the CallerPrincipal group member
DomainInfo info = (DomainInfo) domainCache.get(principal);
if( info != null )
result = info.callerPrincipal;
// If the mapping did not have a callerPrincipal just use principal
if( result == null )
result = principal;
}
return result;
}
/** Does the current Subject have a role(a Principal) that equates to one
of the role names. This method obtains the Principal set from
the currently authenticated Subject and then creates a SimplePrincipal
for each name in roleNames. If the role is in the Subject
Principal set the user has the role. If the role is not in the set,
the set of Principals that are also Groups is obtained and each
group is queried to see if the role is a member.
@param principal, ignored. The current authenticated Subject determines
the active user and assigned user roles.
@param roleNames, a set of String names for the roles to check.
@see java.security.acl.Group;
@see Subject#getPrincipals()
*/
public boolean doesUserHaveRole(Principal principal, Set roleNames)
{
boolean hasRole = false;
Subject subject = getActiveSubject();
if( subject != null && domainCache != null )
{
DomainInfo info = (DomainInfo) domainCache.get(principal);
Group roles = null;
if( info != null )
roles = info.roles;
if( roles != null )
{
Iterator iter = roleNames.iterator();
while( hasRole == false && iter.hasNext() )
{
String name = (String) iter.next();
SimplePrincipal role = new SimplePrincipal(name);
hasRole = roles.isMember(role);
}
}
}
System.out.println("hasRole = "+hasRole);
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)
{
LoginContext lc = null;
Subject subject = null;
boolean authenticated = false;
try
{
// Clear any current subject
activeSubject.set(null);
// Get the AppPolicy login info. Not implemented yet.
AppPolicy policy = null;
subject = defaultLogin(principal, credential);
// Set the current subject if login was successful
if( subject != null )
{
activeSubject.set(subject);
authenticated = true;
// Build the Subject based DomainInfo cache value
updateCache(subject, principal, credential);
}
}
catch(LoginException e)
{
e.printStackTrace();
}
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 Subject defaultLogin(Principal principal, Object credential)
throws LoginException
{
// We our internal CallbackHandler to provide the security info
handler.setSecurityInfo(principal, credential);
Subject subject = new Subject();
LoginContext lc = new LoginContext(securityDomain, subject, handler);
lc.login();
Subject lcSubject = lc.getSubject();
System.out.println("JaasSecurityManager, subject == lcSubject: "+(subject ==
lcSubject));
return subject;
}
/** Validate the cache credential value against the provided credential
*/
private boolean validateCache(DomainInfo info, Object credential)
{
Object subjectCredential = info.credential;
boolean isValid = false;
if( subjectCredential.getClass().isAssignableFrom(credential.getClass()) ==
false )
return false;
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
{
isValid = subjectCredential.equals(credential);
}
if( isValid )
{
activeSubject.set(info.subject);
}
return isValid;
}
private void updateCache(Subject subject, Principal principal, Object credential)
{
DomainInfo info = new DomainInfo();
info.subject = subject;
info.credential = credential;
// If we don't have a cache policy create a default timed cache
if( domainCache == null )
{
domainCache = new TimedCachePolicy();
try
{
domainCache.init();
domainCache.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
/* Get the Subject callerPrincipal by looking for a Group called
'CallerPrincipal' and roles by looking for a Group called 'Roles'
*/
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();
}
else if( name.equals("Roles") )
info.roles = grp;
}
/* If the user already exists another login is active. Currently
only one is allowed so remove the old and insert the new.
*/
if( domainCache.peek(principal) != null )
domainCache.remove(principal);
domainCache.insert(principal, info);
}
}
1.1
jbosssx/src/main/org/jboss/security/plugins/ProxyLoginModule.java
Index: ProxyLoginModule.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;
import java.io.InputStream;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.Callback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
/** A proxy LoginModule that loads a delegate LoginModule using
the current thread context class loader. The purpose of this
module is to work around the current JAAS class loader limitation
that requires LoginModules to be on the classpath. Some LoginModules
use core JBoss classes that would have to be moved into the jboss-jaas.jar
and packaging becomes a mess. Instead, these LoginModules are left
in the jbosssx.jar and the ProxyLoginModule is used to bootstrap
the non-classpath LoginModule.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class ProxyLoginModule implements LoginModule
{
private String moduleName;
private LoginModule delegate;
public ProxyLoginModule()
{
}
// --- Begin LoginModule interface methods
/** Initialize this LoginModule. This method loads the LoginModule
specified by the moduleName option using the current thread
context class loader and then delegates the initialize call
to it.
@param options, include:
moduleName: the classname of the module that this proxy module
delegates all calls to.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
moduleName = (String) options.get("moduleName");
if( moduleName == null )
{
System.out.println("Required moduleName option not given");
return;
}
// Load the delegate module using the thread class loader
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
Class clazz = loader.loadClass(moduleName);
delegate = (LoginModule) clazz.newInstance();
}
catch(Throwable t)
{
System.out.println("ProxyLoginModule failed to load: "+moduleName);
t.printStackTrace();
return;
}
delegate.initialize(subject, callbackHandler, sharedState, options);
}
/** Perform the login. If either the moduleName option was not
specified or the module could not be loaded in initalize(),
this method throws a LoginException.
@exception LoginException, throw in the delegate login module failed.
*/
public boolean login() throws LoginException
{
if( moduleName == null )
throw new LoginException("Required moduleName option not given");
if( delegate == null )
throw new LoginException("Failed to load LoginModule: "+moduleName);
return delegate.login();
}
public boolean commit() throws LoginException
{
boolean ok = false;
if( delegate != null )
ok = delegate.commit();
return ok;
}
public boolean abort() throws LoginException
{
boolean ok = true;
if( delegate != null )
ok = delegate.abort();
return ok;
}
public boolean logout() throws LoginException
{
boolean ok = true;
if( delegate != null )
ok = delegate.logout();
return ok;
}
// --- End LoginModule interface methods
}
1.1 jbosssx/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 org.jboss.security.srp.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 jbosssx/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 org.jboss.naming.NonSerializableFactory;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.srp.SRPRemoteServer;
import org.jboss.security.srp.SRPRemoteServer.SRPServerListener;
import org.jboss.security.srp.SRPServerInterface;
import org.jboss.security.srp.SRPServerSession;
import org.jboss.security.srp.SRPVerifierStore;
import org.jboss.util.ServiceMBeanSupport;
import org.jboss.util.TimedCachePolicy;
/** The JMX mbean interface for the SRP service. This mbean sets up an
RMI implementation of the 'Secure Remote Password' cryptographic authentication
system described in RFC2945.
@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);
byte[] credential = session.getClientResponse();
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, credential);
}
}
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 jbosssx/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
jbosssx/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 org.jboss.naming.NonSerializableFactory;
import org.jboss.security.srp.SerialObjectStore;
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 org.jboss.security.srp.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
{
try
{
store.addUser(username, password);
save();
System.out.println("Added username: "+username);
}
catch(Exception e)
{
e.printStackTrace();
}
}
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
jbosssx/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
jbosssx/src/main/org/jboss/security/plugins/SecurityAssociationCallback.java
Index: SecurityAssociationCallback.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins;
import java.security.Principal;
import javax.security.auth.callback.Callback;
/** An implementation of Callback useful on the server side for
propagating the request Principal and credentials to LoginModules.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SecurityAssociationCallback implements Callback
{
private transient Principal principal;
private transient Object credential;
/** Initialize the SecurityAssociationCallback
*/
public SecurityAssociationCallback()
{
}
public Principal getPrincipal()
{
return principal;
}
public void setPrincipal(Principal principal)
{
this.principal = principal;
}
public Object getCredential()
{
return credential;
}
public void setCredential(Object credential)
{
this.credential = credential;
}
public void clearCredential()
{
this.credential = null;
}
}
1.1
jbosssx/src/main/org/jboss/security/plugins/SecurityAssociationHandler.java
Index: SecurityAssociationHandler.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;
import java.lang.reflect.Method;
import java.security.Principal;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
/** A simple implementation of CallbackHandler that sets a username and
password in the handle(Callback[]) method to that passed in to
the constructor. This is suitable for environments that need non-interactive
JAAS logins.
@see javax.security.auth.callback.CallbackHandler
@see #handle(Callback[])
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SecurityAssociationHandler implements CallbackHandler
{
private transient Principal principal;
private transient Object credential;
public SecurityAssociationHandler()
{
}
/** Initialize the UsernamePasswordHandler with the principal
and credentials to use.
*/
public SecurityAssociationHandler(Principal principal, Object credential)
{
this.principal = principal;
this.credential = credential;
}
public void setSecurityInfo(Principal principal, Object credential)
{
this.principal = principal;
this.credential = credential;
}
/** Handles SecurityAssociationCallback, NameCallback and
PasswordCallback types. A NameCallback name property is set to
the Prinicpal.getName() value. A PasswordCallback password
property is set to the getPassword() value. The preferred
SecurityAssociationCallback has its principal and credential
properties set to the instance principal and credential.
@see #getPassword()
@exception UnsupportedCallbackException, thrown if any callback of
type other than NameCallback or PasswordCallback are seen.
*/
public void handle(Callback[] callbacks) throws
UnsupportedCallbackException
{
for(int i = 0; i < callbacks.length; i++)
{
Callback c = callbacks[i];
if( c instanceof SecurityAssociationCallback )
{
SecurityAssociationCallback sac = (SecurityAssociationCallback) c;
sac.setPrincipal(principal);
sac.setCredential(credential);
}
else if ( c instanceof NameCallback)
{
NameCallback nc = (NameCallback) c;
nc.setName(principal.getName());
}
else if( c instanceof PasswordCallback )
{
PasswordCallback pc = (PasswordCallback) c;
char[] password = getPassword();
pc.setPassword(password);
}
else
{
throw new UnsupportedCallbackException(c, "Unrecognized Callback");
}
}
}
/** Try to convert the credential value into a char[] using the
first of the following attempts which succeeds:
1. Check for instanceof char[]
2. Check for instanceof String and then use toCharArray()
3. See if credential has a toCharArray() method and use it
4. Use toString() followed by toCharArray().
@return a char[] representation of the credential.
*/
private char[] getPassword()
{
char[] password = null;
if( credential instanceof char[] )
{
password = (char[]) credential;
}
else if( credential instanceof String )
{
String s = (String) credential;
password = s.toCharArray();
}
else
{
try
{
Class[] types = {};
Method m = credential.getClass().getMethod("toCharArray", types);
Object[] args = {};
m.invoke(credential, args);
}
catch(Exception e)
{
String s = credential.toString();
password = s.toCharArray();
}
}
return password;
}
}
1.1
jbosssx/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 javax.security.auth.login.Configuration;
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 startService() 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);
// Install securityPolicy as the JAAS Configuration
Configuration.setConfiguration(securityPolicy.getLoginConfiguration());
}
}
1.1
jbosssx/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
jbosssx/src/main/org/jboss/security/plugins/UsernamePasswordHandler.java
Index: UsernamePasswordHandler.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;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
/** A simple implementation of CallbackHandler that sets a username and
password in the handle(Callback[]) method to that passed in to
the constructor. This is suitable for environments that need non-interactive
JAAS logins.
@see javax.security.auth.callback.CallbackHandler
@see #handle(Callback[])
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class UsernamePasswordHandler implements CallbackHandler
{
private transient String username;
private transient char[] password;
/** Initialize the UsernamePasswordHandler with the usernmae
and password to use.
*/
public UsernamePasswordHandler(String username, char[] password)
{
this.username = username;
this.password = password;
}
/** Sets any NameCallback name property to the instance username
and sets any PasswordCallback password property to the instance
password.
@exception UnsupportedCallbackException, thrown if any callback of
type other than NameCallback or PasswordCallback are seen.
*/
public void handle(Callback[] callbacks) throws
UnsupportedCallbackException
{
for(int i = 0; i < callbacks.length; i++)
{
if (callbacks[i] instanceof NameCallback)
{
NameCallback nc = (NameCallback) callbacks[i];
nc.setName(username);
}
else if(callbacks[i] instanceof PasswordCallback)
{
PasswordCallback pc = (PasswordCallback) callbacks[i];
pc.setPassword(password);
}
else
{
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized
Callback");
}
}
}
}