39 Commits
Author SHA1 Message Date
krogoth 0386df2606 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.
2011-02-03 16:48:11 +01:00
krogoth ca0076c043 Refactored scribe 1.1.0 to handdle properly encodings as per RFC5849. This is the first try for comment. 2011-02-03 00:03:45 +01:00
Pablo Fernandez 70358ad651 Added specific tests for + symbol encoding 2011-01-31 16:15:18 -03:00
dustin norlander 0f39d37ddc add api() method to service builder 2011-01-26 10:27:35 -03:00
Pablo Fernandez da3a3f4a0d Removed isEmpty for old VM compatibility 2011-01-19 13:41:41 -03:00
Pablo Fernandez 380d858b13 Changed version number for release 2011-01-16 12:45:26 -03:00
Pablo Fernandez 9c4f5bc337 Refactored OOB checking in fbook api 2011-01-13 23:50:36 -03:00
Pablo Fernandez 09ee10dbd1 Added builder tests 2011-01-13 23:50:32 -03:00
Pablo Fernandez 690b9d4e21 (minor) removed specific import 2011-01-12 21:46:27 -03:00
diegossilveira 080dd962a9 Encoding the callback url 2011-01-12 18:05:50 -02:00
Pablo Fernandez 40bb525374 Added url params before making the connection
Renamed method to keep consistency
2011-01-10 15:04:26 -03:00
Pablo Fernandez 8e23e81c57 Explicited that you need a personal pair of keys to use Facebook's example 2011-01-09 21:37:44 -03:00
Pablo Fernandez 1f055d7eeb Minor exception handling refactoring 2011-01-09 16:10:00 -03:00
Pablo Fernandez 1f36fd0f32 Added Facebook Api and example 2011-01-09 15:58:58 -03:00
Pablo Fernandez 9ea686a3f8 Added OAuth 2.0 classes 2011-01-09 15:51:34 -03:00
Pablo Fernandez 7e92db3413 Added functionallity for appending querystring params once the request is created 2011-01-09 15:44:14 -03:00
Pablo Fernandez f6c3cb9bdb Lazy http connection creation 2011-01-09 15:34:19 -03:00
Pablo Fernandez 088fc5e443 Renamed OAuth 2.0 service class 2011-01-09 14:43:56 -03:00
Pablo Fernandez 27bac50073 Added append parameters to URL method 2011-01-09 14:14:08 -03:00
Pablo Fernandez 6fc5146706 Added Diego to list of developers 2011-01-09 13:56:34 -03:00
Pablo Fernandez 0e5ae92d3e Added exceptions to both token methods on 2.0 service
Rebased 1.0.9
2011-01-07 13:24:18 -03:00
Pablo Fernandez c145ee8842 Added Evernote playground api 2011-01-07 13:15:29 -03:00
Pablo Fernandez bdfd14309f Added some more apis to the readme 2011-01-07 13:15:29 -03:00
Pablo Fernandez 82f03604c3 Added OAuth2 service props 2011-01-07 13:15:29 -03:00
Pablo Fernandez 5ac849313d Added authorization URL to the Apis 2011-01-07 13:15:26 -03:00
Pablo Fernandez c12da16a38 Made 2.0 impl fit the internal refactor 2011-01-07 13:10:43 -03:00
Pablo Fernandez b78ca90df4 Added plumbing code for 2.0 2011-01-07 13:10:43 -03:00
Pablo Fernandez 577c18c752 corrected javadocs to reflect changes 2011-01-07 13:10:43 -03:00
Pablo Fernandez 41cbee06d7 Minor name refactor 2011-01-07 13:10:43 -03:00
Pablo Fernandez 8eb2062e95 Used OAuthConfig when possible instead of bunch of Strings 2011-01-07 13:10:43 -03:00
Pablo Fernandez 8f0760664f Removed endpoints and verbs from config (they are in the Api object anyways) 2011-01-07 13:10:42 -03:00
Pablo Fernandez 0be82d6832 OAuth 1.0a service refactor to remove many properties 2011-01-07 13:10:39 -03:00
Pablo Fernandez d0fa8689cb Added changes to changelog and version to pom 2010-11-30 15:05:10 -03:00
roger 896e738156 Signature test fixed. New reference signature as api & token secret must be urlencoded. 2010-11-30 15:01:12 -03:00
roger cf84381127 Added URLDecoding to verifier 2010-11-30 14:49:47 -03:00
klakegg 806d548629 Parameters scope and oauth_callback are needed in the request_token step only. 2010-11-30 14:25:42 -03:00
Roger 959c093620 keyString for SecretKey must be encoded 2010-11-30 14:10:57 -03:00
Pablo Fernandez fc2c46bd3a Changed GoogleApi to use GET 2010-11-23 17:35:42 -03:00
klakegg f1ecabdb52 Token implements Serializable - nice to have when creating web service. 2010-11-23 17:29:24 -03:00
46 changed files with 910 additions and 208 deletions

No files matched your search

+6
View File
@@ -32,6 +32,12 @@ h3. Supports all major OAuth APIs out-of-the-box
* Foursquare
* Evernote
* Vimeo
* Yammer
* and many more! check the "examples folder":http://github.com/fernandezpablo85/scribe-java/tree/master/src/test/java/org/scribe/examples
h3. Small and modular
+16
View File
@@ -13,3 +13,19 @@
* FIX: Fixed Evernote Api (uses GET for request and access tokens)
* REFACTOR: URLEncoding stuff. LinkedIn specific decoder is no longer needed
* FEATURE: Added Google example
[1.0.9]
* FEATURE: Token made Serializable
* FIX: Google Api encoding issues (thanks @roger and @klakegg)
[1.1.0]
* FEATURE: OAuth 2.0 Support and Facebook support out of the box (thanks Diego Silveira)
* REFACTOR: Api creation and OAuthService refactors
* REFACTOR: Connections are created lazily (just before sending the request)
[1.1.1]
* 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)
+7 -1
View File
@@ -4,7 +4,7 @@
<groupId>org.scribe</groupId>
<artifactId>scribe</artifactId>
<packaging>jar</packaging>
<version>1.0.8</version>
<version>1.1.0</version>
<name>Scribe OAuth Library</name>
<description>The best OAuth library out there</description>
<url>http://github.com/fernandezpablo85/scribe-java</url>
@@ -22,6 +22,12 @@
<email>fernandezpablo85@gmail.com</email>
<timezone>-3</timezone>
</developer>
<developer>
<id>diegossilveira</id>
<name>Diego Silveira</name>
<email>diegossilveira@gmail.com</email>
<timezone>-3</timezone>
</developer>
</developers>
<licenses>
@@ -2,7 +2,6 @@ package org.scribe.builder;
import org.scribe.builder.api.*;
import org.scribe.exceptions.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
import org.scribe.utils.*;
@@ -57,6 +56,21 @@ public class ServiceBuilder
return api;
}
/**
* Configures the {@link Api}
*
* Overloaded version. Let's you use an instance instead of a class.
*
* @param api instance of {@link Api}s
* @return the {@link ServiceBuilder} instance for method chaining
*/
public ServiceBuilder provider(Api api)
{
Preconditions.checkNotNull(api, "Api cannot be null");
this.api = api;
return this;
}
/**
* Adds an OAuth callback url
*
@@ -119,6 +133,6 @@ public class ServiceBuilder
Preconditions.checkNotNull(api, "You must specify a valid api through the provider() method");
Preconditions.checkEmptyString(apiKey, "You must provide an api key");
Preconditions.checkEmptyString(apiSecret, "You must provide an api secret");
return api.createService(apiKey, apiSecret, callback, scope);
return api.createService(new OAuthConfig(apiKey, apiSecret, callback), scope);
}
}
@@ -1,5 +1,6 @@
package org.scribe.builder.api;
import org.scribe.model.*;
import org.scribe.oauth.*;
/**
@@ -20,5 +21,5 @@ public interface Api
*
* @return fully configured {@link OAuthService}
*/
OAuthService createService(String apiKey, String apiSecret, String callback, String scope);
OAuthService createService(OAuthConfig config, String scope);
}
@@ -8,52 +8,97 @@ import org.scribe.services.*;
/**
* Default implementation of the OAuth protocol, version 1.0a
*
* This class is meant to be extended by concrete implementations of the API.
* This class is meant to be extended by concrete implementations of the API,
* providing the endpoints and endpoint-http-verbs.
*
* If your Api adheres to the 1.0a protocol correctly, you just need to extend
* this class and define the getters for your endpoints.
*
* If your Api does something a bit different, you can override the different
* extractors or services, in order to fine-tune the process. Please read the
* javadocs of the interfaces to get an idea of what to do.
*
* @author Pablo Fernandez
*
*/
public abstract class DefaultApi10a implements Api
{
protected AccessTokenExtractor getAccessTokenExtractor()
/**
* Returns the access token extractor.
*
* @return access token extractor
*/
public AccessTokenExtractor getAccessTokenExtractor()
{
return new TokenExtractorImpl();
}
protected BaseStringExtractor getBaseStringExtractor()
/**
* Returns the base string extractor.
*
* @return base string extractor
*/
public BaseStringExtractor getBaseStringExtractor()
{
return new BaseStringExtractorImpl();
}
protected HeaderExtractor getHeaderExtractor()
/**
* Returns the header extractor.
*
* @return header extractor
*/
public HeaderExtractor getHeaderExtractor()
{
return new HeaderExtractorImpl();
}
protected RequestTokenExtractor getRequestTokenExtractor()
/**
* Returns the request token extractor.
*
* @return request token extractor
*/
public RequestTokenExtractor getRequestTokenExtractor()
{
return new TokenExtractorImpl();
}
protected SignatureService getSignatureService()
/**
* Returns the signature service.
*
* @return signature service
*/
public SignatureService getSignatureService()
{
return new HMACSha1SignatureService();
}
protected TimestampService getTimestampService()
/**
* Returns the timestamp service.
*
* @return timestamp service
*/
public TimestampService getTimestampService()
{
return new TimestampServiceImpl();
}
protected Verb getAccessTokenVerb()
/**
* Returns the verb for the access token endpoint (defaults to POST)
*
* @return access token endpoint verb
*/
public Verb getAccessTokenVerb()
{
return Verb.POST;
}
protected Verb getRequestTokenVerb()
/**
* Returns the verb for the request token endpoint (defaults to POST)
*
* @return request token endpoint verb
*/
public Verb getRequestTokenVerb()
{
return Verb.POST;
}
@@ -63,14 +108,23 @@ public abstract class DefaultApi10a implements Api
*
* @return request token URL
*/
protected abstract String getRequestTokenEndpoint();
public abstract String getRequestTokenEndpoint();
/**
* Returns the URL that receives the access token requests.
*
* @return access token URL
*/
protected abstract String getAccessTokenEndpoint();
public abstract String getAccessTokenEndpoint();
/**
* Returns the URL where you should redirect your users to authenticate
* your application.
*
* @param requestToken the request token you need to authorize
* @return the URL where you should redirect your users
*/
public abstract String getAuthorizationUrl(Token requestToken);
/**
* Returns the {@link OAuthService} for this Api
@@ -80,35 +134,15 @@ public abstract class DefaultApi10a implements Api
* @param callback OAuth callback (either URL or 'oob')
* @param scope OAuth scope (optional)
*/
public OAuthService createService(String apiKey, String apiSecret, String callback, String scope)
public OAuthService createService(OAuthConfig config, String scope)
{
OAuthService service = createService(apiKey, apiSecret, callback);
OAuthService service = doCreateService(config);
service.addScope(scope);
return service;
}
private OAuthService createService(String apiKey, String apiSecret, String callback)
private OAuthService doCreateService(OAuthConfig config)
{
return new OAuth10aServiceImpl( getSignatureService(),
getTimestampService(),
getBaseStringExtractor(),
getHeaderExtractor(),
getRequestTokenExtractor(),
getAccessTokenExtractor(),
createConfig(apiKey, apiSecret, callback));
return new OAuth10aServiceImpl(this, config);
}
private OAuthConfig createConfig(String apiKey, String apiSecret, String callback)
{
OAuthConfig config = new OAuthConfig();
config.setRequestTokenVerb(getRequestTokenVerb());
config.setRequestTokenEndpoint(getRequestTokenEndpoint());
config.setAccessTokenVerb(getAccessTokenVerb());
config.setAccessTokenEndpoint(getAccessTokenEndpoint());
config.setApiKey(apiKey);
config.setApiSecret(apiSecret);
config.setCallback(callback);
return config;
}
}
@@ -0,0 +1,42 @@
package org.scribe.builder.api;
import org.scribe.model.*;
import org.scribe.oauth.*;
/**
* Default implementation of the OAuth protocol, version 2.0 (draft 11)
*
* This class is meant to be extended by concrete implementations of the API,
* providing the endpoints and endpoint-http-verbs.
*
* If your Api adheres to the 2.0 (draft 11) protocol correctly, you just need to extend
* this class and define the getters for your endpoints.
*
* If your Api does something a bit different, you can override the different
* extractors or services, in order to fine-tune the process. Please read the
* javadocs of the interfaces to get an idea of what to do.
*
* @author Diego Silveira
*
*/
public abstract class DefaultApi20 implements Api
{
/**
* Returns the URL where you should redirect your users to authenticate
* your application.
*
* @param config OAuth 2.0 configuration param object
* @return the URL where you should redirect your users
*/
public abstract String getAuthorizationUrl(OAuthConfig config);
/**
* {@inheritDoc}
*/
public OAuthService createService(OAuthConfig config, String scope)
{
return new OAuth20ServiceImpl(this, config);
}
}
@@ -1,11 +1,14 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
import org.scribe.model.Verb;
public class EvernoteApi extends DefaultApi10a
{
private static final String AUTHORIZATION_URL = "https://www.evernote.com/OAuth.action?oauth_token=%s";
@Override
protected Verb getRequestTokenVerb()
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
@@ -17,7 +20,7 @@ public class EvernoteApi extends DefaultApi10a
}
@Override
protected Verb getAccessTokenVerb()
public Verb getAccessTokenVerb()
{
return Verb.GET;
}
@@ -27,4 +30,33 @@ public class EvernoteApi extends DefaultApi10a
{
return "https://www.evernote.com/oauth";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
public static class Sandbox extends EvernoteApi
{
private static final String SANDBOX_URL = "https://sandbox.evernote.com/oauth";
@Override
public String getRequestTokenEndpoint()
{
return SANDBOX_URL;
}
@Override
public String getAccessTokenEndpoint()
{
return SANDBOX_URL;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(SANDBOX_URL + "?oauth_token=%s", requestToken.getToken());
}
}
}
@@ -0,0 +1,16 @@
package org.scribe.builder.api;
import org.scribe.model.*;
import org.scribe.utils.*;
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";
@Override
public String getAuthorizationUrl(OAuthConfig config)
{
Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB");
return String.format(AUTHORIZE_URL, config.getApiKey(), URLUtils.urlEncodeWrapper(config.getCallback()));
}
}
@@ -1,16 +1,26 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class FoursquareApi extends DefaultApi10a
{
private static final String AUTHORIZATION_URL = "http://foursquare.com/oauth/authorize?oauth_token=%s";
@Override
protected String getAccessTokenEndpoint()
public String getAccessTokenEndpoint()
{
return "http://foursquare.com/oauth/access_token";
}
@Override
protected String getRequestTokenEndpoint()
public String getRequestTokenEndpoint()
{
return "http://foursquare.com/oauth/request_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
}
@@ -1,16 +1,38 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class GoogleApi extends DefaultApi10a
{
private static final String AUTHORIZATION_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=%s";
@Override
protected String getAccessTokenEndpoint()
public String getAccessTokenEndpoint()
{
return "https://www.google.com/accounts/OAuthGetAccessToken";
}
@Override
protected String getRequestTokenEndpoint()
public String getRequestTokenEndpoint()
{
return "https://www.google.com/accounts/OAuthGetRequestToken";
}
@Override
public Verb getAccessTokenVerb()
{
return Verb.GET;
}
@Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
}
@@ -1,16 +1,27 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class LinkedInApi extends DefaultApi10a
{
private static final String AUTHORIZE_URL = "https://api.linkedin.com/uas/oauth/authorize?oauth_token=%s";
@Override
protected String getAccessTokenEndpoint()
public String getAccessTokenEndpoint()
{
return "https://api.linkedin.com/uas/oauth/accessToken";
}
@Override
protected String getRequestTokenEndpoint()
public String getRequestTokenEndpoint()
{
return "https://api.linkedin.com/uas/oauth/requestToken";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
}
@@ -1,16 +1,26 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class TwitterApi extends DefaultApi10a
{
private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token=%s";
@Override
protected String getAccessTokenEndpoint()
public String getAccessTokenEndpoint()
{
return "http://api.twitter.com/oauth/access_token";
}
@Override
protected String getRequestTokenEndpoint()
public String getRequestTokenEndpoint()
{
return "http://api.twitter.com/oauth/request_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
}
@@ -1,16 +1,26 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class VimeoApi extends DefaultApi10a
{
private static final String AUTHORIZATION_URL = "http://vimeo.com/oauth/authorize?oauth_token=%s";
@Override
protected String getAccessTokenEndpoint()
public String getAccessTokenEndpoint()
{
return "http://vimeo.com/oauth/access_token";
}
@Override
protected String getRequestTokenEndpoint()
public String getRequestTokenEndpoint()
{
return "http://vimeo.com/oauth/request_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
}
@@ -1,16 +1,26 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class YahooApi extends DefaultApi10a
{
private static final String AUTHORIZE_URL = "https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token=%s";
@Override
protected String getAccessTokenEndpoint()
public String getAccessTokenEndpoint()
{
return "https://api.login.yahoo.com/oauth/v2/get_token";
}
@Override
protected String getRequestTokenEndpoint()
public String getRequestTokenEndpoint()
{
return "https://api.login.yahoo.com/oauth/v2/get_request_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
}
@@ -1,7 +1,10 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class YammerApi extends DefaultApi10a
{
private static final String AUTHORIZATION_URL = "'https://www.yammer.com/oauth/authorize?oauth_token=%s'";
@Override
public String getRequestTokenEndpoint()
@@ -15,4 +18,9 @@ public class YammerApi extends DefaultApi10a
return "https://www.yammer.com/oauth/access_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
}
@@ -32,11 +32,31 @@ public class BaseStringExtractorImpl implements BaseStringExtractor
private String getSortedAndEncodedParams(OAuthRequest request)
{
Map<String, String> params = new HashMap<String, String>();
params.putAll(request.getQueryStringParams());
params.putAll(request.getBodyParams());
params.putAll(request.getOauthParameters());
Map<String, String> tmp = null;
//params.putAll(request.getQueryStringParams());
tmp = request.getQueryStringParams();
for (String key:tmp.keySet()){
params.put(
URLUtils.percentEncode(key),
URLUtils.percentEncode(tmp.get(key))
);
}
tmp = request.getBodyParams();
for (String key:tmp.keySet()){
params.put(
URLUtils.percentEncode(key),
URLUtils.percentEncode(tmp.get(key))
);
}
tmp = request.getOauthParameters();
for (String key:tmp.keySet()){
params.put(
URLUtils.percentEncode(key),
URLUtils.percentEncode(tmp.get(key))
);
}
params = MapUtils.sort(params);
return URLUtils.percentEncode(URLUtils.formURLEncodeMap(params));
return URLUtils.percentEncode(URLUtils.concatSortedPercentEncodedParams(params));
}
private void checkPreconditions(OAuthRequest request)
@@ -27,8 +27,8 @@ public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExt
Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
if (matcher.matches())
{
String token = URLUtils.percentDecode(matcher.group(1));
String secret = URLUtils.percentDecode(matcher.group(2));
String token = URLUtils.urlDecodeWrapper(matcher.group(1));
String secret = URLUtils.urlDecodeWrapper(matcher.group(2));
return new Token(token, secret);
} else
{
+12 -45
View File
@@ -10,10 +10,18 @@ public class OAuthConfig
private String apiKey;
private String apiSecret;
private String callback;
private String requestTokenEndpoint;
private String accessTokenEndpoint;
private Verb requestTokenVerb;
private Verb accessTokenVerb;
public OAuthConfig(String key, String secret)
{
this(key,secret,null);
}
public OAuthConfig(String key, String secret, String callback)
{
this.apiKey = key;
this.apiSecret = secret;
this.callback = callback;
}
public String getApiKey()
{
@@ -44,45 +52,4 @@ public class OAuthConfig
{
this.callback = callback;
}
public String getRequestTokenEndpoint()
{
return requestTokenEndpoint;
}
public void setRequestTokenEndpoint(String requestTokenEndpoint)
{
this.requestTokenEndpoint = requestTokenEndpoint;
}
public String getAccessTokenEndpoint()
{
return accessTokenEndpoint;
}
public void setAccessTokenEndpoint(String accessTokenEndpoint)
{
this.accessTokenEndpoint = accessTokenEndpoint;
}
public Verb getRequestTokenVerb()
{
return requestTokenVerb != null ? requestTokenVerb : Verb.GET;
}
public void setRequestTokenVerb(Verb requestTokenVerb)
{
this.requestTokenVerb = requestTokenVerb;
}
public Verb getAccessTokenVerb()
{
return accessTokenVerb != null ? accessTokenVerb : Verb.GET;
}
public void setAccessTokenVerb(Verb accessTokenVerb)
{
this.accessTokenVerb = accessTokenVerb;
}
}
@@ -38,4 +38,7 @@ public class OAuthConstants
public static final String HEADER = "Authorization";
public static final Token EMPTY_TOKEN = new Token("", "");
public static final String SCOPE = "scope";
//OAuth 2.0
public static final String ACCESS_TOKEN = "access_token";
}
@@ -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<String, String>();
+36 -20
View File
@@ -17,8 +17,9 @@ class Request
{
private static final String CONTENT_LENGTH = "Content-Length";
private String url;
private URL url;
private Verb verb;
private Map<String, String> querystringParams;
private Map<String, String> bodyParams;
private Map<String, String> headers;
private String payload = null;
@@ -29,20 +30,15 @@ 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<String, String>();
this.bodyParams = new HashMap<String, String>();
this.headers = new HashMap<String, String>();
try
{
connection = (HttpURLConnection) new URL(url).openConnection();
} catch (IOException ioe)
{
throw new OAuthException("Could not open connection to: " + url, ioe);
}
}
/**
@@ -56,6 +52,7 @@ class Request
{
try
{
createConnection();
return doSend();
} catch (IOException ioe)
{
@@ -63,6 +60,15 @@ class Request
}
}
private void createConnection() throws IOException
{
String effectiveUrl = URLUtils.appendParametersToQueryString(url.toString(), querystringParams);
if (connection == null)
{
connection = (HttpURLConnection) new URL(effectiveUrl).openConnection();
}
}
Response doSend() throws IOException
{
connection.setRequestMethod(this.verb.name());
@@ -109,6 +115,17 @@ class Request
this.bodyParams.put(key, value);
}
/**
* Add a QueryString parameter
*
* @param key the parameter name
* @param value the parameter value
*/
public void addQuerystringParameter(String key, String value)
{
this.querystringParams.put(key, value);
}
/**
* Add body payload.
*
@@ -130,24 +147,23 @@ class Request
* @return a map containing the query string parameters
*/
public Map<String, String> getQueryStringParams()
{
try
{
Map<String, String> params = new HashMap<String, String>();
String query = new URL(url).getQuery();
String query = url.getQuery();
if (query != null)
{
for (String param : query.split("&"))
{
String pair[] = param.split("=");
params.put(pair[0], pair[1]);
String valuePart = "";
if (pair.length > 1) {
valuePart = URLUtils.urlDecodeWrapper(pair[1]);
}
params.put(URLUtils.urlDecodeWrapper(pair[0]),valuePart );
}
}
params.putAll(querystringParams);
return params;
} catch (MalformedURLException mue)
{
throw new OAuthException("Malformed URL", mue);
}
}
/**
@@ -167,7 +183,7 @@ class Request
*/
public String getUrl()
{
return url;
return url.toString();
}
/**
@@ -177,7 +193,7 @@ class Request
*/
public String getSanitizedUrl()
{
return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", "");
return URLUtils.convertUrlToBaseStringURI(url);
}
/**
+5 -1
View File
@@ -1,12 +1,16 @@
package org.scribe.model;
import java.io.Serializable;
/**
* Represents an OAuth token (either request or access token) and its secret
*
* @author Pablo Fernandez
*/
public class Token
public class Token implements Serializable
{
private static final long serialVersionUID = 715000866082812683L;
private final String token;
private final String secret;
@@ -7,6 +7,7 @@ package org.scribe.model;
*/
public class Verifier
{
private final String value;
/**
@@ -16,6 +17,9 @@ public class Verifier
*/
public Verifier(String value)
{
if (value == null) {
throw new IllegalArgumentException();
}
this.value = value;
}
@@ -1,8 +1,10 @@
package org.scribe.oauth;
import org.scribe.extractors.*;
import java.net.MalformedURLException;
import org.scribe.builder.api.*;
import org.scribe.exceptions.OAuthException;
import org.scribe.model.*;
import org.scribe.services.*;
/**
* OAuth 1.0a implementation of {@link OAuthService}
@@ -15,34 +17,18 @@ public class OAuth10aServiceImpl implements OAuthService
private static final String VERSION = "1.0";
private OAuthConfig config;
private SignatureService signatureService;
private TimestampService timestampService;
private BaseStringExtractor baseStringExtractor;
private HeaderExtractor headerExtractor;
private RequestTokenExtractor rtExtractor;
private AccessTokenExtractor atExtractor;
private DefaultApi10a api;
private String scope;
/**
* Default constructor
*
* @param signatureService OAuth 1.0a signature service
* @param timestampService OAuth 1.0a timestamp service
* @param baseStringExtractor OAuth 1.0a base string extractor
* @param headerExtractor OAuth 1.0a http header extractor
* @param rtExtractor OAuth 1.0a request token extractor
* @param atExtractor OAuth 1.0a access token extractor
* @param api OAuth1.0a api information
* @param config OAuth 1.0a configuration param object
*/
public OAuth10aServiceImpl(SignatureService signatureService, TimestampService timestampService, BaseStringExtractor baseStringExtractor,
HeaderExtractor headerExtractor, RequestTokenExtractor rtExtractor, AccessTokenExtractor atExtractor, OAuthConfig config)
public OAuth10aServiceImpl(DefaultApi10a api, OAuthConfig config)
{
this.signatureService = signatureService;
this.timestampService = timestampService;
this.baseStringExtractor = baseStringExtractor;
this.headerExtractor = headerExtractor;
this.rtExtractor = rtExtractor;
this.atExtractor = atExtractor;
this.api = api;
this.config = config;
this.scope = NO_SCOPE;
}
@@ -52,19 +38,24 @@ public class OAuth10aServiceImpl implements OAuthService
*/
public Token getRequestToken()
{
OAuthRequest request = new OAuthRequest(config.getRequestTokenVerb(), config.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();
return rtExtractor.extract(response.getBody());
return api.getRequestTokenExtractor().extract(response.getBody());
}
private void addOAuthParams(OAuthRequest request, Token token)
{
request.addOAuthParameter(OAuthConstants.TIMESTAMP, timestampService.getTimestampInSeconds());
request.addOAuthParameter(OAuthConstants.NONCE, timestampService.getNonce());
request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds());
request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce());
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, signatureService.getSignatureMethod());
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
if(scope != NO_SCOPE) request.addOAuthParameter(OAuthConstants.SCOPE, scope);
@@ -76,13 +67,18 @@ public class OAuth10aServiceImpl implements OAuthService
*/
public Token getAccessToken(Token requestToken, Verifier verifier)
{
OAuthRequest request = new OAuthRequest(config.getAccessTokenVerb(), config.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);
addOAuthHeader(request);
Response response = request.send();
return atExtractor.extract(response.getBody());
return api.getAccessTokenExtractor().extract(response.getBody());
}
/**
@@ -111,15 +107,23 @@ public class OAuth10aServiceImpl implements OAuthService
this.scope = scope;
}
/**
* {@inheritDoc}
*/
public String getAuthorizationUrl(Token requestToken)
{
return api.getAuthorizationUrl(requestToken);
}
private String getSignature(OAuthRequest request, Token token)
{
String baseString = baseStringExtractor.extract(request);
return signatureService.getSignature(baseString, config.getApiSecret(), token.getSecret());
String baseString = api.getBaseStringExtractor().extract(request);
return api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret());
}
private void addOAuthHeader(OAuthRequest request)
{
String oauthHeader = headerExtractor.extract(request);
String oauthHeader = api.getHeaderExtractor().extract(request);
request.addHeader(OAuthConstants.HEADER, oauthHeader);
}
}
@@ -0,0 +1,73 @@
package org.scribe.oauth;
import org.scribe.builder.api.*;
import org.scribe.model.*;
public class OAuth20ServiceImpl implements OAuthService
{
private static final String VERSION = "2.0";
private final DefaultApi20 api;
private final OAuthConfig config;
/**
* Default constructor
*
* @param api OAuth2.0 api information
* @param config OAuth 2.0 configuration param object
*/
public OAuth20ServiceImpl(DefaultApi20 api, OAuthConfig config)
{
this.api = api;
this.config = config;
}
/**
* {@inheritDoc}
*/
public void addScope(String scope)
{
throw new UnsupportedOperationException("OAuth 2 does not use scopes");
}
/**
* {@inheritDoc}
*/
public Token getAccessToken(Token requestToken, Verifier verifier)
{
throw new UnsupportedOperationException("Unsupported operation, please use 'getAuthorizationUrl' and redirect your users there");
}
/**
* {@inheritDoc}
*/
public Token getRequestToken()
{
throw new UnsupportedOperationException("Unsupported operation, please use 'getAuthorizationUrl' and redirect your users there");
}
/**
* {@inheritDoc}
*/
public String getVersion()
{
return VERSION;
}
/**
* {@inheritDoc}
*/
public void signRequest(Token accessToken, OAuthRequest request)
{
request.addQuerystringParameter(OAuthConstants.ACCESS_TOKEN, accessToken.getToken());
}
/**
* {@inheritDoc}
*/
public String getAuthorizationUrl(Token requestToken)
{
return api.getAuthorizationUrl(config);
}
}
@@ -48,4 +48,13 @@ public interface OAuthService
* @param scope OAuth Api scope (optional)
*/
public void addScope(String scope);
/**
* Returns the URL where you should redirect your users to authenticate
* your application.
*
* @param requestToken the request token you need to authorize
* @return the URL where you should redirect your users
*/
public String getAuthorizationUrl(Token requestToken);
}
@@ -30,7 +30,7 @@ public class HMACSha1SignatureService implements SignatureService
{
Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string");
Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string");
return doSign(baseString, apiSecret + '&' + tokenSecret);
return doSign(baseString, URLUtils.percentEncode(apiSecret) + '&' + URLUtils.percentEncode(tokenSecret));
}
catch (Exception e)
{
@@ -36,7 +36,7 @@ public class StreamUtils
return out.toString();
} catch (IOException ioe)
{
throw new RuntimeException("Error while reading response body", ioe);
throw new IllegalStateException("Error while reading response body", ioe);
}
}
}
+88 -8
View File
@@ -4,8 +4,6 @@ import java.io.*;
import java.net.*;
import java.util.*;
import org.scribe.exceptions.*;
/**
* Utils to deal with URL and url-encodings
*
@@ -17,6 +15,11 @@ public class URLUtils
private static final String UTF_8 = "UTF-8";
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);
@@ -32,7 +35,7 @@ public class URLUtils
}
/**
* Turns a map into a form-url-encoded string (key=value&key2=value2)
* Turns a map into a form-url-encoded string (key=value&key2&key3=value)
*
* @param map any map
* @return form-url-encoded string
@@ -52,7 +55,10 @@ public class URLUtils
{
encodedString.append(PARAM_SEPARATOR);
}
encodedString.append(percentEncode(key)).append(PAIR_SEPARATOR).append(percentEncode(map.get(key)));
encodedString.append(urlEncodeWrapper(key));
if (map.get(key).length() > 0) {
encodedString.append(PAIR_SEPARATOR).append(urlEncodeWrapper(map.get(key)));
}
}
return encodedString.toString();
}
@@ -77,17 +83,36 @@ public class URLUtils
}
catch (UnsupportedEncodingException uee)
{
throw new OAuthException(ERROR_MSG, uee);
throw new IllegalStateException(ERROR_MSG, uee);
}
}
/**
* Percent decodes a string
* URL encodes a string
*
* @param plain
* @return percent encoded string
*/
public static String urlEncodeWrapper(String string)
{
Preconditions.checkNotNull(string, "Cannot encode null string");
try
{
return URLEncoder.encode(string, UTF_8);
}
catch (UnsupportedEncodingException uee)
{
throw new IllegalStateException(ERROR_MSG, uee);
}
}
/**
* URL decodes a string
*
* @param string percent encoded string
* @return plain string
*/
public static String percentDecode(String string)
public static String urlDecodeWrapper(String string)
{
Preconditions.checkNotNull(string, "Cannot decode null string");
try
@@ -96,10 +121,29 @@ public class URLUtils
}
catch (UnsupportedEncodingException uee)
{
throw new OAuthException(ERROR_MSG, uee);
throw new IllegalStateException(ERROR_MSG, uee);
}
}
/**
* Append given parameters to the query string of the url
*
* @param url the url to append parameters to
* @param params any map
* @return new url with parameters on query string
*/
public static String appendParametersToQueryString(String url, Map<String, String> params)
{
Preconditions.checkNotNull(url, "Cannot append to null URL");
String queryString = URLUtils.formURLEncodeMap(params);
if (queryString.length() == 0) 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;
url += queryString;
return url;
}
private static final class EncodingRule
{
private final String ch;
@@ -115,4 +159,40 @@ public class URLUtils
return string.replace(ch, toCh);
}
}
public static String concatSortedPercentEncodedParams(Map<String, String> params) {
StringBuilder target = new StringBuilder();
for (String key:params.keySet()){
target.append(key);
target.append(PAIR_SEPARATOR);
target.append(params.get(key));
target.append(PARAM_SEPARATOR);
}
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();
}
}
@@ -0,0 +1,66 @@
package org.scribe.builder;
import static org.junit.Assert.*;
import org.junit.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class ServiceBuilderTest
{
private ServiceBuilder builder;
@Before
public void setup()
{
builder = new ServiceBuilder();
}
@Test
public void shouldReturnOOBasDefaultCallback()
{
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").build();
assertEquals(ApiMock.config.getApiKey(), "key");
assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.config.getCallback(), OAuthConstants.OUT_OF_BAND);
}
@Test
public void shouldAcceptValidCallbackUrl()
{
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").callback("http://example.com").build();
assertEquals(ApiMock.config.getApiKey(), "key");
assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.config.getCallback(), "http://example.com");
}
@Test(expected=IllegalArgumentException.class)
public void shouldNotAcceptAnInvalidUrlAsCallback()
{
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").callback("example.com").build();
}
@Test
public void shouldAcceptAnScope()
{
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").scope("rss-api").build();
assertEquals(ApiMock.config.getApiKey(), "key");
assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.scope, "rss-api");
}
public static class ApiMock implements Api
{
public static OAuthConfig config;
public static String scope;
@Override
public OAuthService createService(OAuthConfig config, String scope)
{
ApiMock.config = config;
ApiMock.scope = scope;
return null;
}
}
}
@@ -0,0 +1,59 @@
package org.scribe.examples;
import java.net.MalformedURLException;
import java.util.*;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class FacebookExample
{
private static final String NETWORK_NAME = "Facebook";
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;
public static void main(String[] args) throws MalformedURLException
{
// Replace these with your own api key and secret
String apiKey = "your_api_key";
String apiSecret = "your_api_secret";
OAuthService service = new ServiceBuilder()
.provider(FacebookApi.class)
.apiKey(apiKey)
.apiSecret(apiSecret)
.callback("http://www.example.com/oauth_callback/")
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println();
// Obtain the Authorization URL
System.out.println("Fetching the Authorization URL...");
String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN);
System.out.println("Got the Authorization URL!");
System.out.println("Now go and authorize Scribe here:");
System.out.println(authorizationUrl);
System.out.println("And paste the access token here");
System.out.print(">>");
Token accessToken = new Token(in.nextLine(), NO_SECRET_NEEDED);
System.out.println();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL);
service.signRequest(accessToken, request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getCode());
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
}
}
@@ -1,5 +1,6 @@
package org.scribe.examples;
import java.net.MalformedURLException;
import java.util.Scanner;
import org.scribe.builder.*;
@@ -9,10 +10,9 @@ import org.scribe.oauth.*;
public class FoursquareExample
{
private static final String AUTHORIZE_URL = "http://foursquare.com/oauth/authorize?oauth_token=";
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)
@@ -31,7 +31,7 @@ public class FoursquareExample
System.out.println();
System.out.println("Now go and authorize Scribe here:");
System.out.println(AUTHORIZE_URL + requestToken.getToken());
System.out.println(service.getAuthorizationUrl(requestToken));
System.out.println("And paste the verifier here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
@@ -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)
@@ -1,5 +1,6 @@
package org.scribe.examples;
import java.net.MalformedURLException;
import java.util.Scanner;
import org.scribe.builder.*;
@@ -9,18 +10,17 @@ import org.scribe.oauth.*;
public class LinkedInExample
{
private static final String AUTHORIZE_URL = "https://api.linkedin.com/uas/oauth/authorize?oauth_token=";
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)
.apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV")
.apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6")
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== LinkedIn's OAuth Workflow ===");
System.out.println();
@@ -31,7 +31,7 @@ public class LinkedInExample
System.out.println();
System.out.println("Now go and authorize Scribe here:");
System.out.println(AUTHORIZE_URL + requestToken.getToken());
System.out.println(service.getAuthorizationUrl(requestToken));
System.out.println("And paste the verifier here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
@@ -1,5 +1,6 @@
package org.scribe.examples;
import java.net.MalformedURLException;
import java.util.Scanner;
import org.scribe.builder.*;
@@ -9,10 +10,9 @@ import org.scribe.oauth.*;
public class TwitterExample
{
private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token=";
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)
@@ -31,7 +31,7 @@ public class TwitterExample
System.out.println();
System.out.println("Now go and authorize Scribe here:");
System.out.println(AUTHORIZE_URL + requestToken.getToken());
System.out.println(service.getAuthorizationUrl(requestToken));
System.out.println("And paste the verifier here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
@@ -1,5 +1,6 @@
package org.scribe.examples;
import java.net.MalformedURLException;
import java.util.Scanner;
import org.scribe.builder.*;
@@ -9,11 +10,9 @@ import org.scribe.oauth.*;
public class YahooExample
{
private static final String NETWORK_NAME = "Yahoo";
private static final String AUTHORIZE_URL = "https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token=";
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)
@@ -22,7 +21,7 @@ public class YahooExample
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println("=== Yahoo's OAuth Workflow ===");
System.out.println();
// Obtain the Request Token
@@ -32,7 +31,7 @@ public class YahooExample
System.out.println();
System.out.println("Now go and authorize Scribe here:");
System.out.println(AUTHORIZE_URL + requestToken.getToken());
System.out.println(service.getAuthorizationUrl(requestToken));
System.out.println("And paste the verifier here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
@@ -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
@@ -28,6 +34,14 @@ public class BaseStringExtractorTest
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);
@@ -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);
@@ -10,22 +10,17 @@ public class OAuthConfigTest
@Test
public void shouldReturnDefaultValuesIfNotSet()
{
OAuthConfig config = new OAuthConfig();
assertEquals(Verb.GET, config.getAccessTokenVerb());
assertEquals(Verb.GET, config.getRequestTokenVerb());
OAuthConfig config = new OAuthConfig("key", "secret");
assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback());
}
@Test
public void shouldOverrideDefaultsIfSet()
{
OAuthConfig config = new OAuthConfig();
config.setCallback("http://callback");
config.setAccessTokenVerb(Verb.POST);
config.setRequestTokenVerb(Verb.POST);
OAuthConfig config = new OAuthConfig("key", "secret", "http://callback");
assertEquals("http://callback", config.getCallback());
assertEquals(Verb.POST, config.getAccessTokenVerb());
assertEquals(Verb.POST, config.getRequestTokenVerb());
assertEquals("key", config.getApiKey());
assertEquals("secret", config.getApiSecret());
}
}
@@ -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");
}
@@ -2,6 +2,8 @@ package org.scribe.model;
import static org.junit.Assert.*;
import java.net.MalformedURLException;
import org.junit.*;
public class RequestTest
@@ -17,7 +19,7 @@ public class RequestTest
connection = new ConnectionStub();
postRequest = new Request(Verb.POST, "http://example.com");
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);
}
@@ -34,6 +36,8 @@ public class RequestTest
assertEquals(2, getRequest.getQueryStringParams().size());
assertEquals(0, postRequest.getQueryStringParams().size());
assertTrue(getRequest.getQueryStringParams().containsKey("qsparam"));
assertTrue(getRequest.getQueryStringParams().get("qsparam").equals("value"));
assertTrue(getRequest.getQueryStringParams().get("other param").equals("value with spaces"));
}
@Test
@@ -52,7 +56,7 @@ public class RequestTest
postRequest.addBodyParameter("param", "value");
postRequest.addBodyParameter("param two", "value with spaces");
postRequest.send();
assertEquals("param%20two=value%20with%20spaces&param=value", postRequest.getBodyContents());
assertEquals("param+two=value+with+spaces&param=value", postRequest.getBodyContents());
assertTrue(connection.getHeaders().containsKey("Content-Length"));
}
@@ -65,4 +69,46 @@ public class RequestTest
assertTrue(connection.getHeaders().containsKey("Content-Length"));
}
@Test
public void shouldAllowAddingQuerystringParametersAfterCreation() throws MalformedURLException
{
Request request = new Request(Verb.GET, "http://example.com?one=val");
request.addQuerystringParameter("two", "other val");
request.addQuerystringParameter("more", "params");
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());
}
}
@@ -0,0 +1,14 @@
package org.scribe.model;
import org.junit.*;
public class VerifierTest
{
@Test(expected = IllegalArgumentException.class)
public void shouldThrowErrorForNullString()
{
new Verifier(null);
}
}
@@ -3,7 +3,7 @@ package org.scribe.services;
import static org.junit.Assert.*;
import org.junit.*;
import org.scribe.exceptions.OAuthException;
import org.scribe.exceptions.*;
public class HMACSha1SignatureServiceTest
{
@@ -29,7 +29,7 @@ public class HMACSha1SignatureServiceTest
String apiSecret = "api secret";
String tokenSecret = "token secret";
String baseString = "base string";
String signature = "cyxvUDZY/5cQBcBiKulaNgnhN/w=";
String signature = "uGymw2KHOTWI699YEaoi5xyLT50=";
assertEquals(signature, service.getSignature(baseString, apiSecret, tokenSecret));
}
@@ -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;
}
}
@@ -16,7 +16,7 @@ public class URLUtilsTest
params.put("key with spaces", "value with spaces");
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));
}
@@ -41,7 +41,7 @@ public class URLUtilsTest
{
String toDecode = "this+is+a+test+%26%5E";
String expected = "this is a test &^";
assertEquals(expected, URLUtils.percentDecode(toDecode));
assertEquals(expected, URLUtils.urlDecodeWrapper(toDecode));
}
@Test
@@ -50,7 +50,7 @@ public class URLUtilsTest
String plain = "!*'();:@&=+$,/?#[]";
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(plain, URLUtils.percentDecode(encoded));
assertEquals(plain, URLUtils.urlDecodeWrapper(encoded));
}
@Test
@@ -79,7 +79,69 @@ public class URLUtilsTest
public void shouldThrowExceptionIfStringToDecodeIsNull()
{
String toDecode = null;
URLUtils.percentDecode(toDecode);
URLUtils.urlDecodeWrapper(toDecode);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenAppendingNullMapToQuerystring()
{
String url = "http://www.example.com";
Map<String, String> nullMap = null;
URLUtils.appendParametersToQueryString(url, nullMap);
}
@Test
public void shouldAppendNothingToQuerystringIfGivenEmptyMap()
{
String url = "http://www.example.com";
Map<String, String> emptyMap = new HashMap<String, String>();
String newUrl = URLUtils.appendParametersToQueryString(url, emptyMap);
Assert.assertEquals(url, newUrl);
}
@Test
public void shouldAppendParametersToSimpleUrl()
{
String url = "http://www.example.com";
String expectedUrl = "http://www.example.com?param1=value1&param2=value+with+spaces";
Map<String, String> params = new HashMap<String, String>();
params.put("param1", "value1");
params.put("param2", "value with spaces");
url = URLUtils.appendParametersToQueryString(url, params);
Assert.assertEquals(url, expectedUrl);
}
@Test
public void shouldAppendParametersToUrlWithQuerystring()
{
String url = "http://www.example.com?already=present";
String expectedUrl = "http://www.example.com?already=present&param1=value1&param2=value+with+spaces";
Map<String, String> params = new HashMap<String, String>();
params.put("param1", "value1");
params.put("param2", "value with spaces");
url = URLUtils.appendParametersToQueryString(url, params);
Assert.assertEquals(url, expectedUrl);
}
@Test
public void shouldEncodePlusSymbol()
{
String plain = "7aEP+jNAwvjc0mjhqg0nuXPf";
String encoded = "7aEP%2BjNAwvjc0mjhqg0nuXPf";
Assert.assertEquals(encoded, URLUtils.percentEncode(plain));
}
@Test
public void shouldDecodePlusSymbol()
{
String encoded = "oauth_verifier=7aEP%2BjNAwvjc0mjhqg0nuXPf";
String expected = "oauth_verifier=7aEP+jNAwvjc0mjhqg0nuXPf";
Assert.assertEquals(expected, URLUtils.urlDecodeWrapper(encoded));
}
}