User: starksm
Date: 01/04/10 19:04:21
Added: src/main/org/jboss/security/auth/spi
AbstractServerLoginModule.java
DatabaseServerLoginModule.java
IdentityLoginModule.java LdapLoginModule.java
SimpleServerLoginModule.java
UsernamePasswordLoginModule.java
UsersRolesLoginModule.java
Log:
Clean up the package structure.
Revision Changes Path
1.1
jbosssx/src/main/org/jboss/security/auth/spi/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.auth.spi;
import java.util.*;
import java.io.*;
import java.security.Principal;
import java.security.acl.Group;
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.NestableGroup;
import org.jboss.security.SimpleGroup;
/** This class implements the common functionality required for a JAAS
server side LoginModule and implements the JBossSX standard Subject usage
pattern of storing identities and roles. Subclass this module to create your
own custom LoginModule and override the getRoles() and getIdentity()
methods.
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>, 12th Dec
2000
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public abstract class AbstractServerLoginModule implements LoginModule
{
protected Subject subject;
protected CallbackHandler callbackHandler;
protected Map sharedState;
protected Map options;
/** Flag indicating if the shared credential should be used */
protected boolean useFirstPass;
//--- Begin LoginModule interface methods
/** Initialize the login module. This stores the subject, callbackHandler
and sharedState and options for the login session.
@param options,
@option
@option password-stacking: if true, the login identity will be taken from the
javax.security.auth.login.name value of the sharedState map, and
the proof of identity from the javax.security.auth.login.password
value sharedState map.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
/* Check for password sharing options. Any non-null value for
password_stacking sets useFirstPass as this module has no way to
validate any shared password.
*/
String passwordStacking = (String) options.get("password-stacking");
if( passwordStacking != null &&
passwordStacking.equalsIgnoreCase("useFirstPass") )
useFirstPass = true;
}
/** Looks for javax.security.auth.login.name and
javax.security.auth.login.password
values in the sharedState map if the useFirstPass option was true and returns
true if they exist. If they do not or are null this method returns false.
*/
public boolean login() throws LoginException
{
// If useFirstPass is true, look for the shared password
if( useFirstPass == true )
{
try
{
Object identity = sharedState.get("javax.security.auth.login.name");
Object credential =
sharedState.get("javax.security.auth.login.password");
if( identity != null && credential != null )
return true;
// Else, fall through and perform the login
}
catch(Exception e)
{ // Dump the exception and continue
e.printStackTrace();
}
}
return false;
}
/** Method to commit the authentication process (phase 2).
It adds the getIdentity() value to the subject getPrincipals() Set.
It also adds the members of each Group returned by getRoleSets()
to the subject getPrincipals() Set.
@see javax.security.auth.Subject;
@see java.security.acl.Group;
@return true always.
*/
public boolean commit() throws LoginException
{
Set principals = subject.getPrincipals();
Principal identity = getIdentity();
principals.add(identity);
Group[] roleSets = getRoleSets();
for(int g = 0; g < roleSets.length; g ++)
{
Group group = roleSets[g];
String name = group.getName();
Group subjectGroup = createGroup(name, principals);
if( subjectGroup instanceof NestableGroup )
{
/* A NestableGroup only allows Groups to be added to it so we
need to add a SimpleGroup to subjectRoles to contain the roles
*/
SimpleGroup tmp = new SimpleGroup("Roles");
subjectGroup.addMember(tmp);
subjectGroup = tmp;
}
// Copy the group members to the Subject group
Enumeration members = group.members();
while( members.hasMoreElements() )
{
Principal role = (Principal) members.nextElement();
subjectGroup.addMember(role);
}
}
return true;
}
/** Method to abort the authentication process (phase 2).
@return true alaways
*/
public boolean abort() throws LoginException
{
return true;
}
/** Remove the user identity and roles added to the Subject during commit.
@return true always.
*/
public boolean logout() throws LoginException
{
// Remove the user identity
Principal identity = getIdentity();
Set principals = subject.getPrincipals();
principals.remove(identity);
// Remove any added Groups...
return true;
}
//--- End LoginModule interface methods
// --- Protected methods
/** Overriden by subclasses to return the Principal that corresponds to
the user primary identity.
*/
abstract protected Principal getIdentity();
/** Overriden by subclasses to return the Groups that correspond to the
to the role sets assigned to the user. Subclasses should create at
least a Group named "Roles" that contains the roles assigned to the user.
A second common group is "CallerPrincipal" that provides the application
identity of the user rather than the security domain identity.
@return Group[] containing the sets of roles
*/
abstract protected Group[] getRoleSets() throws LoginException;
protected boolean getUseFirstPass()
{
return useFirstPass;
}
/** Find or create a Group with the given name. Subclasses should use this
method to locate the 'Roles' group or create additional types of groups.
@return A named Group from the principals set.
*/
protected Group createGroup(String name, Set principals)
{
Group roles = null;
Iterator iter = principals.iterator();
while( iter.hasNext() )
{
Object next = iter.next();
if( (next instanceof Group) == false )
continue;
Group grp = (Group) next;
if( grp.getName().equals(name) )
{
roles = grp;
break;
}
}
// If we did not find a group create one
if( roles == null )
{
roles = new NestableGroup(name);
principals.add(roles);
}
return roles;
}
}
1.1
jbosssx/src/main/org/jboss/security/auth/spi/DatabaseServerLoginModule.java
Index: DatabaseServerLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.spi;
import java.security.acl.Group;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.login.FailedLoginException;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
/** A JDBC based login module that supports authentication and role mapping.
It is based on two logical tables:
Principals(PrincipalID text, Password text)
Roles(PrincipalID text, Role text, RoleGroup text)
LoginModule options:
dsJndiName: The name of the DataSource of the database containing the Principals,
Roles tables
principalsQuery: The prepared statement query equivalent to:
"select Password from Principals where PrincipalID=?"
rolesQuery: The prepared statement query equivalent to:
"select Role, RoleGroup from Roles where PrincipalID=?"
@author <a href="[EMAIL PROTECTED]">Oleg Nitz</a>
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class DatabaseServerLoginModule extends UsernamePasswordLoginModule
{
private String dsJndiName;
private String principalsQuery = "select Password from Principals where
PrincipalID=?";
private String rolesQuery = "select Role, RoleGroup from Roles where
PrincipalID=?";
/**
* Initialize this LoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
super.initialize(subject, callbackHandler, sharedState, options);
dsJndiName = (String) options.get("dsJndiName");
Object tmp = options.get("principalsQuery");
if( tmp != null )
principalsQuery = tmp.toString();
tmp = options.get("rolesQuery");
if( tmp != null )
rolesQuery = tmp.toString();
}
/** Get the expected password for the current username available via
* the getUsername() method. This is called from within the login()
* method after the CallbackHandler has returned the username and
* candidate password.
* @return the valid password String
*/
protected String getUsersPassword() throws LoginException
{
String username = getUsername();
String password = null;
Connection conn = null;
try
{
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(dsJndiName);
conn = ds.getConnection();
// Get the password
PreparedStatement ps = conn.prepareStatement(principalsQuery);
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
if( rs.next() == false )
throw new FailedLoginException("No matching username found in
Principals");
password = rs.getString(1);
password = convertRawPassword(password);
ps.close();
rs.close();
}
catch(NamingException ex)
{
throw new LoginException(ex.toString(true));
}
catch(SQLException ex)
{
ex.printStackTrace();
throw new LoginException(ex.toString());
}
finally
{
if( conn != null )
{
try
{
conn.close();
}
catch (Exception ex)
{
}
}
}
return password;
}
/** Overriden by subclasses to return the Groups that correspond to the
to the role sets assigned to the user. Subclasses should create at
least a Group named "Roles" that contains the roles assigned to the user.
A second common group is "CallerPrincipal" that provides the application
identity of the user rather than the security domain identity.
@return Group[] containing the sets of roles
*/
protected Group[] getRoleSets() throws LoginException
{
String username = getUsername();
Connection conn = null;
HashMap setsMap = new HashMap();
try
{
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(dsJndiName);
conn = ds.getConnection();
// Get the users role names
PreparedStatement ps = conn.prepareStatement(rolesQuery);
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
if( rs.next() == false )
throw new FailedLoginException("No matching username found in
Roles");
do
{
String name = rs.getString(1);
String groupName = rs.getString(2);
if( groupName == null || groupName.length() == 0 )
groupName = "Roles";
Group group = (Group) setsMap.get(groupName);
if( group == null )
{
group = new SimpleGroup(groupName);
setsMap.put(groupName, group);
}
group.addMember(new SimplePrincipal(name));
} while( rs.next() );
ps.close();
rs.close();
}
catch(NamingException ex)
{
throw new LoginException(ex.toString(true));
}
catch(SQLException ex)
{
ex.printStackTrace();
throw new LoginException(ex.toString());
}
finally
{
if( conn != null )
{
try
{
conn.close();
}
catch (Exception ex)
{
}
}
}
Group[] roleSets = new Group[setsMap.size()];
setsMap.values().toArray(roleSets);
return roleSets;
}
/** A hook to allow subclasses to convert a password from the database
into a plain text string or whatever form is used for matching against
the user input. It is called from within the getUsersPassword() method.
@param rawPassword, the password as obtained from the database
@return the argument rawPassword
*/
protected String convertRawPassword(String rawPassword)
{
return rawPassword;
}
}
1.1
jbosssx/src/main/org/jboss/security/auth/spi/IdentityLoginModule.java
Index: IdentityLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.spi;
import java.security.Principal;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.Map;
import java.util.StringTokenizer;
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.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
/** 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.SimpleGroup
@see org.jboss.security.SimplePrincipal
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class IdentityLoginModule extends AbstractServerLoginModule
{
private String principalName;
private String roleNames;
/** Creates new IdentityLoginModule */
public IdentityLoginModule()
{
}
public void initialize(Subject subject, CallbackHandler handler, Map
sharedState, Map options)
{
super.initialize(subject, handler, sharedState, options);
principalName = (String) options.get("principal");
if( principalName == null )
principalName = "guest";
roleNames = (String) options.get("roles");
}
public boolean login() throws LoginException
{
if( super.login() == true )
return true;
Principal principal = new SimplePrincipal(principalName);
subject.getPrincipals().add(principal);
// Put the principal into the sharedState map
sharedState.put("javax.security.auth.login.name", principal);
return true;
}
protected Principal getIdentity()
{
Principal principal = new SimplePrincipal(principalName);
return principal;
}
protected Group[] getRoleSets() throws LoginException
{
SimpleGroup roles = new SimpleGroup("Roles");
Group[] roleSets = {roles};
if( roleNames != null )
{
StringTokenizer tokenizer = new StringTokenizer(roleNames, ",");
while( tokenizer.hasMoreTokens() )
{
String roleName = tokenizer.nextToken();
roles.addMember(new SimplePrincipal(roleName));
}
}
return roleSets;
}
}
1.1
jbosssx/src/main/org/jboss/security/auth/spi/LdapLoginModule.java
Index: LdapLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.spi;
import java.security.Principal;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
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.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.callback.ObjectCallback;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
/** An implementation of LoginModule that authenticates against an LDAP server
using JNDI based on the configuration properties.
The LoginModule options include whatever options your LDAP JNDI provider
support. Examples of standard property names are:
Context.INITIAL_CONTEXT_FACTORY = "java.naming.factory.initial"
Context.SECURITY_PROTOCOL = "java.naming.security.protocol"
Context.PROVIDER_URL = "java.naming.provider.url"
Context.SECURITY_AUTHENTICATION = "java.naming.security.authentication"
The Context.SECURITY_PRINCIPAL is set to the distinguished name of the user
as obtained by the callback handler and the Context.SECURITY_CREDENTIALS
property is either set to the String password or Object credential depending
on the useObjectCredential option.
Additional module properties include:
principalDNPrefix, principalDNSuffix : A prefix and suffix to add to the
username when forming the user distiguished name. This is useful if you
prompt a user for a username and you don't want them to have to enter the
fully distinguished name. Using this property and principalDNSuffix the
userDN will be formed as:
<code>String userDN = principalDNPrefix + username + principalDNSuffix;</code>
useObjectCredential : indicates that the credential should be obtained as
an opaque Object using the org.jboss.security.plugins.ObjectCallback type
of Callback rather than as a char[] password using a JAAS PasswordCallback.
rolesCtxDN : The distinguished name to the context to search for user roles.
roleAttributeName : The name of the attribute that contains the user roles
uidAttributeName : The name of the attribute that in the object containing
the user roles that corresponds to the userid. This is used to locate the
user roles.
A sample login config:
testLdap {
org.jboss.security.plugins.samples.LdapLoginModule required
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
principalDNPrefix=uid=
uidAttributeID=userid
roleAttributeID=rolenames
principalDNSuffix=,ou=People,o=displayscape.com
rolesCtxDN=ou=Users,cn=Project1,ou=Projects,o=displayscape.com
java.naming.provider.url=ldap://siren-int/
java.naming.security.authentication=simple
};
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class LdapLoginModule extends AbstractServerLoginModule
{
private static final String USE_OBJECT_CREDENTIAL_OPT = "useObjectCredential";
private static final String PRINCIPAL_DN_PREFIX_OPT = "principalDNPrefix";
private static final String PRINCIPAL_DN_SUFFIX_OPT = "principalDNSuffix";
private static final String ROLES_CTX_DN_OPT = "rolesCtxDN";
private static final String UID_ATTRIBUTE_ID_OPT = "uidAttributeID";
private static final String ROLE_ATTRIBUTE_ID_OPT = "roleAttributeID";
public LdapLoginModule()
{
}
private transient String username;
private transient Object credential;
private transient SimpleGroup userRoles = new SimpleGroup("Roles");
public boolean login() throws javax.security.auth.login.LoginException
{
System.out.println("LdapLoginModule.login");
if( super.login() == true )
{
// Use the shared username and password
Object identity = sharedState.get("javax.security.auth.login.name");
credential = sharedState.get("javax.security.auth.login.password");
username = identity.toString();
}
else
{
// Use the callbackHander to get username and password
getUsernamePassword();
}
// Validate the user & password by creating an LDAP initial context.
try
{
createLdapInitContext();
}
catch(NamingException e)
{
throw new FailedLoginException(e.toString(true));
}
catch(Throwable t)
{
throw new FailedLoginException("Unexpected failure:
"+t.getMessage());
}
return true;
}
protected Principal getIdentity()
{
return new SimplePrincipal(username);
}
protected Group[] getRoleSets() throws LoginException
{
Group[] roleSets = {userRoles};
return roleSets;
}
private void getUsernamePassword() throws LoginException
{
if( callbackHandler == null )
throw new LoginException("Error: no CallbackHandler
available");
NameCallback ncallback = new NameCallback("LdapLoginModule username:
");
PasswordCallback pcallback = new PasswordCallback("LdapLoginModule
password: ", false);
ObjectCallback ocallback = new ObjectCallback("LdapLoginModule credential:
");
try
{
Object useObjectCred = options.get(USE_OBJECT_CREDENTIAL_OPT);
if( useObjectCred == null ||
Boolean.valueOf(useObjectCred.toString()).booleanValue() == false )
{
Callback[] callbacks = {ncallback, pcallback};
callbackHandler.handle(callbacks);
char[] tmpPassword = pcallback.getPassword();
credential = new String(tmpPassword);
pcallback.clearPassword();
}
else
{
Callback[] callbacks = {ncallback, ocallback};
callbackHandler.handle(callbacks);
credential = ocallback.getCredential();
}
username = ncallback.getName();
}
catch(java.io.IOException ioe)
{
throw new LoginException(ioe.toString());
}
catch(UnsupportedCallbackException uce)
{
throw new LoginException("Error: " +
uce.getCallback().toString());
}
}
private void createLdapInitContext() throws NamingException
{
Properties env = new Properties();
// Map all option into the JNDI InitialLdapContext env
Iterator iter = options.entrySet().iterator();
while( iter.hasNext() )
{
Entry entry = (Entry) iter.next();
env.put(entry.getKey(), entry.getValue());
}
// Set defaults for key values if they are missing
String factoryName = env.getProperty(Context.INITIAL_CONTEXT_FACTORY);
if( factoryName == null )
{
factoryName = "com.sun.jndi.ldap.LdapCtxFactory";
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName);
}
String authType = env.getProperty(Context.SECURITY_AUTHENTICATION);
if( authType == null )
env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
String protocol = env.getProperty(Context.SECURITY_PROTOCOL);
String providerURL = (String) options.get(Context.PROVIDER_URL);
if( providerURL == null )
providerURL = "ldap://localhost:" + ((protocol != null &&
protocol.equals("ssl")) ? "389" : "636");
String principalDNPrefix = (String)
options.get(PRINCIPAL_DN_PREFIX_OPT);
if( principalDNPrefix == null )
principalDNPrefix="";
String principalDNSuffix = (String)
options.get(PRINCIPAL_DN_SUFFIX_OPT);
if( principalDNSuffix == null )
principalDNSuffix="";
String userDN = principalDNPrefix + username + principalDNSuffix;
env.setProperty(Context.PROVIDER_URL, providerURL);
env.setProperty(Context.SECURITY_PRINCIPAL, userDN);
env.put(Context.SECURITY_CREDENTIALS, credential);
System.out.println("Logging into LDAP server, env="+env);
InitialLdapContext ctx = new InitialLdapContext(env, null);
System.out.println("Logged into LDAP server, "+ctx);
// Query the user's roles...
String rolesCtxDN = (String) options.get(ROLES_CTX_DN_OPT);
if( rolesCtxDN != null )
{
String uidAttrName = (String) options.get(UID_ATTRIBUTE_ID_OPT);
if( uidAttrName == null )
uidAttrName = "uid";
String roleAttrName = (String) options.get(ROLE_ATTRIBUTE_ID_OPT);
if( roleAttrName == null )
roleAttrName = "roles";
BasicAttributes matchAttrs = new BasicAttributes(true);
matchAttrs.put(uidAttrName, username);
String[] roleAttr = {roleAttrName};
try
{
NamingEnumeration answer = ctx.search(rolesCtxDN, matchAttrs,
roleAttr);
while( answer.hasMore() )
{
SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();
Attribute roles = attrs.get(roleAttrName);
for(int r = 0; r < roles.size(); r ++)
{
Object value = roles.get(r);
String roleName = value.toString();
userRoles.addMember(new SimplePrincipal(roleName));
}
}
}
catch(NamingException e)
{
}
}
// Close the context to release the connection
ctx.close();
}
}
1.1
jbosssx/src/main/org/jboss/security/auth/spi/SimpleServerLoginModule.java
Index: SimpleServerLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.spi;
import java.security.Principal;
import java.security.acl.Group;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
/** A simple server login module useful to quick setup of security for testing
purposes. It implements the following simple algorithm:
- if password is null, authenticate the user and assign an identity of guest
and a role of "guest".
- else if password is equal to the user name, assign an identity equal to
the username and both "user" and "guest" roles
- else authentication fails.
@author <a href="[EMAIL PROTECTED]">Oleg Nitz</a>
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SimpleServerLoginModule extends UsernamePasswordLoginModule
{
private SimplePrincipal user;
private boolean guestOnly;
protected Principal getIdentity()
{
Principal principal = user;
if( principal == null )
principal = super.getIdentity();
return principal;
}
protected boolean validatePassword(String inputPassword, String expectedPassword)
{
boolean isValid = false;
if( inputPassword == null )
{
guestOnly = true;
isValid = true;
user = new SimplePrincipal("guest");
}
else
{
isValid = inputPassword.equals(expectedPassword);
}
return isValid;
}
/** Overriden by subclasses to return the Groups that correspond to the
* to the role sets assigned to the user. Subclasses should create at
* least a Group named "Roles" that contains the roles assigned to the user.
* A second common group is "CallerPrincipal" that provides the application
* identity of the user rather than the security domain identity.
* @return Group[] containing the sets of roles
*/
protected Group[] getRoleSets() throws LoginException
{
Group[] roleSets = {new SimpleGroup("Roles")};
if( guestOnly == false )
roleSets[0].addMember(new SimplePrincipal("user"));
roleSets[0].addMember(new SimplePrincipal("guest"));
return roleSets;
}
/** Get the expected password for the current username available via
* the getUsername() method. This is called from within the login()
* method after the CallbackHandler has returned the username and
* candidate password.
* @return the value of getUsername()
*/
protected String getUsersPassword() throws LoginException
{
return getUsername();
}
}
1.1
jbosssx/src/main/org/jboss/security/auth/spi/UsernamePasswordLoginModule.java
Index: UsernamePasswordLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.spi;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.security.Principal;
import java.security.acl.Group;
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;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
/** An abstract subclass of AbstractServerLoginModule that imposes a
an identity == String username, credentials == String password view on
the login process. Subclasses override the getUsersPassword()
and getUsersRoles() methods to return the expected password and roles
for the user.
@see #getUsername()
@see #getUsersPassword()
@see #getUsersRoles()
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public abstract class UsernamePasswordLoginModule extends AbstractServerLoginModule
{
/** The login identity */
private Principal identity;
/** The proof of login identity */
private char[] credential;
/**
*/
public boolean login() throws LoginException
{
// See if shared credentials exist
if( super.login() == true )
{
// Setup our view of the user
Object username = sharedState.get("javax.security.auth.login.name");
if( username instanceof Principal )
identity = (Principal) username;
else
{
String name = username.toString();
identity = new SimplePrincipal(name);
}
Object password = sharedState.get("javax.security.auth.login.password");
if( password instanceof char[] )
credential = (char[]) password;
else
{
String tmp = password.toString();
credential = tmp.toCharArray();
}
return true;
}
String[] info = getUsernameAndPassword();
String username = info[0];
String password = info[1];
identity = new SimplePrincipal(username);
// Validate the password supplied by the subclass
String expectedPassword = getUsersPassword();
if( validatePassword(password, expectedPassword) == false )
{
System.out.println("[JAASSecurity] Bad password.");
throw new FailedLoginException("Password Incorrect/Password Required");
}
System.out.print("[JAASSecurity] User '" + username + "' authenticated.\n");
if( getUseFirstPass() == true )
{ // Add the username and password to the shared state map
sharedState.put("javax.security.auth.login.name", identity);
sharedState.put("javax.security.auth.login.password", credential);
}
return true;
}
protected Principal getIdentity()
{
return identity;
}
protected Object getCredentials()
{
return credential;
}
protected String getUsername()
{
return getIdentity().getName();
}
/** Called by login() to acquire the username and password strings for
authentication. This method does no validation of either.
@return String[], [0] = username, [1] = password
@exception LoginException thrown if CallbackHandler is not set or fails.
*/
protected String[] getUsernameAndPassword() throws LoginException
{
String[] info = {null, null};
// prompt for a username and password
if( callbackHandler == null )
{
throw new LoginException("Error: no CallbackHandler available " +
"to garner authentication information from the
user");
}
NameCallback nc = new NameCallback("User name: ", "guest");
PasswordCallback pc = new PasswordCallback("Password: ", false);
Callback[] callbacks = {nc, pc};
String username = null;
String password = null;
try
{
callbackHandler.handle(callbacks);
username = nc.getName();
char[] tmpPassword = pc.getPassword();
if( tmpPassword != null )
{
credential = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, credential, 0, tmpPassword.length);
pc.clearPassword();
}
password = new String(credential);
}
catch(java.io.IOException ioe)
{
throw new LoginException(ioe.toString());
}
catch(UnsupportedCallbackException uce)
{
throw new LoginException("CallbackHandler does not support: " +
uce.getCallback());
}
info[0] = username;
info[1] = password;
return info;
}
/** A hook that allows subclasses to change the validation of the input
password against the expected password. This version checks that
neither inputPassword or expectedPassword are null that that
inputPassword.equals(expectedPassword) is true;
@return true if the inputPassword is valid, false otherwise.
*/
protected boolean validatePassword(String inputPassword, String expectedPassword)
{
if( inputPassword == null || expectedPassword == null )
return false;
return inputPassword.equals(expectedPassword);
}
/** Get the expected password for the current username available via
the getUsername() method. This is called from within the login()
method after the CallbackHandler has returned the username and
candidate password.
@return the valid password String
*/
abstract protected String getUsersPassword() throws LoginException;
}
1.1
jbosssx/src/main/org/jboss/security/auth/spi/UsersRolesLoginModule.java
Index: UsersRolesLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.spi;
import java.util.*;
import java.io.*;
import java.security.acl.Group;
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;
import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
/** A simple properties file based login module that consults two Java Properties
formatted text files for username to password("users.properties") and
username to roles("roles.properties") mapping. The properties files are loaded
during initialization using the thread context class loader. This means that
these files can be placed into the J2EE deployment jar or the JBoss config
directory.
The users.properties file uses a format:
username1=password1
username2=password2
...
to define all valid usernames and their corresponding passwords.
The roles.properties file uses a format:
username1=role1,role2,...
username1.RoleGroup1=role3,role4,...
username2=role1,role3,...
to define the sets of roles for valid usernames. The "username.XXX" form of
property name is used to assign the username roles to a particular named
group of roles where the XXX portion of the property name is the group name.
The "username=..." form is an abbreviation for "username.Roles=...".
The following are therefore equivalent:
jduke=TheDuke,AnimatedCharacter
jduke.Roles=TheDuke,AnimatedCharacter
@author <a href="[EMAIL PROTECTED]">Edward Kenworthy</a>, 12th Dec
2000
@author [EMAIL PROTECTED]
*/
public class UsersRolesLoginModule extends UsernamePasswordLoginModule
{
// users+passwords, users+roles
private Properties _users; // You might think these should be static. The only
problem with
private Properties _roles; // static attributes is they are shared across the
VM. So I chose safety
// over performance.
/**
* Initialize this LoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
super.initialize(subject, callbackHandler, sharedState, options);
try
{
// Load the properties file that contains the list of users and passwords
LoadUsers();
LoadRoles();
}
catch (Exception e)
{
System.out.print("[JAASSecurity] PANIC! Couldn't load users/passwords/role
files.\n");
e.printStackTrace();
// Note that although this exception isn't passed on, _users or _roles will be null
// so that any call to login will throw a LoginException.
}
}
/**
* Method to authenticate a Subject (phase 1).
*
* Most of the changes from the original SimpleServerLoginModule
* are made in this method. They are:
* users and passwords read from users.properties file
* users and roles read from roles.properties file
*
* I've also removed the notion of a guest login. If you want to provide 'guest'
* access to your beans then simply disable security on them.
*
*/
public boolean login() throws LoginException
{
if (_users == null || _roles == null)
{
throw new LoginException("Missing _users or _roles properties file.");
}
return super.login();
}
/** Create the set of roles the user belongs to by parsing the roles.properties
data for username=role1,role2,... and username.XXX=role1,role2,...
patterns.
@return Group[] containing the sets of roles
*/
protected Group[] getRoleSets() throws LoginException
{
Enumeration users = _roles.propertyNames();
SimpleGroup rolesGroup = new SimpleGroup("Roles");
ArrayList groups = new ArrayList();
groups.add(rolesGroup);
while( users.hasMoreElements() )
{
String user = (String) users.nextElement();
String value = _roles.getProperty(user);
// Check for username.RoleGroup pattern
int index = user.indexOf('.');
if( index > 0 )
{
String groupName = user.substring(index+1);
if( groupName.equals("Roles") )
parseGroupMembers(rolesGroup, value);
else
{
SimpleGroup group = new SimpleGroup(groupName);
parseGroupMembers(rolesGroup, value);
groups.add(group);
}
}
else
{
// Place these roles into the Default "Roles" group
parseGroupMembers(rolesGroup, value);
}
}
Group[] roleSets = new Group[groups.size()];
groups.toArray(roleSets);
return roleSets;
}
protected String getUsersPassword()
{
return _users.getProperty(getUsername(), null);
}
// utility methods
private void parseGroupMembers(Group group, String value)
{
StringTokenizer tokenizer = new StringTokenizer(value, ",");
while( tokenizer.hasMoreTokens() )
{
String token = tokenizer.nextToken();
SimplePrincipal p = new SimplePrincipal(token);
group.addMember(p);
}
}
private void LoadUsers() throws IOException
{
_users = LoadProperties("users.properties");
}
private void LoadRoles() throws IOException
{
_roles = LoadProperties("roles.properties");
}
/**
* Loads the given properties file and returns a Properties object containing the
* key,value pairs in that file.
* The properties files should be in the class path.
*/
private Properties LoadProperties(String propertiesName) throws IOException
{
Properties bundle = null;
InputStream is
=Thread.currentThread().getContextClassLoader().getResource(propertiesName).openStream();
if (null != is)
{
bundle = new Properties();
bundle.load(is);
}
else
{
throw new IOException("Properties file " + propertiesName + " not found");
}
return bundle;
}
}
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development