Author: scottbw
Date: Tue Feb 18 20:19:13 2014
New Revision: 1569518

URL: http://svn.apache.org/r1569518
Log:
Created a HMAC authorization provider for Wookie REST APIs (see WOOKIE-279, and 
linked discussion with Tien). This will be used in place of "plaintext" API 
keys in Wookie 2.x

Added:
    
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/Hmac.java
    
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/NonceCache.java
    
wookie/trunk/wookie-server/src/test/java/org/apache/wookie/tests/server/security/HmacTest.java

Added: 
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/Hmac.java
URL: 
http://svn.apache.org/viewvc/wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/Hmac.java?rev=1569518&view=auto
==============================================================================
--- 
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/Hmac.java
 (added)
+++ 
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/Hmac.java
 Tue Feb 18 20:19:13 2014
@@ -0,0 +1,293 @@
+/*
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ */
+package org.apache.wookie.server.security;
+
+import java.security.SignatureException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * Utilities for creating and validating HMAC authentication for REST API calls
+ * 
+ * We are using a HMAC scheme very similar to that used by Amazon Web Services.
+ * The canonical form for each request is computed from the HTTP verb, host, 
URI
+ * and an alpha-sorted array of parameters, including a timestamp and a nonce. 
+ * 
+ * This canonical string is then signed with the shared secret for the 
application 
+ * using HMAC-SHA256. 
+ * 
+ * The signature is placed in the Authorization header of the request, 
preceded by 
+ * the public key of the requesting application (the "API key" used in 
previous APIs)
+ * 
+ */
+public class Hmac {
+       
+       /**
+        * Date formatter for ISO datetime
+        */
+       private static DateFormat dateFormat = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"){ 
+               private static final long serialVersionUID = 
7465240007718011363L;
+               public Date parse(String source,ParsePosition pos) {    
+               return 
super.parse(source.replaceFirst(":(?=[0-9]{2}$)",""),pos);
+           }
+       };
+
+       /**
+        * The hashing algorithm to use
+        */
+       private static final String HMAC_ALGORITHM = "HmacSHA256";
+       
+       /**
+        * The amount of clock skew we allow for requests - if the timestamp on 
a 
+        * request is older than this, we reject it
+        */
+       private static final long CLOCK_SKEW_ALLOWANCE = 180000L; // allow 
three minutes for clock skew
+       
+       /**
+        * Gets the public key associated with the request
+        * @param request
+        * @return the public key or null if there is no key
+        */
+       public static String getPublicKey(HttpServletRequest request){
+               String header = request.getHeader("Authorization");
+               if (header == null || header.trim().length() == 0 || 
header.split(" ").length != 2) return null;
+               return header.split(" ")[0];
+       }
+       
+       /**
+        * Gets the signature associated with the request
+        * @param request
+        * @return the signture or null if there is no key
+        */
+       public static String getSignature(HttpServletRequest request){
+               String header = request.getHeader("Authorization");
+               if (header == null || header.trim().length() == 0 || 
header.split(" ").length != 2) return null;
+               return header.split(" ")[1];
+       }
+       
+       /**
+        * Validates a signed request
+        */
+       public static boolean isValidSignedRequest(HttpServletRequest request){
+               
+               //
+               // Get the header
+               //
+               String auth = request.getHeader("Authorization");
+               
+               //
+               // If no auth header, not valid.
+               //
+               if (auth == null) return false;
+               
+               //
+               // Split the header into the api key and signature
+               // If either part is missing, or there are additional
+               // parts, the request is not valid.
+               //
+               String apiKey = getPublicKey(request);
+               String signature = getSignature(request);
+               if (apiKey == null || signature == null) return false;
+               
+               //
+               // Validate the api public key exists
+               //
+               if (!ApiKeys.getInstance().validate(apiKey)) return false;
+               
+               //
+               // Get the API key secret
+               //
+               String secret = 
ApiKeys.getInstance().getApiKey(apiKey).getEmail();
+               
+               //
+               // Check the timestamp. If no timestamp is
+               // provided, the request is not valid
+               //
+               String timestamp = request.getParameter("timestamp");
+               if (timestamp == null) return false;
+
+               //
+               // Parse the timestamp. If its not a valid
+               // datetime, the request is not valid
+               //
+               Date timestampDate = null;
+               try {
+                       timestampDate = dateFormat.parse(timestamp);
+               } catch (ParseException e1) {
+                       return false;
+               }
+               
+               //
+               // Compute the window of validity for the timestamp,
+               // equivalent to now minus an allowance for clock
+               // skew
+               //
+               long now = System.currentTimeMillis();
+               long window = now - CLOCK_SKEW_ALLOWANCE;
+               
+               //
+               // Check that the timestamp provided falls within the
+               // allowed range. This is to prevent replay attacks
+               //
+               if ((timestampDate.getTime()) < window){
+                       return false;
+               }
+               
+               //
+               // Get the nonce used. If there is no nonce, the
+               // request is not valid
+               //
+               String nonce = request.getParameter("nonce");
+               if (nonce == null || nonce.trim().length() == 0) return false;
+               
+               //
+               // Check the nonce hasn't been reused lately
+               //
+               if (!NonceCache.getInstance().isValid(nonce)) return false;
+               
+               //
+               // Get the canonical request string to validate
+               //
+               String canonicalRequest = toCanonicalForm(request);
+
+               //
+               // Calculate the signature that should have been used
+               //
+               String correctSignature = null;
+               try {
+                       correctSignature = getHmac(canonicalRequest, secret);
+               } catch (SignatureException e) {
+                       return false;
+               }
+               
+               //
+               // Compare the signature hashes. If they match
+               // then the request is valid
+               //
+               if (correctSignature.equals(signature)){
+                       return true;
+               } else {
+                       return false;
+               }
+               
+       }
+       
+       /**
+        * Converts a Java Date object to an ISO-formatted date string
+        * @param date
+        * @return the ISO string
+        */
+       public static String getFormattedDate(Date date){
+               return dateFormat.format(date); 
+       }
+
+       /**
+        * Converts a HTTP request into its canonical form used for signing
+        */
+       private static String toCanonicalForm(HttpServletRequest request){      
        
+               return getCanonicalRequest(request.getMethod(), 
request.getHeader("Host"), request.getRequestURI(), 
getCanonicalParameters(request.getParameterMap()));
+       }       
+       
+       /**
+        * Gets a canonical request to sign
+        * @param verb  the HTTP verb, e.g. POST
+        * @param host  the host, e.g. wookie.apache.org
+        * @param uri   the URI, e.g. /wookie
+        * @param query the canonical parameters for the request - see 
getCanonicalParameters
+        * @return the canonical string representation of the request
+        */
+       public static String getCanonicalRequest(String verb, String host, 
String uri, String query){
+               String canonical = "";
+               verb = verb.toUpperCase();
+               host = host.toLowerCase();
+               uri = uri.toLowerCase();
+               query = query.toLowerCase();
+               canonical = verb + "\n" + host + "\n" + uri + "\n" + query;
+               return canonical;
+       }
+       
+       /**
+        * Sorts parameters and returns a querystring in canonical form usable 
for signing
+        * @param parameterMap
+        * @return a String with all parameters sorted and represented correctly
+        */
+       public static String 
getCanonicalParameters(@SuppressWarnings("rawtypes") Map parameterMap){
+               String query = "?";
+               ArrayList<String> parameterNames = new ArrayList<String>();
+               @SuppressWarnings("rawtypes")
+               Iterator it = parameterMap.keySet().iterator();
+               while (it.hasNext()) parameterNames.add((String) it.next());
+               Collections.sort(parameterNames);
+               for (String name:parameterNames){
+                       if (!query.equals("?")) query += "&";
+                       Object value = parameterMap.get(name);
+                       if (value instanceof String[]){
+                               query += name.toLowerCase() + "=" + 
((String[])value)[0].toLowerCase();
+                       } else {
+                               query += name.toLowerCase() 
+"="+((String)value).toLowerCase();                 
+                       }
+
+               }
+               return query;
+       }
+
+
+       /**
+        * Computes a HMAC signature.
+        * @param data The data to be signed.
+        * @param key The signing key.
+        * @return The HMAC signature.
+        * @throws java.security.SignatureException when signature generation 
fails
+        */
+       public static String getHmac(String data, String key)
+       throws java.security.SignatureException
+       {
+               String hmac64;
+               try {
+
+                       // get an hmac_sha1 key from the raw key bytes
+                       SecretKeySpec signingKey = new 
SecretKeySpec(key.getBytes(), HMAC_ALGORITHM);
+
+                       // get an hmac_sha1 Mac instance and initialize with 
the signing key
+                       Mac mac = Mac.getInstance(HMAC_ALGORITHM);
+                       mac.init(signingKey);
+
+                       // compute the hmac on input data bytes
+                       byte[] hmac = mac.doFinal(data.getBytes());
+
+                       // base64-encode the hmac
+                       hmac64 = Base64.encodeBase64String(hmac);
+
+               } catch (Exception e) {
+                       throw new SignatureException("Failed to generate HMAC : 
" + e.getMessage());
+               }
+               return hmac64;
+       }
+       
+}

Added: 
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/NonceCache.java
URL: 
http://svn.apache.org/viewvc/wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/NonceCache.java?rev=1569518&view=auto
==============================================================================
--- 
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/NonceCache.java
 (added)
+++ 
wookie/trunk/wookie-server/src/main/java/org/apache/wookie/server/security/NonceCache.java
 Tue Feb 18 20:19:13 2014
@@ -0,0 +1,85 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ */
+package org.apache.wookie.server.security;
+
+import java.util.LinkedList;
+
+/**
+ * A simple cache for nonces so we can guard against
+ * replay attacks reusing nonces.
+ */
+public class NonceCache {
+       
+       /**
+        * The singleton instance
+        */
+       private static NonceCache instance;
+       
+       /**
+        * The cache, a simple linked list
+        */
+       private LinkedList<String> cache;
+       
+       /**
+        * The number of nonces to hold in the cache
+        */
+       private static final int CACHE_SIZE = 100;
+       
+       /**
+        * Private constructor for singleton
+        */
+       private NonceCache(){
+               cache = new LinkedList<String>();
+       }
+       
+       /**
+        * Get single instance
+        * @return the NonceCache
+        */
+       public static NonceCache getInstance(){
+               if (instance == null) instance = new NonceCache();
+               return instance;
+       }
+       
+       /**
+        * Checks whether a nonce is valid - whether it
+        * has been recently used.
+        * @param nonce
+        * @return true if the nonce is valid, false if it is recycled
+        */
+       public boolean isValid(String nonce){
+               
+               //
+               // Has it been used?
+               //
+               if (cache.contains(nonce)) return false;
+               
+               //
+               // If not, add it to the end of the cache
+               //
+               cache.addLast(nonce);
+               
+               //
+               // If the cache has grown to its max size, pop
+               // off the first nonce
+               //
+               if (cache.size() > CACHE_SIZE) cache.removeFirst();
+               return true;
+       }
+       
+       
+
+}

Added: 
wookie/trunk/wookie-server/src/test/java/org/apache/wookie/tests/server/security/HmacTest.java
URL: 
http://svn.apache.org/viewvc/wookie/trunk/wookie-server/src/test/java/org/apache/wookie/tests/server/security/HmacTest.java?rev=1569518&view=auto
==============================================================================
--- 
wookie/trunk/wookie-server/src/test/java/org/apache/wookie/tests/server/security/HmacTest.java
 (added)
+++ 
wookie/trunk/wookie-server/src/test/java/org/apache/wookie/tests/server/security/HmacTest.java
 Tue Feb 18 20:19:13 2014
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.tests.server.security;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.security.SignatureException;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.wookie.server.security.Hmac;
+import org.apache.wookie.tests.helpers.MockHttpServletRequest;
+import org.apache.wookie.w3c.util.RandomGUID;
+import org.junit.Test;
+
+public class HmacTest {
+
+       @Test
+       public void basicSignedRequest() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(System.currentTimeMillis())));
+               request.addParameter("nonce", new RandomGUID().toString());
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertTrue(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestWithMultipleParameters() throws 
SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "one two".split(" "));
+               request.addParameter("nonce", new RandomGUID().toString());
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(System.currentTimeMillis())));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertTrue(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void basicSignedRequestWithCasing() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "WOOKIE.APACHE.org");
+               request.setRequestURI("/");
+               request.setMethod("PoST");
+               request.addParameter("TEST", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(System.currentTimeMillis())));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertTrue(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestWithNoTimestamp() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRestPostRequest() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/http://notsupported";);
+               request.setMethod("POST");
+               request.addParameter("nonce", new RandomGUID().toString());
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(System.currentTimeMillis())));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", request.getRequestURI(), query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertTrue(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestTwoMinutesOld() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/http://notsupported";);
+               request.setMethod("POST");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = Calendar.getInstance().getTimeInMillis()-120000L; 
// set to 2 mins ago
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", request.getRequestURI(), query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertTrue(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestOneHourOld() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis()-3600000L; // set to one 
hour ago
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       // Set authz header with signature but no key
+       @Test
+       public void signedRequestWithNoApiKey() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       // Set authz header with extra info
+       @Test
+       public void signedRequestWithExtraInfo() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature+" 
EXTRASTUFF");
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       // Set authz header with key but no signaure    
+       @Test
+       public void unsignedRequestWithApiKey() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               request.addHeader("Authorization", "TEST");
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       // Set authz header with key but no signaure
+       @Test
+       public void unsignedRequestEmptyHeader() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               request.addHeader("Authorization", "");
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       // Wrong secret for key used to sign request
+       @Test
+       public void signedRequestSignedWithBadSecret() throws 
SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "wrongkey");
+               request.addHeader("Authorization", "TEST "+ signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestSignedWithBadSignature() throws 
SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+ signature+"9");
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestSignedWithBadApiKey() throws 
SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "BANANA "+ signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestWithBadTimeStamp() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               request.addParameter("timestamp", "99999999999999");
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+ signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void unsignedRequest() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", new RandomGUID().toString());
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestWithNoNonce() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+ signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+       @Test
+       public void signedRequestWithReusedNonce() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", "banana");
+               long time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+ signature);
+               assertTrue(Hmac.isValidSignedRequest(request));
+               
+               request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("nonce", "banana");
+               time = System.currentTimeMillis();
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(time)));
+               query = Hmac.getCanonicalParameters(request.getParameterMap());
+               reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+ signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+
+       @Test
+       public void signedRequestEmptyNonce() throws SignatureException{
+               MockHttpServletRequest request = new MockHttpServletRequest();
+               request.addHeader("Host", "wookie.apache.org");
+               request.setRequestURI("/");
+               request.setMethod("POST");
+               request.addParameter("test", "test-value");
+               request.addParameter("timestamp", Hmac.getFormattedDate(new 
Date(System.currentTimeMillis())));
+               request.addParameter("nonce", "  ");
+               String query = 
Hmac.getCanonicalParameters(request.getParameterMap());
+               String reqString = Hmac.getCanonicalRequest("POST", 
"wookie.apache.org", "/", query);
+               String signature = Hmac.getHmac(reqString, "[email protected]");
+               request.addHeader("Authorization", "TEST "+signature);
+               assertFalse(Hmac.isValidSignedRequest(request));
+       }
+       
+}


Reply via email to