From 0386df2606546b19f3ba672354983b01ec626320 Mon Sep 17 00:00:00 2001 From: krogoth Date: Thu, 3 Feb 2011 16:43:33 +0100 Subject: [PATCH] Fix for basestring URI not properly encoded regarding RFC5849 ch 3.4.1.2 This will prevent failure for non standard port and uppercase host or scheme strings Added related test cases. Warning : Request constructor signature changed. A java.net.MalformedURLException exception will be throw when creating a request if not a proper URL previously this cannot occur until send. --- .../java/org/scribe/model/OAuthRequest.java | 4 +- src/main/java/org/scribe/model/Request.java | 25 +++++-------- .../org/scribe/oauth/OAuth10aServiceImpl.java | 17 ++++++++- src/main/java/org/scribe/utils/URLUtils.java | 29 +++++++++++++++ .../org/scribe/examples/FacebookExample.java | 3 +- .../scribe/examples/FoursquareExample.java | 3 +- .../org/scribe/examples/GoogleExample.java | 3 +- .../org/scribe/examples/LinkedInExample.java | 3 +- .../org/scribe/examples/TwitterExample.java | 3 +- .../org/scribe/examples/YahooExample.java | 3 +- .../extractors/BaseStringExtractorTest.java | 18 ++++++++- .../extractors/HeaderExtractorTest.java | 6 ++- .../org/scribe/model/OAuthRequestTest.java | 4 +- .../java/org/scribe/model/RequestTest.java | 37 ++++++++++++++++++- .../org/scribe/test/helpers/ObjectMother.java | 14 ++++++- 15 files changed, 140 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/scribe/model/OAuthRequest.java b/src/main/java/org/scribe/model/OAuthRequest.java index 4389227..41a4eaf 100644 --- a/src/main/java/org/scribe/model/OAuthRequest.java +++ b/src/main/java/org/scribe/model/OAuthRequest.java @@ -1,5 +1,6 @@ package org.scribe.model; +import java.net.MalformedURLException; import java.util.*; /** @@ -19,8 +20,9 @@ public class OAuthRequest extends Request * * @param verb Http verb/method * @param url resource URL + * @throws MalformedURLException */ - public OAuthRequest(Verb verb, String url) + public OAuthRequest(Verb verb, String url) throws MalformedURLException { super(verb, url); this.oauthParameters = new HashMap(); diff --git a/src/main/java/org/scribe/model/Request.java b/src/main/java/org/scribe/model/Request.java index fcec4b3..49c558f 100644 --- a/src/main/java/org/scribe/model/Request.java +++ b/src/main/java/org/scribe/model/Request.java @@ -17,7 +17,7 @@ class Request { private static final String CONTENT_LENGTH = "Content-Length"; - private String url; + private URL url; private Verb verb; private Map querystringParams; private Map bodyParams; @@ -30,11 +30,12 @@ class Request * * @param verb Http Verb (GET, POST, etc) * @param url url with optional querystring parameters. + * @throws MalformedURLException */ - public Request(Verb verb, String url) + public Request(Verb verb, String url) throws MalformedURLException { this.verb = verb; - this.url = url; + this.url = new URL(url); this.querystringParams = new HashMap(); this.bodyParams = new HashMap(); this.headers = new HashMap(); @@ -61,7 +62,7 @@ class Request private void createConnection() throws IOException { - String effectiveUrl = URLUtils.appendParametersToQueryString(url, querystringParams); + String effectiveUrl = URLUtils.appendParametersToQueryString(url.toString(), querystringParams); if (connection == null) { connection = (HttpURLConnection) new URL(effectiveUrl).openConnection(); @@ -144,14 +145,11 @@ class Request * Get a {@link Map} of the query string parameters. * * @return a map containing the query string parameters - * @throws UnsupportedEncodingException */ public Map getQueryStringParams() { - try - { Map params = new HashMap(); - String query = new URL(url).getQuery(); + String query = url.getQuery(); if (query != null) { for (String param : query.split("&")) @@ -165,12 +163,7 @@ class Request } } params.putAll(querystringParams); - return params; - } - catch (MalformedURLException mue) - { - throw new OAuthException("Malformed URL", mue); - } + return params; } /** @@ -190,7 +183,7 @@ class Request */ public String getUrl() { - return url; + return url.toString(); } /** @@ -200,7 +193,7 @@ class Request */ public String getSanitizedUrl() { - return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", ""); + return URLUtils.convertUrlToBaseStringURI(url); } /** diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 9ab565a..2f47ed8 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -1,6 +1,9 @@ package org.scribe.oauth; +import java.net.MalformedURLException; + import org.scribe.builder.api.*; +import org.scribe.exceptions.OAuthException; import org.scribe.model.*; /** @@ -35,7 +38,12 @@ public class OAuth10aServiceImpl implements OAuthService */ public Token getRequestToken() { - OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); + OAuthRequest request = null;; + try { + request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); + } catch (MalformedURLException e) { + throw new OAuthException("Problems while creating connection", e); + } addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); addOAuthHeader(request); Response response = request.send(); @@ -59,7 +67,12 @@ public class OAuth10aServiceImpl implements OAuthService */ public Token getAccessToken(Token requestToken, Verifier verifier) { - OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); + OAuthRequest request = null; + try { + request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); + } catch (MalformedURLException e) { + throw new OAuthException("Problems while creating connection", e); + } request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); addOAuthParams(request, requestToken); diff --git a/src/main/java/org/scribe/utils/URLUtils.java b/src/main/java/org/scribe/utils/URLUtils.java index 893cd48..8fcbc96 100644 --- a/src/main/java/org/scribe/utils/URLUtils.java +++ b/src/main/java/org/scribe/utils/URLUtils.java @@ -16,6 +16,10 @@ public class URLUtils private static final char PAIR_SEPARATOR = '='; private static final char PARAM_SEPARATOR = '&'; private static final char QUERY_STRING_SEPARATOR = '?'; + private static final String HTTP_PROTOCOL = "http"; + private static final int HTTP_DEFAULT_PORT = 80; + private static final String HTTPS_PROTOCOL = "https"; + private static final int HTTPS_DEFAULT_PORT = 443; private static final String ERROR_MSG = String.format("Cannot find specified encoding: %s", UTF_8); @@ -166,4 +170,29 @@ public class URLUtils } return target.deleteCharAt(target.length() - 1).toString(); } + + public static String convertUrlToBaseStringURI(URL url){ + URI uri = null; + try { + uri = url.toURI(); + } catch (URISyntaxException e1) { + e1.printStackTrace(); + } + String scheme = uri.getScheme().toLowerCase(); + String host = uri.getHost().toLowerCase(); + int port = uri.getPort(); + if ( + (scheme.equals(HTTP_PROTOCOL) && port == HTTP_DEFAULT_PORT) + || (scheme.equals(HTTPS_PROTOCOL) && port == HTTPS_DEFAULT_PORT) + ){ + port = -1; + } + URI baseUri = null; + try { + baseUri = new URI(scheme,null, host, port, uri.getPath(), null, null); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return baseUri.toString(); + } } diff --git a/src/test/java/org/scribe/examples/FacebookExample.java b/src/test/java/org/scribe/examples/FacebookExample.java index 74e8ed0..347b866 100644 --- a/src/test/java/org/scribe/examples/FacebookExample.java +++ b/src/test/java/org/scribe/examples/FacebookExample.java @@ -1,5 +1,6 @@ package org.scribe.examples; +import java.net.MalformedURLException; import java.util.*; import org.scribe.builder.*; @@ -14,7 +15,7 @@ public class FacebookExample private static final String NO_SECRET_NEEDED = ""; private static final Token EMPTY_TOKEN = null; - public static void main(String[] args) + public static void main(String[] args) throws MalformedURLException { // Replace these with your own api key and secret String apiKey = "your_api_key"; diff --git a/src/test/java/org/scribe/examples/FoursquareExample.java b/src/test/java/org/scribe/examples/FoursquareExample.java index b227488..22202d0 100644 --- a/src/test/java/org/scribe/examples/FoursquareExample.java +++ b/src/test/java/org/scribe/examples/FoursquareExample.java @@ -1,5 +1,6 @@ package org.scribe.examples; +import java.net.MalformedURLException; import java.util.Scanner; import org.scribe.builder.*; @@ -11,7 +12,7 @@ public class FoursquareExample { private static final String PROTECTED_RESOURCE_URL = "http://api.foursquare.com/v1/user"; - public static void main(String[] args) + public static void main(String[] args) throws MalformedURLException { OAuthService service = new ServiceBuilder() .provider(FoursquareApi.class) diff --git a/src/test/java/org/scribe/examples/GoogleExample.java b/src/test/java/org/scribe/examples/GoogleExample.java index fef1b43..516cfd1 100644 --- a/src/test/java/org/scribe/examples/GoogleExample.java +++ b/src/test/java/org/scribe/examples/GoogleExample.java @@ -1,5 +1,6 @@ package org.scribe.examples; +import java.net.MalformedURLException; import java.util.*; import org.scribe.builder.*; @@ -14,7 +15,7 @@ public class GoogleExample private static final String PROTECTED_RESOURCE_URL = "https://docs.google.com/feeds/default/private/full/"; private static final String SCOPE = "https://docs.google.com/feeds/"; - public static void main(String[] args) + public static void main(String[] args) throws MalformedURLException { OAuthService service = new ServiceBuilder() .provider(GoogleApi.class) diff --git a/src/test/java/org/scribe/examples/LinkedInExample.java b/src/test/java/org/scribe/examples/LinkedInExample.java index 703cc82..d3be561 100644 --- a/src/test/java/org/scribe/examples/LinkedInExample.java +++ b/src/test/java/org/scribe/examples/LinkedInExample.java @@ -1,5 +1,6 @@ package org.scribe.examples; +import java.net.MalformedURLException; import java.util.Scanner; import org.scribe.builder.*; @@ -11,7 +12,7 @@ public class LinkedInExample { private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)"; - public static void main(String[] args) + public static void main(String[] args) throws MalformedURLException { OAuthService service = new ServiceBuilder() .provider(LinkedInApi.class) diff --git a/src/test/java/org/scribe/examples/TwitterExample.java b/src/test/java/org/scribe/examples/TwitterExample.java index f47fa0e..155ad4e 100644 --- a/src/test/java/org/scribe/examples/TwitterExample.java +++ b/src/test/java/org/scribe/examples/TwitterExample.java @@ -1,5 +1,6 @@ package org.scribe.examples; +import java.net.MalformedURLException; import java.util.Scanner; import org.scribe.builder.*; @@ -11,7 +12,7 @@ public class TwitterExample { private static final String PROTECTED_RESOURCE_URL = "http://api.twitter.com/1/account/verify_credentials.xml"; - public static void main(String[] args) + public static void main(String[] args) throws MalformedURLException { OAuthService service = new ServiceBuilder() .provider(TwitterApi.class) diff --git a/src/test/java/org/scribe/examples/YahooExample.java b/src/test/java/org/scribe/examples/YahooExample.java index 2e3f336..f74d0de 100644 --- a/src/test/java/org/scribe/examples/YahooExample.java +++ b/src/test/java/org/scribe/examples/YahooExample.java @@ -1,5 +1,6 @@ package org.scribe.examples; +import java.net.MalformedURLException; import java.util.Scanner; import org.scribe.builder.*; @@ -11,7 +12,7 @@ public class YahooExample { private static final String PROTECTED_RESOURCE_URL = "http://social.yahooapis.com/v1/user/A6ROU63MXWDCW3Y5MGCYWVHDJI/profile/status?format=json"; - public static void main(String[] args) + public static void main(String[] args) throws MalformedURLException { OAuthService service = new ServiceBuilder() .provider(YahooApi.class) diff --git a/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java b/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java index 8fe872f..f637a9c 100644 --- a/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java +++ b/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java @@ -2,6 +2,8 @@ package org.scribe.extractors; import static org.junit.Assert.*; +import java.net.MalformedURLException; + import org.junit.*; import org.scribe.exceptions.*; import org.scribe.model.*; @@ -12,12 +14,16 @@ public class BaseStringExtractorTest private BaseStringExtractorImpl extractor; private OAuthRequest request; + private OAuthRequest request2; @Before - public void setup() + public void setup() throws MalformedURLException { request = ObjectMother.createSampleOAuthRequest(); + request2 = ObjectMother.createSampleOAuthRequest2(); extractor = new BaseStringExtractorImpl(); + + } @Test @@ -27,6 +33,14 @@ public class BaseStringExtractorTest String baseString = extractor.extract(request); assertEquals(expected, baseString); } + + @Test + public void shouldExtractBaseStringFromOAuthRequest2() + { + String expected = "GET&http%3A%2F%2Fexample.com&oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456"; + String baseString = extractor.extract(request2); + assertEquals(expected, baseString); + } @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfRquestIsNull() @@ -36,7 +50,7 @@ public class BaseStringExtractorTest } @Test(expected = OAuthParametersMissingException.class) - public void shouldThrowExceptionIfRquestHasNoOAuthParameters() + public void shouldThrowExceptionIfRquestHasNoOAuthParameters() throws MalformedURLException { OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com"); extractor.extract(request); diff --git a/src/test/java/org/scribe/extractors/HeaderExtractorTest.java b/src/test/java/org/scribe/extractors/HeaderExtractorTest.java index bdc727c..06d9087 100644 --- a/src/test/java/org/scribe/extractors/HeaderExtractorTest.java +++ b/src/test/java/org/scribe/extractors/HeaderExtractorTest.java @@ -2,6 +2,8 @@ package org.scribe.extractors; import static org.junit.Assert.*; +import java.net.MalformedURLException; + import org.junit.*; import org.scribe.exceptions.*; import org.scribe.model.*; @@ -14,7 +16,7 @@ public class HeaderExtractorTest private OAuthRequest request; @Before - public void setup() + public void setup() throws MalformedURLException { request = ObjectMother.createSampleOAuthRequest(); extractor = new HeaderExtractorImpl(); @@ -37,7 +39,7 @@ public class HeaderExtractorTest } @Test(expected = OAuthParametersMissingException.class) - public void shouldExceptionIfRequestHasNoOAuthParams() + public void shouldExceptionIfRequestHasNoOAuthParams() throws MalformedURLException { OAuthRequest emptyRequest = new OAuthRequest(Verb.GET, "http://example.com"); extractor.extract(emptyRequest); diff --git a/src/test/java/org/scribe/model/OAuthRequestTest.java b/src/test/java/org/scribe/model/OAuthRequestTest.java index 1ea2f2f..ab72390 100644 --- a/src/test/java/org/scribe/model/OAuthRequestTest.java +++ b/src/test/java/org/scribe/model/OAuthRequestTest.java @@ -2,6 +2,8 @@ package org.scribe.model; import static org.junit.Assert.*; +import java.net.MalformedURLException; + import org.junit.*; public class OAuthRequestTest @@ -10,7 +12,7 @@ public class OAuthRequestTest private OAuthRequest request; @Before - public void setup() + public void setup() throws MalformedURLException { request = new OAuthRequest(Verb.GET, "http://example.com"); } diff --git a/src/test/java/org/scribe/model/RequestTest.java b/src/test/java/org/scribe/model/RequestTest.java index f7681dd..ae90e21 100644 --- a/src/test/java/org/scribe/model/RequestTest.java +++ b/src/test/java/org/scribe/model/RequestTest.java @@ -2,6 +2,8 @@ package org.scribe.model; import static org.junit.Assert.*; +import java.net.MalformedURLException; + import org.junit.*; public class RequestTest @@ -68,7 +70,7 @@ public class RequestTest } @Test - public void shouldAllowAddingQuerystringParametersAfterCreation() + public void shouldAllowAddingQuerystringParametersAfterCreation() throws MalformedURLException { Request request = new Request(Verb.GET, "http://example.com?one=val"); request.addQuerystringParameter("two", "other val"); @@ -76,4 +78,37 @@ public class RequestTest assertEquals(3, request.getQueryStringParams().size()); } + @Test + public void sanatizeUrlTest() throws MalformedURLException + { + Request request = new Request(Verb.GET, "http://example.com?one=val"); + assertEquals("http://example.com", request.getSanitizedUrl()); + + request = new Request(Verb.GET, "http://EXAMPLE.com:80/?one=val"); + assertEquals("http://example.com/", request.getSanitizedUrl()); + + request = new Request(Verb.GET, "http://EXAMPLE.com:8080?one=val"); + assertEquals("http://example.com:8080", request.getSanitizedUrl()); + + request = new Request(Verb.GET, "http://EXAMPLE.com:8080?one=val"); + assertEquals("http://example.com:8080", request.getSanitizedUrl()); + + request = new Request(Verb.GET, "http://EXAMPLE.com:80/test/?one=val"); + assertEquals("http://example.com/test/", request.getSanitizedUrl()); + + request = new Request(Verb.GET, "http://EXAMPLE.com:8080/test/?one=val#Hello"); + assertEquals("http://example.com:8080/test/", request.getSanitizedUrl()); + + request = new Request(Verb.GET, "HTTP://EXAMPLE.com:8080/test/?one=val#Hello"); + assertEquals("http://example.com:8080/test/", request.getSanitizedUrl()); + + //From RFC5849 example p.20 + request = new Request(Verb.GET, "http://example.com:80/r%20v/X?id=123"); + assertEquals("http://example.com/r%20v/X", request.getSanitizedUrl()); + + //From RFC5849 example p.20 + request = new Request(Verb.GET, "https://www.example.com:8080/?q=1"); + assertEquals("https://www.example.com:8080/", request.getSanitizedUrl()); + } + } \ No newline at end of file diff --git a/src/test/java/org/scribe/test/helpers/ObjectMother.java b/src/test/java/org/scribe/test/helpers/ObjectMother.java index a69a3c1..8bfd5e3 100644 --- a/src/test/java/org/scribe/test/helpers/ObjectMother.java +++ b/src/test/java/org/scribe/test/helpers/ObjectMother.java @@ -1,11 +1,13 @@ package org.scribe.test.helpers; +import java.net.MalformedURLException; + import org.scribe.model.*; public class ObjectMother { - public static OAuthRequest createSampleOAuthRequest() + public static OAuthRequest createSampleOAuthRequest() throws MalformedURLException { OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com"); request.addOAuthParameter(OAuthConstants.TIMESTAMP, "123456"); @@ -14,4 +16,14 @@ public class ObjectMother request.addOAuthParameter(OAuthConstants.SIGNATURE, "OAuth-Signature"); return request; } + + public static OAuthRequest createSampleOAuthRequest2() throws MalformedURLException + { + OAuthRequest request = new OAuthRequest(Verb.GET, "http://EXAMPLE.com"); + request.addOAuthParameter(OAuthConstants.TIMESTAMP, "123456"); + request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "AS#$^*@&"); + request.addOAuthParameter(OAuthConstants.CALLBACK, "http://example/callback"); + request.addOAuthParameter(OAuthConstants.SIGNATURE, "OAuth-Signature"); + return request; + } }