Coverage Report - org.kuali.maven.plugins.dnsme.DNSMEUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
DNSMEUtil
83%
51/61
100%
4/4
1.467
 
 1  
 package org.kuali.maven.plugins.dnsme;
 2  
 
 3  
 import java.io.UnsupportedEncodingException;
 4  
 import java.security.GeneralSecurityException;
 5  
 import java.text.SimpleDateFormat;
 6  
 import java.util.ArrayList;
 7  
 import java.util.Date;
 8  
 import java.util.List;
 9  
 import java.util.TimeZone;
 10  
 
 11  
 import javax.crypto.Mac;
 12  
 import javax.crypto.SecretKey;
 13  
 import javax.crypto.spec.SecretKeySpec;
 14  
 
 15  
 import org.apache.commons.httpclient.Header;
 16  
 import org.apache.commons.httpclient.HttpMethod;
 17  
 import org.apache.commons.httpclient.methods.DeleteMethod;
 18  
 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
 19  
 import org.apache.commons.httpclient.methods.GetMethod;
 20  
 import org.apache.commons.httpclient.methods.RequestEntity;
 21  
 import org.apache.commons.httpclient.methods.StringRequestEntity;
 22  
 import org.kuali.maven.plugins.dnsme.beans.Account;
 23  
 
 24  
 public class DNSMEUtil {
 25  
     // Sat, 12 Feb 2011 20:59:04 GMT
 26  
     public static final String DEFAULT_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z";
 27  
     public static final String DEFAULT_TIME_ZONE = "GMT";
 28  
     public static final String DEFAULT_ALGORITHM = "HmacSHA1";
 29  
     public static final String API_KEY_HEADER = "x-dnsme-apiKey";
 30  
     public static final String DATE_HEADER = "x-dnsme-requestDate";
 31  
     public static final String HMAC_HEADER = "x-dnsme-hmac";
 32  
     public static final int ONE_MINUTE_DELAY = 1000 * 60;
 33  
 
 34  
     String format;
 35  
     String algorithm;
 36  
     SimpleDateFormat sdf;
 37  
     TimeZone timeZone;
 38  
 
 39  
     public DNSMEUtil() {
 40  9
         super();
 41  9
         setFormat(DEFAULT_DATE_FORMAT);
 42  9
         setTimeZone(TimeZone.getTimeZone(DEFAULT_TIME_ZONE));
 43  9
         setAlgorithm(DEFAULT_ALGORITHM);
 44  9
     }
 45  
 
 46  
     public synchronized void setAlgorithm(String algorithm) {
 47  9
         this.algorithm = algorithm;
 48  9
     }
 49  
 
 50  
     public synchronized void setFormat(String format) {
 51  9
         this.format = format;
 52  9
         sdf = new SimpleDateFormat(format);
 53  9
     }
 54  
 
 55  
     public synchronized void setTimeZone(TimeZone timezone) {
 56  9
         this.timeZone = timezone;
 57  9
         sdf.setTimeZone(timezone);
 58  9
     }
 59  
 
 60  
     public synchronized String getHTTPDate(Date date) {
 61  4
         return sdf.format(date);
 62  
     }
 63  
 
 64  
     public synchronized String getHash(String key, String data) {
 65  
         try {
 66  6
             Mac mac = Mac.getInstance(algorithm);
 67  6
             SecretKey secretKey = new SecretKeySpec(key.getBytes(), algorithm);
 68  6
             mac.init(secretKey);
 69  6
             byte[] finalBytes = mac.doFinal(data.getBytes());
 70  6
             return getHexString(finalBytes);
 71  0
         } catch (GeneralSecurityException e) {
 72  0
             throw new DNSMEException(e);
 73  
         }
 74  
     }
 75  
 
 76  
     public List<Header> getAuthenticationHeaders(Account account) {
 77  
         /**
 78  
          * The geniuses at DNS Made Easy did not account for computer clocks that have drifted forward.
 79  
          *
 80  
          * The DNSME timestamp tolerance logic has 2 rules:<br>
 81  
          * 1 - All timestamp values must be less than their own internal clock<br>
 82  
          * 2 - All timestamp values must be within 5-6 minutes of their own clock.<br>
 83  
          *
 84  
          * This is pretty retarded since computer clocks outside of DNSME are just as likely to drift forwards as they
 85  
          * are backwards.<br>
 86  
          *
 87  
          * If the timestamp you supply them is ahead of their internal clocks (even by a few milliseconds) the request
 88  
          * gets denied. So, to compensate for any potential forward clock drift we subtract one minute from the current
 89  
          * timestamp of the machine we are on. This only works as long as the machine we are on is less than one minute
 90  
          * ahead of the DNSME clocks.
 91  
          *
 92  
          * It would have been much better of them to accept timestamps that are within 5 minutes (plus OR minus) of
 93  
          * their internal clocks.
 94  
          */
 95  3
         long millis = System.currentTimeMillis() - ONE_MINUTE_DELAY;
 96  3
         String requestDate = getHTTPDate(new Date(millis));
 97  3
         String hash = getHash(account.getSecretKey(), requestDate);
 98  3
         List<Header> headers = new ArrayList<Header>();
 99  3
         headers.add(new Header(API_KEY_HEADER, account.getApiKey()));
 100  3
         headers.add(new Header(DATE_HEADER, requestDate));
 101  3
         headers.add(new Header(HMAC_HEADER, hash));
 102  3
         return headers;
 103  
     }
 104  
 
 105  
     public HttpMethod getDeleteMethod(Account account, String url) {
 106  0
         HttpMethod method = new DeleteMethod(url);
 107  0
         addAuthenticationHeaders(account, method);
 108  0
         return method;
 109  
     }
 110  
 
 111  
     public void updateMethod(Account account, String json, EntityEnclosingMethod method) {
 112  
         try {
 113  1
             RequestEntity requestEntity = new StringRequestEntity(json, "application/json", "UTF-8");
 114  1
             method.setRequestEntity(requestEntity);
 115  1
             addAuthenticationHeaders(account, method);
 116  1
             Header accept = new Header("accept", "application/json");
 117  1
             Header contentType = new Header("content-type", "application/json");
 118  1
             method.addRequestHeader(accept);
 119  1
             method.addRequestHeader(contentType);
 120  0
         } catch (UnsupportedEncodingException e) {
 121  0
             throw new DNSMEException(e);
 122  1
         }
 123  1
     }
 124  
 
 125  
     public GetMethod getGetMethod(Account account, String url) {
 126  2
         GetMethod method = new GetMethod(url);
 127  2
         addAuthenticationHeaders(account, method);
 128  2
         return method;
 129  
     }
 130  
 
 131  
     protected void addAuthenticationHeaders(Account account, HttpMethod method) {
 132  3
         List<Header> headers = getAuthenticationHeaders(account);
 133  3
         for (Header header : headers) {
 134  9
             method.addRequestHeader(header);
 135  
         }
 136  3
     }
 137  
 
 138  
     public String getHexString(byte[] b) {
 139  6
         StringBuilder sb = new StringBuilder();
 140  126
         for (int i = 0; i < b.length; i++) {
 141  120
             int intValue1 = b[i] & 0xff;
 142  120
             int intValue2 = intValue1 + 0x100;
 143  120
             String s = Integer.toString(intValue2, 16);
 144  120
             String one = s.substring(1);
 145  120
             sb.append(one);
 146  
         }
 147  6
         return sb.toString();
 148  
     }
 149  
 
 150  
     public String getFormat() {
 151  0
         return format;
 152  
     }
 153  
 
 154  
     public TimeZone getTimeZone() {
 155  0
         return timeZone;
 156  
     }
 157  
 
 158  
     public String getAlgorithm() {
 159  0
         return algorithm;
 160  
     }
 161  
 
 162  
 }