75 Commits
Author SHA1 Message Date
Pablo Fernandez 97f45d75e7 bounced version numbers for release 2011-05-04 12:00:45 -03:00
Pablo Fernandez 624fdfb714 removed unused statics 2011-04-29 15:08:35 -03:00
Pablo Fernandez bd51ae9f25 Added plaintext signature for Yammer Api and fixed fucked up indentation 2011-04-29 15:05:09 -03:00
Pablo Fernandez 40ab98d506 added Twitter SSL support 2011-04-27 11:44:55 -03:00
Pablo Fernandez 0abe7f80d4 fixed bug in facebook url generation 2011-04-25 19:21:00 -03:00
Pablo Fernandez 592b1b5fdd Added scope to facebook api 2011-04-25 13:24:11 -03:00
Pablo Fernandez 2112d3d8a9 Added scopes to 2.0 apis 2011-04-25 13:23:37 -03:00
Pablo Fernandez 109c93b4e4 Moved scope inside OAuthConfig 2011-04-25 13:15:25 -03:00
Pablo Fernandez 41b6da1a44 bounced version on pom.xml 2011-04-19 22:59:30 -03:00
Pablo Fernandez 91cb9b8407 changed readme to last version 2011-04-19 22:56:59 -03:00
Pablo Fernandez c265e730a3 removed auto-generated comments 2011-04-19 22:52:36 -03:00
Matthew Laudato 5719d7a18a Support for ConstantContact REST API 2011-04-19 22:42:25 -03:00
Pablo Fernandez 8abdde928a added convenience methods for the builder api 2011-04-19 22:32:32 -03:00
Pablo Fernandez 193dcd2e25 added SignatureType and querystring signing functionallity 2011-04-19 22:17:23 -03:00
Pablo Fernandez 931236561a rename method
to support both querystring and header signatures
2011-04-19 22:04:06 -03:00
Pablo Fernandez 5f40e0dca0 removed unused extractor (JsonTokenExtractor handles this) 2011-04-19 21:51:36 -03:00
Tom Tasche 8afb142b7f Add Foursquare2 API and example 2011-04-19 21:50:12 -03:00
Pablo Fernandez bfcf0655da added Dropbox Api 2011-04-13 19:03:56 -03:00
Pablo Fernandez db88d53807 made extractor independent of token/secret order 2011-04-13 19:02:45 -03:00
Pablo Fernandez cbfd88d749 removed picture from readme since link is broken 2011-04-11 14:06:39 -03:00
Pablo Fernandez 1eb0b1003c Added raw string to Token, for retrieving additional parameters 2011-04-11 14:06:08 -03:00
Stuart Grimshaw 75bcb0013d Added Lovefilm Api and example 2011-03-30 00:37:44 -03:00
Stuart Grimshaw 145c009fc3 Fix for HttpUrlConnection on pre-Gingerbread Android devices 2011-03-30 00:24:12 -03:00
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
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
53 changed files with 1444 additions and 295 deletions

No files matched your search

+10 -4
View File
@@ -1,5 +1,3 @@
!http://img411.imageshack.us/img411/2851/scribelogo.png!
h2. Welcome to the home of Scribe, the simple OAuth Java lib! h2. Welcome to the home of Scribe, the simple OAuth Java lib!
h1. Why use Scribe? h1. Why use Scribe?
@@ -20,10 +18,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
@@ -32,6 +32,12 @@ h3. Supports all major OAuth APIs out-of-the-box
* Foursquare * 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 * 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 h3. Small and modular
@@ -55,7 +61,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.2.0</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
+32
View File
@@ -18,3 +18,35 @@
* FEATURE: Token made Serializable * FEATURE: Token made Serializable
* FIX: Google Api encoding issues (thanks @roger and @klakegg) * 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)
* 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.3]
* FEATURE: Added rawResponse to Token, for extracting additional parameters (thanks Dirk McCormick)
* FEATURE: Added Dropbox Api
* FIX: Token responses now work despite of the token/secret order
* FEATURE: Added Foursquare OAuth 2.0 Api (thanks Tom Tasche)
* FEATURE: Added support for OAuth1.0a signatures via querystring parameters
* FEATURE: Added ConstantContact Api (thanks Matthew Laudato)
[1.2]
* REFACTOR: Moved scope inside OAuthConfig (breaks backwards compatibility)
* FEATURE: Added scopes to Facebook 2.0 Api
* FEATURE: Added Plaintext signature for Yammer
* FEATURE: Added Twitter SSL endpoints (use TwitterApi.SSL.class)
+7 -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.0.9</version> <version>1.2.0</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>
@@ -22,6 +22,12 @@
<email>fernandezpablo85@gmail.com</email> <email>fernandezpablo85@gmail.com</email>
<timezone>-3</timezone> <timezone>-3</timezone>
</developer> </developer>
<developer>
<id>diegossilveira</id>
<name>Diego Silveira</name>
<email>diegossilveira@gmail.com</email>
<timezone>-3</timezone>
</developer>
</developers> </developers>
<licenses> <licenses>
@@ -2,7 +2,6 @@ package org.scribe.builder;
import org.scribe.builder.api.*; import org.scribe.builder.api.*;
import org.scribe.exceptions.*; import org.scribe.exceptions.*;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.oauth.*; import org.scribe.oauth.*;
import org.scribe.utils.*; import org.scribe.utils.*;
@@ -21,6 +20,7 @@ public class ServiceBuilder
private String callback; private String callback;
private Api api; private Api api;
private String scope; private String scope;
private SignatureType signatureType;
/** /**
* Default constructor * Default constructor
@@ -56,7 +56,22 @@ public class ServiceBuilder
} }
return api; 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 * Adds an OAuth callback url
* *
@@ -108,6 +123,19 @@ public class ServiceBuilder
this.scope = scope; this.scope = scope;
return this; return this;
} }
/**
* Configures the signature type, choose between header, querystring, etc. Defaults to Header
*
* @param scope The OAuth scope
* @return the {@link ServiceBuilder} instance for method chaining
*/
public ServiceBuilder signatureType(SignatureType type)
{
Preconditions.checkNotNull(type, "Signature type can't be null");
this.signatureType = type;
return this;
}
/** /**
* Returns the fully configured {@link OAuthService} * Returns the fully configured {@link OAuthService}
@@ -119,6 +147,6 @@ public class ServiceBuilder
Preconditions.checkNotNull(api, "You must specify a valid api through the provider() method"); Preconditions.checkNotNull(api, "You must specify a valid api through the provider() method");
Preconditions.checkEmptyString(apiKey, "You must provide an api key"); Preconditions.checkEmptyString(apiKey, "You must provide an api key");
Preconditions.checkEmptyString(apiSecret, "You must provide an api secret"); Preconditions.checkEmptyString(apiSecret, "You must provide an api secret");
return api.createService(apiKey, apiSecret, callback, scope); return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope));
} }
} }
@@ -1,5 +1,6 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.*;
import org.scribe.oauth.*; import org.scribe.oauth.*;
/** /**
@@ -20,5 +21,5 @@ public interface Api
* *
* @return fully configured {@link OAuthService} * @return fully configured {@link OAuthService}
*/ */
OAuthService createService(String apiKey, String apiSecret, String callback, String scope); OAuthService createService(OAuthConfig config);
} }
@@ -0,0 +1,26 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class ConstantContactApi extends DefaultApi10a
{
private static final String AUTHORIZE_URL = "https://oauth.constantcontact.com/ws/oauth/confirm_access?oauth_token=%s";
@Override
public String getAccessTokenEndpoint()
{
return "https://oauth.constantcontact.com/ws/oauth/access_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
@Override
public String getRequestTokenEndpoint()
{
return "https://oauth.constantcontact.com/ws/oauth/request_token";
}
}
@@ -8,52 +8,97 @@ import org.scribe.services.*;
/** /**
* Default implementation of the OAuth protocol, version 1.0a * 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 * If your Api adheres to the 1.0a protocol correctly, you just need to extend
* this class and define the getters for your endpoints. * 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 * @author Pablo Fernandez
* *
*/ */
public abstract class DefaultApi10a implements Api public abstract class DefaultApi10a implements Api
{ {
/**
protected AccessTokenExtractor getAccessTokenExtractor() * Returns the access token extractor.
*
* @return access token extractor
*/
public AccessTokenExtractor getAccessTokenExtractor()
{ {
return new TokenExtractorImpl(); return new TokenExtractorImpl();
} }
protected BaseStringExtractor getBaseStringExtractor() /**
* Returns the base string extractor.
*
* @return base string extractor
*/
public BaseStringExtractor getBaseStringExtractor()
{ {
return new BaseStringExtractorImpl(); return new BaseStringExtractorImpl();
} }
protected HeaderExtractor getHeaderExtractor() /**
* Returns the header extractor.
*
* @return header extractor
*/
public HeaderExtractor getHeaderExtractor()
{ {
return new HeaderExtractorImpl(); return new HeaderExtractorImpl();
} }
protected RequestTokenExtractor getRequestTokenExtractor() /**
* Returns the request token extractor.
*
* @return request token extractor
*/
public RequestTokenExtractor getRequestTokenExtractor()
{ {
return new TokenExtractorImpl(); return new TokenExtractorImpl();
} }
protected SignatureService getSignatureService() /**
* Returns the signature service.
*
* @return signature service
*/
public SignatureService getSignatureService()
{ {
return new HMACSha1SignatureService(); return new HMACSha1SignatureService();
} }
protected TimestampService getTimestampService() /**
* Returns the timestamp service.
*
* @return timestamp service
*/
public TimestampService getTimestampService()
{ {
return new TimestampServiceImpl(); 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; 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; return Verb.POST;
} }
@@ -63,14 +108,23 @@ public abstract class DefaultApi10a implements Api
* *
* @return request token URL * @return request token URL
*/ */
protected abstract String getRequestTokenEndpoint(); public abstract String getRequestTokenEndpoint();
/** /**
* Returns the URL that receives the access token requests. * Returns the URL that receives the access token requests.
* *
* @return access token URL * @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 * Returns the {@link OAuthService} for this Api
@@ -80,35 +134,8 @@ public abstract class DefaultApi10a implements Api
* @param callback OAuth callback (either URL or 'oob') * @param callback OAuth callback (either URL or 'oob')
* @param scope OAuth scope (optional) * @param scope OAuth scope (optional)
*/ */
public OAuthService createService(String apiKey, String apiSecret, String callback, String scope) public OAuthService createService(OAuthConfig config)
{ {
OAuthService service = createService(apiKey, apiSecret, callback); return new OAuth10aServiceImpl(this, config);
service.addScope(scope);
return service;
} }
private OAuthService createService(String apiKey, String apiSecret, String callback)
{
return new OAuth10aServiceImpl( getSignatureService(),
getTimestampService(),
getBaseStringExtractor(),
getHeaderExtractor(),
getRequestTokenExtractor(),
getAccessTokenExtractor(),
createConfig(apiKey, apiSecret, callback));
}
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,70 @@
package org.scribe.builder.api;
import org.scribe.extractors.*;
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 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
* 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)
{
return new OAuth20ServiceImpl(this, config);
}
}
@@ -0,0 +1,25 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class DropBoxApi extends DefaultApi10a
{
@Override
public String getAccessTokenEndpoint()
{
return "https://api.dropbox.com/0/oauth/access_token";
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return "https://www.dropbox.com/0/oauth/authorize?oauth_token="+requestToken.getToken();
}
@Override
public String getRequestTokenEndpoint()
{
return "https://api.dropbox.com/0/oauth/request_token";
}
}
@@ -1,11 +1,14 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.Token;
import org.scribe.model.Verb; import org.scribe.model.Verb;
public class EvernoteApi extends DefaultApi10a public class EvernoteApi extends DefaultApi10a
{ {
private static final String AUTHORIZATION_URL = "https://www.evernote.com/OAuth.action?oauth_token=%s";
@Override @Override
protected Verb getRequestTokenVerb() public Verb getRequestTokenVerb()
{ {
return Verb.GET; return Verb.GET;
} }
@@ -17,7 +20,7 @@ public class EvernoteApi extends DefaultApi10a
} }
@Override @Override
protected Verb getAccessTokenVerb() public Verb getAccessTokenVerb()
{ {
return Verb.GET; return Verb.GET;
} }
@@ -27,4 +30,33 @@ public class EvernoteApi extends DefaultApi10a
{ {
return "https://www.evernote.com/oauth"; 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,34 @@
package org.scribe.builder.api;
import org.scribe.model.*;
import org.scribe.utils.*;
import static org.scribe.utils.URLUtils.*;
public class FacebookApi extends DefaultApi20
{
private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";
@Override
public String getAccessTokenEndpoint()
{
return "https://graph.facebook.com/oauth/access_token";
}
@Override
public String getAuthorizationUrl(OAuthConfig config)
{
Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB");
// Append scope if present
if(config.hasScope())
{
return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), formURLEncode(config.getCallback()), formURLEncode(config.getScope()));
}
else
{
return String.format(AUTHORIZE_URL, config.getApiKey(), formURLEncode(config.getCallback()));
}
}
}
@@ -0,0 +1,29 @@
package org.scribe.builder.api;
import org.scribe.extractors.*;
import org.scribe.model.*;
import org.scribe.utils.*;
public class Foursquare2Api extends DefaultApi20
{
private static final String AUTHORIZATION_URL = "https://foursquare.com/oauth2/authenticate?client_id=%s&response_type=code&redirect_uri=%s";
@Override
public String getAccessTokenEndpoint()
{
return "https://foursquare.com/oauth2/access_token?grant_type=authorization_code";
}
@Override
public String getAuthorizationUrl(OAuthConfig config)
{
Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Foursquare2 does not support OOB");
return String.format(AUTHORIZATION_URL, config.getApiKey(), URLUtils.formURLEncode(config.getCallback()));
}
@Override
public AccessTokenExtractor getAccessTokenExtractor()
{
return new JsonTokenExtractor();
}
}
@@ -1,16 +1,26 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.Token;
public class FoursquareApi extends DefaultApi10a public class FoursquareApi extends DefaultApi10a
{ {
private static final String AUTHORIZATION_URL = "http://foursquare.com/oauth/authorize?oauth_token=%s";
@Override @Override
protected String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "http://foursquare.com/oauth/access_token"; return "http://foursquare.com/oauth/access_token";
} }
@Override @Override
protected String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "http://foursquare.com/oauth/request_token"; return "http://foursquare.com/oauth/request_token";
} }
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
} }
@@ -4,27 +4,35 @@ import org.scribe.model.*;
public class GoogleApi extends DefaultApi10a public class GoogleApi extends DefaultApi10a
{ {
private static final String AUTHORIZATION_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=%s";
@Override @Override
protected String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "https://www.google.com/accounts/OAuthGetAccessToken"; return "https://www.google.com/accounts/OAuthGetAccessToken";
} }
@Override @Override
protected String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "https://www.google.com/accounts/OAuthGetRequestToken"; return "https://www.google.com/accounts/OAuthGetRequestToken";
} }
@Override @Override
protected Verb getAccessTokenVerb() public Verb getAccessTokenVerb()
{ {
return Verb.GET; return Verb.GET;
} }
@Override @Override
protected Verb getRequestTokenVerb() public Verb getRequestTokenVerb()
{ {
return Verb.GET; 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; package org.scribe.builder.api;
import org.scribe.model.*;
public class LinkedInApi extends DefaultApi10a public class LinkedInApi extends DefaultApi10a
{ {
private static final String AUTHORIZE_URL = "https://api.linkedin.com/uas/oauth/authorize?oauth_token=%s";
@Override @Override
protected String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "https://api.linkedin.com/uas/oauth/accessToken"; return "https://api.linkedin.com/uas/oauth/accessToken";
} }
@Override @Override
protected String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "https://api.linkedin.com/uas/oauth/requestToken"; return "https://api.linkedin.com/uas/oauth/requestToken";
} }
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
} }
@@ -0,0 +1,28 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class LoveFilmApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "http://openapi.lovefilm.com/oauth/request_token";
private static final String ACCESS_TOKEN_URL = "http://openapi.lovefilm.com/oauth/access_token";
private static final String AUTHORIZE_URL = "https://www.lovefilm.com/activate?oauth_token=%s";
@Override
public String getRequestTokenEndpoint()
{
return REQUEST_TOKEN_URL;
}
@Override
public String getAccessTokenEndpoint()
{
return ACCESS_TOKEN_URL;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
}
@@ -1,16 +1,43 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.Token;
public class TwitterApi extends DefaultApi10a public class TwitterApi extends DefaultApi10a
{ {
private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token=%s";
private static final String REQUEST_TOKEN_RESOURCE = "api.twitter.com/oauth/request_token";
private static final String ACCESS_TOKEN_RESOURCE = "api.twitter.com/oauth/access_token";
@Override @Override
protected String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "http://api.twitter.com/oauth/access_token"; return "http://" + ACCESS_TOKEN_RESOURCE;
} }
@Override @Override
protected String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "http://api.twitter.com/oauth/request_token"; return "http://" + REQUEST_TOKEN_RESOURCE;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
public static class SSL extends TwitterApi
{
@Override
public String getAccessTokenEndpoint()
{
return "https://" + ACCESS_TOKEN_RESOURCE;
}
@Override
public String getRequestTokenEndpoint()
{
return "https://" + REQUEST_TOKEN_RESOURCE;
}
} }
} }
@@ -1,16 +1,26 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.Token;
public class VimeoApi extends DefaultApi10a public class VimeoApi extends DefaultApi10a
{ {
private static final String AUTHORIZATION_URL = "http://vimeo.com/oauth/authorize?oauth_token=%s";
@Override @Override
protected String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "http://vimeo.com/oauth/access_token"; return "http://vimeo.com/oauth/access_token";
} }
@Override @Override
protected String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "http://vimeo.com/oauth/request_token"; 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; package org.scribe.builder.api;
import org.scribe.model.Token;
public class YahooApi extends DefaultApi10a public class YahooApi extends DefaultApi10a
{ {
private static final String AUTHORIZE_URL = "https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token=%s";
@Override @Override
protected String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "https://api.login.yahoo.com/oauth/v2/get_token"; return "https://api.login.yahoo.com/oauth/v2/get_token";
} }
@Override @Override
protected String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "https://api.login.yahoo.com/oauth/v2/get_request_token"; 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,18 +1,33 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.*;
import org.scribe.services.*;
public class YammerApi extends DefaultApi10a public class YammerApi extends DefaultApi10a
{ {
private static final String AUTHORIZATION_URL = "'https://www.yammer.com/oauth/authorize?oauth_token=%s'";
@Override @Override
public String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "https://www.yammer.com/oauth/request_token"; return "https://www.yammer.com/oauth/request_token";
} }
@Override @Override
public String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "https://www.yammer.com/oauth/access_token"; return "https://www.yammer.com/oauth/access_token";
} }
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
@Override
public SignatureService getSignatureService()
{
return new PlaintextSignatureService();
}
} }
@@ -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,28 @@
package org.scribe.extractors;
import java.util.regex.*;
import org.scribe.exceptions.*;
import org.scribe.model.*;
import org.scribe.utils.*;
public class JsonTokenExtractor implements AccessTokenExtractor
{
private Pattern accessTokenPattern = Pattern.compile("\"access_token\":\"(\\S*)\"");
@Override
public Token extract(String response)
{
Preconditions.checkEmptyString(response, "Cannot extract a token from a null or empty String");
Matcher matcher = accessTokenPattern.matcher(response);
if(matcher.find())
{
return new Token(matcher.group(1), "");
}
else
{
throw new OAuthException("Cannot extract an acces token. Response was: "+response);
}
}
}
@@ -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, response);
}
else
{
throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
}
}
}
@@ -15,7 +15,8 @@ import org.scribe.utils.*;
*/ */
public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExtractor public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExtractor
{ {
private static final String TOKEN_REGEX = "oauth_token=(\\S*)&oauth_token_secret=(\\S*?)(&(.*))?"; private static final Pattern TOKEN_REGEX = Pattern.compile("oauth_token=([^&]+)");
private static final Pattern SECRET_REGEX = Pattern.compile("oauth_token_secret=([^&]+)");
/** /**
* {@inheritDoc} * {@inheritDoc}
@@ -23,16 +24,21 @@ public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExt
public Token extract(String response) public Token extract(String response)
{ {
Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string"); Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string");
String token = extract(response, TOKEN_REGEX);
String secret = extract(response, SECRET_REGEX);
return new Token(token, secret, response);
}
Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response); private String extract(String response, Pattern p)
if (matcher.matches()) {
Matcher matcher = p.matcher(response);
if (matcher.find() && matcher.groupCount() >= 1)
{ {
String token = URLUtils.percentDecode(matcher.group(1)); return URLUtils.formURLDecode(matcher.group(1));
String secret = URLUtils.percentDecode(matcher.group(2)); }
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 token and secret from this: '" + response + "'", null);
} }
} }
} }
+26 -55
View File
@@ -7,82 +7,53 @@ package org.scribe.model;
*/ */
public class OAuthConfig public class OAuthConfig
{ {
private String apiKey; private final String apiKey;
private String apiSecret; private final String apiSecret;
private String callback; private final String callback;
private String requestTokenEndpoint; private final SignatureType signatureType;
private String accessTokenEndpoint; private final String scope;
private Verb requestTokenVerb;
private Verb accessTokenVerb; public OAuthConfig(String key, String secret)
{
this(key, secret, null, null, null);
}
public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope)
{
this.apiKey = key;
this.apiSecret = secret;
this.callback = callback != null ? callback : OAuthConstants.OUT_OF_BAND;
this.signatureType = (type != null) ? type : SignatureType.Header;
this.scope = scope;
}
public String getApiKey() public String getApiKey()
{ {
return apiKey; return apiKey;
} }
public void setApiKey(String apiKey)
{
this.apiKey = apiKey;
}
public String getApiSecret() public String getApiSecret()
{ {
return apiSecret; return apiSecret;
} }
public void setApiSecret(String apiSecret)
{
this.apiSecret = apiSecret;
}
public String getCallback() public String getCallback()
{ {
return callback != null ? callback : OAuthConstants.OUT_OF_BAND; return callback;
} }
public void setCallback(String callback) public SignatureType getSignatureType()
{ {
this.callback = callback; return signatureType;
} }
public String getRequestTokenEndpoint() public String getScope()
{ {
return requestTokenEndpoint; return scope;
} }
public void setRequestTokenEndpoint(String requestTokenEndpoint) public boolean hasScope()
{ {
this.requestTokenEndpoint = requestTokenEndpoint; return scope != null;
} }
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,12 @@ public class OAuthConstants
public static final String HEADER = "Authorization"; public static final String HEADER = "Authorization";
public static final Token EMPTY_TOKEN = new Token("", ""); public static final Token EMPTY_TOKEN = new Token("", "");
public static final String SCOPE = "scope"; public static final String SCOPE = "scope";
//OAuth 2.0
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";
} }
+30 -17
View File
@@ -19,6 +19,7 @@ class Request
private String url; private String url;
private Verb verb; private Verb verb;
private Map<String, String> querystringParams;
private Map<String, String> bodyParams; private Map<String, String> bodyParams;
private Map<String, String> headers; private Map<String, String> headers;
private String payload = null; private String payload = null;
@@ -34,15 +35,9 @@ class Request
{ {
this.verb = verb; this.verb = verb;
this.url = url; this.url = url;
this.querystringParams = new HashMap<String, String>();
this.bodyParams = new HashMap<String, String>(); this.bodyParams = new HashMap<String, String>();
this.headers = 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 +51,7 @@ class Request
{ {
try try
{ {
createConnection();
return doSend(); return doSend();
} catch (IOException ioe) } catch (IOException ioe)
{ {
@@ -63,6 +59,16 @@ class Request
} }
} }
private void createConnection() throws IOException
{
String effectiveUrl = URLUtils.appendParametersToQueryString(url, querystringParams);
if (connection == null)
{
System.setProperty("http.keepAlive", "false");
connection = (HttpURLConnection) new URL(effectiveUrl).openConnection();
}
}
Response doSend() throws IOException Response doSend() throws IOException
{ {
connection.setRequestMethod(this.verb.name()); connection.setRequestMethod(this.verb.name());
@@ -109,6 +115,17 @@ class Request
this.bodyParams.put(key, value); 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. * Add body payload.
* *
@@ -128,23 +145,19 @@ 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]);
}
}
return params; return params;
} catch (MalformedURLException mue) }
catch (MalformedURLException mue)
{ {
throw new OAuthException("Malformed URL", mue); throw new OAuthException("Malformed URL", mue);
} }
@@ -0,0 +1,7 @@
package org.scribe.model;
public enum SignatureType
{
Header,
QueryString
}
+16
View File
@@ -13,6 +13,7 @@ public class Token implements Serializable
private final String token; private final String token;
private final String secret; private final String secret;
private final String rawResponse;
/** /**
* Default constructor * Default constructor
@@ -21,9 +22,15 @@ public class Token implements Serializable
* @param secret token secret * @param secret token secret
*/ */
public Token(String token, String secret) public Token(String token, String secret)
{
this(token, secret, null);
}
public Token(String token, String secret, String rawResponse)
{ {
this.token = token; this.token = token;
this.secret = secret; this.secret = secret;
this.rawResponse = rawResponse;
} }
public String getToken() public String getToken()
@@ -36,6 +43,15 @@ public class Token implements Serializable
return secret; return secret;
} }
public String getRawResponse()
{
if (rawResponse == null)
{
throw new IllegalStateException("This token object was not constructed by scribe and does not have a rawResponse");
}
return rawResponse;
}
@Override @Override
public String toString() public String toString()
{ {
+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()
@@ -1,8 +1,9 @@
package org.scribe.oauth; package org.scribe.oauth;
import org.scribe.extractors.*; import java.util.*;
import org.scribe.builder.api.*;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.services.*;
/** /**
* OAuth 1.0a implementation of {@link OAuthService} * OAuth 1.0a implementation of {@link OAuthService}
@@ -11,40 +12,21 @@ import org.scribe.services.*;
*/ */
public class OAuth10aServiceImpl implements OAuthService public class OAuth10aServiceImpl implements OAuthService
{ {
private static final String NO_SCOPE = null;
private static final String VERSION = "1.0"; private static final String VERSION = "1.0";
private OAuthConfig config; private OAuthConfig config;
private SignatureService signatureService; private DefaultApi10a api;
private TimestampService timestampService;
private BaseStringExtractor baseStringExtractor;
private HeaderExtractor headerExtractor;
private RequestTokenExtractor rtExtractor;
private AccessTokenExtractor atExtractor;
private String scope;
/** /**
* Default constructor * Default constructor
* *
* @param signatureService OAuth 1.0a signature service * @param api OAuth1.0a api information
* @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 config OAuth 1.0a configuration param object * @param config OAuth 1.0a configuration param object
*/ */
public OAuth10aServiceImpl(SignatureService signatureService, TimestampService timestampService, BaseStringExtractor baseStringExtractor, public OAuth10aServiceImpl(DefaultApi10a api, OAuthConfig config)
HeaderExtractor headerExtractor, RequestTokenExtractor rtExtractor, AccessTokenExtractor atExtractor, OAuthConfig config)
{ {
this.signatureService = signatureService; this.api = api;
this.timestampService = timestampService;
this.baseStringExtractor = baseStringExtractor;
this.headerExtractor = headerExtractor;
this.rtExtractor = rtExtractor;
this.atExtractor = atExtractor;
this.config = config; this.config = config;
this.scope = NO_SCOPE;
} }
/** /**
@@ -52,22 +34,22 @@ public class OAuth10aServiceImpl implements OAuthService
*/ */
public Token getRequestToken() public Token getRequestToken()
{ {
OAuthRequest request = new OAuthRequest(config.getRequestTokenVerb(), config.getRequestTokenEndpoint()); OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback()); request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
if(scope != NO_SCOPE) request.addOAuthParameter(OAuthConstants.SCOPE, scope);
addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
addOAuthHeader(request); addSignature(request);
Response response = request.send(); Response response = request.send();
return rtExtractor.extract(response.getBody()); return api.getRequestTokenExtractor().extract(response.getBody());
} }
private void addOAuthParams(OAuthRequest request, Token token) private void addOAuthParams(OAuthRequest request, Token token)
{ {
request.addOAuthParameter(OAuthConstants.TIMESTAMP, timestampService.getTimestampInSeconds()); request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds());
request.addOAuthParameter(OAuthConstants.NONCE, timestampService.getNonce()); request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce());
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey()); 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.VERSION, getVersion());
if(config.hasScope()) request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token)); request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
} }
@@ -76,13 +58,13 @@ public class OAuth10aServiceImpl implements OAuthService
*/ */
public Token getAccessToken(Token requestToken, Verifier verifier) public Token getAccessToken(Token requestToken, Verifier verifier)
{ {
OAuthRequest request = new OAuthRequest(config.getAccessTokenVerb(), config.getAccessTokenEndpoint()); OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken());
request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue());
addOAuthParams(request, requestToken); addOAuthParams(request, requestToken);
addOAuthHeader(request); addSignature(request);
Response response = request.send(); Response response = request.send();
return atExtractor.extract(response.getBody()); return api.getAccessTokenExtractor().extract(response.getBody());
} }
/** /**
@@ -92,7 +74,7 @@ public class OAuth10aServiceImpl implements OAuthService
{ {
request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken()); request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken());
addOAuthParams(request, token); addOAuthParams(request, token);
addOAuthHeader(request); addSignature(request);
} }
/** /**
@@ -106,20 +88,31 @@ public class OAuth10aServiceImpl implements OAuthService
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public void addScope(String scope) public String getAuthorizationUrl(Token requestToken)
{ {
this.scope = scope; return api.getAuthorizationUrl(requestToken);
} }
private String getSignature(OAuthRequest request, Token token) private String getSignature(OAuthRequest request, Token token)
{ {
String baseString = baseStringExtractor.extract(request); String baseString = api.getBaseStringExtractor().extract(request);
return signatureService.getSignature(baseString, config.getApiSecret(), token.getSecret()); return api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret());
} }
private void addOAuthHeader(OAuthRequest request) private void addSignature(OAuthRequest request)
{ {
String oauthHeader = headerExtractor.extract(request); switch (config.getSignatureType())
request.addHeader(OAuthConstants.HEADER, oauthHeader); {
case Header:
String oauthHeader = api.getHeaderExtractor().extract(request);
request.addHeader(OAuthConstants.HEADER, oauthHeader);
break;
case QueryString:
for (Map.Entry<String, String> entry : request.getOauthParameters().entrySet())
{
request.addQuerystringParameter(entry.getKey(), entry.getValue());
}
break;
}
} }
} }
@@ -0,0 +1,72 @@
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 Token getAccessToken(Token requestToken, Verifier verifier)
{
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());
if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
Response response = request.send();
return api.getAccessTokenExtractor().extract(response.getBody());
}
/**
* {@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);
}
}
@@ -41,11 +41,13 @@ public interface OAuthService
* @return oauth version as string * @return oauth version as string
*/ */
public String getVersion(); public String getVersion();
/** /**
* Adds the 'scope' parameter. This is **not** a default OAuth parameter and the setting is optional. * Returns the URL where you should redirect your users to authenticate
* your application.
* *
* @param scope OAuth Api scope (optional) * @param requestToken the request token you need to authorize
* @return the URL where you should redirect your users
*/ */
public void addScope(String scope); public String getAuthorizationUrl(Token requestToken);
} }
@@ -0,0 +1,40 @@
package org.scribe.services;
import org.scribe.exceptions.*;
import org.scribe.utils.*;
/**
* plaintext implementation of {@SignatureService}
*
* @author Pablo Fernandez
*
*/
public class PlaintextSignatureService implements SignatureService
{
private static final String METHOD = "plaintext";
/**
* {@inheritDoc}
*/
public String getSignature(String baseString, String apiSecret, String tokenSecret)
{
try
{
Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string");
return URLUtils.percentEncode(apiSecret) + '&' + URLUtils.percentEncode(tokenSecret);
}
catch (Exception e)
{
throw new OAuthSignatureException(baseString, e);
}
}
/**
* {@inheritDoc}
*/
public String getSignatureMethod()
{
return METHOD;
}
}
@@ -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)));
}
}
} }
@@ -36,7 +36,7 @@ public class StreamUtils
return out.toString(); return out.toString();
} catch (IOException ioe) } catch (IOException ioe)
{ {
throw new RuntimeException("Error while reading response body", ioe); throw new IllegalStateException("Error while reading response body", ioe);
} }
} }
} }
+97 -23
View File
@@ -4,19 +4,18 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import org.scribe.exceptions.*;
/** /**
* Utils to deal with URL and url-encodings * Utils to deal with URL and url-encodings
* *
* @author Pablo Fernandez * @author Pablo Fernandez
*/ */
public class URLUtils 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 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);
@@ -32,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
@@ -48,46 +47,57 @@ 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)
{ {
throw new OAuthException(ERROR_MSG, uee); throw new IllegalStateException(ERROR_MSG, uee);
} }
} }
/** /**
* 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
@@ -96,10 +106,74 @@ public class URLUtils
} }
catch (UnsupportedEncodingException uee) 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.equals(EMPTY_STRING))
{
return url;
}
else
{
url += url.indexOf(QUERY_STRING_SEPARATOR) != -1 ? PARAM_SEPARATOR : QUERY_STRING_SEPARATOR;
url += queryString;
return url;
}
}
/**
* Concats a key-value map into a querystring-like String
*
* @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
{ {
private final String ch; private final String ch;
@@ -0,0 +1,74 @@
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 shouldReturnConfigDefaultValues()
{
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);
assertEquals(ApiMock.config.getSignatureType(), SignatureType.Header);
}
@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
public void shouldAcceptASignatureType()
{
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").signatureType(SignatureType.QueryString).build();
assertEquals(ApiMock.config.getApiKey(), "key");
assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.config.getSignatureType(), SignatureType.QueryString);
}
@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.config.getScope(), "rss-api");
}
public static class ApiMock implements Api
{
public static OAuthConfig config;
@Override
public OAuthService createService(OAuthConfig config)
{
ApiMock.config = config;
return null;
}
}
}
@@ -0,0 +1,64 @@
package org.scribe.examples;
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 Token EMPTY_TOKEN = null;
public static void main(String[] args)
{
// Replace these with your own api key and secret
String apiKey = "your_app_id";
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 authorization code here");
System.out.print(">>");
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();
// 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! :)");
}
}
@@ -0,0 +1,63 @@
package org.scribe.examples;
import java.util.*;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class Foursquare2Example
{
private static final String PROTECTED_RESOURCE_URL = "https://api.foursquare.com/v2/users/self/friends?oauth_token=";
private static final Token EMPTY_TOKEN = null;
public static void main(String[] args)
{
// Replace these with your own api key and secret
String apiKey = "FEGFXJUFANVVDHVSNUAMUKTTXCP1AJQD53E33XKJ44YP1S4I";
String apiSecret = "AYWKUL5SWPNC0CTQ202QXRUG2NLZYXMRA34ZSDW4AUYBG2RC";
OAuthService service = new ServiceBuilder()
.provider(Foursquare2Api.class)
.apiKey(apiKey)
.apiSecret(apiSecret)
.callback("http://localhost:9000/")
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== Foursquare2'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 authorization code here");
System.out.print(">>");
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();
// 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 + accessToken.getToken());
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! :)");
}
}
@@ -9,7 +9,6 @@ import org.scribe.oauth.*;
public class FoursquareExample 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"; 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)
@@ -31,7 +30,7 @@ public class FoursquareExample
System.out.println(); System.out.println();
System.out.println("Now go and authorize Scribe here:"); 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.println("And paste the verifier here");
System.out.print(">>"); System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine()); Verifier verifier = new Verifier(in.nextLine());
@@ -9,18 +9,17 @@ import org.scribe.oauth.*;
public class LinkedInExample 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)"; 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)
{ {
OAuthService service = new ServiceBuilder() OAuthService service = new ServiceBuilder()
.provider(LinkedInApi.class) .provider(LinkedInApi.class)
.apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV") .apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV")
.apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6") .apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6")
.build(); .build();
Scanner in = new Scanner(System.in); Scanner in = new Scanner(System.in);
System.out.println("=== LinkedIn's OAuth Workflow ==="); System.out.println("=== LinkedIn's OAuth Workflow ===");
System.out.println(); System.out.println();
@@ -31,7 +30,7 @@ public class LinkedInExample
System.out.println(); System.out.println();
System.out.println("Now go and authorize Scribe here:"); 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.println("And paste the verifier here");
System.out.print(">>"); System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine()); Verifier verifier = new Verifier(in.nextLine());
@@ -0,0 +1,64 @@
package org.scribe.examples;
import java.util.*;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class LoveFilmExample
{
private static final String NETWORK_NAME = "LoveFilm";
private static final String PROTECTED_RESOURCE_URL = "https://api.lovefilm.com/users";
public static void main(String[] args)
{
// Replace these with your own api key and secret
String apiKey = "your_key";
String apiSecret = "your_secret";
OAuthService service = new ServiceBuilder().provider(LoveFilmApi.class).apiKey(apiKey).apiSecret(apiSecret).build();
Scanner in = new Scanner(System.in);
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println();
// Grab a request token.
System.out.println("Fetching request token.");
Token requestToken = service.getRequestToken();
System.out.println("Got it ... ");
System.out.println(requestToken.getToken());
// Obtain the Authorization URL
System.out.println("Fetching the Authorization URL...");
String authorizationUrl = service.getAuthorizationUrl(requestToken);
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 authorization code here");
System.out.print(">>");
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(requestToken, verifier);
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
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! :)");
}
}
@@ -9,7 +9,6 @@ import org.scribe.oauth.*;
public class TwitterExample 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"; 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)
@@ -31,7 +30,7 @@ public class TwitterExample
System.out.println(); System.out.println();
System.out.println("Now go and authorize Scribe here:"); 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.println("And paste the verifier here");
System.out.print(">>"); System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine()); Verifier verifier = new Verifier(in.nextLine());
@@ -9,20 +9,18 @@ import org.scribe.oauth.*;
public class YahooExample 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"; 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)
{ {
OAuthService service = new ServiceBuilder() OAuthService service = new ServiceBuilder()
.provider(YahooApi.class) .provider(YahooApi.class)
.apiKey("dj0yJmk9TXZDWVpNVVdGaVFmJmQ9WVdrOWMweHZXbkZLTkhVbWNHbzlNVEl5TWprd05qUTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0wMw--") .apiKey("dj0yJmk9TXZDWVpNVVdGaVFmJmQ9WVdrOWMweHZXbkZLTkhVbWNHbzlNVEl5TWprd05qUTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0wMw--")
.apiSecret("262be559f92a2be20c4c039419018f2b48cdfce9") .apiSecret("262be559f92a2be20c4c039419018f2b48cdfce9")
.build(); .build();
Scanner in = new Scanner(System.in); Scanner in = new Scanner(System.in);
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); System.out.println("=== Yahoo's OAuth Workflow ===");
System.out.println(); System.out.println();
// Obtain the Request Token // Obtain the Request Token
@@ -32,7 +30,7 @@ public class YahooExample
System.out.println(); System.out.println();
System.out.println("Now go and authorize Scribe here:"); 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.println("And paste the verifier here");
System.out.print(">>"); System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine()); Verifier verifier = new Verifier(in.nextLine());
@@ -0,0 +1,31 @@
package org.scribe.extractors;
import static org.junit.Assert.*;
import org.junit.*;
import org.scribe.model.*;
public class JsonTokenExtractorTest
{
private String response = "'{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T3X\"}'";
private JsonTokenExtractor extractor = new JsonTokenExtractor();
@Test
public void shouldParseResponse()
{
Token token = extractor.extract(response);
assertEquals(token.getToken(), "I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T3X");
}
@Test(expected=IllegalArgumentException.class)
public void shouldThrowExceptionIfForNullParameters()
{
extractor.extract(null);
}
@Test(expected=IllegalArgumentException.class)
public void shouldThrowExceptionIfForEmptyStrings()
{
extractor.extract("");
}
}
@@ -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);
}
}
@@ -26,6 +26,15 @@ public class TokenExtractorTest
assertEquals("hdhd0244k9j7ao03", extracted.getSecret()); assertEquals("hdhd0244k9j7ao03", extracted.getSecret());
} }
@Test
public void shouldExtractTokenFromInvertedOAuthStandardResponse()
{
String response = "oauth_token_secret=hh5s93j4hdidpola&oauth_token=hdhd0244k9j7ao03";
Token extracted = extractor.extract(response);
assertEquals("hh5s93j4hdidpola", extracted.getSecret());
assertEquals("hdhd0244k9j7ao03", extracted.getToken());
}
@Test @Test
public void shouldExtractTokenFromResponseWithCallbackConfirmed() public void shouldExtractTokenFromResponseWithCallbackConfirmed()
{ {
@@ -10,22 +10,19 @@ public class OAuthConfigTest
@Test @Test
public void shouldReturnDefaultValuesIfNotSet() public void shouldReturnDefaultValuesIfNotSet()
{ {
OAuthConfig config = new OAuthConfig(); OAuthConfig config = new OAuthConfig("key", "secret");
assertEquals(Verb.GET, config.getAccessTokenVerb());
assertEquals(Verb.GET, config.getRequestTokenVerb());
assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback()); assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback());
assertEquals(SignatureType.Header, config.getSignatureType());
assertFalse(config.hasScope());
} }
@Test @Test
public void shouldOverrideDefaultsIfSet() public void shouldOverrideDefaultsIfSet()
{ {
OAuthConfig config = new OAuthConfig(); OAuthConfig config = new OAuthConfig("key", "secret", "http://callback", SignatureType.Header, "scope");
config.setCallback("http://callback");
config.setAccessTokenVerb(Verb.POST);
config.setRequestTokenVerb(Verb.POST);
assertEquals("http://callback", config.getCallback()); assertEquals("http://callback", config.getCallback());
assertEquals(Verb.POST, config.getAccessTokenVerb()); assertEquals("key", config.getApiKey());
assertEquals(Verb.POST, config.getRequestTokenVerb()); assertEquals("secret", config.getApiSecret());
} }
} }
@@ -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"));
} }
@@ -65,4 +66,18 @@ public class RequestTest
assertTrue(connection.getHeaders().containsKey("Content-Length")); assertTrue(connection.getHeaders().containsKey("Content-Length"));
} }
@Test
public void shouldAllowAddingQuerystringParametersAfterCreation()
{
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 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,69 @@ 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)
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 shouldPercentEncodePlusSymbol()
{
String plain = "7aEP+jNAwvjc0mjhqg0nuXPf";
String encoded = "7aEP%2BjNAwvjc0mjhqg0nuXPf";
Assert.assertEquals(encoded, URLUtils.percentEncode(plain));
}
@Test
public void shouldURLDecodePlusSymbol()
{
String encoded = "oauth_verifier=7aEP%2BjNAwvjc0mjhqg0nuXPf";
String expected = "oauth_verifier=7aEP+jNAwvjc0mjhqg0nuXPf";
Assert.assertEquals(expected, URLUtils.formURLDecode(encoded));
}
} }