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

Reply via email to