View Javadoc

1   package com.bradmcevoy.http.http11.auth;
2   
3   import org.apache.commons.codec.digest.DigestUtils;
4   import org.slf4j.Logger;
5   import org.slf4j.LoggerFactory;
6   
7   /**
8    *
9    * @author brad
10   */
11  public class DigestGenerator {
12  
13      private static final Logger log = LoggerFactory.getLogger( DigestGenerator.class );
14  
15      /**
16       * Computes the <code>response</code> portion of a Digest authentication header. Both the server and user
17       * agent should compute the <code>response</code> independently. Provided as a static method to simplify the
18       * coding of user agents.
19       *
20       * @param dr - the auth request from the client
21       * @param password - plain text unencoded password
22       * @return the MD5 of the digest authentication response, encoded in hex
23       * @throws IllegalArgumentException if the supplied qop value is unsupported.
24       */
25      public String generateDigest( DigestResponse dr, String password ) throws IllegalArgumentException {
26          log.debug( "user:" + dr.getUser() + ":realm:" + dr.getRealm() + ":" + password );
27          String p = password == null ? "" : password;
28          String a1Md5 = encodePasswordInA1Format( dr.getUser(), dr.getRealm(), p );
29          return generateDigestWithEncryptedPassword( dr, a1Md5 );
30      }
31  
32      /**
33       * Use this method if you are persisting a one way hash of the user name, password
34       * and realm (referred to as a1md5 in the spec)
35       *
36       * @param dr
37       * @param a1Md5
38       * @return
39       * @throws IllegalArgumentException
40       */
41      public String generateDigestWithEncryptedPassword( DigestResponse dr, String a1Md5 ) throws IllegalArgumentException {
42          String httpMethod = dr.getMethod().code;
43          String a2Md5 = encodeMethodAndUri( httpMethod, dr.getUri() );
44  
45          String qop = dr.getQop();
46          String nonce = dr.getNonce();
47  
48          //String digest;
49          if( qop == null ) {
50              // as per RFC 2069 compliant clients (also reaffirmed by RFC 2617)
51              //digest = a1Md5 + ":" + dr.getNonce() + ":" + a2Md5;
52              return md5( a1Md5, dr.getNonce(), a2Md5 );
53          } else if( "auth".equals( qop ) ) {
54              // As per RFC 2617 compliant clients
55              return md5( a1Md5, nonce, dr.getNc(), dr.getCnonce(), dr.getQop(), a2Md5 );
56              //digest = a1Md5 + ":" + nonce + ":" + dr.getNc() + ":" + dr.getCnonce() + ":" + qop + ":" + a2Md5;
57          } else {
58              throw new IllegalArgumentException( "This method does not support a qop '" + qop + "'" );
59          }
60      }
61  
62      public String encodePasswordInA1Format( String username, String realm, String password ) {
63          String a1 = username + ":" + realm + ":" + password;
64          String a1Md5 = new String( DigestUtils.md5Hex( a1 ) );
65  
66          return a1Md5;
67      }
68  
69      String encodeMethodAndUri( String httpMethod, String uri ) {
70          String a2 = httpMethod + ":" + uri;
71          String a2Md5 = new String( DigestUtils.md5Hex( a2 ) );
72          return a2Md5;
73      }
74  
75      String md5( String... ss ) {
76          String d = "";
77          for( int i = 0; i < ss.length; i++ ) {
78              if( i > 0 ) d += ":";
79              d = d + ss[i];
80          }
81          return new String( DigestUtils.md5Hex( d ) );
82      }
83  }