You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2009/11/03 20:08:00 UTC

svn commit: r832513 - in /incubator/pivot/trunk: core/src/org/apache/pivot/util/HexUtils.java core/src/org/apache/pivot/util/MD5.java web/src/org/apache/pivot/web/DigestAuthentication.java

Author: gbrown
Date: Tue Nov  3 19:07:59 2009
New Revision: 832513

URL: http://svn.apache.org/viewvc?rev=832513&view=rev
Log:
Consolidate HexUtils into MD5; eliminate unused methods and properties; remove unused code from DigestAuthentication.

Removed:
    incubator/pivot/trunk/core/src/org/apache/pivot/util/HexUtils.java
Modified:
    incubator/pivot/trunk/core/src/org/apache/pivot/util/MD5.java
    incubator/pivot/trunk/web/src/org/apache/pivot/web/DigestAuthentication.java

Modified: incubator/pivot/trunk/core/src/org/apache/pivot/util/MD5.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/util/MD5.java?rev=832513&r1=832512&r2=832513&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/util/MD5.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/util/MD5.java Tue Nov  3 19:07:59 2009
@@ -21,24 +21,24 @@
 import java.security.NoSuchAlgorithmException;
 
 /**
- * Encode / Decode an MD5 digest into / from a String.
+ * Encode/decode an MD5 digest to/from a string.
  * <p>
- * The 128 bit MD5 hash is converted into a 32 character long String.
- * Each character of the String is the hexadecimal representation of 4 bits
+ * The 128 bit MD5 hash is converted into a 32-character string. Each
+ * character of the String is the hexadecimal representation of 4 bits
  * of the digest.
- * <br/>
- * Portions of code here are taken from Apache Tomcat,
- * see org.apache.catalina.util.MD5Encoder
- *
+ * <p>
+ * Portions of code here are taken from Apache Tomcat; see
+ * <tt>org.apache.catalina.util.MD5Encoder</tt>.
  */
 public final class MD5 {
     public static final int MD5_DIGEST_LENTGH_IN_BYTES = 16;
     public static final String MD5_ALGORITHM_NAME = "MD5";
 
-    /** The MD5 message digest generator. */
     private static MessageDigest md5 = null;
 
-    /** Constructor for private usage */
+    private static final char[] hexadecimal = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        'a', 'b', 'c', 'd', 'e', 'f' };
+
     private MD5() {
     }
 
@@ -56,6 +56,7 @@
 
         byte[] dataDigested = null;
 
+        // TODO Why is this commented out?
         // synchronized (MD5.class) {
             if (md5 == null) {
                 try {
@@ -78,14 +79,23 @@
      * Transform the given string in a byte array, using the given encoding.
      * Note that any Exception is handled inside.
      *
-     * @param string the string
-     * @param encoding the encoding, or if null a default will be used
-     * @return the string transformed to byte array
+     * @param string
+     * The string to transform.
+     *
+     * @param encoding
+     * The encoding to use, or <tt>null</tt> to use the default encoding.
+     *
+     * @return
+     * The string transformed into a byte array.
      */
     public static final byte[] digest(final String string, final String encoding) {
         byte[] data = null;
         try {
-            data = HexUtils.toByteArray(string, encoding);
+            if (encoding == null) {
+                data = string.getBytes();
+            } else {
+                data = string.getBytes(encoding);
+            }
         } catch (UnsupportedEncodingException e) {
         }
 
@@ -93,33 +103,14 @@
         return dataDigested;
     }
 
-    public static boolean isEqual(byte[] digesta, byte[] digestb) {
-        // Two arrays are equal if they have the same length and each element
-        // is equal to the corresponding element in the other array;
-        // otherwise, they aren't.
-
-        if (digesta == null || digestb == null) {
-            return false;
-        }
-        else if (digesta.length == MD5_DIGEST_LENTGH_IN_BYTES
-            && digestb.length == MD5_DIGEST_LENTGH_IN_BYTES) {
-            for (int i = 0; i < MD5_DIGEST_LENTGH_IN_BYTES; i++) {
-                if (digesta[i] != digestb[i])
-                    return false;
-            }
-
-            return true;
-        } else {
-            return false;
-        }
-
-    }
-
     /**
      * Encodes the 128 bit (16 bytes) MD5 into a 32 character String.
      *
-     * @param binaryData The Array containing the digest
-     * @return Encoded MD5, or null if encoding failed
+     * @param binaryData
+     * The byte array containing the digest.
+     *
+     * @return
+     * The encoded MD5 string.
      */
     public static final String encode(byte[] binaryData) {
         if (binaryData.length != MD5_DIGEST_LENTGH_IN_BYTES) {
@@ -132,8 +123,8 @@
             int low = binaryData[i] & 0x0f;
             int high = (binaryData[i] & 0xf0) >> 4;
 
-            buffer[i * 2] = HexUtils.hexadecimal[high];
-            buffer[i * 2 + 1] = HexUtils.hexadecimal[low];
+            buffer[i * 2] = hexadecimal[high];
+            buffer[i * 2 + 1] = hexadecimal[low];
         }
 
         return new String(buffer);
@@ -142,9 +133,14 @@
     /**
      * Transform the given string in a digested version, using the given encoding.
      *
-     * @param string the string
-     * @param encoding the encoding, or if null a default will be used
-     * @return the string digested, and transformed as s String
+     * @param string
+     * The string to digest.
+     *
+     * @param encoding
+     * The encoding to use, or <tt>null to use the default encoding.</tt>
+     *
+     * @return
+     * The digested string.
      */
     public static final String digestAsString(final String string, final String encoding) {
         byte[] digestBytes = MD5.digest(string, encoding);
@@ -153,4 +149,30 @@
         return dataDigested;
     }
 
+    /**
+     * Convert a byte array into a printable format containing a string of
+     * hexadecimal digit characters (two per byte).
+     *
+     * @param bytes
+     * Byte array representation.
+     */
+    public static String toHexString(byte bytes[]) {
+        StringBuffer sb = new StringBuffer(bytes.length * 2);
+        for (int i = 0; i < bytes.length; i++) {
+            sb.append(convertDigit(bytes[i] >> 4));
+            sb.append(convertDigit(bytes[i] & 0x0f));
+        }
+
+        return (sb.toString());
+    }
+
+    private static char convertDigit(int value) {
+        value &= 0x0f;
+
+        if (value >= 10) {
+            return ((char) (value - 10 + 'a'));
+        }
+
+        return ((char) (value + '0'));
+    }
 }

Modified: incubator/pivot/trunk/web/src/org/apache/pivot/web/DigestAuthentication.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/web/src/org/apache/pivot/web/DigestAuthentication.java?rev=832513&r1=832512&r2=832513&view=diff
==============================================================================
--- incubator/pivot/trunk/web/src/org/apache/pivot/web/DigestAuthentication.java (original)
+++ incubator/pivot/trunk/web/src/org/apache/pivot/web/DigestAuthentication.java Tue Nov  3 19:07:59 2009
@@ -22,7 +22,6 @@
 
 import org.apache.pivot.collections.HashMap;
 import org.apache.pivot.collections.Map;
-import org.apache.pivot.util.HexUtils;
 import org.apache.pivot.util.MD5;
 import org.apache.pivot.util.concurrent.TaskExecutionException;
 
@@ -30,24 +29,20 @@
  * Implementation of the {@link Authentication} interface supporting the
  * HTTP <a href="http://tools.ietf.org/rfc/rfc2617.txt">Digest Authentication</a> scheme.
  * <br/>
- * Portions of code here are taken from Apache Tomcat, and from Apache Commons HTTP Client,
- * see DigestScheme and related classes from HTTPCommons 3.1 sources
- * See DigestAuthenticator and related classes from Tomcat 6 sources
- *
+ * Portions of code here are taken from Apache Tomcat, and from Apache Commons HTTP Client.
+ * See <tt>DigestScheme</tt> and related classes from HTTPCommons 3.1 sources; see
+ * <tt>DigestAuthenticator</tt> and related classes from Tomcat 6 sources.
+ * <p>
  * TODO:
- *   - verify how to reuse the authorization data (if already authenticated) ...
- *   - verify if/how to handle the nonce count, for queries after the first ...
- *
- *   - future work:
- *     -- verify if this works with redirects, proxy, etc ...
- *     -- verify if implement also the algorithm "MD5-sess"
+ * - Verify how to reuse the authorization data (if already authenticated).
+ * - Verify if/how to handle the nonce count, for queries after the first.
+ * - Verify that this works with redirects, proxy, etc.
+ * - Also implement the "MD5-sess" algorithm?
  *
  */
 public class DigestAuthentication implements Authentication {
     private static final String HTTP_RESPONSE_AUTHENTICATE_HEADER_KEY = "WWW-Authenticate";
     private static final String HTTP_REPLY_AUTHENTICATE_HEADER_KEY = "Authorization";
-    // private static final String HTTP_RESPONSE_AUTHENTICATED_HEADER_KEY = "Authentication-Info";
-    // private static final String HTTP_RESPONSE_MIME_TYPE_HEADER_KEY = "Content-Type";
 
     private static final String HTTP_REPLY_FIELD_SEPARATOR = ":";
 
@@ -64,7 +59,6 @@
 
     private static final String AUTH_FIELD_VALUE_QOP_AUTH = "auth";
     private static final String AUTH_FIELD_VALUE_ALGORITHM_AUTH_MD5 = "MD5";
-    // private static final String AUTH_FIELD_VALUE_ALGORITHM_AUTH_MD5_SESSION = "MD5-sess";
 
     private static final String AUTH_FIELD_VALUE_NC_FIRST = "00000001";
 
@@ -99,33 +93,32 @@
     private String encoding;
 
     /**
-     * Default constructor.
+     * Constructor.
      *
-     * Do not use. Null user name or Null Password are no longer
-     * allowed.
-     */
-    public DigestAuthentication() {
-        this(null, null, null, null);
-    }
-
-    /**
-     * The constructor with the username and password arguments.
+     * @param username
+     * The user name.
      *
-     * @param username the user name
-     * @param password the password
+     * @param password
+     * The password.
      */
     public DigestAuthentication(String username, String password) {
         this(username, password, DEFAULT_ALGORITHM, null);
     }
 
     /**
-     * The constructor with the username, password, and other invariant
-     * arguments.
+     * Constructor.
      *
-     * @param username the user name
-     * @param password the password
-     * @param algorithm the algorithm to use (if null, the default will be used)
-     * @param encoding the encoding for Strings (for digesting strings)
+     * @param username
+     * The user name.
+     *
+     * @param password
+     * The password.
+     *
+     * @param algorithm
+     * The algorithm to use, or <tt>null</tt> to use the default algorithm.
+     *
+     * @param encoding
+     * The encoding to use for digesting strings.
      */
     public DigestAuthentication(String username, String password, String algorithm, String encoding) {
         super();
@@ -146,87 +139,51 @@
     }
 
     /**
-     * Return the User Name property.
-     *
-     * @return the username
+     * Returns the user name.
      */
     public String getUsername() {
         return username;
     }
 
     /**
-     * Return the Password property.
-     *
-     * @return the password
+     * Returns the password.
      */
     public String getPassword() {
         return password;
     }
 
     /**
-     * Return the message digest algorithm for this Manager.
-     *
-     * @return the algorithm
+     * Returns the message digest algorithm.
      */
     public String getAlgorithm() {
         return algorithm;
     }
 
     /**
-     * Get this object string.
-     *
-     * @return main data in a formed string
-     */
-    @Override
-    public String toString() {
-        StringBuffer result = new StringBuffer();
-
-        result.append(this.getClass().getName());
-        result.append(HTTP_REPLY_FIELD_SEPARATOR);
-        result.append(username);
-        result.append(HTTP_REPLY_FIELD_SEPARATOR);
-        result.append(password);
-        result.append(HTTP_REPLY_FIELD_SEPARATOR);
-        result.append(algorithm);
-        result.append(HTTP_REPLY_FIELD_SEPARATOR);
-        result.append(encoding);
-
-        return result.toString();
-    }
-
-    /**
-     * Returns the (digest) encoding charset.
-     *
-     * @return The charset (may be null) for platform default
+     * Returns the digest encoding.
      */
     public String getDigestEncoding() {
         return encoding;
     }
 
     /**
-     * Set the (digest) encoding to use.
+     * Set the digest encoding.
      *
-     * @param encoding The encoding to use, or if null a default will be used
+     * @param encoding
+     * The encoding to use, or <tt>null</tt> to use the default encoding.
      */
     private void setDigestEncoding(String encoding) {
-        // this.encoding = encoding;
-
-        // String charset = getParameter("charset"); // future: read the charset from the response header
-        String charset = encoding;
-
-        // if a charset is not specified, default to ISO-8859-1
-        // if (charset == null)
-        // charset = "ISO-8859-1";
-
-        this.encoding = charset;
-        // System.out.println("charset = \"" + charset + "\"");
+        this.encoding = encoding;
     }
 
     /**
      * Returns the IP Address of the given Host.
      *
-     * @param hostName the host name, or if null the local host will be used
-     * @return the ID Address, as a String
+     * @param hostName
+     * The host name, or <tt>null</tt> to use the local host.
+     *
+     * @return
+     * The IP address, as a string.
      */
     protected static String getIPAddress(String hostName) throws UnknownHostException {
         InetAddress inetAddr = null;
@@ -253,18 +210,16 @@
     }
 
     /**
-     * Authenticate
+     * Authenticate the query.
      *
-     * @param query The Query
+     * @param query
+     * The query to authenticate.
      */
     public void authenticate(Query<?> query) {
-
         try {
-            String responseAuthenticateHeader = query.getResponseHeaders().get(
-                HTTP_RESPONSE_AUTHENTICATE_HEADER_KEY);
-// System.out.println("responseAuthenticateHeader " +
-// HTTP_RESPONSE_AUTHENTICATE_HEADER_KEY + " = \n" +
-// responseAuthenticateHeader + "\n");
+            String responseAuthenticateHeader =
+                query.getResponseHeaders().get(HTTP_RESPONSE_AUTHENTICATE_HEADER_KEY);
+
             if (responseAuthenticateHeader == null) {
                 // Digest authentication needs a first query to retrieve
                 // authentication hints from the server,
@@ -272,15 +227,12 @@
                 // first query call here ...
                 try {
                     query.execute();
-                } catch (TaskExecutionException tee) {
-                    // tee.printStackTrace(); // expected, so ignore it
+                } catch (TaskExecutionException exception) {
+                    // No-op
                 }
 
                 responseAuthenticateHeader = query.getResponseHeaders().get(
                     HTTP_RESPONSE_AUTHENTICATE_HEADER_KEY);
-// System.out.println("responseAuthenticateHeader " +
-// HTTP_RESPONSE_AUTHENTICATE_HEADER_KEY + " = \n" +
-// responseAuthenticateHeader + "\n");
                 if (responseAuthenticateHeader == null) {
                     return;
                 }
@@ -293,7 +245,6 @@
                 // try to reuse it, reading hints from
                 // HTTP_RESPONSE_AUTHENTICATED_HEADER_KEY
                 // -- for example, the nonce_count value to use should be read from there ...
-                ;
             }
 
             String uri = query.getPath();
@@ -374,9 +325,6 @@
                 authenticateHeader.append("\"");
             }
 
-// System.out.println("authenticateHeader " + HTTP_REPLY_AUTHENTICATE_HEADER_KEY +
-// " = \n" + authenticateHeader.toString() + "\n");
-
             query.getRequestHeaders().put(HTTP_REPLY_AUTHENTICATE_HEADER_KEY,
                 authenticateHeader.toString());
         } catch (Exception e) {
@@ -390,16 +338,32 @@
      * authentication header, as described in RFC 2069; otherwise return
      * <code>null</code>.
      *
-     * @param username Username of the Principal to look up
-     * @param realm Realm name
-     * @param nOnce Unique (or supposedly unique) token which has been used for
-     * this request
-     * @param nc Number of query (starting from 1) with this authentication info
-     * @param cnonce Value (usually random) chosen by the client
-     * @param qop Quality Of Protection flag
-     * @param method The HTTP method
-     * @param uri The URI of the query
-     * @return the digested value for the response field
+     * @param username
+     * Username of the principal to look up.
+     *
+     * @param realm
+     * Realm name.
+     *
+     * @param nOnce
+     * Unique (or supposedly unique) token which has been used for this request.
+     *
+     * @param nc
+     * Number of query (starting from 1) with this authentication info.
+     *
+     * @param cnonce
+     * Value (usually random) chosen by the client.
+     *
+     * @param qop
+     * Quality Of Protection flag.
+     *
+     * @param method
+     * The HTTP method.
+     *
+     * @param uri
+     * The URI of the query.
+     *
+     * @return
+     * The digested value for the response field.
      */
     private String calculateResponse(final String username, final String realm, final String nOnce,
         final String nc, final String cnonce, final String qop, final String method,
@@ -407,13 +371,11 @@
         String response = null;
 
         String md5a1 = getDigestUsernameAndRealm(getAlgorithm(), username, realm);
-        // System.out.println("md5a1 = \"" + md5a1 + "\"");
         if (md5a1 == null) {
             return null;
         }
 
         String md5a2 = getDigestMethodAndUri(qop, method, uri);
-        // System.out.println("md5a2 = \"" + md5a2 + "\"");
         if (md5a2 == null) {
             return null;
         }
@@ -437,11 +399,7 @@
         sbCompleteValue.append(md5a2);
 
         String a3 = sbCompleteValue.toString();
-// System.out.println("a3 = \"" + a3 + "\"");
-        // byte[] digestBytes = MD5.digest(a3, getDigestEncoding());
-        // String md5a3 = MD5.encode(digestBytes);
         String md5a3 = MD5.digestAsString(a3, encoding);
-// System.out.println("md5a3 = \"" + md5a3 + "\"");
 
         response = md5a3;
         return response;
@@ -451,8 +409,11 @@
      * Removes the quotes on a string. RFC2617 states quotes are optional for
      * all parameters except realm.
      *
-     * @param quotedString The string with enclosing quotes
-     * @param quotesRequired If quotes are required on the previous parameter
+     * @param quotedString
+     * The string with enclosing quotes.
+     *
+     * @param quotesRequired
+     * If quotes are required on the previous parameter.
      */
     protected static String removeQuotes(final String quotedString, boolean quotesRequired) {
         // support both quoted and non-quoted
@@ -468,7 +429,8 @@
     /**
      * Removes the quotes on a string.
      *
-     * @param quotedString The string with enclosing quotes
+     * @param quotedString
+     * The string with enclosing quotes.
      */
     protected static String removeQuotes(String quotedString) {
         return removeQuotes(quotedString, false);
@@ -481,12 +443,13 @@
      * some of these info are required to construct other fields for the
      * following reply.
      *
-     * @param authorizationHeader the authorization info returned from the
-     * Server.
-     * @return a Map of key / value, both Strings
+     * @param authorizationHeader
+     * The authorization info returned from the server.
+     *
+     * @return
+     * The key/value map.
      */
     protected static Map<String, String> splitAuthenticationHeader(String authorizationHeader) {
-// System.out.println("Authorization header: " + authorizationHeader);
         Map<String, String> map = new HashMap<String, String>();
 
         // Validate the authorization credentials format
@@ -524,8 +487,6 @@
 
             String currentTokenName = currentToken.substring(0, equalSign).trim();
             String currentTokenValue = currentToken.substring(equalSign + 1).trim();
-// System.out.println("tokens[" + i + "]: currentTokenName = \"" + currentTokenName
-// + "\", currentTokenValue = \"" + currentTokenValue + "\"");
 
             if (AUTH_FIELD_KEY_USERNAME.equals(currentTokenName)) {
                 userName = removeQuotes(currentTokenValue);
@@ -557,14 +518,11 @@
                 response = removeQuotes(currentTokenValue);
                 map.put(AUTH_FIELD_KEY_RESPONSE, response);
             } else {
-// System.out.println("Unknown token name: \"" + currentTokenName + "\"");
                 map.put(currentTokenName, currentTokenValue);
             }
-
         }
 
         if ((realmName == null) || (nOnce == null)) {
-// System.out.println("One of the mandatory fields is null , returning an empty map");
             return new HashMap<String, String>();
         }
 
@@ -603,7 +561,7 @@
         } else {
             a1 = "";
         }
-// System.out.println("a1 = \"" + a1 + "\"");
+
         return MD5.digestAsString(a1, encoding);
     }
 
@@ -626,12 +584,33 @@
             a2 = ""; // dummy, to avoid NPE ...
             throw new RuntimeException("not supported qop value: \"" + qop + "\"");
         }
-// System.out.println("a2 = \"" + a2 + "\"");
 
         return MD5.digestAsString(a2, encoding);
     }
 
     /**
+     * Get this object string.
+     *
+     * @return main data in a formed string
+     */
+    @Override
+    public String toString() {
+        StringBuffer result = new StringBuffer();
+
+        result.append(this.getClass().getName());
+        result.append(HTTP_REPLY_FIELD_SEPARATOR);
+        result.append(username);
+        result.append(HTTP_REPLY_FIELD_SEPARATOR);
+        result.append(password);
+        result.append(HTTP_REPLY_FIELD_SEPARATOR);
+        result.append(algorithm);
+        result.append(HTTP_REPLY_FIELD_SEPARATOR);
+        result.append(encoding);
+
+        return result.toString();
+    }
+
+    /**
      * Digest the given string using the algorithm specified and convert the
      * result to a corresponding hex string. If exception, the plain credentials
      * string is returned
@@ -640,9 +619,8 @@
      * @param algorithm Algorithm used to do the digest
      * @param encoding Character encoding of the string to digest
      */
-    public final static String digestString(final String value, final String algorithm,
+    public static String digestString(final String value, final String algorithm,
         final String encoding) {
-
         try {
             // Obtain a new message digest with "digest" encryption
             MessageDigest md = (MessageDigest) MessageDigest.getInstance(algorithm).clone();
@@ -656,11 +634,9 @@
             }
 
             // Digest the credentials and return as hexadecimal
-            return (HexUtils.convert(md.digest()));
+            return (MD5.toHexString(md.digest()));
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
-
     }
-
 }