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);
}
-
}
-
}