User: luke_t
Date: 01/12/18 18:47:02
Modified: src/main/org/jboss/security/auth/spi
UsernamePasswordLoginModule.java
Log:
password hashing functionality added. Hasn't been checked thouroughly for
compatibily with external tools yet, but shoudn't break any existing code.
Revision Changes Path
1.8 +147 -6
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.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- UsernamePasswordLoginModule.java 2001/12/17 00:07:44 1.7
+++ UsernamePasswordLoginModule.java 2001/12/19 02:47:02 1.8
@@ -8,8 +8,11 @@
package org.jboss.security.auth.spi;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.security.Principal;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
@@ -20,6 +23,8 @@
import javax.security.auth.login.FailedLoginException;
import org.jboss.security.SimplePrincipal;
+import org.jboss.security.Util;
+import org.jboss.security.Base64Encoder;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
@@ -37,7 +42,8 @@
* @see #getRoleSets()
*
* @author [EMAIL PROTECTED]
- * @version $Revision: 1.7 $
+ * @author [EMAIL PROTECTED]
+ * @version $Revision: 1.8 $
*/
public abstract class UsernamePasswordLoginModule extends AbstractServerLoginModule
{
@@ -50,13 +56,34 @@
/** 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;
+ /**
+ * the name of the charset/encoding to use when converting the password String to
a byte array.
+ * Default is the platform's default encoding.
+ */
+ private String hashCharset = null;
+ /** the string encoding format to use. Defaults to base64. */
+ private String hashEncoding = null;
+
/**
* Override the superclass method to look for an <em>unauthenticatedIdentity</em>
* property. This is the name of the principal to assign and authenticate
* when a null username and password are seen.
* <p>
+ * The options map will also be checked for the parameter <em>hashAlgorithm</em>
+ * to see if password hashing should be used instead of plain passwords.
+ * If you set this parameter, passwords will be hashed using the specified
+ * algorithm (for example "SHA" or "MD5") and will be encoded as strings.
+ * <p>
+ * The string encoding format is set using the optional parameter
+ * <em>hashEncoding</em>. Currently supported are MIME "BASE64" encoded
+ * strings as defined in
+ * (<a href="http://ietf.org/rfc/rfc1521.txt">rfc1521</a>)
+ * or "HEX" encoded strings. BASE64 is the default if omitted.
+ * <p>
* This method first invokes the super version.
- *
+ *
* @param options the map of paramers passed to this login module.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
@@ -66,13 +93,28 @@
String name = (String) options.get("unauthenticatedIdentity");
if( name != null )
unauthenticatedIdentity = new SimplePrincipal(name);
+
+ // 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");
+ if(hashAlgorithm != null)
+ {
+ hashEncoding = (String) options.get("hashEncoding");
+ if(hashEncoding == null)
+ hashEncoding = "BASE64";
+ hashCharset = (String) options.get("hashCharset");
+ if(log.isDebugEnabled())
+ {
+ log.debug("Passworg hashing activated: algorithm = " + hashAlgorithm +
+ ", encoding = " + hashEncoding+ (hashCharset == null ? "" : "charset
= " + hashCharset));
+ }
+ }
}
- /** */
public boolean login() throws LoginException
{
// See if shared credentials exist
- if( super.login() == true )
+ if( super.login() )
{
// Setup our view of the user
Object username = sharedState.get("javax.security.auth.login.name");
@@ -102,15 +144,19 @@
if( identity == null )
{
identity = new SimplePrincipal(username);
+ // hash the user entered password if password hashing is in use
+ if(hashAlgorithm != null)
+ password = createPasswordHash(username, password);
// Validate the password supplied by the subclass
String expectedPassword = getUsersPassword();
if( validatePassword(password, expectedPassword) == false )
{
- System.out.println("Bad password for username=" + username);
+ log.warn("Bad password for username = " + username);
throw new FailedLoginException("Password Incorrect/Password Required");
}
}
- System.out.print("User '" + identity + "' authenticated.\n");
+ if( log.isInfoEnabled() )
+ log.info("User '" + identity + "' authenticated.");
if( getUseFirstPass() == true )
{ // Add the username and password to the shared state map
@@ -187,6 +233,73 @@
return info;
}
+ /**
+ * If hashing is enabled, this method is called from <code>login()</code>
+ * prior to password validation.
+ * <p>
+ * Subclasses may override it to provide customized password hashing,
+ * for example by adding user-specific information or salting.
+ * <p>
+ * The default version calculates the hash based on the following options:
+ * <ul>
+ * <li><em>hashAlgorithm</em>: The digest algorithm to use.
+ * <li><em>hashEncoding</em>: The format used to store the hashes (base64 or hex)
+ * <li><em>hashCharset</em>: The encoding used to convert the password to bytes
+ * for hashing.
+ * </ul>
+ * It will return null if the hash fails for any reason, which will in turn
+ * cause <code>validatePassword()</code> to fail.
+ *
+ * @param username ignored in default version
+ * @param password the password string to be hashed
+ */
+ protected String createPasswordHash(String username, String password)
+ {
+ byte[] passBytes;
+ byte[] hash;
+ String passwordHash = null;
+
+ // convert password to byte data
+ try
+ {
+ if(hashCharset == null)
+ passBytes = password.getBytes();
+ else
+ passBytes = password.getBytes(hashCharset);
+ }
+ catch(UnsupportedEncodingException uee)
+ {
+ log.error("charset " + hashCharset + " not found. Using platform
default.", uee);
+ passBytes = password.getBytes();
+ }
+
+ // calculate the hash and apply the encoding.
+ try
+ {
+ hash = MessageDigest.getInstance(hashAlgorithm).digest(passBytes);
+ if(hashEncoding.equalsIgnoreCase("BASE64"))
+ {
+ passwordHash = Base64Encoder.encode(hash);
+// test to compare with sun's builtin encoder.
+// String sunB64 = new sun.misc.BASE64Encoder().encode(hash);
+// System.out.println("Hashes: sun " + sunB64 + ", jboss " +
passwordHash);
+ }
+ else if(hashEncoding.equalsIgnoreCase("HEX"))
+ {
+ passwordHash = hexEncode(hash);
+ }
+ else
+ {
+ log.error("Unsupported hash encoding format " + hashEncoding);
+ }
+ }
+ catch(Exception e)
+ {
+ log.error("Password hash calculation failed ", e);
+ }
+ return passwordHash;
+ }
+
/**
* A hook that allows subclasses to change the validation of the input
* password against the expected password. This version checks that
@@ -212,4 +325,32 @@
*/
abstract protected String getUsersPassword() throws LoginException;
+// Private ---------------------------------------------------------------------
+ /**
+ * Hex encoding of hashes, as used by Catalina. Each byte is converted to
+ * the corresponding two hex characters.
+ */
+ private String hexEncode(byte[] bytes)
+ {
+ StringBuffer sb = new StringBuffer(bytes.length * 2);
+ for (int i = 0; i < bytes.length; i++)
+ {
+ byte b = bytes[i];
+ // top 4 bits
+ char c = (char)((b >> 4) & 0xf);
+ if(c > 9)
+ c = (char)((c - 10) + 'a');
+ else
+ c = (char)(c + '0');
+ sb.append(c);
+ // bottom 4 bits
+ c = (char)(b & 0xf);
+ if (c > 9)
+ c = (char)((c - 10) + 'a');
+ else
+ c = (char)(c + '0');
+ sb.append(c);
+ }
+ return sb.toString();
+ }
}
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development