diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java
index 5538f6dc26..1637ca481f 100644
--- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java
+++ b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java
@@ -71,6 +71,10 @@ public class OAuthSignatureCalculator implements SignatureCalculator {
protected final RequestToken userAuth;
+ protected final Long testTimestamp;
+
+ protected final String testNonce;
+
/**
* @param consumerAuth Consumer key to use for signature calculation
* @param userAuth Request/access token to use for signature calculation
@@ -79,14 +83,26 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth)
mac = new ThreadSafeHMAC(consumerAuth, userAuth);
this.consumerAuth = consumerAuth;
this.userAuth = userAuth;
+ this.testTimestamp = 0L;
+ this.testNonce = null;
random = new Random(System.identityHashCode(this) + System.currentTimeMillis());
}
+ OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth, Long testTimestamp, String testNonce) {
+ mac = new ThreadSafeHMAC(consumerAuth, userAuth);
+ this.consumerAuth = consumerAuth;
+ this.userAuth = userAuth;
+ this.testTimestamp = testTimestamp;
+ this.testNonce = testNonce;
+ random = new Random(System.identityHashCode(this) + System.currentTimeMillis());
+ }
+
+
//@Override // silly 1.5; doesn't allow this for interfaces
public void calculateAndAddSignature(Request request, RequestBuilderBase> requestBuilder) {
- String nonce = generateNonce();
- long timestamp = System.currentTimeMillis() / 1000L;
+ String nonce = (this.testNonce != null) ? this.testNonce : generateNonce();
+ long timestamp = (this.testTimestamp > 0L) ? this.testTimestamp : System.currentTimeMillis() / 1000L;
String signature = calculateSignature(request.getMethod(), request.getUri(), timestamp, nonce, request.getFormParams(), request.getQueryParams());
String headerValue = constructAuthHeader(signature, nonce, timestamp);
requestBuilder.setHeader(HEADER_AUTHORIZATION, headerValue);
diff --git a/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java b/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java
index b3c696dc40..300922602d 100644
--- a/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java
+++ b/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java
@@ -16,14 +16,30 @@
package org.asynchttpclient.oauth;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.asynchttpclient.FluentCaseInsensitiveStringsMap;
import org.asynchttpclient.Param;
+import org.asynchttpclient.Request;
+import org.asynchttpclient.RequestBuilder;
import org.asynchttpclient.uri.Uri;
import org.testng.annotations.Test;
+/**
+ * Tests the OAuth signature behavior.
+ *
+ * See Signature Tester for an
+ * online oauth signature checker.
+ *
+ */
public class TestSignatureCalculator {
private static final String CONSUMER_KEY = "dpf43f3p2l4k3l03";
@@ -40,7 +56,7 @@ public class TestSignatureCalculator {
// based on the reference test case from
// http://oauth.pbwiki.com/TestCases
@Test(groups = "fast")
- public void test() {
+ public void testGetCalculateSignature() {
ConsumerKey consumer = new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET);
RequestToken user = new RequestToken(TOKEN_KEY, TOKEN_SECRET);
OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, user);
@@ -52,4 +68,80 @@ public void test() {
assertEquals(sig, "tR3+Ty81lMeYAr/Fid0kMTYa/WM=");
}
+
+ @Test(groups = "fast")
+ public void testPostCalculateSignature() {
+ ConsumerKey consumer = new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET);
+ RequestToken user = new RequestToken(TOKEN_KEY, TOKEN_SECRET);
+ OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, user, TIMESTAMP, NONCE);
+
+ List formParams = new ArrayList();
+ formParams.add(new Param("file", "vacation.jpg"));
+ formParams.add(new Param("size", "original"));
+ String url = "http://photos.example.net/photos";
+ final Request req = new RequestBuilder("POST")
+ .setUri(Uri.create(url))
+ .setFormParams(formParams)
+ .setSignatureCalculator(calc).build();
+
+ // From the signature tester, POST should look like:
+ // normalized parameters: file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original
+ // signature base string: POST&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal
+ // signature: wPkvxykrw+BTdCcGqKr+3I+PsiM=
+ // header: OAuth realm="",oauth_version="1.0",oauth_consumer_key="dpf43f3p2l4k3l03",oauth_token="nnch734d00sl2jdk",oauth_timestamp="1191242096",oauth_nonce="kllo9940pd9333jh",oauth_signature_method="HMAC-SHA1",oauth_signature="wPkvxykrw%2BBTdCcGqKr%2B3I%2BPsiM%3D"
+
+ String authHeader = req.getHeaders().get("Authorization").get(0);
+ Matcher m = Pattern.compile("oauth_signature=\"(.+?)\"").matcher(authHeader);
+ assertEquals(m.find(), true);
+ String encodedSig = m.group(1);
+ String sig = null;
+ try {
+ sig = URLDecoder.decode(encodedSig, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ fail("bad encoding", e);
+ }
+
+ assertEquals(sig, "wPkvxykrw+BTdCcGqKr+3I+PsiM=");
+ }
+
+ @Test(groups = "fast")
+ public void testGetWithRequestBuilder() {
+ ConsumerKey consumer = new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET);
+ RequestToken user = new RequestToken(TOKEN_KEY, TOKEN_SECRET);
+ OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, user, TIMESTAMP, NONCE);
+
+ List queryParams = new ArrayList();
+ queryParams.add(new Param("file", "vacation.jpg"));
+ queryParams.add(new Param("size", "original"));
+ String url = "http://photos.example.net/photos";
+
+ final Request req = new RequestBuilder("GET")
+ .setUri(Uri.create(url))
+ .setQueryParams(queryParams)
+ .setSignatureCalculator(calc).build();
+
+ final List params = req.getQueryParams();
+ assertEquals(params.size(), 2);
+
+ // From the signature tester, the URL should look like:
+ //normalized parameters: file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original
+ //signature base string: GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal
+ //signature: tR3+Ty81lMeYAr/Fid0kMTYa/WM=
+ //Authorization header: OAuth realm="",oauth_version="1.0",oauth_consumer_key="dpf43f3p2l4k3l03",oauth_token="nnch734d00sl2jdk",oauth_timestamp="1191242096",oauth_nonce="kllo9940pd9333jh",oauth_signature_method="HMAC-SHA1",oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D"
+
+ String authHeader = req.getHeaders().get("Authorization").get(0);
+ Matcher m = Pattern.compile("oauth_signature=\"(.+?)\"").matcher(authHeader);
+ assertEquals(m.find(), true);
+ String encodedSig = m.group(1);
+ String sig = null;
+ try {
+ sig = URLDecoder.decode(encodedSig, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ fail("bad encoding", e);
+ }
+
+ assertEquals(sig, "tR3+Ty81lMeYAr/Fid0kMTYa/WM=");
+
+ }
+
}