User: stark
Date: 01/03/06 00:35:33
Added: src/main/org/jboss/security/srp/jaas
SRPCacheLoginModule.java SRPLoginModule.java
Log:
Added srp package that was missed. Updated AbstractServerLoginModule to
support password stacking. Updated RolesLoginModule to use existing
Groups. Updated JaasSecurityManager to operate correctly as a role-mapping
only manager when so configured.
Revision Changes Path
1.1
jbosssx/src/main/org/jboss/security/srp/jaas/SRPCacheLoginModule.java
Index: SRPCacheLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.srp.jaas;
import java.security.Principal;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.plugins.SecurityAssociationCallback;
import org.jboss.security.srp.PkgCategory;
import org.jboss.security.srp.SRPClientSession;
import org.jboss.security.srp.SRPServerInterface;
import org.jboss.security.srp.SRPServerInterface.SRPParameters;
import org.jboss.util.CachePolicy;
/** A server side login module that validates a username and
their session key hash against the cache of authentication
info maintained by the SRPService mbean. This module needs
a CallbackHandler that supplies the user principal and
credential via the SecurityAssociationCallback object.
module options:
cacheJndiName, the JNDI name of the CachePolicy of <Principal,Subject>
information managed by the SRPSerice.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SRPCacheLoginModule implements LoginModule
{
private Subject subject;
private CallbackHandler handler;
private Map sharedState;
private String domainName;
private String cacheJndiName;
private byte[] sessionKey;
private Principal userPrincipal;
private boolean debug;
private boolean loginFailed;
public SRPCacheLoginModule()
{
}
// --- Begin LoginModule interface methods
/**
@param subject, the subject to authenticate
@param handler, the app CallbackHandler used to obtain username & password
@param sharedState, used to propagate the authenticated principal and
credential hash.
@param options, the login module options. These include:
cacheJndiName: the JNDI name of the CachePolicy of <Principal,Subject>
information managed by the SRPSerice.
domainName: the security domain name.
*/
public void initialize(Subject subject, CallbackHandler handler, Map
sharedState, Map options)
{
this.subject = subject;
this.handler = handler;
this.sharedState = sharedState;
cacheJndiName = (String) options.get("cacheJndiName");
domainName = (String) options.get("domainName");
String d = (String) options.get("debug");
if( d != null )
debug = Boolean.valueOf(d).booleanValue();
}
/** Access the
@return true is login succeeds, false if login does not apply.
@exception LoginException, thrown on login failure.
*/
public boolean login() throws LoginException
{
loginFailed = true;
getUserInfo();
String username = userPrincipal.getName();
// First try to locate an SRPServerInterface using JNDI
try
{
if( cacheJndiName == null )
throw new LoginException("Required cacheJndiName option not set");
InitialContext iniCtx = new InitialContext();
CachePolicy cache = (CachePolicy) iniCtx.lookup(cacheJndiName);
Object cacheCredential = cache.get(userPrincipal);
if( validateCache(cacheCredential) == false )
throw new LoginException("Failed to validate SRP session key for:
"+username);
}
catch(NamingException e)
{
e.printStackTrace();
throw new LoginException("Failed to load SRP auth cache:
"+e.toString(true));
}
PkgCategory.debug("Login succeeded");
// Put the username and the client challenge into the sharedState map
sharedState.put("javax.security.auth.login.name", username);
sharedState.put("javax.security.auth.login.password", sessionKey);
loginFailed = false;
return true;
}
/** All login modules have completed the login() phase, comit if we
succeeded. This entails adding the princial to the subject Principals set.
@return false, if the login() failed, true if the commit succeeds.
@exception LoginException, thrown on failure to add the principal.
*/
public boolean commit() throws LoginException
{
if( loginFailed == true )
return false;
Set principals = subject.getPrincipals();
subject.getPrincipals().add(userPrincipal);
subject.getPublicCredentials().add(sessionKey);
return true;
}
public boolean abort() throws LoginException
{
userPrincipal = null;
sessionKey = null;
return true;
}
/** Remove the userPrincipal associated with the subject.
@return true always.
@exception LoginException, thrown on exception during remove of the Principal
added during the commit.
*/
public boolean logout() throws LoginException
{
try
{
if( subject.isReadOnly() == false )
{ // Remove userPrincipal
Set s = subject.getPrincipals(userPrincipal.getClass());
s.remove(userPrincipal);
}
}
catch(Exception e)
{
throw new LoginException("Failed to remove user principal,
"+e.getMessage());
}
return true;
}
// --- End LoginModule interface methods
private void getUserInfo() throws LoginException
{
// Get the security association info
if( handler == null )
throw new LoginException("No CallbackHandler provied");
SecurityAssociationCallback sac = new SecurityAssociationCallback();
Callback[] callbacks = { sac };
try
{
handler.handle(callbacks);
userPrincipal = sac.getPrincipal();
sessionKey = (byte[]) sac.getCredential();
sac.clearCredential();
}
catch(java.io.IOException e)
{
throw new LoginException(e.toString());
}
catch(UnsupportedCallbackException uce)
{
throw new LoginException("UnsupportedCallback: " +
uce.getCallback().toString());
}
catch(ClassCastException e)
{
throw new LoginException("Credential info is not of type byte[], "+
e.getMessage());
}
}
private boolean validateCache(Object cacheCredential)
{
boolean isValid = false;
if( cacheCredential instanceof byte[] )
{
byte[] a1 = (byte[]) cacheCredential;
isValid = Arrays.equals(a1, sessionKey);
}
return isValid;
}
}
1.1 jbosssx/src/main/org/jboss/security/srp/jaas/SRPLoginModule.java
Index: SRPLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.srp.jaas;
import java.lang.reflect.Constructor;
import java.rmi.Naming;
import java.security.Principal;
import java.util.Map;
import java.util.Set;
import javax.naming.InitialContext;
import javax.security.auth.Subject;
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 javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.srp.PkgCategory;
import org.jboss.security.srp.SRPClientSession;
import org.jboss.security.srp.SRPServerInterface;
import org.jboss.security.srp.SRPServerInterface.SRPParameters;
/** A login module that uses the SRP protocol documented in RFC2945
to authenticate a username & password in a secure fashion without
using an encrypted channel.
This product uses the 'Secure Remote Password' cryptographic
authentication system developed by Tom Wu ([EMAIL PROTECTED]).
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SRPLoginModule implements LoginModule
{
private Subject subject;
private CallbackHandler handler;
private Map sharedState;
private String principalClassName;
private String srpServerRmiUrl;
private String srpServerJndiName;
private String username;
private String password;
private Principal userPrincipal;
private boolean debug;
private boolean loginFailed;
/** Creates new SRPLoginModule */
public SRPLoginModule()
{
}
// --- Begin LoginModule interface methods
/**
@param subject, the subject to authenticate
@param handler, the app CallbackHandler used to obtain username & password
@param sharedState, used to propagate the authenticated principal and
credential hash.
@param options, the login module options. These include:
principalClassName: the java.security.Principal class name implimentation to
use.
srpServerJndiName: the jndi name of the SRPServerInterface implimentation to
use. This
is tried before srpServerRmiUrl.
srpServerRmiUrl: the rmi url for the SRPServerInterface implimentation to
use.
debug: if true, print the login module progress details
*/
public void initialize(Subject subject, CallbackHandler handler, Map
sharedState, Map options)
{
this.subject = subject;
this.handler = handler;
this.sharedState = sharedState;
principalClassName = (String) options.get("principalClassName");
srpServerJndiName = (String) options.get("srpServerJndiName");
srpServerRmiUrl = (String) options.get("srpServerRmiUrl");
String o = (String) options.get("debug");
if( o != null )
debug = Boolean.valueOf(o).booleanValue();
}
/** This is where the SRP protocol exchange occurs.
@return true is login succeeds, false if login does not apply.
@exception LoginException, thrown on login failure.
*/
public boolean login() throws LoginException
{
loginFailed = true;
getUserInfo();
SRPServerInterface server;
// First try to locate an SRPServerInterface using JNDI
if( srpServerJndiName != null )
{
server = loadServerFromJndi(srpServerJndiName);
}
else if( srpServerRmiUrl != null )
{
server = loadServer(srpServerRmiUrl);
}
else
{
throw new LoginException("No option specified to access a
SRPServerInterface instance");
}
if( server == null )
throw new LoginException("Failed to access a SRPServerInterface
instance");
byte[] M1, M2;
SRPClientSession client = null;
try
{ // Perform the SRP login protocol
PkgCategory.debug("Getting SRP parameters for username: "+username);
SRPParameters params = server.getSRPParameters(username);
PkgCategory.debug("Creating SRPClientSession");
client = new SRPClientSession(username, password, params.s, params.N,
params.g);
PkgCategory.debug("Generating client public key");
byte[] A = client.exponential();
PkgCategory.debug("Exchanging public keys");
byte[] B = server.init(username, A);
PkgCategory.debug("Generating server challenge");
M1 = client.response(B);
PkgCategory.debug("Exchanging challenges");
M2 = server.verify(username, M1);
}
catch(Exception e)
{
PkgCategory.warn("Failed complete SRP login", e);
throw new LoginException("Failed complete SRP login,
msg="+e.getMessage());
}
finally
{
server = null;
}
PkgCategory.debug("Verifying server response");
if( client.verify(M2) == false )
throw new LoginException("Failed to validate server reply");
PkgCategory.debug("Login succeeded");
// Put the username and the client challenge into the sharedState map
sharedState.put("javax.security.auth.login.name", username);
sharedState.put("javax.security.auth.login.password", M1);
loginFailed = false;
return true;
}
/** All login modules have completed the login() phase, comit if we
succeeded. This entails adding an instance of principalClassName to the
subject principals set.
@return false, if the login() failed, true if the commit succeeds.
@exception LoginException, thrown on failure to create a Principal.
*/
public boolean commit() throws LoginException
{
if( loginFailed == true )
return false;
if( principalClassName == null )
throw new LoginException("No principalClassName specified");
// Associate an instance of Principal with the subject
userPrincipal = null;
try
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass(principalClassName);
Class[] parameterTypes = {String.class};
Constructor ctor = clazz.getConstructor(parameterTypes);
String[] args = {username};
userPrincipal = (Principal) ctor.newInstance(args);
}
catch(Exception e)
{
throw new LoginException("Failed to create Principal, "+e.getMessage());
}
finally
{
password = null;
}
subject.getPrincipals().add(userPrincipal);
return true;
}
public boolean abort() throws LoginException
{
username = null;
password = null;
return true;
}
/** Remove the userPrincipal associated with the subject.
@return true always.
@exception LoginException, thrown on exception during remove of the Principal
added during the commit.
*/
public boolean logout() throws LoginException
{
try
{
if( subject.isReadOnly() == false )
{ // Remove userPrincipal
Set s = subject.getPrincipals(userPrincipal.getClass());
s.remove(userPrincipal);
}
}
catch(Exception e)
{
throw new LoginException("Failed to remove user principal,
"+e.getMessage());
}
return true;
}
// --- End LoginModule interface methods
private void getUserInfo() throws LoginException
{
// See if there is a shared username & password
String _username = (String)
sharedState.get("javax.security.auth.login.name");
char[] _password = null;
if( username != null )
{
Object pw = sharedState.get("javax.security.auth.login.password");
if( pw instanceof char[] )
_password = (char[]) pw;
else if( pw != null )
_password = pw.toString().toCharArray();
}
// If we have a username, password return
if( _username != null && _password != null )
{
username = _username;
password = new String(_password);
return;
}
// Request a username and password
if( handler == null )
throw new LoginException("No CallbackHandler provied to SRPLoginModule");
NameCallback nc = new NameCallback("Username: ", "guest");
PasswordCallback pc = new PasswordCallback("Password: ", false);
Callback[] callbacks = { nc, pc };
try
{
handler.handle(callbacks);
username = nc.getName();
_password = pc.getPassword();
if( _password != null )
password = new String(_password);
pc.clearPassword();
}
catch(java.io.IOException e)
{
throw new LoginException(e.toString());
}
catch(UnsupportedCallbackException uce)
{
throw new LoginException("UnsupportedCallback: " +
uce.getCallback().toString());
}
}
private SRPServerInterface loadServerFromJndi(String jndiName)
{
SRPServerInterface server = null;
try
{
InitialContext ctx = new InitialContext();
server = (SRPServerInterface) ctx.lookup(jndiName);
}
catch(Exception e)
{
e.printStackTrace();
}
return server;
}
private SRPServerInterface loadServer(String rmiUrl)
{
SRPServerInterface server = null;
try
{
server = (SRPServerInterface) Naming.lookup(rmiUrl);
}
catch(Exception e)
{
e.printStackTrace();
}
return server;
}
}