Java tutorial
/* * Copyright 2011-2018 GatlingCorp (https://gatling.io) * * 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 io.gatling.http.client.ahc.oauth; import io.gatling.http.client.Param; import io.gatling.http.client.Request; import io.gatling.http.client.RequestBuilder; import io.gatling.http.client.ahc.uri.Uri; import io.gatling.http.client.body.form.FormUrlEncodedRequestBody; import io.gatling.http.client.body.form.FormUrlEncodedRequestBodyBuilder; import io.gatling.http.client.sign.OAuthSignatureCalculator; import io.gatling.netty.util.ahc.Utf8UrlEncoder; import io.netty.handler.codec.http.HttpMethod; import org.junit.jupiter.api.Test; import java.net.URLDecoder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import static io.netty.handler.codec.http.HttpHeaderNames.AUTHORIZATION; import static org.junit.jupiter.api.Assertions.*; /** * Tests the OAuth signature behavior. * <p> * See <a href= "https://oauth.googlecode.com/svn/code/javascript/example/signature.html" >Signature Tester</a> for an online oauth signature checker. */ class OAuthSignatureCalculatorTest { private static final String TOKEN_KEY = "nnch734d00sl2jdk"; private static final String TOKEN_SECRET = "pfkkdhi9sl3r4s00"; private static final String NONCE = "kllo9940pd9333jh"; private static final long TIMESTAMP = 1191242096; private static final String CONSUMER_KEY = "dpf43f3p2l4k3l03"; private static final String CONSUMER_SECRET = "kd94hf93k423kf44"; // sample from RFC https://tools.ietf.org/html/rfc5849#section-3.4.1 private void testSignatureBaseString(Request request) throws NoSuchAlgorithmException { String signatureBaseString = new OAuthSignatureCalculatorInstance().signatureBaseString(// new ConsumerKey("9djdj82h48djs9d2", CONSUMER_SECRET), new RequestToken("kkk9d7dh3k39sjv7", TOKEN_SECRET), request.getMethod(), request.getUri(), request.getBody() instanceof FormUrlEncodedRequestBody ? ((FormUrlEncodedRequestBody) request.getBody()).getContent() : null, 137131201, "7d8f3e4a").toString(); assertEquals("POST&" + "http%3A%2F%2Fexample.com%2Frequest" + "&a2%3Dr%2520b%26" + "a3%3D2%2520q%26" + "a3%3Da%26" + "b5%3D%253D%25253D%26" + "c%2540%3D%26" + "c2%3D%26" + "oauth_consumer_key%3D9djdj82h48djs9d2%26" + "oauth_nonce%3D7d8f3e4a%26" + "oauth_signature_method%3DHMAC-SHA1%26" + "oauth_timestamp%3D137131201%26" + "oauth_token%3Dkkk9d7dh3k39sjv7%26" + "oauth_version%3D1.0", signatureBaseString); } // fork above test with an OAuth token that requires encoding private void testSignatureBaseStringWithEncodableOAuthToken(Request request) throws NoSuchAlgorithmException { String signatureBaseString = new OAuthSignatureCalculatorInstance().signatureBaseString(// new ConsumerKey("9djdj82h48djs9d2", CONSUMER_SECRET), new RequestToken("kkk9d7dh3k39sjv7", TOKEN_SECRET), request.getMethod(), request.getUri(), request.getBody() instanceof FormUrlEncodedRequestBody ? ((FormUrlEncodedRequestBody) request.getBody()).getContent() : null, 137131201, Utf8UrlEncoder.percentEncodeQueryElement("ZLc92RAkooZcIO/0cctl0Q==")).toString(); assertEquals("POST&" + "http%3A%2F%2Fexample.com%2Frequest" + "&a2%3Dr%2520b%26" + "a3%3D2%2520q%26" + "a3%3Da%26" + "b5%3D%253D%25253D%26" + "c%2540%3D%26" + "c2%3D%26" + "oauth_consumer_key%3D9djdj82h48djs9d2%26" + "oauth_nonce%3DZLc92RAkooZcIO%252F0cctl0Q%253D%253D%26" + "oauth_signature_method%3DHMAC-SHA1%26" + "oauth_timestamp%3D137131201%26" + "oauth_token%3Dkkk9d7dh3k39sjv7%26" + "oauth_version%3D1.0", signatureBaseString); } @Test void testSignatureBaseStringWithProperlyEncodedUri() throws NoSuchAlgorithmException { List<Param> formParams = new ArrayList<>(); formParams.add(new Param("c2", "")); formParams.add(new Param("a3", "2 q")); Request request = new RequestBuilder(HttpMethod.POST, Uri.create("http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b")) .setBodyBuilder(new FormUrlEncodedRequestBodyBuilder(formParams)).build(); testSignatureBaseString(request); testSignatureBaseStringWithEncodableOAuthToken(request); } @Test void testSignatureBaseStringWithRawUri() throws NoSuchAlgorithmException { // note: @ is legal so don't decode it into %40 because it won't be // encoded back // note: we don't know how to fix a = that should have been encoded as // %3D but who would be stupid enough to do that? List<Param> formParams = new ArrayList<>(); formParams.add(new Param("c2", "")); formParams.add(new Param("a3", "2 q")); Request request = new RequestBuilder(HttpMethod.POST, Uri.create("http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r b")) .setBodyBuilder(new FormUrlEncodedRequestBodyBuilder(formParams)).build(); testSignatureBaseString(request); testSignatureBaseStringWithEncodableOAuthToken(request); } // based on the reference test case from // http://oauth.pbwiki.com/TestCases @Test void testGetCalculateSignature() throws NoSuchAlgorithmException, InvalidKeyException { List<Param> queryParams = new ArrayList<>(); queryParams.add(new Param("file", "vacation.jpg")); queryParams.add(new Param("size", "original")); Request request = new RequestBuilder(HttpMethod.GET, Uri.create("http://photos.example.net/photos")) .setQueryParams(queryParams).build(); String signature = new OAuthSignatureCalculatorInstance().computeSignature( new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET), new RequestToken(TOKEN_KEY, TOKEN_SECRET), request.getMethod(), request.getUri(), null, TIMESTAMP, NONCE); assertEquals("tR3+Ty81lMeYAr/Fid0kMTYa/WM=", signature); } @Test void testPostCalculateSignature() throws Exception { StaticOAuthSignatureCalculator calc = // new StaticOAuthSignatureCalculator(// new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET), new RequestToken(TOKEN_KEY, TOKEN_SECRET), NONCE, TIMESTAMP); List<Param> postParams = new ArrayList<>(); postParams.add(new Param("file", "vacation.jpg")); postParams.add(new Param("size", "original")); final Request req = new RequestBuilder(HttpMethod.POST, Uri.create("http://photos.example.net/photos")) .setBodyBuilder(new FormUrlEncodedRequestBodyBuilder(postParams)).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" calc.sign(req); String authHeader = req.getHeaders().get(AUTHORIZATION); Matcher m = Pattern.compile("oauth_signature=\"(.+?)\"").matcher(authHeader); assertTrue(m.find()); String encodedSig = m.group(1); String sig = URLDecoder.decode(encodedSig, "UTF-8"); assertEquals("wPkvxykrw+BTdCcGqKr+3I+PsiM=", sig); } @Test void testGetWithRequestBuilder() throws Exception { StaticOAuthSignatureCalculator calc = new StaticOAuthSignatureCalculator( new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET), new RequestToken(TOKEN_KEY, TOKEN_SECRET), NONCE, TIMESTAMP); List<Param> queryParams = new ArrayList<>(); queryParams.add(new Param("file", "vacation.jpg")); queryParams.add(new Param("size", "original")); final Request req = new RequestBuilder(HttpMethod.GET, Uri.create("http://photos.example.net/photos")) .setQueryParams(queryParams).build(); final List<Param> params = req.getUri().getEncodedQueryParams(); assertEquals(2, params.size()); // 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" calc.sign(req); String authHeader = req.getHeaders().get(AUTHORIZATION); Matcher m = Pattern.compile("oauth_signature=\"(.+?)\"").matcher(authHeader); assertTrue(m.find()); String encodedSig = m.group(1); String sig = URLDecoder.decode(encodedSig, "UTF-8"); assertEquals("tR3+Ty81lMeYAr/Fid0kMTYa/WM=", sig); assertEquals("http://photos.example.net/photos?file=vacation.jpg&size=original", req.getUri().toUrl()); } @Test void testGetWithRequestBuilderAndQuery() throws Exception { StaticOAuthSignatureCalculator calc = // new StaticOAuthSignatureCalculator(// new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET), new RequestToken(TOKEN_KEY, TOKEN_SECRET), NONCE, TIMESTAMP); final Request req = new RequestBuilder(HttpMethod.GET, Uri.create("http://photos.example.net/photos?file=vacation.jpg&size=original")).build(); final List<Param> params = req.getUri().getEncodedQueryParams(); assertEquals(2, params.size()); // 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" calc.sign(req); String authHeader = req.getHeaders().get(AUTHORIZATION); Matcher m = Pattern.compile("oauth_signature=\"(.+?)\"").matcher(authHeader); assertTrue(m.find()); String encodedSig = m.group(1); String sig = URLDecoder.decode(encodedSig, "UTF-8"); assertEquals("tR3+Ty81lMeYAr/Fid0kMTYa/WM=", sig); assertEquals("http://photos.example.net/photos?file=vacation.jpg&size=original", req.getUri().toUrl()); assertEquals( "OAuth oauth_consumer_key=\"dpf43f3p2l4k3l03\", oauth_token=\"nnch734d00sl2jdk\", oauth_signature_method=\"HMAC-SHA1\", oauth_signature=\"tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D\", oauth_timestamp=\"1191242096\", oauth_nonce=\"kllo9940pd9333jh\", oauth_version=\"1.0\"", authHeader); } @Test void testWithNullRequestToken() throws NoSuchAlgorithmException { final Request request = new RequestBuilder(HttpMethod.GET, Uri.create("http://photos.example.net/photos?file=vacation.jpg&size=original")).build(); String signatureBaseString = new OAuthSignatureCalculatorInstance().signatureBaseString(// new ConsumerKey("9djdj82h48djs9d2", CONSUMER_SECRET), new RequestToken(null, null), request.getMethod(), request.getUri(), null, 137131201, Utf8UrlEncoder.percentEncodeQueryElement("ZLc92RAkooZcIO/0cctl0Q==")).toString(); assertEquals("GET&" + "http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26" + "oauth_consumer_key%3D9djdj82h48djs9d2%26" + "oauth_nonce%3DZLc92RAkooZcIO%252F0cctl0Q%253D%253D%26" + "oauth_signature_method%3DHMAC-SHA1%26" + "oauth_timestamp%3D137131201%26" + "oauth_version%3D1.0%26size%3Doriginal", signatureBaseString); } @Test void testWithStarQueryParameterValue() throws NoSuchAlgorithmException { final Request request = new RequestBuilder(HttpMethod.GET, Uri.create("http://term.ie/oauth/example/request_token.php?testvalue=*")).build(); String signatureBaseString = new OAuthSignatureCalculatorInstance() .signatureBaseString(new ConsumerKey("key", "secret"), new RequestToken(null, null), request.getMethod(), request.getUri(), null, 1469019732, "6ad17f97334700f3ec2df0631d5b7511") .toString(); assertEquals("GET&" + "http%3A%2F%2Fterm.ie%2Foauth%2Fexample%2Frequest_token.php&" + "oauth_consumer_key%3Dkey%26" + "oauth_nonce%3D6ad17f97334700f3ec2df0631d5b7511%26" + "oauth_signature_method%3DHMAC-SHA1%26" + "oauth_timestamp%3D1469019732%26" + "oauth_version%3D1.0%26" + "testvalue%3D%252A", signatureBaseString); } @Test void testSignatureGenerationWithAsteriskInPath() throws InvalidKeyException, NoSuchAlgorithmException { ConsumerKey consumerKey = new ConsumerKey("key", "secret"); RequestToken requestToken = new RequestToken(null, null); String nonce = "6ad17f97334700f3ec2df0631d5b7511"; long timestamp = 1469019732; final Request request = new RequestBuilder(HttpMethod.GET, Uri.create("http://example.com/oauth/example/*path/wi*th/asterisks*")).build(); String actualSignature = new OAuthSignatureCalculatorInstance().computeSignature(consumerKey, requestToken, request.getMethod(), request.getUri(), null, timestamp, nonce); assertEquals("cswi/v3ZqhVkTyy5MGqW841BxDA=", actualSignature); String generatedAuthHeader = new OAuthSignatureCalculatorInstance().computeAuthorizationHeader(consumerKey, requestToken, actualSignature, timestamp, nonce); assertTrue(generatedAuthHeader.contains("oauth_signature=\"cswi%2Fv3ZqhVkTyy5MGqW841BxDA%3D\"")); } @Test void testPercentEncodeKeyValues() throws Exception { // see https://github.com/AsyncHttpClient/async-http-client/issues/1415 String keyValue = "\u3b05\u000c\u375b"; ConsumerKey consumer = new ConsumerKey(keyValue, "secret"); RequestToken reqToken = new RequestToken(keyValue, "secret"); OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, reqToken); Request request = new RequestBuilder(HttpMethod.GET, Uri.create( "https://api.dropbox.com/1/oauth/access_token?oauth_token=%EC%AD%AE%E3%AC%82%EC%BE%B8%E7%9C%9A%E8%BD%BD%E1%94%A5%E8%AD%AF%E8%98%93%E0%B9%99%E5%9E%96%EF%92%A2%EA%BC%97%EA%90%B0%E4%8A%91%E8%97%BF%EF%A8%BB%E5%B5%B1%DA%98%E2%90%87%E2%96%96%EE%B5%B5%E7%B9%AD%E9%AD%87%E3%BE%93%E5%AF%92%EE%BC%8F%E3%A0%B2%E8%A9%AB%E1%8B%97%EC%BF%80%EA%8F%AE%ED%87%B0%E5%97%B7%E9%97%BF%E8%BF%87%E6%81%A3%E5%BB%A1%EC%86%92%E8%92%81%E2%B9%94%EB%B6%86%E9%AE%8A%E6%94%B0%EE%AC%B5%E6%A0%99%EB%8B%AD%EB%BA%81%E7%89%9F%E5%B3%B7%EA%9D%B7%EC%A4%9C%E0%BC%BA%EB%BB%B9%ED%84%A9%E8%A5%B9%E8%AF%A0%E3%AC%85%0C%E3%9D%9B%E8%B9%8B%E6%BF%8C%EB%91%98%E7%8B%B3%E7%BB%A8%E2%A7%BB%E6%A3%84%E1%AB%B2%E8%8D%93%E4%BF%98%E9%B9%B9%EF%9A%8B%E8%A5%93")) .build(); calc.sign(request); } }