22 Commits
Author SHA1 Message Date
Pablo Fernandez 72901165f8 updated readme with new pom version 2011-03-30 00:09:46 -03:00
Stuart Grimshaw 4f23cfaf20 Moved callback header above call to addOAthParams so it gets properly
signed.
2011-03-29 19:06:19 -03:00
Pablo Fernandez 5c0d150547 Added mvn-bundle script 2011-03-13 10:49:31 -03:00
Pablo Fernandez 6bdae4999e Fixed wrong method call 2011-03-13 10:44:31 -03:00
Pablo Fernandez c441b7d8a4 Merged Diego's changes for OAuth2.0 server-side flow 2011-03-13 10:40:09 -03:00
Pablo Fernandez d8ab4ba404 oauth_callback param should only be sent on the request_token request 2011-03-13 10:25:52 -03:00
Pablo Fernandez 6923d3311f Added facebook and 2.0 info on readme 2011-03-13 10:21:43 -03:00
Pablo Fernandez 0832613b60 Changed artifact version in README 2011-03-13 10:21:43 -03:00
Pablo Fernandez 73a53b363a Fixed RequestTests 2011-03-13 10:21:43 -03:00
Pablo Fernandez 16b3475926 Added uitilty method to MapUtils for appending and encoding parameters 2011-03-13 10:21:42 -03:00
Pablo Fernandez 22367de553 Changed getQuerystringParameters impl to form-urldecode the parameters 2011-03-13 10:21:42 -03:00
Pablo Fernandez 906a979e63 Removed encoding in Verifier constructor 2011-03-13 10:21:42 -03:00
Pablo Fernandez bb872e4466 Changed percentEncodings 2011-03-13 10:21:42 -03:00
Pablo Fernandez d19c5d6e35 Removed Verifier test (unused) 2011-03-13 10:21:42 -03:00
Pablo Fernandez e0e8df98d3 Added formURLEncode/Decode methods 2011-03-13 10:21:39 -03:00
diegossilveira de8f0d621d Changed the Facebook example to conform to the OAuth 2.0 server-side flow 2011-02-10 22:09:18 -02:00
diegossilveira db37744fa3 Fixed package imports 2011-02-10 21:54:46 -02:00
diegossilveira 02f3d4dac2 Changed the Facebook example to conform to the OAuth 2.0 server-side flow 2011-02-10 17:13:03 -02:00
diegossilveira 7385d3702e Added specific token extractor for OAuth 2.0 2011-02-10 17:09:11 -02:00
diegossilveira 581e2b6d84 Changed the getAccessToken() method implementation to conform to the OAuth 2.0 server-side flow 2011-02-10 17:03:28 -02:00
diegossilveira 08aebb5fb1 Added specific constants for OAuth 2.0 2011-02-10 16:56:10 -02:00
diegossilveira c7176c97e2 Added access_token related methods to OAuth 2.0 APIs 2011-02-10 16:54:28 -02:00
21 changed files with 318 additions and 92 deletions

No files matched your search

+4 -2
View File
@@ -20,10 +20,12 @@ h3. Threadsafe
Hit Scribe as hard and with many threads as you like. Hit Scribe as hard and with many threads as you like.
h3. Supports all major OAuth APIs out-of-the-box h3. Supports all major 1.0a and 2.0 OAuth APIs out-of-the-box
* Google * Google
* Facebook
* Yahoo * Yahoo
* LinkedIn * LinkedIn
@@ -61,7 +63,7 @@ You can pull scribe from a maven repository, just add this to your __pom.xml__ f
@<dependency>@ @<dependency>@
@<groupId>org.scribe</groupId>@ @<groupId>org.scribe</groupId>@
@<artifactId>scribe</artifactId>@ @<artifactId>scribe</artifactId>@
@<version>1.0.6</version>@ @<version>1.1.2</version>@
@</dependency>@ @</dependency>@
h1. Getting started in less than 2 minutes h1. Getting started in less than 2 minutes
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
mvn source:jar javadoc:jar package gpg:sign repository:bundle-create -Dgpg.passphrase=$1
+7 -1
View File
@@ -28,4 +28,10 @@
[1.1.1] [1.1.1]
* FIX: Removed isEmpty() from OAuth2.0 code in order to support older JVMs * FIX: Removed isEmpty() from OAuth2.0 code in order to support older JVMs
* FEATURE: Overloaded provider() method to support instances as well as classes (thanks dustismo) * FEATURE: Overloaded provider() method to support instances as well as classes (thanks dustismo)
* FIX: White-space parameter bug (thanks Krogoth)
* FEATURE: OAuth 2.0 now implements server-flow (thanks Diego Silveira)
[1.1.2]
* FIX: Fixed ugly bug that made 1.1.1 practically unusable (thanks Stubbs)
+1 -1
View File
@@ -4,7 +4,7 @@
<groupId>org.scribe</groupId> <groupId>org.scribe</groupId>
<artifactId>scribe</artifactId> <artifactId>scribe</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>1.1.0</version> <version>1.1.2</version>
<name>Scribe OAuth Library</name> <name>Scribe OAuth Library</name>
<description>The best OAuth library out there</description> <description>The best OAuth library out there</description>
<url>http://github.com/fernandezpablo85/scribe-java</url> <url>http://github.com/fernandezpablo85/scribe-java</url>
@@ -1,5 +1,6 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.extractors.*;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.oauth.*; import org.scribe.oauth.*;
@@ -22,6 +23,33 @@ import org.scribe.oauth.*;
public abstract class DefaultApi20 implements Api public abstract class DefaultApi20 implements Api
{ {
/**
* Returns the access token extractor.
*
* @return access token extractor
*/
public AccessTokenExtractor getAccessTokenExtractor()
{
return new TokenExtractor20Impl();
}
/**
* Returns the verb for the access token endpoint (defaults to GET)
*
* @return access token endpoint verb
*/
public Verb getAccessTokenVerb()
{
return Verb.GET;
}
/**
* Returns the URL that receives the access token requests.
*
* @return access token URL
*/
public abstract String getAccessTokenEndpoint();
/** /**
* Returns the URL where you should redirect your users to authenticate * Returns the URL where you should redirect your users to authenticate
* your application. * your application.
@@ -5,12 +5,18 @@ import org.scribe.utils.*;
public class FacebookApi extends DefaultApi20 public class FacebookApi extends DefaultApi20
{ {
private static final String AUTHORIZE_URL = "https://graph.facebook.com/oauth/authorize?response_type=token&client_id=%s&redirect_uri=%s"; private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s";
@Override
public String getAccessTokenEndpoint()
{
return "https://graph.facebook.com/oauth/access_token";
}
@Override @Override
public String getAuthorizationUrl(OAuthConfig config) public String getAuthorizationUrl(OAuthConfig config)
{ {
Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB"); Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB");
return String.format(AUTHORIZE_URL, config.getApiKey(), URLUtils.percentEncode(config.getCallback())); return String.format(AUTHORIZE_URL, config.getApiKey(), URLUtils.formURLEncode(config.getCallback()));
} }
} }
@@ -32,11 +32,11 @@ public class BaseStringExtractorImpl implements BaseStringExtractor
private String getSortedAndEncodedParams(OAuthRequest request) private String getSortedAndEncodedParams(OAuthRequest request)
{ {
Map<String, String> params = new HashMap<String, String>(); Map<String, String> params = new HashMap<String, String>();
params.putAll(request.getQueryStringParams()); MapUtils.decodeAndAppendEntries(request.getQueryStringParams(), params);
params.putAll(request.getBodyParams()); MapUtils.decodeAndAppendEntries(request.getBodyParams(), params);
params.putAll(request.getOauthParameters()); MapUtils.decodeAndAppendEntries(request.getOauthParameters(), params);
params = MapUtils.sort(params); params = MapUtils.sort(params);
return URLUtils.percentEncode(URLUtils.formURLEncodeMap(params)); return URLUtils.percentEncode(URLUtils.concatSortedPercentEncodedParams(params));
} }
private void checkPreconditions(OAuthRequest request) private void checkPreconditions(OAuthRequest request)
@@ -0,0 +1,36 @@
package org.scribe.extractors;
import java.util.regex.*;
import org.scribe.exceptions.*;
import org.scribe.model.*;
import org.scribe.utils.*;
/**
* Default implementation of {@AccessTokenExtractor}. Conforms to OAuth 2.0
*
*/
public class TokenExtractor20Impl implements AccessTokenExtractor
{
private static final String TOKEN_REGEX = "access_token=(\\S*?)(&(\\S*))?";
private static final String EMPTY_SECRET = "";
/**
* {@inheritDoc}
*/
public Token extract(String response)
{
Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string");
Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
if (matcher.matches())
{
String token = URLUtils.formURLDecode(matcher.group(1));
return new Token(token, EMPTY_SECRET);
}
else
{
throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
}
}
}
@@ -27,10 +27,11 @@ public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExt
Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response); Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
if (matcher.matches()) if (matcher.matches())
{ {
String token = URLUtils.percentDecode(matcher.group(1)); String token = URLUtils.formURLDecode(matcher.group(1));
String secret = URLUtils.percentDecode(matcher.group(2)); String secret = URLUtils.formURLDecode(matcher.group(2));
return new Token(token, secret); return new Token(token, secret);
} else }
else
{ {
throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null); throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
} }
@@ -41,4 +41,9 @@ public class OAuthConstants
//OAuth 2.0 //OAuth 2.0
public static final String ACCESS_TOKEN = "access_token"; public static final String ACCESS_TOKEN = "access_token";
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
public static final String REDIRECT_URI = "redirect_uri";
public static final String CODE = "code";
} }
+4 -10
View File
@@ -144,22 +144,16 @@ class Request
* Get a {@link Map} of the query string parameters. * Get a {@link Map} of the query string parameters.
* *
* @return a map containing the query string parameters * @return a map containing the query string parameters
* @throws OAuthException if the URL is not valid
*/ */
public Map<String, String> getQueryStringParams() public Map<String, String> getQueryStringParams()
{ {
try try
{ {
Map<String, String> params = new HashMap<String, String>(); Map<String, String> params = new HashMap<String, String>();
String query = new URL(url).getQuery(); String queryString = new URL(url).getQuery();
if (query != null) params.putAll(URLUtils.queryStringToMap(queryString));
{ params.putAll(this.querystringParams);
for (String param : query.split("&"))
{
String pair[] = param.split("=");
params.put(pair[0], pair[1]);
}
}
params.putAll(querystringParams);
return params; return params;
} }
catch (MalformedURLException mue) catch (MalformedURLException mue)
+2 -1
View File
@@ -19,7 +19,8 @@ public class Verifier
*/ */
public Verifier(String value) public Verifier(String value)
{ {
this.value = URLUtils.percentDecode(value); Preconditions.checkNotNull(value, "Must provide a valid string as verifier");
this.value = value;
} }
public String getValue() public String getValue()
@@ -36,6 +36,7 @@ public class OAuth10aServiceImpl implements OAuthService
public Token getRequestToken() public Token getRequestToken()
{ {
OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
addOAuthHeader(request); addOAuthHeader(request);
Response response = request.send(); Response response = request.send();
@@ -49,7 +50,6 @@ public class OAuth10aServiceImpl implements OAuthService
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey()); request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod()); request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
request.addOAuthParameter(OAuthConstants.VERSION, getVersion()); request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
if(scope != NO_SCOPE) request.addOAuthParameter(OAuthConstants.SCOPE, scope); if(scope != NO_SCOPE) request.addOAuthParameter(OAuthConstants.SCOPE, scope);
request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token)); request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
} }
@@ -35,7 +35,13 @@ public class OAuth20ServiceImpl implements OAuthService
*/ */
public Token getAccessToken(Token requestToken, Verifier verifier) public Token getAccessToken(Token requestToken, Verifier verifier)
{ {
throw new UnsupportedOperationException("Unsupported operation, please use 'getAuthorizationUrl' and redirect your users there"); OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
Response response = request.send();
return api.getAccessTokenExtractor().extract(response.getBody());
} }
/** /**
@@ -33,4 +33,19 @@ public class MapUtils
Collections.sort(keys); Collections.sort(keys);
return keys; return keys;
} }
/**
* Form-urlDecodes and appends all keys from the source {@link Map} to the
* target {@link Map}
*
* @param source Map from where the keys get copied and decoded
* @param target Map where the decoded keys are copied to
*/
public static void decodeAndAppendEntries(Map<String, String> source, Map<String, String> target)
{
for (String key: source.keySet())
{
target.put(URLUtils.percentEncode(key), URLUtils.percentEncode(source.get(key)));
}
}
} }
+78 -22
View File
@@ -13,8 +13,8 @@ public class URLUtils
{ {
private static final String EMPTY_STRING = ""; private static final String EMPTY_STRING = "";
private static final String UTF_8 = "UTF-8"; private static final String UTF_8 = "UTF-8";
private static final char PAIR_SEPARATOR = '='; private static final String PAIR_SEPARATOR = "=";
private static final char PARAM_SEPARATOR = '&'; private static final String PARAM_SEPARATOR = "&";
private static final char QUERY_STRING_SEPARATOR = '?'; private static final char QUERY_STRING_SEPARATOR = '?';
private static final String ERROR_MSG = String.format("Cannot find specified encoding: %s", UTF_8); private static final String ERROR_MSG = String.format("Cannot find specified encoding: %s", UTF_8);
@@ -31,7 +31,7 @@ public class URLUtils
} }
/** /**
* Turns a map into a form-url-encoded string (key=value&key2=value2) * Turns a map into a form-urlencoded string
* *
* @param map any map * @param map any map
* @return form-url-encoded string * @return form-url-encoded string
@@ -47,32 +47,43 @@ public class URLUtils
StringBuffer encodedString = new StringBuffer(map.size() * 20); StringBuffer encodedString = new StringBuffer(map.size() * 20);
for (String key : map.keySet()) for (String key : map.keySet())
{ {
if(encodedString.length() > 0) encodedString.append(PARAM_SEPARATOR).append(formURLEncode(key));
if(map.get(key) != null)
{ {
encodedString.append(PARAM_SEPARATOR); encodedString.append(PAIR_SEPARATOR).append(formURLEncode(map.get(key)));
} }
encodedString.append(percentEncode(key)).append(PAIR_SEPARATOR).append(percentEncode(map.get(key)));
} }
return encodedString.toString(); return encodedString.toString().substring(1);
} }
/** /**
* Percent encodes a string * Percent encodes a string
* *
* @param plain * @param string plain string
* @return percent encoded string * @return percent encoded string
*/ */
public static String percentEncode(String string) public static String percentEncode(String string)
{
String encoded = formURLEncode(string);
for (EncodingRule rule : ENCODING_RULES)
{
encoded = rule.apply(encoded);
}
return encoded;
}
/**
* Translates a string into application/x-www-form-urlencoded format
*
* @param plain
* @return form-urlencoded string
*/
public static String formURLEncode(String string)
{ {
Preconditions.checkNotNull(string, "Cannot encode null string"); Preconditions.checkNotNull(string, "Cannot encode null string");
try try
{ {
String encoded = URLEncoder.encode(string, UTF_8); return URLEncoder.encode(string, UTF_8);
for(EncodingRule rule : ENCODING_RULES)
{
encoded = rule.apply(encoded);
}
return encoded;
} }
catch (UnsupportedEncodingException uee) catch (UnsupportedEncodingException uee)
{ {
@@ -81,12 +92,12 @@ public class URLUtils
} }
/** /**
* Percent decodes a string * Decodes a application/x-www-form-urlencoded string
* *
* @param string percent encoded string * @param string form-urlencoded string
* @return plain string * @return plain string
*/ */
public static String percentDecode(String string) public static String formURLDecode(String string)
{ {
Preconditions.checkNotNull(string, "Cannot decode null string"); Preconditions.checkNotNull(string, "Cannot decode null string");
try try
@@ -110,12 +121,57 @@ public class URLUtils
{ {
Preconditions.checkNotNull(url, "Cannot append to null URL"); Preconditions.checkNotNull(url, "Cannot append to null URL");
String queryString = URLUtils.formURLEncodeMap(params); String queryString = URLUtils.formURLEncodeMap(params);
if (queryString.length() == 0) return url; if (queryString.equals(EMPTY_STRING))
{
return url;
}
else
{
url += url.indexOf(QUERY_STRING_SEPARATOR) != -1 ? PARAM_SEPARATOR : QUERY_STRING_SEPARATOR;
url += queryString;
return url;
}
}
// Check if there are parameters in the url already and use '&' instead of '?' /**
url += url.indexOf(QUERY_STRING_SEPARATOR) != -1 ? PARAM_SEPARATOR : QUERY_STRING_SEPARATOR; * Concats a key-value map into a querystring-like String
url += queryString; *
return url; * @param params key-value map
* @return querystring-like String
*/
// TODO Move to MapUtils
public static String concatSortedPercentEncodedParams(Map<String, String> params)
{
StringBuilder result = new StringBuilder();
for (String key : params.keySet())
{
result.append(key).append(PAIR_SEPARATOR);
result.append(params.get(key)).append(PARAM_SEPARATOR);
}
return result.toString().substring(0, result.length() - 1);
}
/**
* Parses and form-urldecodes a querystring-like string into a map
*
* @param queryString querystring-like String
* @return a map with the form-urldecoded parameters
*/
// TODO Move to MapUtils
public static Map<String, String> queryStringToMap(String queryString)
{
Map<String, String> result = new HashMap<String, String>();
if (queryString != null && queryString.length() > 0)
{
for (String param : queryString.split(PARAM_SEPARATOR))
{
String pair[] = param.split(PAIR_SEPARATOR);
String key = formURLDecode(pair[0]);
String value = pair.length > 1 ? formURLDecode(pair[1]) : EMPTY_STRING;
result.put(key, value);
}
}
return result;
} }
private static final class EncodingRule private static final class EncodingRule
@@ -11,13 +11,12 @@ public class FacebookExample
{ {
private static final String NETWORK_NAME = "Facebook"; private static final String NETWORK_NAME = "Facebook";
private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/me"; private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/me";
private static final String NO_SECRET_NEEDED = "";
private static final Token EMPTY_TOKEN = null; private static final Token EMPTY_TOKEN = null;
public static void main(String[] args) public static void main(String[] args)
{ {
// Replace these with your own api key and secret // Replace these with your own api key and secret
String apiKey = "your_api_key"; String apiKey = "your_app_id";
String apiSecret = "your_api_secret"; String apiSecret = "your_api_secret";
OAuthService service = new ServiceBuilder() OAuthService service = new ServiceBuilder()
.provider(FacebookApi.class) .provider(FacebookApi.class)
@@ -36,9 +35,16 @@ public class FacebookExample
System.out.println("Got the Authorization URL!"); System.out.println("Got the Authorization URL!");
System.out.println("Now go and authorize Scribe here:"); System.out.println("Now go and authorize Scribe here:");
System.out.println(authorizationUrl); System.out.println(authorizationUrl);
System.out.println("And paste the access token here"); System.out.println("And paste the authorization code here");
System.out.print(">>"); System.out.print(">>");
Token accessToken = new Token(in.nextLine(), NO_SECRET_NEEDED); Verifier verifier = new Verifier(in.nextLine());
System.out.println();
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
System.out.println(); System.out.println();
// Now let's go and ask for a protected resource! // Now let's go and ask for a protected resource!
@@ -0,0 +1,58 @@
package org.scribe.extractors;
import static org.junit.Assert.*;
import org.junit.*;
import org.scribe.exceptions.*;
import org.scribe.model.*;
public class TokenExtractor20Test
{
private TokenExtractor20Impl extractor;
@Before
public void setup()
{
extractor = new TokenExtractor20Impl();
}
@Test
public void shouldExtractTokenFromOAuthStandardResponse()
{
String response = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE";
Token extracted = extractor.extract(response);
assertEquals("166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE", extracted.getToken());
assertEquals("", extracted.getSecret());
}
@Test
public void shouldExtractTokenFromResponseWithExpiresParam()
{
String response = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE&expires=5108";
Token extracted = extractor.extract(response);
assertEquals("166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE", extracted.getToken());
assertEquals("", extracted.getSecret());
}
@Test(expected = OAuthException.class)
public void shouldThrowExceptionIfTokenIsAbsent()
{
String response = "&expires=5108";
extractor.extract(response);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfResponseIsNull()
{
String response = null;
extractor.extract(response);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfResponseIsEmptyString()
{
String response = "";
extractor.extract(response);
}
}
@@ -16,8 +16,10 @@ public class RequestTest
{ {
connection = new ConnectionStub(); connection = new ConnectionStub();
postRequest = new Request(Verb.POST, "http://example.com"); postRequest = new Request(Verb.POST, "http://example.com");
postRequest.addBodyParameter("param", "value");
postRequest.addBodyParameter("param with spaces", "value with spaces");
postRequest.setConnection(connection); postRequest.setConnection(connection);
getRequest = new Request(Verb.GET, "http://example.com?qsparam=value&other=value+with+spaces"); getRequest = new Request(Verb.GET, "http://example.com?qsparam=value&other+param=value+with+spaces");
getRequest.setConnection(connection); getRequest.setConnection(connection);
} }
@@ -34,6 +36,7 @@ public class RequestTest
assertEquals(2, getRequest.getQueryStringParams().size()); assertEquals(2, getRequest.getQueryStringParams().size());
assertEquals(0, postRequest.getQueryStringParams().size()); assertEquals(0, postRequest.getQueryStringParams().size());
assertTrue(getRequest.getQueryStringParams().containsKey("qsparam")); assertTrue(getRequest.getQueryStringParams().containsKey("qsparam"));
assertTrue(getRequest.getQueryStringParams().get("qsparam").equals("value"));
} }
@Test @Test
@@ -47,12 +50,10 @@ public class RequestTest
} }
@Test @Test
public void shouldSetBodyParamsAndHeaders() public void shouldSetBodyParamsAndAddContentLength()
{ {
postRequest.addBodyParameter("param", "value"); assertEquals("param=value&param+with+spaces=value+with+spaces", postRequest.getBodyContents());
postRequest.addBodyParameter("param two", "value with spaces");
postRequest.send(); postRequest.send();
assertEquals("param%20two=value%20with%20spaces&param=value", postRequest.getBodyContents());
assertTrue(connection.getHeaders().containsKey("Content-Length")); assertTrue(connection.getHeaders().containsKey("Content-Length"));
} }
@@ -74,4 +75,9 @@ public class RequestTest
assertEquals(3, request.getQueryStringParams().size()); assertEquals(3, request.getQueryStringParams().size());
} }
@Test
public void shouldHandleQueryStringSpaceEncodingProperly()
{
assertTrue(getRequest.getQueryStringParams().get("other param").equals("value with spaces"));
}
} }
@@ -1,21 +0,0 @@
package org.scribe.model;
import static org.junit.Assert.*;
import org.junit.*;
public class VerifierTest
{
@Test
public void shouldParse()
{
Verifier verifier = new Verifier("p8k%2BGIjIL9PblXq%2BpH6LmT9l");
assertEquals(verifier.getValue(), "p8k+GIjIL9PblXq+pH6LmT9l");
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowErrorForNullString()
{
new Verifier(null);
}
}
@@ -16,7 +16,7 @@ public class URLUtilsTest
params.put("key with spaces", "value with spaces"); params.put("key with spaces", "value with spaces");
params.put("&symbols!", "#!"); params.put("&symbols!", "#!");
String expected = "key=value&key%20with%20spaces=value%20with%20spaces&%26symbols%21=%23%21"; String expected = "key=value&key+with+spaces=value+with+spaces&%26symbols%21=%23%21";
assertEquals(expected, URLUtils.formURLEncodeMap(params)); assertEquals(expected, URLUtils.formURLEncodeMap(params));
} }
@@ -28,6 +28,17 @@ public class URLUtilsTest
assertEquals(expected, URLUtils.formURLEncodeMap(params)); assertEquals(expected, URLUtils.formURLEncodeMap(params));
} }
@Test
public void shouldFormURLEncodeMapWithMissingValues()
{
Map<String, String> params = new LinkedHashMap<String, String>();
params.put("key", "value");
params.put("key with spaces", null);
String expected = "key=value&key+with+spaces";
assertEquals(expected, URLUtils.formURLEncodeMap(params));
}
@Test @Test
public void shouldPercentEncodeString() public void shouldPercentEncodeString()
{ {
@@ -37,24 +48,32 @@ public class URLUtilsTest
} }
@Test @Test
public void shouldPercentDecodeString() public void shouldFormURLEncodeString()
{ {
String toDecode = "this+is+a+test+%26%5E"; String toEncode = "this is a test &^";
String expected = "this is a test &^"; String expected = "this+is+a+test+%26%5E";
assertEquals(expected, URLUtils.percentDecode(toDecode)); assertEquals(expected, URLUtils.formURLEncode(toEncode));
} }
@Test @Test
public void shouldEncodeAllSpecialCharacters() public void shouldFormURLDecodeString()
{
String toDecode = "this+is+a+test+%26%5E";
String expected = "this is a test &^";
assertEquals(expected, URLUtils.formURLDecode(toDecode));
}
@Test
public void shouldPercentEncodeAllSpecialCharacters()
{ {
String plain = "!*'();:@&=+$,/?#[]"; String plain = "!*'();:@&=+$,/?#[]";
String encoded = "%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%23%5B%5D"; String encoded = "%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%23%5B%5D";
assertEquals(encoded, URLUtils.percentEncode(plain)); assertEquals(encoded, URLUtils.percentEncode(plain));
assertEquals(plain, URLUtils.percentDecode(encoded)); assertEquals(plain, URLUtils.formURLDecode(encoded));
} }
@Test @Test
public void shouldNotEncodeReservedCharacters() public void shouldNotPercentEncodeReservedCharacters()
{ {
String plain = "abcde123456-._~"; String plain = "abcde123456-._~";
String encoded = plain; String encoded = plain;
@@ -79,7 +98,7 @@ public class URLUtilsTest
public void shouldThrowExceptionIfStringToDecodeIsNull() public void shouldThrowExceptionIfStringToDecodeIsNull()
{ {
String toDecode = null; String toDecode = null;
URLUtils.percentDecode(toDecode); URLUtils.formURLDecode(toDecode);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
@@ -103,7 +122,7 @@ public class URLUtilsTest
public void shouldAppendParametersToSimpleUrl() public void shouldAppendParametersToSimpleUrl()
{ {
String url = "http://www.example.com"; String url = "http://www.example.com";
String expectedUrl = "http://www.example.com?param1=value1&param2=value%20with%20spaces"; String expectedUrl = "http://www.example.com?param1=value1&param2=value+with+spaces";
Map<String, String> params = new HashMap<String, String>(); Map<String, String> params = new HashMap<String, String>();
params.put("param1", "value1"); params.put("param1", "value1");
@@ -117,7 +136,7 @@ public class URLUtilsTest
public void shouldAppendParametersToUrlWithQuerystring() public void shouldAppendParametersToUrlWithQuerystring()
{ {
String url = "http://www.example.com?already=present"; String url = "http://www.example.com?already=present";
String expectedUrl = "http://www.example.com?already=present&param1=value1&param2=value%20with%20spaces"; String expectedUrl = "http://www.example.com?already=present&param1=value1&param2=value+with+spaces";
Map<String, String> params = new HashMap<String, String>(); Map<String, String> params = new HashMap<String, String>();
params.put("param1", "value1"); params.put("param1", "value1");
@@ -128,7 +147,7 @@ public class URLUtilsTest
} }
@Test @Test
public void shouldEncodePlusSymbol() public void shouldPercentEncodePlusSymbol()
{ {
String plain = "7aEP+jNAwvjc0mjhqg0nuXPf"; String plain = "7aEP+jNAwvjc0mjhqg0nuXPf";
String encoded = "7aEP%2BjNAwvjc0mjhqg0nuXPf"; String encoded = "7aEP%2BjNAwvjc0mjhqg0nuXPf";
@@ -137,11 +156,11 @@ public class URLUtilsTest
} }
@Test @Test
public void shouldDecodePlusSymbol() public void shouldURLDecodePlusSymbol()
{ {
String encoded = "oauth_verifier=7aEP%2BjNAwvjc0mjhqg0nuXPf"; String encoded = "oauth_verifier=7aEP%2BjNAwvjc0mjhqg0nuXPf";
String expected = "oauth_verifier=7aEP+jNAwvjc0mjhqg0nuXPf"; String expected = "oauth_verifier=7aEP+jNAwvjc0mjhqg0nuXPf";
Assert.assertEquals(expected, URLUtils.percentDecode(encoded)); Assert.assertEquals(expected, URLUtils.formURLDecode(encoded));
} }
} }