From: Scott M S. <st...@us...> - 2004-05-26 21:07:30
|
User: starksm Date: 04/05/26 14:07:22 Modified: src/main/org/jboss/security/auth/spi AbstractServerLoginModule.java CertRolesLoginModule.java DatabaseCertLoginModule.java DatabaseServerLoginModule.java UsernamePasswordLoginModule.java UsersRolesLoginModule.java Added: src/main/org/jboss/security/auth/spi BaseCertLoginModule.java Removed: src/main/org/jboss/security/auth/spi AbstractCertLoginModule.java Log: - Refactor to move the principalClassName and unauthenticatedIdentity option to the AbstractServerLoginModule as these are not specific to username and password based login modules - The AbstractCertLoginModule was renamed BaseCertLoginModule and made non-abstract so authentication only could be performed Revision Changes Path 1.11 +72 -11 jbosssx/src/main/org/jboss/security/auth/spi/AbstractServerLoginModule.java Index: AbstractServerLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/AbstractServerLoginModule.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- AbstractServerLoginModule.java 27 Aug 2003 04:31:47 -0000 1.10 +++ AbstractServerLoginModule.java 26 May 2004 21:07:17 -0000 1.11 @@ -13,6 +13,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.lang.reflect.Constructor; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; @@ -22,6 +23,7 @@ import org.jboss.logging.Logger; import org.jboss.security.NestableGroup; import org.jboss.security.SimpleGroup; +import org.jboss.security.SimplePrincipal; /** * This class implements the common functionality required for a JAAS @@ -50,7 +52,7 @@ * *@author <a href="edw...@cr...">Edward Kenworthy</a>, 12th Dec 2000 *@author Sco...@jb... - *@version $Revision: 1.10 $ + *@version $Revision: 1.11 $ */ public abstract class AbstractServerLoginModule implements LoginModule { @@ -65,27 +67,35 @@ the login method must set this to true on successful completion of login */ protected boolean loginOk; + /** An optional custom Principal class implementation */ + protected String principalClassName; + /** the principal to use when a null username and password are seen */ + protected Principal unauthenticatedIdentity; //--- Begin LoginModule interface methods - /** - * Initialize the login module. This stores the subject, callbackHandler + /** Initialize the login module. This stores the subject, callbackHandler * and sharedState and options for the login session. Subclasses should override * if they need to process their own options. A call to super.initialize(...) * must be made in the case of an override. * <p> - * The options are checked for the <em>password-stacking</em> parameter. - * If this is set to "useFirstPass", the login identity will be taken from the - * <code>javax.security.auth.login.name</code> value of the sharedState map, - * and the proof of identity from the - * <code>javax.security.auth.login.password</code> value of the sharedState map. - * + * @option password-stacking: If this is set to "useFirstPass", the login + * identity will be taken from the <code>javax.security.auth.login.name</code> + * value of the sharedState map, and the proof of identity from the + * <code>javax.security.auth.login.password</code> value of the sharedState + * map. + * @option principalClass: A Principal implementation that support a ctor + * taking a String argument for the princpal name. + * @option unauthenticatedIdentity: the name of the principal to asssign + * and authenticate when a null username and password are seen. + * * @param subject the Subject to update after a successful login. * @param callbackHandler the CallbackHandler that will be used to obtain the * the user identity and credentials. * @param sharedState a Map shared between all configured login module instances * @param options the parameters passed to the login module. */ - public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; @@ -100,6 +110,24 @@ String passwordStacking = (String) options.get("password-stacking"); if( passwordStacking != null && passwordStacking.equalsIgnoreCase("useFirstPass") ) useFirstPass = true; + + // Check for a custom Principal implementation + principalClassName = (String) options.get("principalClass"); + + // Check for unauthenticatedIdentity option. + String name = (String) options.get("unauthenticatedIdentity"); + if( name != null ) + { + try + { + unauthenticatedIdentity = createIdentity(name); + log.trace("Saw unauthenticatedIdentity="+name); + } + catch(Exception e) + { + log.warn("Failed to create custom unauthenticatedIdentity", e); + } + } } /** Looks for javax.security.auth.login.name and javax.security.auth.login.password @@ -225,7 +253,11 @@ { return useFirstPass; } - + protected Principal getUnauthenticatedIdentity() + { + return unauthenticatedIdentity; + } + /** 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. @@ -254,4 +286,33 @@ } return roles; } + + /** Utility method to create a Principal for the given username. This + * creates an instance of the principalClassName type if this option was + * specified using the class constructor matching: ctor(String). If + * principalClassName was not specified, a SimplePrincipal is created. + * + * @param username the name of the principal + * @return the principal instance + * @throws java.lang.Exception thrown if the custom principal type cannot be created. + */ + protected Principal createIdentity(String username) + throws Exception + { + Principal p = null; + if( principalClassName == null ) + { + p = new SimplePrincipal(username); + } + else + { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Class clazz = loader.loadClass(principalClassName); + Class[] ctorSig = {String.class}; + Constructor ctor = clazz.getConstructor(ctorSig); + Object[] ctorArgs = {username}; + p = (Principal) ctor.newInstance(ctorArgs); + } + return p; + } } 1.2 +40 -67 jbosssx/src/main/org/jboss/security/auth/spi/CertRolesLoginModule.java Index: CertRolesLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/CertRolesLoginModule.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- CertRolesLoginModule.java 23 Mar 2004 16:18:51 -0000 1.1 +++ CertRolesLoginModule.java 26 May 2004 21:07:17 -0000 1.2 @@ -9,9 +9,8 @@ package org.jboss.security.auth.spi; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; import java.security.acl.Group; +import java.security.Principal; import java.util.ArrayList; import java.util.Enumeration; import java.util.Map; @@ -23,7 +22,7 @@ import javax.security.auth.login.LoginException; import org.jboss.security.SimpleGroup; -import org.jboss.security.SimplePrincipal; + /** * <dl> @@ -34,22 +33,31 @@ * </dd> * <p> * </dl> + * @see org.jboss.security.auth.spi.BaseCertLoginModule + * @author <a href="mailto:ja...@gr...">Jason Essington</a> - * @version $Revision: 1.1 $ - * @see org.jboss.security.auth.spi.UsersRolesLoginModule - * @see org.jboss.security.auth.spi.AbstractCertLoginModule + * @author Sco...@jb... + * @version $Revision: 1.2 $ */ -public class CertRolesLoginModule extends AbstractCertLoginModule +public class CertRolesLoginModule extends BaseCertLoginModule { + /** The name of the properties resource containing user/roles */ private String rolesRsrcName = "roles.properties"; + /** The roles.properties mappings */ private Properties roles; - public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) + /** Initialize this LoginModule. + *@param options - the login module option map. Supported options include: + *rolesProperties: The name of the properties resource containing user/roles + The default is "roles.properties". + */ + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + super.initialize(subject, callbackHandler, sharedState, options); if (log.isDebugEnabled()) log.debug("enter: initialize(Subject, CallbackHandler, Map, Map)"); - super.initialize(subject, callbackHandler, sharedState, options); try { String option = (String) options.get("rolesProperties"); @@ -101,29 +109,8 @@ { String user = (String) users.nextElement(); String value = roles.getProperty(user); - // See if this entry is of the form targetUser[.GroupName]=roles - int index = user.indexOf('.'); - boolean isRoleGroup = false; - boolean userMatch = false; - if (index > 0 && targetUser.regionMatches(0, user, 0, index) == true) - isRoleGroup = true; - else - userMatch = targetUser.equals(user); - - // Check for username.RoleGroup pattern - if (isRoleGroup == true) - { - String groupName = user.substring(index + 1); - if (groupName.equals("Roles")) - parseGroupMembers(rolesGroup, value); - else - { - SimpleGroup group = new SimpleGroup(groupName); - parseGroupMembers(group, value); - groups.add(group); - } - } - else if (userMatch == true) + boolean userMatch = targetUser.equals(user); + if (userMatch == true) { // Place these roles into the Default "Roles" group parseGroupMembers(rolesGroup, value); @@ -136,50 +123,36 @@ return roleSets; } - /** - * @see org.jboss.security.auth.spi.UsersRolesLoginModule#parseGroupMembers - */ - private void parseGroupMembers(Group group, String value) + /** Parse the comma delimited roles names given by value and add them to + * group. The type of Principal created for each name is determined by + * the createIdentity method. + * + * @see #createIdentity(String) + * + * @param group - the Group to add the roles to. + * @param roles - the comma delimited role names. + */ + private void parseGroupMembers(Group group, String roles) { - StringTokenizer tokenizer = new StringTokenizer(value, ","); + StringTokenizer tokenizer = new StringTokenizer(roles, ","); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); - SimplePrincipal p = new SimplePrincipal(token); - group.addMember(p); + try + { + Principal p = createIdentity(token); + group.addMember(p); + } + catch (Exception e) + { + log.warn("Failed to create principal for: "+token, e); + } } } - /** - * @see org.jboss.security.auth.spi.UsersRolesLoginModule#loadRoles - */ private void loadRoles() throws IOException { - roles = loadProperties(rolesRsrcName); - } - - /** - * @see org.jboss.security.auth.spi.UsersRolesLoginModule#loadProperties - */ - private Properties loadProperties(String propertiesName) throws IOException - { - Properties bundle = null; - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - URL url = loader.getResource(propertiesName); - if (url == null) - throw new IOException("Properties file " + propertiesName + " not found"); - super.log.trace("Properties file=" + url); - InputStream is = url.openStream(); - if (is != null) - { - bundle = new Properties(); - bundle.load(is); - } - else - { - throw new IOException("Properties file " + propertiesName + " not avilable"); - } - return bundle; + roles = UsersRolesLoginModule.loadProperties(rolesRsrcName, log); } } 1.2 +10 -6 jbosssx/src/main/org/jboss/security/auth/spi/DatabaseCertLoginModule.java Index: DatabaseCertLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/DatabaseCertLoginModule.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DatabaseCertLoginModule.java 23 Mar 2004 16:18:51 -0000 1.1 +++ DatabaseCertLoginModule.java 26 May 2004 21:07:17 -0000 1.2 @@ -29,19 +29,23 @@ /** * <dl> - * <dt><b>Title: </b><dd>Certificate Login Module that gets its role information from a database.</dd> + * <dt><b>Title: </b><dd>Certificate Login Module that gets its role + * information from a database.</dd> * <p> * <dt><b>Description: </b><dd>This module is the functional equivelant of the - * {@link org.jboss.security.auth.spi.DatabaseServerLoginModule} minus the usersQuery. Most of the code in this module - * was borrowed from {@link org.jboss.security.auth.spi.DatabaseServerLoginModule}. + * {@link org.jboss.security.auth.spi.DatabaseServerLoginModule} minus the + * usersQuery. Most of the code in this module was borrowed from + * {@link org.jboss.security.auth.spi.DatabaseServerLoginModule}. * </dd> * <p> * </dl> - * @author <a href="mailto:ja...@gr...">Jason Essington</a> - * @version $Revision: 1.1 $ * @see org.jboss.security.auth.spi.DatabaseServerLoginModule + * + * @author <a href="mailto:ja...@gr...">Jason Essington</a> + * @author Sco...@jb... + * @version $Revision: 1.2 $ */ -public class DatabaseCertLoginModule extends AbstractCertLoginModule +public class DatabaseCertLoginModule extends BaseCertLoginModule { private String dsJndiName; 1.11 +5 -7 jbosssx/src/main/org/jboss/security/auth/spi/DatabaseServerLoginModule.java Index: DatabaseServerLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/DatabaseServerLoginModule.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- DatabaseServerLoginModule.java 16 Mar 2004 22:34:29 -0000 1.10 +++ DatabaseServerLoginModule.java 26 May 2004 21:07:17 -0000 1.11 @@ -48,7 +48,7 @@ * * @author <a href="mailto:on...@ib...">Oleg Nitz</a> * @author Sco...@jb... - * @version $Revision: 1.10 $ + * @version $Revision: 1.11 $ */ public class DatabaseServerLoginModule extends UsernamePasswordLoginModule { @@ -147,11 +147,9 @@ 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. + /** Execute the rolesQuery against the dsJndiName to obtain the roles for + the authenticated user. + @return Group[] containing the sets of roles */ protected Group[] getRoleSets() throws LoginException @@ -262,7 +260,7 @@ /** 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 + @param rawPassword - the password as obtained from the database @return the argument rawPassword */ protected String convertRawPassword(String rawPassword) 1.18 +4 -61 jbosssx/src/main/org/jboss/security/auth/spi/UsernamePasswordLoginModule.java Index: UsernamePasswordLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/UsernamePasswordLoginModule.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- UsernamePasswordLoginModule.java 30 Mar 2004 21:11:18 -0000 1.17 +++ UsernamePasswordLoginModule.java 26 May 2004 21:07:17 -0000 1.18 @@ -8,7 +8,6 @@ import java.security.Principal; import java.util.Map; -import java.lang.reflect.Constructor; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; @@ -19,7 +18,6 @@ import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; -import org.jboss.security.SimplePrincipal; import org.jboss.security.Util; import org.jboss.security.auth.spi.AbstractServerLoginModule; @@ -38,18 +36,14 @@ * @see #createIdentity(String) @author Sco...@jb... - @version $Revision: 1.17 $ + @version $Revision: 1.18 $ */ public abstract class UsernamePasswordLoginModule extends AbstractServerLoginModule { /** The login identity */ private Principal identity; - /** An optional custom Principal class implementation */ - private String identityClassName; /** The proof of login identity */ private char[] credential; - /** the principal to use when a null username and password are seen */ - private Principal unauthenticatedIdentity; /** the message digest algorithm used to hash passwords. If null then plain passwords will be used. */ private String hashAlgorithm = null; @@ -62,13 +56,9 @@ /** A flag indicating if the password comparison should ignore case */ private boolean ignorePasswordCase; - /** Override the superclass method to look for a unauthenticatedIdentity - property. This method first invokes the super version. - @param options - @option principalClass: A Principal implementation that support a ctor - taking a String argument for the princpal name. - @option unauthenticatedIdentity: the name of the principal to asssign - and authenticate when a null username and password are seen. + /** Override the superclass method to look for the following options after + first invoking the super version. + @param options : @option hashAlgorithm: the message digest algorithm used to hash passwords. If null then plain passwords will be used. @option hashCharset: the name of the charset/encoding to use when converting @@ -83,24 +73,6 @@ { super.initialize(subject, callbackHandler, sharedState, options); - // Check for a custom Principal implementation - identityClassName = (String) options.get("principalClass"); - - // Check for unauthenticatedIdentity option. - String name = (String) options.get("unauthenticatedIdentity"); - if( name != null ) - { - try - { - unauthenticatedIdentity = createIdentity(name); - super.log.trace("Saw unauthenticatedIdentity="+name); - } - catch(Exception e) - { - super.log.warn("Failed to create custom unauthenticatedIdentity", e); - } - } - // Check to see if password hashing has been enabled. // If an algorithm is set, check for a format and charset. hashAlgorithm = (String) options.get("hashAlgorithm"); @@ -311,35 +283,6 @@ } - /** Create a Principal for the given username. This creates an instance of - * the principalClass type if this option was specified using the - * ctor(String). If principalClass was not specified, a SimplePrincipal is - * created. - * - * @param username the name of the principal - * @return the principal instance - * @throws Exception thrown if the custom principal type cannot be created. - */ - protected Principal createIdentity(String username) - throws Exception - { - Principal p = null; - if( identityClassName == null ) - { - p = new SimplePrincipal(username); - } - else - { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - Class clazz = loader.loadClass(identityClassName); - Class[] ctorSig = {String.class}; - Constructor ctor = clazz.getConstructor(ctorSig); - Object[] ctorArgs = {username}; - p = (Principal) ctor.newInstance(ctorArgs); - } - return p; - } - /** 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 1.15 +80 -45 jbosssx/src/main/org/jboss/security/auth/spi/UsersRolesLoginModule.java Index: UsersRolesLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/auth/spi/UsersRolesLoginModule.java,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- UsersRolesLoginModule.java 13 Mar 2004 21:15:54 -0000 1.14 +++ UsersRolesLoginModule.java 26 May 2004 21:07:17 -0000 1.15 @@ -6,22 +6,26 @@ */ package org.jboss.security.auth.spi; -import org.jboss.security.SimpleGroup; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.security.Principal; -import java.security.acl.Group; +import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; +import java.security.acl.Group; +import java.security.Principal; +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.LoginException; + +import org.jboss.security.SimpleGroup; +import org.jboss.security.auth.spi.UsernamePasswordLoginModule; +import org.jboss.logging.Logger; + /** 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 names of the properties @@ -59,19 +63,20 @@ private String usersRsrcName = "users.properties"; /** The name of the properties resource containing user/roles */ private String rolesRsrcName = "roles.properties"; - /** The users.properties values */ + /** The users.properties mappings */ private Properties users; - /** The roles.properties values */ + /** The roles.properties mappings */ private Properties roles; /** Initialize this LoginModule. - *@param options the login module option map. Supported options include: + *@param options - the login module option map. Supported options include: *usersProperties: The name of the properties resource containing user/passwords. The default is "users.properties" *rolesProperties: The name of the properties resource containing user/roles The default is "roles.properties". */ - public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { super.initialize(subject, callbackHandler, sharedState, options); try @@ -170,47 +175,39 @@ } // utility methods - private void parseGroupMembers(Group group, String value) - { - StringTokenizer tokenizer = new StringTokenizer(value, ","); - while (tokenizer.hasMoreTokens()) - { - String token = tokenizer.nextToken(); - try - { - Principal p = createIdentity(token.trim()); - group.addMember(p); - } - catch (Exception e) - { - log.warn("Failed to create principal for: "+token, e); - } - } - } - private void loadUsers() throws IOException - { - users = loadProperties(usersRsrcName); - } - - private void loadRoles() throws IOException - { - roles = loadProperties(rolesRsrcName); - } - - /** - * 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. + /** Utility method which 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 as this method looks + * to the thread context class loader (TCL) to locate the resource. If the + * TCL is a URLClassLoader the findResource(String) method is first tried. + * If this fails or the TCL is not a URLClassLoader getResource(String) is + * tried. + * @param propertiesName - the name of the properties file resource + * @param log - the logger used for trace level messages + * @return the loaded properties file if found + * @exception IOException thrown if the properties file cannot be found + * or loaded */ - private Properties loadProperties(String propertiesName) throws IOException + static Properties loadProperties(String propertiesName, Logger log) + throws IOException { Properties bundle = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); - URL url = loader.getResource(propertiesName); + URL url = null; + // First check for local visibility via a URLClassLoader.findResource + if( loader instanceof URLClassLoader ) + { + URLClassLoader ucl = (URLClassLoader) loader; + url = ucl.findResource(propertiesName); + log.trace("findResource: "+url); + } + // Do a general resource search + if( url == null ) + url = loader.getResource(propertiesName); if (url == null) throw new IOException("Properties file " + propertiesName + " not found"); - super.log.trace("Properties file=" + url); + log.trace("Properties file=" + url); InputStream is = url.openStream(); if (is != null) { @@ -223,4 +220,42 @@ } return bundle; } + + protected void loadUsers() throws IOException + { + users = loadProperties(usersRsrcName, log); + } + + protected void loadRoles() throws IOException + { + roles = loadProperties(rolesRsrcName, log); + } + + /** Parse the comma delimited roles names given by value and add them to + * group. The type of Principal created for each name is determined by + * the createIdentity method. + * + * @see #createIdentity(String) + * + * @param group - the Group to add the roles to. + * @param roles - the comma delimited role names. + */ + protected void parseGroupMembers(Group group, String roles) + { + StringTokenizer tokenizer = new StringTokenizer(roles, ","); + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken(); + try + { + Principal p = createIdentity(token); + group.addMember(p); + } + catch (Exception e) + { + log.warn("Failed to create principal for: "+token, e); + } + } + } + } 1.2 +359 -0 jbosssx/src/main/org/jboss/security/auth/spi/BaseCertLoginModule.java |