103 Commits
Author SHA1 Message Date
Pablo Fernandez 0a63f935d2 added 'debug' method to service builder 2011-12-16 16:13:57 -03:00
Pablo Fernandez 61c0b4cc9f getCompleteUrl method for getting the whole url (host+resource+querystring) 2011-12-14 17:50:02 -03:00
Pablo Fernandez 3f366589ea bounced version numbers 2011-12-14 17:22:19 -03:00
Pablo Fernandez 83b62f6079 removed URLUtils 2011-12-14 16:18:06 -03:00
Pablo Fernandez b380b3af3d removed MapUtils 2011-12-14 15:46:07 -03:00
Pablo Fernandez ce531cdc38 first step towards ParameterList refactoring 2011-12-14 13:31:12 -03:00
Pablo Fernandez 56561acdac added reference to stackoverflow tag 2011-11-30 18:00:08 -03:00
Pablo Fernandez 05988a63cd Twitter examples about percent encoding
see: https://dev.twitter.com/docs/auth/percent-encoding-parameters
2011-11-07 15:36:13 -03:00
Pablo Fernandez 611c6464f2 added SimpleGeo Api to changelog 2011-09-25 23:32:20 -03:00
Pablo Fernandez 7fba153218 fixed mistake in changelog, soundcloud is going to be in release 2.0 2011-09-25 23:30:50 -03:00
Pablo Fernandez 9070edd20a bounced version numbers for release 2011-09-25 23:22:19 -03:00
liuce 78fd342d92 Added Kaixin and QWeibo Apis 2011-09-25 20:28:58 -03:00
Pablo Fernandez 7510111d28 changed method name for javabean convention 2011-09-25 20:12:53 -03:00
Pablo Fernandez 852368e0a7 Sapo Api support 2011-09-25 20:12:23 -03:00
Pablo Fernandez dbf00c9227 added features to changelog 2011-09-25 20:12:23 -03:00
Pablo Fernandez ce139bb28b Merge pull request #147 from dreamcwli/master
Mobile Plurk Api
2011-09-25 16:11:49 -07:00
Pablo Fernandez 40c8a27bb0 SimpleGeo Api (just for 2 Legged OAuth) 2011-09-25 19:26:38 -03:00
Pablo Fernandez ae3a1b11c9 added default content type 2011-09-25 19:14:57 -03:00
Pablo Fernandez 24babbae02 better error messages when scribe can't establish a network connection 2011-09-25 16:37:49 -03:00
Pablo Fernandez 9f4569fbbc made token extraction regex easier and added a test case for multiple parameters 2011-09-24 16:56:07 -03:00
Pablo Fernandez 7e7d3ff7e0 Twitter's /authenticate endpoint 2011-09-19 18:43:22 -03:00
Pablo Fernandez dcd13835ba moved map functions to MapUtils 2011-08-29 10:53:38 -03:00
Pablo Fernandez daf45d7078 documented changes so far 2011-08-29 10:53:38 -03:00
Pablo Fernandez 8a7336b7d4 added intellij ignores 2011-08-29 10:53:00 -03:00
Pablo Fernandez 207df8a3d4 Merge pull request #150 from sripathikrishnan/master
Scribe Release - 1.2.2
2011-08-29 06:43:04 -07:00
Sripathi Krishnan 4f8315f7f7 Bumping release number in pom.xml snippet in README 2011-08-29 16:59:20 +05:30
Sripathi Krishnan e719c73d92 Bumping release version to 1.2.2 2011-08-29 16:52:42 +05:30
Chia-Wei Li c6bff31353 Move MobilePlurkApi into PlurkApi 2011-08-27 19:32:16 +08:00
Chia-Wei Li 27b1fc390b Fix MobilePlurkApi naming 2011-08-25 13:43:10 +08:00
Chia-Wei Li b917140078 Merge remote-tracking branch 'upstream/master' 2011-08-25 13:24:52 +08:00
Chia-Wei Li 9cdebd1ca6 Add Mobile Plurk API 2011-08-25 11:28:38 +08:00
Pablo Fernandez 2238c2da51 Merge pull request #146 from sripathikrishnan/master
Issue # 145 : Change source and target compatibility to 1.5
2011-08-23 06:03:55 -07:00
Sripathi Krishnan bf9a4bac68 Issue # 145 : Changing source and target compatibility to 1.5
This allows the library to be used in JDK 5 as well as JDK 6
2011-08-23 16:12:33 +05:30
Pablo Fernandez d8e384f9c7 Merge pull request #137 from wscoble/live-example-eclipse-fix
fixed "invalid character constant" message from eclipse
2011-08-08 12:44:45 -07:00
Scott Scoble 35ca23f442 fixed "invalid character constant" message from eclipse 2011-08-08 00:28:23 -07:00
Pablo Fernandez 93602c4120 Merge pull request #135 from tomaslin/master
Windows Live oAuth Support
2011-08-02 09:04:26 -07:00
Tomas Lin 62b43855c2 wrapped line format 2011-08-02 15:56:43 +01:00
Tomas Lin a62fa36da0 added windows live support and example 2011-08-02 13:05:54 +01:00
Chia-Wei Li 0390ae7eb7 Fix naming convention 2011-07-20 19:47:32 +08:00
Pablo Fernandez 1d59fbd014 Merge pull request #130 from dreamcwli/master
Add Plurk API
2011-07-18 05:56:13 -07:00
Chia-Wei Li 79fa710e47 Fix code style 2011-07-17 14:01:31 +08:00
Chia-Wei Li 079ce6a2c2 Add Plurk API 2011-07-17 11:48:16 +08:00
Pablo Fernandez c86d7174af Merge pull request #124 from thepizzle/master
fixed NPE when setting connection timeouts.
2011-06-29 19:19:31 -07:00
Pablo Fernandez 5f47bebced bounced version number for release 2011-06-27 12:18:58 -03:00
ThePizzle 10c56bda27 Fix indentation and remove commented code 2011-06-09 09:23:33 -04:00
ThePizzle 1be46776e5 Set timeout parameters in doSend() to avoid NPE 2011-06-08 17:15:53 -04:00
Pablo Fernandez cc5a0a0471 missing entry on changelog 2011-06-03 16:49:30 -03:00
Pablo Fernandez 0c3fc722b1 enable persistent http connections 2011-06-03 16:46:16 -03:00
Arthur Wang 203cf83dc0 Added Sohu Weibo api and example. 2011-06-03 10:56:37 -03:00
Arthur Wang 7b587c3d1d Added Netease Weibo(t.163.com) api and example. 2011-06-03 10:50:17 -03:00
Arthur Wang f89279c682 Added Sina Weibo Api and example. 2011-06-03 10:46:29 -03:00
Pablo Fernandez 7b6b9056d3 multipart request support 2011-06-02 09:31:39 -03:00
Boris ca7950004b Implemented Vkontakte.ru support 2011-05-25 18:40:57 -03:00
Pablo Fernandez 543b53475f changelog charset update 2011-05-07 13:18:52 -03:00
Pablo Fernandez de1ac1f467 request charset handling 2011-05-07 13:15:35 -03:00
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
69 changed files with 2172 additions and 544 deletions

No files matched your search

+5
View File
@@ -5,6 +5,11 @@
.project .project
.settings .settings
# IntelliJ Idea settings
.idea
scribe.iml
# Binaries # Binaries
target target
+12 -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
@@ -38,6 +38,8 @@ h3. Supports all major OAuth APIs out-of-the-box
* Yammer * Yammer
* Windows Live
* 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
@@ -61,7 +63,7 @@ You can pull scribe from a maven repository, just add this to your __pom.xml__ f
@<dependency>@ @<dependency>@
@<groupId>org.scribe</groupId>@ @<groupId>org.scribe</groupId>@
@<artifactId>scribe</artifactId>@ @<artifactId>scribe</artifactId>@
@<version>1.0.6</version>@ @<version>1.3.0</version>@
@</dependency>@ @</dependency>@
h1. Getting started in less than 2 minutes h1. Getting started in less than 2 minutes
@@ -70,6 +72,12 @@ Check the "Getting Started":http://wiki.github.com/fernandezpablo85/scribe-java/
h1. Please Read the "FAQ":http://wiki.github.com/fernandezpablo85/scribe-java/faq before creating an issue :) h1. Please Read the "FAQ":http://wiki.github.com/fernandezpablo85/scribe-java/faq before creating an issue :)
h1. Questions?
Feel free to drop me an email, but there's already a "StackOvferflow":http://stackoverflow.com tag for "scribe":http://stackoverflow.com/questions/tagged/scribe you should use. I'm subscribed to it so I'll pick the question immediately.
Note that it really helps to run scribe on **debug** mode (since 1.3.0), to get additional info. To do this simply call the @.debug()@ method on the @ServiceBuilder@.
h1. About me h1. About me
"LinkedIn profile":http://www.linkedin.com/in/fernandezpablo85 "LinkedIn profile":http://www.linkedin.com/in/fernandezpablo85
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
mvn source:jar javadoc:jar package gpg:sign repository:bundle-create -Dgpg.passphrase=$1
+47
View File
@@ -24,3 +24,50 @@
* FEATURE: OAuth 2.0 Support and Facebook support out of the box (thanks Diego Silveira) * FEATURE: OAuth 2.0 Support and Facebook support out of the box (thanks Diego Silveira)
* REFACTOR: Api creation and OAuthService refactors * REFACTOR: Api creation and OAuthService refactors
* REFACTOR: Connections are created lazily (just before sending the request) * 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)
[1.2.1]
* FEATURE: Added custom charset support to Request (thanks Eric Genet)
* FEATURE: Added support for Vkontakte (thanks dotbg)
* FEATURE: Added Sohu Weibo, Netease Weibo & Sina Weibo Apis (thanks Arthur Wang)
* FEATURE: Added support for persistent Http Connections (thanks Craig Minton)
[1.2.2]
* FIX: Added support for JDK 1.5. Issue #146 (thanks Sripathi Krishnan)
* FIX: Invalid character constant error message. Issue #137 (thanks Scott Scoble)
* FEATURE: Added a Api class to handle windows live authentication. Issue #135 (thanks Tomas Lin)
* FEATURE: Added refresh token feature for Yahoo! API. Issue #134 (thanks Aaron Foltz)
* FEATURE: Added support for Plurk API. Issue #130 (thanks Chia-Wei Li)
* FIX: Request.setConnectTimeout() and setReadTimeout() throw NPE. Issue #123 (thanks thepizzle)
[1.2.3]
* FEATURE: Added default Content-Type header
* FEATURE: Sapo Api
* FEATURE: Plurk Mobile Api
* FEATURE: Kaixin and QWeibo Apis
* FEATURE: SimpleGeo Api
+3 -3
View File
@@ -4,7 +4,7 @@
<groupId>org.scribe</groupId> <groupId>org.scribe</groupId>
<artifactId>scribe</artifactId> <artifactId>scribe</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>1.1.0</version> <version>1.3.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>
@@ -63,8 +63,8 @@
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<source>1.6</source> <source>1.5</source>
<target>1.6</target> <target>1.5</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@@ -1,5 +1,6 @@
package org.scribe.builder; package org.scribe.builder;
import java.io.*;
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.*;
@@ -20,6 +21,8 @@ public class ServiceBuilder
private String callback; private String callback;
private Api api; private Api api;
private String scope; private String scope;
private SignatureType signatureType;
private OutputStream debugStream;
/** /**
* Default constructor * Default constructor
@@ -27,6 +30,8 @@ public class ServiceBuilder
public ServiceBuilder() public ServiceBuilder()
{ {
this.callback = OAuthConstants.OUT_OF_BAND; this.callback = OAuthConstants.OUT_OF_BAND;
this.signatureType = SignatureType.Header;
this.debugStream = null;
} }
/** /**
@@ -56,6 +61,21 @@ 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 +128,32 @@ public class ServiceBuilder
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;
}
public ServiceBuilder debugStream(OutputStream stream)
{
Preconditions.checkNotNull(stream, "debug stream can't be null");
this.debugStream = stream;
return this;
}
public ServiceBuilder debug()
{
this.debugStream(System.out);
return this;
}
/** /**
* Returns the fully configured {@link OAuthService} * Returns the fully configured {@link OAuthService}
* *
@@ -118,6 +164,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(new OAuthConfig(apiKey, apiSecret, callback), scope); return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, debugStream));
} }
} }
@@ -21,5 +21,5 @@ public interface Api
* *
* @return fully configured {@link OAuthService} * @return fully configured {@link OAuthService}
*/ */
OAuthService createService(OAuthConfig config, 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";
}
}
@@ -134,14 +134,7 @@ 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(OAuthConfig config, String scope) public OAuthService createService(OAuthConfig config)
{
OAuthService service = doCreateService(config);
service.addScope(scope);
return service;
}
private OAuthService doCreateService(OAuthConfig config)
{ {
return new OAuth10aServiceImpl(this, config); return new OAuth10aServiceImpl(this, config);
} }
@@ -1,5 +1,6 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.extractors.*;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.oauth.*; import org.scribe.oauth.*;
@@ -22,6 +23,33 @@ import org.scribe.oauth.*;
public abstract class DefaultApi20 implements Api public abstract class DefaultApi20 implements Api
{ {
/**
* Returns the access token extractor.
*
* @return access token extractor
*/
public AccessTokenExtractor getAccessTokenExtractor()
{
return new TokenExtractor20Impl();
}
/**
* Returns the verb for the access token endpoint (defaults to GET)
*
* @return access token endpoint verb
*/
public Verb getAccessTokenVerb()
{
return Verb.GET;
}
/**
* Returns the URL that receives the access token requests.
*
* @return access token URL
*/
public abstract String getAccessTokenEndpoint();
/** /**
* Returns the URL where you should redirect your users to authenticate * Returns the URL where you should redirect your users to authenticate
* your application. * your application.
@@ -34,7 +62,7 @@ public abstract class DefaultApi20 implements Api
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public OAuthService createService(OAuthConfig config, String scope) public OAuthService createService(OAuthConfig config)
{ {
return new OAuth20ServiceImpl(this, 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,16 +1,33 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.utils.*; import org.scribe.utils.*;
public class FacebookApi extends DefaultApi20 public class FacebookApi extends DefaultApi20
{ {
private static final String AUTHORIZE_URL = "https://graph.facebook.com/oauth/authorize?response_type=token&client_id=%s&redirect_uri=%s"; private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";
@Override
public String getAccessTokenEndpoint()
{
return "https://graph.facebook.com/oauth/access_token";
}
@Override @Override
public String getAuthorizationUrl(OAuthConfig config) public String getAuthorizationUrl(OAuthConfig config)
{ {
Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB"); Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB");
return String.format(AUTHORIZE_URL, config.getApiKey(), URLUtils.percentEncode(config.getCallback()));
// Append scope if present
if(config.hasScope())
{
return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope()));
}
else
{
return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(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(), OAuthEncoder.encode(config.getCallback()));
}
@Override
public AccessTokenExtractor getAccessTokenExtractor()
{
return new JsonTokenExtractor();
}
}
@@ -0,0 +1,40 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class KaixinApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "http://api.kaixin001.com/oauth/request_token";
private static final String ACCESS_TOKEN_URL = "http://api.kaixin001.com/oauth/access_token";
private static final String AUTHORIZE_URL = "http://api.kaixin001.com/oauth/authorize?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());
}
@Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
@Override
public Verb getAccessTokenVerb()
{
return Verb.GET;
}
}
@@ -0,0 +1,40 @@
package org.scribe.builder.api;
import org.scribe.extractors.*;
import org.scribe.model.*;
import org.scribe.utils.*;
public class LiveApi extends DefaultApi20
{
private static final String AUTHORIZE_URL = "https://oauth.live.com/authorize?client_id=%s&redirect_uri=%s&response_type=code";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";
@Override
public String getAccessTokenEndpoint()
{
return "https://oauth.live.com/token?grant_type=authorization_code";
}
@Override
public String getAuthorizationUrl(OAuthConfig config)
{
Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Live does not support OOB");
// Append scope if present
if (config.hasScope())
{
return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope()));
}
else
{
return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()));
}
}
@Override
public AccessTokenExtractor getAccessTokenExtractor()
{
return new JsonTokenExtractor();
}
}
@@ -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());
}
}
@@ -0,0 +1,47 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class NeteaseWeibooApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "http://api.t.163.com/oauth/request_token";
private static final String ACCESS_TOKEN_URL = "http://api.t.163.com/oauth/access_token";
private static final String AUTHORIZE_URL = "http://api.t.163.com/oauth/authorize?oauth_token=%s";
private static final String AUTHENTICATE_URL = "http://api.t.163.com/oauth/authenticate?oauth_token=%s";
@Override
public String getRequestTokenEndpoint()
{
return REQUEST_TOKEN_URL;
}
@Override
public String getAccessTokenEndpoint()
{
return ACCESS_TOKEN_URL;
}
@Override
/**
* this method will ignore your callback
* if you're creating a desktop client please choose this url
* else your can call getAuthenticateUrl
*
* via http://open.t.163.com/wiki/index.php?title=%E8%AF%B7%E6%B1%82%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83Token(oauth/authorize)
*/
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
/**
* this method is for web client with callback url
* if you're creating a desktop client please call getAuthorizationUrl
*
* via http://open.t.163.com/wiki/index.php?title=%E8%AF%B7%E6%B1%82%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83Token(oauth/authenticate)
*/
public String getAuthenticateUrl(Token requestToken)
{
return String.format(AUTHENTICATE_URL, requestToken.getToken());
}
}
@@ -0,0 +1,39 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
public class PlurkApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "http://www.plurk.com/OAuth/request_token";
private static final String AUTHORIZATION_URL = "http://www.plurk.com/OAuth/authorize?oauth_token=%s";
private static final String ACCESS_TOKEN_URL = "http://www.plurk.com/OAuth/access_token";
@Override
public String getRequestTokenEndpoint()
{
return REQUEST_TOKEN_URL;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
@Override
public String getAccessTokenEndpoint()
{
return ACCESS_TOKEN_URL;
}
public class Mobile extends PlurkApi
{
private static final String AUTHORIZATION_URL = "http://www.plurk.com/m/authorize?oauth_token=%s";
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZATION_URL, requestToken.getToken());
}
}
}
@@ -0,0 +1,28 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class QWeiboApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "https://open.t.qq.com/cgi-bin/request_token";
private static final String ACCESS_TOKEN_URL = "https://open.t.qq.com/cgi-bin/access_token";
private static final String AUTHORIZE_URL = "https://open.t.qq.com/cgi-bin/authorize?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());
}
}
@@ -0,0 +1,40 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class SapoApi extends DefaultApi10a
{
private static final String AUTHORIZE_URL = "https://id.sapo.pt/oauth/authorize?oauth_token=%s";
private static final String ACCESS_URL = "https://id.sapo.pt/oauth/access_token";
private static final String REQUEST_URL = "https://id.sapo.pt/oauth/request_token";
@Override
public String getAccessTokenEndpoint()
{
return ACCESS_URL;
}
@Override
public String getRequestTokenEndpoint()
{
return REQUEST_URL;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHORIZE_URL, requestToken.getToken());
}
@Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
@Override
public Verb getAccessTokenVerb()
{
return Verb.GET;
}
}
@@ -0,0 +1,29 @@
package org.scribe.builder.api;
import org.scribe.model.Token;
/**
* @author: Pablo Fernandez
*/
public class SimpleGeoApi extends DefaultApi10a
{
private static final String ENDPOINT = "these are not used since SimpleGeo uses 2 legged OAuth";
@Override
public String getRequestTokenEndpoint()
{
return ENDPOINT;
}
@Override
public String getAccessTokenEndpoint()
{
return ENDPOINT;
}
@Override
public String getAuthorizationUrl(Token requestToken)
{
return ENDPOINT;
}
}
@@ -0,0 +1,28 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class SinaWeiboApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "http://api.t.sina.com.cn/oauth/request_token";
private static final String ACCESS_TOKEN_URL = "http://api.t.sina.com.cn/oauth/access_token";
private static final String AUTHORIZE_URL = "http://api.t.sina.com.cn/oauth/authorize?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());
}
}
@@ -0,0 +1,28 @@
package org.scribe.builder.api;
import org.scribe.model.*;
public class SohuWeiboApi extends DefaultApi10a
{
private static final String REQUEST_TOKEN_URL = "http://api.t.sohu.com/oauth/request_token";
private static final String ACCESS_TOKEN_URL = "http://api.t.sohu.com/oauth/access_token";
private static final String AUTHORIZE_URL = "http://api.t.sohu.com/oauth/authorize?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());
}
}
@@ -5,17 +5,19 @@ 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 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
public String getAccessTokenEndpoint() public String getAccessTokenEndpoint()
{ {
return "http://api.twitter.com/oauth/access_token"; return "http://" + ACCESS_TOKEN_RESOURCE;
} }
@Override @Override
public String getRequestTokenEndpoint() public String getRequestTokenEndpoint()
{ {
return "http://api.twitter.com/oauth/request_token"; return "http://" + REQUEST_TOKEN_RESOURCE;
} }
@Override @Override
@@ -23,4 +25,42 @@ public class TwitterApi extends DefaultApi10a
{ {
return String.format(AUTHORIZE_URL, requestToken.getToken()); 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;
}
}
/**
* Twitter 'friendlier' authorization endpoint for OAuth.
*
* Uses SSL.
*/
public static class Authenticate extends SSL
{
private static final String AUTHENTICATE_URL = "https://api.twitter.com/oauth/authenticate?oauth_token=%s";
@Override
public String getAuthorizationUrl(Token requestToken)
{
return String.format(AUTHENTICATE_URL, requestToken.getToken());
}
}
/**
* Just an alias to the default (SSL) authorization endpoint.
*
* Need to include this for symmetry with 'Authenticate' only.
*/
public static class Authorize extends SSL{}
} }
@@ -0,0 +1,41 @@
package org.scribe.builder.api;
import org.scribe.extractors.*;
import org.scribe.utils.*;
import org.scribe.model.*;
/**
* @author Boris G. Tsirkin <mail@dotbg.name>
* @since 20.4.2011
*/
public class VkontakteApi extends DefaultApi20
{
private static final String AUTHORIZE_URL = "https://api.vkontakte.ru/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code";
private static final String SCOPED_AUTHORIZE_URL = String.format("%s&scope=%%s", AUTHORIZE_URL);
@Override
public String getAccessTokenEndpoint()
{
return "https://api.vkontakte.ru/oauth/access_token";
}
@Override
public String getAuthorizationUrl(OAuthConfig config)
{
Preconditions.checkValidUrl(config.getCallback(), "Valid url is required for a callback. Vkontakte does not support OOB");
if(config.hasScope())// Appending scope if present
{
return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope()));
}
else
{
return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()));
}
}
@Override
public AccessTokenExtractor getAccessTokenExtractor()
{
return new JsonTokenExtractor();
}
}
@@ -1,26 +1,33 @@
package org.scribe.builder.api; package org.scribe.builder.api;
import org.scribe.model.Token; 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'"; 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 @Override
public String getAuthorizationUrl(Token requestToken) public String getAuthorizationUrl(Token requestToken)
{ {
return String.format(AUTHORIZATION_URL, requestToken.getToken()); return String.format(AUTHORIZATION_URL, requestToken.getToken());
} }
@Override
public SignatureService getSignatureService()
{
return new PlaintextSignatureService();
}
} }
@@ -1,7 +1,5 @@
package org.scribe.extractors; package org.scribe.extractors;
import java.util.*;
import org.scribe.exceptions.*; import org.scribe.exceptions.*;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.utils.*; import org.scribe.utils.*;
@@ -23,20 +21,19 @@ public class BaseStringExtractorImpl implements BaseStringExtractor
public String extract(OAuthRequest request) public String extract(OAuthRequest request)
{ {
checkPreconditions(request); checkPreconditions(request);
String verb = URLUtils.percentEncode(request.getVerb().name()); String verb = OAuthEncoder.encode(request.getVerb().name());
String url = URLUtils.percentEncode(request.getSanitizedUrl()); String url = OAuthEncoder.encode(request.getSanitizedUrl());
String params = getSortedAndEncodedParams(request); String params = getSortedAndEncodedParams(request);
return String.format(AMPERSAND_SEPARATED_STRING, verb, url, params); return String.format(AMPERSAND_SEPARATED_STRING, verb, url, params);
} }
private String getSortedAndEncodedParams(OAuthRequest request) private String getSortedAndEncodedParams(OAuthRequest request)
{ {
Map<String, String> params = new HashMap<String, String>(); ParameterList params = new ParameterList();
params.putAll(request.getQueryStringParams()); params.addAll(request.getQueryStringParams());
params.putAll(request.getBodyParams()); params.addAll(request.getBodyParams());
params.putAll(request.getOauthParameters()); params.addAll(new ParameterList(request.getOauthParameters()));
params = MapUtils.sort(params); return params.sort().asOauthBaseString();
return URLUtils.percentEncode(URLUtils.formURLEncodeMap(params));
} }
private void checkPreconditions(OAuthRequest request) private void checkPreconditions(OAuthRequest request)
@@ -32,7 +32,7 @@ public class HeaderExtractorImpl implements HeaderExtractor
{ {
header.append(PARAM_SEPARATOR); header.append(PARAM_SEPARATOR);
} }
header.append(String.format("%s=\"%s\"", key, URLUtils.percentEncode(parameters.get(key)))); header.append(String.format("%s=\"%s\"", key, OAuthEncoder.encode(parameters.get(key))));
} }
return header.toString(); return header.toString();
} }
@@ -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*\"(\\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), "", response);
}
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=([^&]+)";
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.find())
{
String token = OAuthEncoder.decode(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 OAuthEncoder.decode(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);
} }
} }
} }
+42 -18
View File
@@ -1,5 +1,7 @@
package org.scribe.model; package org.scribe.model;
import java.io.*;
/** /**
* Parameter object that groups OAuth config values * Parameter object that groups OAuth config values
* *
@@ -7,20 +9,26 @@ 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 final SignatureType signatureType;
private final String scope;
private final OutputStream debugStream;
public OAuthConfig(String key, String secret) public OAuthConfig(String key, String secret)
{ {
this(key,secret,null); this(key, secret, null, null, null, null);
} }
public OAuthConfig(String key, String secret, String callback) public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope, OutputStream stream)
{ {
this.apiKey = key; this.apiKey = key;
this.apiSecret = secret; this.apiSecret = secret;
this.callback = callback; this.callback = callback;
this.signatureType = type;
this.scope = scope;
this.debugStream = stream;
} }
public String getApiKey() public String getApiKey()
@@ -28,28 +36,44 @@ public class OAuthConfig
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 getScope()
{
return scope;
}
public boolean hasScope()
{
return scope != null;
}
public void log(String message)
{
if (debugStream != null)
{
message = message + "\n";
try
{
debugStream.write(message.getBytes("UTF8"));
}
catch (Exception e)
{
// do nothing.
}
}
} }
} }
@@ -41,4 +41,9 @@ public class OAuthConstants
//OAuth 2.0 //OAuth 2.0
public static final String ACCESS_TOKEN = "access_token"; public static final String ACCESS_TOKEN = "access_token";
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
public static final String REDIRECT_URI = "redirect_uri";
public static final String CODE = "code";
} }
@@ -0,0 +1,50 @@
package org.scribe.model;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.scribe.exceptions.OAuthException;
import org.scribe.utils.OAuthEncoder;
/**
* @author: Pablo Fernandez
*/
public class Parameter implements Comparable<Parameter>
{
private static final String UTF = "UTF8";
private final String key;
private final String value;
public Parameter(String key, String value)
{
this.key = key;
this.value = value;
}
public String asUrlEncodedPair()
{
return OAuthEncoder.encode(key).concat("=").concat(OAuthEncoder.encode(value));
}
public boolean equals(Object other)
{
if(other == null) return false;
if(other == this) return true;
if(!(other instanceof Parameter)) return false;
Parameter otherParam = (Parameter) other;
return otherParam.key.equals(key) && otherParam.value.equals(value);
}
public int hashCode()
{
return key.hashCode() + value.hashCode();
}
public int compareTo(Parameter parameter)
{
int keyDiff = key.compareTo(parameter.key);
return keyDiff != 0 ? keyDiff : value.compareTo(parameter.value);
}
}
@@ -0,0 +1,123 @@
package org.scribe.model;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.scribe.utils.OAuthEncoder;
import org.scribe.utils.Preconditions;
/**
* @author: Pablo Fernandez
*/
public class ParameterList
{
private static final char QUERY_STRING_SEPARATOR = '?';
private static final String PARAM_SEPARATOR = "&";
private static final String PAIR_SEPARATOR = "=";
private static final String EMPTY_STRING = "";
private final List<Parameter> params;
public ParameterList()
{
params = new ArrayList<Parameter>();
}
ParameterList(List<Parameter> params)
{
this.params = new ArrayList<Parameter>(params);
}
public ParameterList(Map<String, String> map)
{
this();
for(Map.Entry<String, String> entry : map.entrySet())
{
params.add(new Parameter(entry.getKey(), entry.getValue()));
}
}
public void add(String key, String value)
{
params.add(new Parameter(key, value));
}
public String appendTo(String url)
{
Preconditions.checkNotNull(url, "Cannot append to null URL");
String queryString = asFormUrlEncodedString();
if (queryString.equals(EMPTY_STRING))
{
return url;
}
else
{
url += url.indexOf(QUERY_STRING_SEPARATOR) != -1 ? PARAM_SEPARATOR : QUERY_STRING_SEPARATOR;
url += queryString;
return url;
}
}
public String asOauthBaseString()
{
try
{
return URLEncoder.encode(asFormUrlEncodedString(), "UTF8");
}
catch (UnsupportedEncodingException uee)
{
throw new RuntimeException();
}
}
public String asFormUrlEncodedString()
{
if (params.size() == 0) return EMPTY_STRING;
StringBuilder builder = new StringBuilder();
for(Parameter p : params)
{
builder.append('&').append(p.asUrlEncodedPair());
}
return builder.toString().substring(1);
}
public void addAll(ParameterList other)
{
params.addAll(other.params);
}
public void addQuerystring(String queryString)
{
if (queryString != null && queryString.length() > 0)
{
for (String param : queryString.split(PARAM_SEPARATOR))
{
String pair[] = param.split(PAIR_SEPARATOR);
String key = OAuthEncoder.decode(pair[0]);
String value = pair.length > 1 ? OAuthEncoder.decode(pair[1]) : EMPTY_STRING;
params.add(new Parameter(key, value));
}
}
}
public boolean contains(Parameter param)
{
return params.contains(param);
}
public int size()
{
return params.size();
}
public ParameterList sort()
{
ParameterList sorted = new ParameterList(params);
Collections.sort(sorted.params);
return sorted;
}
}
+130 -36
View File
@@ -2,11 +2,11 @@ package org.scribe.model;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.charset.*;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.scribe.exceptions.*; import org.scribe.exceptions.*;
import org.scribe.utils.*;
/** /**
* Represents an HTTP Request object * Represents an HTTP Request object
@@ -16,14 +16,21 @@ import org.scribe.utils.*;
class Request class Request
{ {
private static final String CONTENT_LENGTH = "Content-Length"; private static final String CONTENT_LENGTH = "Content-Length";
private static final String CONTENT_TYPE = "Content-Type";
public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded";
private String url; private String url;
private Verb verb; private Verb verb;
private Map<String, String> querystringParams; private ParameterList querystringParams;
private Map<String, String> bodyParams; private ParameterList bodyParams;
private Map<String, String> headers; private Map<String, String> headers;
private String payload = null; private String payload = null;
private HttpURLConnection connection; private HttpURLConnection connection;
private String charset;
private byte[] bytePayload = null;
private boolean connectionKeepAlive = false;
private Long connectTimeout = null;
private Long readTimeout = null;
/** /**
* Creates a new Http Request * Creates a new Http Request
@@ -35,8 +42,8 @@ class Request
{ {
this.verb = verb; this.verb = verb;
this.url = url; this.url = url;
this.querystringParams = new HashMap<String, String>(); this.querystringParams = new ParameterList();
this.bodyParams = new HashMap<String, String>(); this.bodyParams = new ParameterList();
this.headers = new HashMap<String, String>(); this.headers = new HashMap<String, String>();
} }
@@ -53,28 +60,52 @@ class Request
{ {
createConnection(); createConnection();
return doSend(); return doSend();
} catch (IOException ioe) }
catch (UnknownHostException uhe)
{ {
throw new OAuthException("Problems while creating connection", ioe); throw new OAuthException("Could not reach the desired host. Check your network connection.", uhe);
}
catch (IOException ioe)
{
throw new OAuthException("Problems while creating connection.", ioe);
} }
} }
private void createConnection() throws IOException private void createConnection() throws IOException
{ {
String effectiveUrl = URLUtils.appendParametersToQueryString(url, querystringParams); String completeUrl = getCompleteUrl();
if (connection == null) if (connection == null)
{ {
connection = (HttpURLConnection) new URL(effectiveUrl).openConnection(); System.setProperty("http.keepAlive", connectionKeepAlive ? "true" : "false");
connection = (HttpURLConnection) new URL(completeUrl).openConnection();
} }
} }
/**
* Returns the complete url (host + resource + encoded querystring parameters).
*
* @return the complete url.
*/
public String getCompleteUrl()
{
return querystringParams.appendTo(url);
}
Response doSend() throws IOException Response doSend() throws IOException
{ {
connection.setRequestMethod(this.verb.name()); connection.setRequestMethod(this.verb.name());
if (connectTimeout != null)
{
connection.setConnectTimeout(connectTimeout.intValue());
}
if (readTimeout != null)
{
connection.setReadTimeout(readTimeout.intValue());
}
addHeaders(connection); addHeaders(connection);
if (verb.equals(Verb.PUT) || verb.equals(Verb.POST)) if (verb.equals(Verb.PUT) || verb.equals(Verb.POST))
{ {
addBody(connection, getBodyContents()); addBody(connection, getByteBodyContents());
} }
return new Response(connection); return new Response(connection);
} }
@@ -85,11 +116,17 @@ class Request
conn.setRequestProperty(key, headers.get(key)); conn.setRequestProperty(key, headers.get(key));
} }
void addBody(HttpURLConnection conn, String content) throws IOException void addBody(HttpURLConnection conn, byte[] content) throws IOException
{ {
conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.getBytes().length)); conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length));
// Set default content type if none is set.
if (conn.getRequestProperty(CONTENT_TYPE) == null)
{
conn.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
}
conn.setDoOutput(true); conn.setDoOutput(true);
conn.getOutputStream().write(content.getBytes()); conn.getOutputStream().write(content);
} }
/** /**
@@ -111,7 +148,7 @@ class Request
*/ */
public void addBodyParameter(String key, String value) public void addBodyParameter(String key, String value)
{ {
this.bodyParams.put(key, value); this.bodyParams.add(key, value);
} }
/** /**
@@ -122,7 +159,7 @@ class Request
*/ */
public void addQuerystringParameter(String key, String value) public void addQuerystringParameter(String key, String value)
{ {
this.querystringParams.put(key, value); this.querystringParams.add(key, value);
} }
/** /**
@@ -141,26 +178,30 @@ class Request
} }
/** /**
* Get a {@link Map} of the query string parameters. * Overloaded version for byte arrays
* *
* @return a map containing the query string parameters * @param payload
*/ */
public Map<String, String> getQueryStringParams() public void addPayload(byte[] payload)
{
this.bytePayload = payload;
}
/**
* Get a {@link ParameterList} with the query string parameters.
*
* @return a {@link ParameterList} containing the query string parameters.
* @throws OAuthException if the request URL is not valid.
*/
public ParameterList getQueryStringParams()
{ {
try try
{ {
Map<String, String> params = new HashMap<String, String>(); ParameterList result = new ParameterList();
String query = new URL(url).getQuery(); String queryString = new URL(url).getQuery();
if (query != null) result.addQuerystring(queryString);
{ result.addAll(querystringParams);
for (String param : query.split("&")) return result;
{
String pair[] = param.split("=");
params.put(pair[0], pair[1]);
}
}
params.putAll(querystringParams);
return params;
} }
catch (MalformedURLException mue) catch (MalformedURLException mue)
{ {
@@ -169,11 +210,11 @@ class Request
} }
/** /**
* Obtains a {@link Map} of the body parameters. * Obtains a {@link ParameterList} of the body parameters.
* *
* @return a map containing the body parameters. * @return a {@link ParameterList}containing the body parameters.
*/ */
public Map<String, String> getBodyParams() public ParameterList getBodyParams()
{ {
return bodyParams; return bodyParams;
} }
@@ -202,10 +243,32 @@ class Request
* Returns the body of the request * Returns the body of the request
* *
* @return form encoded string * @return form encoded string
* @throws OAuthException if the charset chosen is not supported
*/ */
public String getBodyContents() public String getBodyContents()
{ {
return (payload != null) ? payload : URLUtils.formURLEncodeMap(bodyParams); try
{
return new String(getByteBodyContents(),getCharset());
}
catch(UnsupportedEncodingException uee)
{
throw new OAuthException("Unsupported Charset: "+charset, uee);
}
}
byte[] getByteBodyContents()
{
if (bytePayload != null) return bytePayload;
String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString();
try
{
return body.getBytes(getCharset());
}
catch(UnsupportedEncodingException uee)
{
throw new OAuthException("Unsupported Charset: "+getCharset(), uee);
}
} }
/** /**
@@ -228,6 +291,16 @@ class Request
return headers; return headers;
} }
/**
* Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set
*
* @return charset
*/
public String getCharset()
{
return charset == null ? Charset.defaultCharset().name() : charset;
}
/** /**
* Sets the connect timeout for the underlying {@link HttpURLConnection} * Sets the connect timeout for the underlying {@link HttpURLConnection}
* *
@@ -237,7 +310,7 @@ class Request
*/ */
public void setConnectTimeout(int duration, TimeUnit unit) public void setConnectTimeout(int duration, TimeUnit unit)
{ {
this.connection.setConnectTimeout((int) unit.toMillis(duration)); this.connectTimeout = unit.toMillis(duration);
} }
/** /**
@@ -249,7 +322,28 @@ class Request
*/ */
public void setReadTimeout(int duration, TimeUnit unit) public void setReadTimeout(int duration, TimeUnit unit)
{ {
this.connection.setReadTimeout((int) unit.toMillis(duration)); this.readTimeout = unit.toMillis(duration);
}
/**
* Set the charset of the body of the request
*
* @param charsetName name of the charset of the request
*/
public void setCharset(String charsetName)
{
this.charset = charsetName;
}
/**
* Sets whether the underlying Http Connection is persistent or not.
*
* @see http://download.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html
* @param connectionKeepAlive
*/
public void setConnectionKeepAlive(boolean connectionKeepAlive)
{
this.connectionKeepAlive = connectionKeepAlive;
} }
/* /*
+7 -7
View File
@@ -27,11 +27,12 @@ public class Response
connection.connect(); connection.connect();
code = connection.getResponseCode(); code = connection.getResponseCode();
headers = parseHeaders(connection); headers = parseHeaders(connection);
stream = wasSuccessful() ? connection.getInputStream() : connection.getErrorStream(); stream = isSuccessful() ? connection.getInputStream() : connection.getErrorStream();
} catch (UnknownHostException e) }
catch (UnknownHostException e)
{ {
code = 404; code = 404;
body = EMPTY; body = Response.EMPTY;
} }
} }
@@ -51,7 +52,7 @@ public class Response
return headers; return headers;
} }
private boolean wasSuccessful() public boolean isSuccessful()
{ {
return getCode() >= 200 && getCode() < 400; return getCode() >= 200 && getCode() < 400;
} }
@@ -100,10 +101,9 @@ public class Response
/** /**
* Obtains a single HTTP Header value, or null if undefined * Obtains a single HTTP Header value, or null if undefined
* *
* @param header * @param name the header name.
* name
* *
* @return header value or null * @return header value or null.
*/ */
public String getHeader(String name) public String getHeader(String name)
{ {
@@ -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,7 +1,10 @@
package org.scribe.oauth; package org.scribe.oauth;
import java.util.*;
import org.scribe.builder.api.*; import org.scribe.builder.api.*;
import org.scribe.model.*; import org.scribe.model.*;
import org.scribe.utils.*;
/** /**
* OAuth 1.0a implementation of {@link OAuthService} * OAuth 1.0a implementation of {@link OAuthService}
@@ -10,12 +13,10 @@ import org.scribe.model.*;
*/ */
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 DefaultApi10a api; private DefaultApi10a api;
private String scope;
/** /**
* Default constructor * Default constructor
@@ -27,7 +28,6 @@ public class OAuth10aServiceImpl implements OAuthService
{ {
this.api = api; this.api = api;
this.config = config; this.config = config;
this.scope = NO_SCOPE;
} }
/** /**
@@ -35,11 +35,21 @@ public class OAuth10aServiceImpl implements OAuthService
*/ */
public Token getRequestToken() public Token getRequestToken()
{ {
config.log("obtaining request token from " + api.getRequestTokenEndpoint());
OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());
config.log("setting oauth_callback to " + config.getCallback());
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
addOAuthHeader(request); appendSignature(request);
config.log("sending request...");
Response response = request.send(); Response response = request.send();
return api.getRequestTokenExtractor().extract(response.getBody()); String body = response.getBody();
config.log("response status code: " + response.getCode());
config.log("response body: " + body);
return api.getRequestTokenExtractor().extract(body);
} }
private void addOAuthParams(OAuthRequest request, Token token) private void addOAuthParams(OAuthRequest request, Token token)
@@ -49,9 +59,10 @@ public class OAuth10aServiceImpl implements OAuthService
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey()); request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod()); request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
request.addOAuthParameter(OAuthConstants.VERSION, getVersion()); request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback()); if(config.hasScope()) request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
if(scope != NO_SCOPE) request.addOAuthParameter(OAuthConstants.SCOPE, scope);
request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token)); request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
config.log("appended additional OAuth parameters: " + MapUtils.toString(request.getOauthParameters()));
} }
/** /**
@@ -59,11 +70,14 @@ public class OAuth10aServiceImpl implements OAuthService
*/ */
public Token getAccessToken(Token requestToken, Verifier verifier) public Token getAccessToken(Token requestToken, Verifier verifier)
{ {
config.log("obtaining access token from " + api.getAccessTokenEndpoint());
OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.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());
config.log("setting token to: " + requestToken + " and verifier to: " + verifier);
addOAuthParams(request, requestToken); addOAuthParams(request, requestToken);
addOAuthHeader(request); appendSignature(request);
Response response = request.send(); Response response = request.send();
return api.getAccessTokenExtractor().extract(response.getBody()); return api.getAccessTokenExtractor().extract(response.getBody());
} }
@@ -73,9 +87,12 @@ public class OAuth10aServiceImpl implements OAuthService
*/ */
public void signRequest(Token token, OAuthRequest request) public void signRequest(Token token, OAuthRequest request)
{ {
config.log("signing request: " + request.getCompleteUrl());
request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken()); request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken());
config.log("setting token to: " + token);
addOAuthParams(request, token); addOAuthParams(request, token);
addOAuthHeader(request); appendSignature(request);
} }
/** /**
@@ -86,14 +103,6 @@ public class OAuth10aServiceImpl implements OAuthService
return VERSION; return VERSION;
} }
/**
* {@inheritDoc}
*/
public void addScope(String scope)
{
this.scope = scope;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -104,13 +113,33 @@ public class OAuth10aServiceImpl implements OAuthService
private String getSignature(OAuthRequest request, Token token) private String getSignature(OAuthRequest request, Token token)
{ {
config.log("generating signature...");
String baseString = api.getBaseStringExtractor().extract(request); String baseString = api.getBaseStringExtractor().extract(request);
return api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret()); String signature = api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret());
config.log("base string is: " + baseString);
config.log("signature is: " + signature);
return signature;
} }
private void addOAuthHeader(OAuthRequest request) private void appendSignature(OAuthRequest request)
{ {
String oauthHeader = api.getHeaderExtractor().extract(request); switch (config.getSignatureType())
request.addHeader(OAuthConstants.HEADER, oauthHeader); {
case Header:
config.log("using Http Header signature");
String oauthHeader = api.getHeaderExtractor().extract(request);
request.addHeader(OAuthConstants.HEADER, oauthHeader);
break;
case QueryString:
config.log("using Querystring signature");
for (Map.Entry<String, String> entry : request.getOauthParameters().entrySet())
{
request.addQuerystringParameter(entry.getKey(), entry.getValue());
}
break;
}
} }
} }
@@ -22,20 +22,19 @@ public class OAuth20ServiceImpl implements OAuthService
this.config = config; this.config = config;
} }
/**
* {@inheritDoc}
*/
public void addScope(String scope)
{
throw new UnsupportedOperationException("OAuth 2 does not use scopes");
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public Token getAccessToken(Token requestToken, Verifier verifier) public Token getAccessToken(Token requestToken, Verifier verifier)
{ {
throw new UnsupportedOperationException("Unsupported operation, please use 'getAuthorizationUrl' and redirect your users there"); OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
Response response = request.send();
return api.getAccessTokenExtractor().extract(response.getBody());
} }
/** /**
@@ -42,13 +42,6 @@ public interface OAuthService
*/ */
public String getVersion(); public String getVersion();
/**
* Adds the 'scope' parameter. This is **not** a default OAuth parameter and the setting is optional.
*
* @param scope OAuth Api scope (optional)
*/
public void addScope(String scope);
/** /**
* Returns the URL where you should redirect your users to authenticate * Returns the URL where you should redirect your users to authenticate
* your application. * your application.
@@ -30,7 +30,7 @@ public class HMACSha1SignatureService implements SignatureService
{ {
Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string"); Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string");
Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string"); Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string");
return doSign(baseString, URLUtils.percentEncode(apiSecret) + '&' + URLUtils.percentEncode(tokenSecret)); return doSign(baseString, OAuthEncoder.encode(apiSecret) + '&' + OAuthEncoder.encode(tokenSecret));
} }
catch (Exception e) catch (Exception e)
{ {
@@ -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 OAuthEncoder.encode(apiSecret) + '&' + OAuthEncoder.encode(tokenSecret);
}
catch (Exception e)
{
throw new OAuthSignatureException(baseString, e);
}
}
/**
* {@inheritDoc}
*/
public String getSignatureMethod()
{
return METHOD;
}
}
+9 -23
View File
@@ -1,36 +1,22 @@
package org.scribe.utils; package org.scribe.utils;
import java.util.*; import java.util.Map;
/** /**
* Utils for {@link Map} manipulation * @author: Pablo Fernandez
*
* @author Pablo Fernandez
*/ */
public class MapUtils public class MapUtils
{ {
/** public static <K,V> String toString(Map<K,V> map)
* Sorts a Map
*
* @param map unsorted map
* @return sorted map
*/
public static final Map<String, String> sort(Map<String, String> map)
{ {
Preconditions.checkNotNull(map, "Cannot sort a null object."); if (map == null) return "";
if (map.isEmpty()) return "{}";
Map<String, String> sorted = new LinkedHashMap<String, String>(); StringBuilder result = new StringBuilder();
for (String key : getSortedKeys(map)) for(Map.Entry<K,V> entry : map.entrySet())
{ {
sorted.put(key, map.get(key)); result.append(String.format(", %s -> %s ", entry.getKey().toString(), entry.getValue().toString()));
} }
return sorted; return "{" + result.substring(1) + "}";
}
private static List<String> getSortedKeys(Map<String, String> map)
{
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
return keys;
} }
} }
@@ -0,0 +1,62 @@
package org.scribe.utils;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.regex.*;
import org.scribe.exceptions.*;
/**
* @author: Pablo Fernandez
*/
public class OAuthEncoder
{
private static String CHARSET = "UTF-8";
private static final Map<String, String> ENCODING_RULES;
static
{
Map<String, String> rules = new HashMap<String, String>();
rules.put("*", "%2A");
rules.put("+", "%20");
rules.put("%7E", "~");
ENCODING_RULES = Collections.unmodifiableMap(rules);
}
public static String encode(String plain)
{
Preconditions.checkNotNull(plain, "Cannot encode null object");
String encoded = "";
try
{
encoded = URLEncoder.encode(plain, CHARSET);
}
catch (UnsupportedEncodingException uee)
{
throw new OAuthException("Charset not found while encoding string: " + CHARSET, uee);
}
for(Map.Entry<String, String> rule : ENCODING_RULES.entrySet())
{
encoded = applyRule(encoded, rule.getKey(), rule.getValue());
}
return encoded;
}
private static String applyRule(String encoded, String toReplace, String replacement)
{
return encoded.replaceAll(Pattern.quote(toReplace), replacement);
}
public static String decode(String encoded)
{
Preconditions.checkNotNull(encoded, "Cannot decode null object");
try
{
return URLDecoder.decode(encoded, CHARSET);
}
catch(UnsupportedEncodingException uee)
{
throw new OAuthException("Charset not found while decoding string: " + CHARSET, uee);
}
}
}
@@ -1,136 +0,0 @@
package org.scribe.utils;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* Utils to deal with URL and url-encodings
*
* @author Pablo Fernandez
*/
public class URLUtils
{
private static final String EMPTY_STRING = "";
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 ERROR_MSG = String.format("Cannot find specified encoding: %s", UTF_8);
private static final Set<EncodingRule> ENCODING_RULES;
static
{
Set<EncodingRule> rules = new HashSet<EncodingRule>();
rules.add(new EncodingRule("*","%2A"));
rules.add(new EncodingRule("+","%20"));
rules.add(new EncodingRule("%7E", "~"));
ENCODING_RULES = Collections.unmodifiableSet(rules);
}
/**
* Turns a map into a form-url-encoded string (key=value&key2=value2)
*
* @param map any map
* @return form-url-encoded string
*/
public static String formURLEncodeMap(Map<String, String> map)
{
Preconditions.checkNotNull(map, "Cannot url-encode a null object");
return (map.size() <= 0) ? EMPTY_STRING : doFormUrlEncode(map);
}
private static String doFormUrlEncode(Map<String, String> map)
{
StringBuffer encodedString = new StringBuffer(map.size() * 20);
for (String key : map.keySet())
{
if(encodedString.length() > 0)
{
encodedString.append(PARAM_SEPARATOR);
}
encodedString.append(percentEncode(key)).append(PAIR_SEPARATOR).append(percentEncode(map.get(key)));
}
return encodedString.toString();
}
/**
* Percent encodes a string
*
* @param plain
* @return percent encoded string
*/
public static String percentEncode(String string)
{
Preconditions.checkNotNull(string, "Cannot encode null string");
try
{
String encoded = URLEncoder.encode(string, UTF_8);
for(EncodingRule rule : ENCODING_RULES)
{
encoded = rule.apply(encoded);
}
return encoded;
}
catch (UnsupportedEncodingException uee)
{
throw new IllegalStateException(ERROR_MSG, uee);
}
}
/**
* Percent decodes a string
*
* @param string percent encoded string
* @return plain string
*/
public static String percentDecode(String string)
{
Preconditions.checkNotNull(string, "Cannot decode null string");
try
{
return URLDecoder.decode(string, UTF_8);
}
catch (UnsupportedEncodingException 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.isEmpty()) 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;
private final String toCh;
EncodingRule(String ch, String toCh)
{
this.ch = ch;
this.toCh = toCh;
}
String apply(String string) {
return string.replace(ch, toCh);
}
}
}
@@ -18,12 +18,13 @@ public class ServiceBuilderTest
} }
@Test @Test
public void shouldReturnOOBasDefaultCallback() public void shouldReturnConfigDefaultValues()
{ {
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").build(); builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").build();
assertEquals(ApiMock.config.getApiKey(), "key"); assertEquals(ApiMock.config.getApiKey(), "key");
assertEquals(ApiMock.config.getApiSecret(), "secret"); assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.config.getCallback(), OAuthConstants.OUT_OF_BAND); assertEquals(ApiMock.config.getCallback(), OAuthConstants.OUT_OF_BAND);
assertEquals(ApiMock.config.getSignatureType(), SignatureType.Header);
} }
@Test @Test
@@ -35,6 +36,15 @@ public class ServiceBuilderTest
assertEquals(ApiMock.config.getCallback(), "http://example.com"); 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) @Test(expected=IllegalArgumentException.class)
public void shouldNotAcceptAnInvalidUrlAsCallback() public void shouldNotAcceptAnInvalidUrlAsCallback()
{ {
@@ -47,19 +57,16 @@ public class ServiceBuilderTest
builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").scope("rss-api").build(); builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").scope("rss-api").build();
assertEquals(ApiMock.config.getApiKey(), "key"); assertEquals(ApiMock.config.getApiKey(), "key");
assertEquals(ApiMock.config.getApiSecret(), "secret"); assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.scope, "rss-api"); assertEquals(ApiMock.config.getScope(), "rss-api");
} }
public static class ApiMock implements Api public static class ApiMock implements Api
{ {
public static OAuthConfig config; public static OAuthConfig config;
public static String scope;
@Override public OAuthService createService(OAuthConfig config)
public OAuthService createService(OAuthConfig config, String scope)
{ {
ApiMock.config = config; ApiMock.config = config;
ApiMock.scope = scope;
return null; return null;
} }
} }
@@ -11,13 +11,12 @@ public class FacebookExample
{ {
private static final String NETWORK_NAME = "Facebook"; private static final String NETWORK_NAME = "Facebook";
private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/me"; private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/me";
private static final String NO_SECRET_NEEDED = "";
private static final Token EMPTY_TOKEN = null; private static final Token EMPTY_TOKEN = null;
public static void main(String[] args) public static void main(String[] args)
{ {
// Replace these with your own api key and secret // Replace these with your own api key and secret
String apiKey = "your_api_key"; String apiKey = "your_app_id";
String apiSecret = "your_api_secret"; String apiSecret = "your_api_secret";
OAuthService service = new ServiceBuilder() OAuthService service = new ServiceBuilder()
.provider(FacebookApi.class) .provider(FacebookApi.class)
@@ -36,9 +35,16 @@ public class FacebookExample
System.out.println("Got the Authorization URL!"); System.out.println("Got the Authorization URL!");
System.out.println("Now go and authorize Scribe here:"); System.out.println("Now go and authorize Scribe here:");
System.out.println(authorizationUrl); System.out.println(authorizationUrl);
System.out.println("And paste the access token here"); System.out.println("And paste the authorization code here");
System.out.print(">>"); System.out.print(">>");
Token accessToken = new Token(in.nextLine(), NO_SECRET_NEEDED); Verifier verifier = new Verifier(in.nextLine());
System.out.println();
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
System.out.println(); System.out.println();
// Now let's go and ask for a protected resource! // Now let's go and ask for a protected resource!
@@ -0,0 +1,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! :)");
}
}
@@ -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 LiveExample
{
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 = "";
String apiSecret = "";
OAuthService service = new ServiceBuilder()
.provider(LiveApi.class)
.apiKey(apiKey)
.apiSecret(apiSecret)
.scope("wl.basic")
.callback("http://localhost:9000/")
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== Windows Live'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! :)");
}
}
@@ -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! :)");
}
}
@@ -0,0 +1,68 @@
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 NeteaseWeiboExample
{
private static final String NETWORK_NAME = "NetEase(163.com) Weibo";
private static final String PROTECTED_RESOURCE_URL = "http://api.t.163.com/account/verify_credentials.json";
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(NeteaseWeibooApi.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! :)");
}
}
@@ -0,0 +1,68 @@
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 SinaWeiboExample
{
private static final String NETWORK_NAME = "SinaWeibo";
private static final String PROTECTED_RESOURCE_URL = "http://api.t.sina.com.cn/account/verify_credentials.json";
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(SinaWeiboApi.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! :)");
}
}
@@ -0,0 +1,68 @@
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 SohuWeiboExample
{
private static final String NETWORK_NAME = "SohuWeibo";
private static final String PROTECTED_RESOURCE_URL = "http://api.t.sohu.com/account/verify_credentials.json";
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(SohuWeiboApi.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,7 @@ import org.scribe.oauth.*;
public class TwitterExample public class TwitterExample
{ {
private static final String PROTECTED_RESOURCE_URL = "http://api.twitter.com/1/account/verify_credentials.xml"; private static final String PROTECTED_RESOURCE_URL = "https://api.twitter.com/1/statuses/update.json";
public static void main(String[] args) public static void main(String[] args)
{ {
@@ -45,7 +45,8 @@ public class TwitterExample
// Now let's go and ask for a protected resource! // Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource..."); System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL);
request.addBodyParameter("status", "this is sparta! *");
service.signRequest(accessToken, request); service.signRequest(accessToken, request);
Response response = request.send(); Response response = request.send();
System.out.println("Got it! Lets see what we found..."); System.out.println("Got it! Lets see what we found...");
@@ -0,0 +1,68 @@
package org.scribe.examples;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
import java.util.*;
/**
* @author Boris G. Tsirkin <mail@dotbg.name>
* @since 20.4.2011
*/
public class VkontakteExample
{
private static final String NETWORK_NAME = "Vkontakte.ru";
private static final String PROTECTED_RESOURCE_URL = "https://api.vkontakte.ru/method/friends.get";
private static final Token EMPTY_TOKEN = null;
public static void main(String[] args)
{
// Replace these with your own api key and secret
final String clientId = "your app id";
final String apiSecret = "your api secret";
OAuthService service = new ServiceBuilder()
.provider(VkontakteApi.class)
.apiKey(clientId)
.apiSecret(apiSecret)
.scope("friends,wall,offline") // replace with desired scope
.callback("http://your.site.com/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,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,67 @@
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
public void shouldExtractTokenFromResponseWithManyParameters()
{
String response = "access_token=foo1234&other_stuff=yeah_we_have_this_too&number=42";
Token extracted = extractor.extract(response);
assertEquals("foo1234", 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()
{ {
@@ -22,6 +22,12 @@ public class ConnectionStub extends HttpURLConnection
headers.put(key, value); headers.put(key, value);
} }
@Override
public String getRequestProperty(String s)
{
return headers.get(s);
}
public Map<String, String> getHeaders() public Map<String, String> getHeaders()
{ {
return headers; return headers;
@@ -1,26 +0,0 @@
package org.scribe.model;
import static org.junit.Assert.*;
import org.junit.*;
public class OAuthConfigTest
{
@Test
public void shouldReturnDefaultValuesIfNotSet()
{
OAuthConfig config = new OAuthConfig("key", "secret");
assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback());
}
@Test
public void shouldOverrideDefaultsIfSet()
{
OAuthConfig config = new OAuthConfig("key", "secret", "http://callback");
assertEquals("http://callback", config.getCallback());
assertEquals("key", config.getApiKey());
assertEquals("secret", config.getApiSecret());
}
}
@@ -0,0 +1,91 @@
package org.scribe.model;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
/**
* @author: Pablo Fernandez
*/
public class ParameterListTest
{
private ParameterList params;
@Before
public void setup()
{
this.params = new ParameterList();
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenAppendingNullMapToQuerystring()
{
String url = null;
params.appendTo(url);
}
@Test
public void shouldAppendNothingToQuerystringIfGivenEmptyMap()
{
String url = "http://www.example.com";
Assert.assertEquals(url, params.appendTo(url));
}
@Test
public void shouldAppendParametersToSimpleUrl()
{
String url = "http://www.example.com";
String expectedUrl = "http://www.example.com?param1=value1&param2=value%20with%20spaces";
params.add("param1", "value1");
params.add("param2", "value with spaces");
url = params.appendTo(url);
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%20with%20spaces";
params.add("param1", "value1");
params.add("param2", "value with spaces");
url = params.appendTo(url);
Assert.assertEquals(url, expectedUrl);
}
@Test
public void shouldProperlySortParameters()
{
params.add("param1", "v1");
params.add("param6", "v2");
params.add("a_param", "v3");
params.add("param2", "v4");
Assert.assertEquals("a_param=v3&param1=v1&param2=v4&param6=v2", params.sort().asFormUrlEncodedString());
}
@Test
public void shouldProperlySortParametersWithTheSameName()
{
params.add("param1", "v1");
params.add("param6", "v2");
params.add("a_param", "v3");
params.add("param1", "v4");
Assert.assertEquals("a_param=v3&param1=v1&param1=v4&param6=v2", params.sort().asFormUrlEncodedString());
}
@Test
public void shouldNotModifyTheOriginalParameterList()
{
params.add("param1", "v1");
params.add("param6", "v2");
assertNotSame(params, params.sort());
}
}
@@ -6,7 +6,6 @@ import org.junit.*;
public class RequestTest public class RequestTest
{ {
private Request getRequest; private Request getRequest;
private Request postRequest; private Request postRequest;
private ConnectionStub connection; private ConnectionStub connection;
@@ -16,8 +15,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);
} }
@@ -33,7 +34,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().contains(new Parameter("qsparam", "value")));
} }
@Test @Test
@@ -47,12 +48,10 @@ public class RequestTest
} }
@Test @Test
public void shouldSetBodyParamsAndHeaders() public void shouldSetBodyParamsAndAddContentLength()
{ {
postRequest.addBodyParameter("param", "value"); assertEquals("param=value&param%20with%20spaces=value%20with%20spaces", postRequest.getBodyContents());
postRequest.addBodyParameter("param two", "value with spaces");
postRequest.send(); postRequest.send();
assertEquals("param%20two=value%20with%20spaces&param=value", postRequest.getBodyContents());
assertTrue(connection.getHeaders().containsKey("Content-Length")); assertTrue(connection.getHeaders().containsKey("Content-Length"));
} }
@@ -74,4 +73,56 @@ public class RequestTest
assertEquals(3, request.getQueryStringParams().size()); assertEquals(3, request.getQueryStringParams().size());
} }
@Test
public void shouldReturnTheCompleteUrl()
{
Request request = new Request(Verb.GET, "http://example.com?one=val");
request.addQuerystringParameter("two", "other val");
request.addQuerystringParameter("more", "params");
assertEquals("http://example.com?one=val&two=other%20val&more=params", request.getCompleteUrl());
}
@Test
public void shouldHandleQueryStringSpaceEncodingProperly()
{
assertTrue(getRequest.getQueryStringParams().contains(new Parameter("other param","value with spaces")));
}
@Test
public void shouldAutomaticallyAddContentTypeForPostRequestsWithBytePayload()
{
postRequest.addPayload("PAYLOAD".getBytes());
postRequest.send();
assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type"));
}
@Test
public void shouldAutomaticallyAddContentTypeForPostRequestsWithStringPayload()
{
postRequest.addPayload("PAYLOAD");
postRequest.send();
assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type"));
}
@Test
public void shouldAutomaticallyAddContentTypeForPostRequestsWithBodyParameters()
{
postRequest.send();
assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type"));
}
@Test
public void shouldBeAbleToOverrideItsContentType()
{
postRequest.addHeader("Content-Type", "my-content-type");
postRequest.send();
assertEquals("my-content-type", connection.getHeaders().get("Content-Type"));
}
@Test
public void shouldNotAddContentTypeForGetRequests()
{
getRequest.send();
assertFalse(connection.getHeaders().containsKey("Content-Type"));
}
} }
@@ -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);
}
}
@@ -1,53 +1,35 @@
package org.scribe.utils; package org.scribe.utils;
import static org.junit.Assert.*;
import java.util.*; import java.util.*;
import org.junit.*; import org.junit.*;
/**
* @author: Pablo Fernandez
*/
public class MapUtilsTest public class MapUtilsTest
{ {
private Map<String, String> unsorted; @Test
public void shouldPrettyPrintMap()
@Before
public void setup()
{ {
unsorted = new LinkedHashMap<String, String>(); Map<Integer, String> map = new HashMap<Integer, String>();
unsorted.put("d", "fourth"); map.put(1, "one");
unsorted.put("a", "first"); map.put(2, "two");
unsorted.put("c", "third"); map.put(3, "three");
unsorted.put("b", "second"); map.put(4, "four");
Assert.assertEquals("{ 1 -> one , 2 -> two , 3 -> three , 4 -> four }", MapUtils.toString(map));
} }
@Test @Test
public void shouldSortMap() public void shouldHandleEmptyMap()
{ {
Map<String, String> sorted = MapUtils.sort(unsorted); Map<Integer, String> map = new HashMap<Integer, String>();
List<String> values = new ArrayList<String>(sorted.values()); Assert.assertEquals("{}", MapUtils.toString(map));
assertEquals("first", values.get(0));
assertEquals("second", values.get(1));
assertEquals("third", values.get(2));
assertEquals("fourth", values.get(3));
} }
@Test @Test
public void shouldNotModifyTheOriginalMap() public void shouldHandleNullInputs()
{ {
Map<String, String> sorted = MapUtils.sort(unsorted); Assert.assertEquals("", MapUtils.toString(null));
assertNotSame(sorted, unsorted);
List<String> values = new ArrayList<String>(unsorted.values());
assertEquals("fourth", values.get(0));
assertEquals("first", values.get(1));
assertEquals("third", values.get(2));
assertEquals("second", values.get(3));
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionForNullMap()
{
MapUtils.sort(null);
} }
} }
@@ -0,0 +1,70 @@
package org.scribe.utils;
import org.junit.*;
import static org.junit.Assert.*;
/**
* @author: Pablo Fernandez
*/
public class OAuthEncoderTest
{
@Test
public void shouldPercentEncodeString()
{
String plain = "this is a test &^";
String encoded = "this%20is%20a%20test%20%26%5E";
assertEquals(encoded, OAuthEncoder.encode(plain));
}
@Test
public void shouldFormURLDecodeString()
{
String encoded = "this+is+a+test+%26%5E";
String plain = "this is a test &^";
assertEquals(plain, OAuthEncoder.decode(encoded));
}
@Test
public void shouldPercentEncodeAllSpecialCharacters()
{
String plain = "!*'();:@&=+$,/?#[]";
String encoded = "%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%23%5B%5D";
assertEquals(encoded, OAuthEncoder.encode(plain));
assertEquals(plain, OAuthEncoder.decode(encoded));
}
@Test
public void shouldNotPercentEncodeReservedCharacters()
{
String plain = "abcde123456-._~";
String encoded = plain;
assertEquals(encoded, OAuthEncoder.encode(plain));
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfStringToEncodeIsNull()
{
String toEncode = null;
OAuthEncoder.encode(toEncode);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfStringToDecodeIsNull()
{
String toDecode = null;
OAuthEncoder.decode(toDecode);
}
@Test
public void shouldPercentEncodeCorrectlyTwitterCodingExamples()
{
// These tests are part of the Twitter dev examples here -> https://dev.twitter.com/docs/auth/percent-encoding-parameters
String sources[] = {"Ladies + Gentlemen", "An encoded string!", "Dogs, Cats & Mice"};
String encoded[] = {"Ladies%20%2B%20Gentlemen", "An%20encoded%20string%21", "Dogs%2C%20Cats%20%26%20Mice"};
for(int i = 0; i < sources.length; i++)
{
Assert.assertEquals(encoded[i], OAuthEncoder.encode(sources[i]));
}
}
}
@@ -1,130 +0,0 @@
package org.scribe.utils;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
public class URLUtilsTest
{
@Test
public void shouldPercentEncodeMap()
{
Map<String, String> params = new LinkedHashMap<String, String>();
params.put("key", "value");
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";
assertEquals(expected, URLUtils.formURLEncodeMap(params));
}
@Test
public void shouldReturnEmptyStringForEmptyMap()
{
Map<String, String> params = new LinkedHashMap<String, String>();
String expected = "";
assertEquals(expected, URLUtils.formURLEncodeMap(params));
}
@Test
public void shouldPercentEncodeString()
{
String toEncode = "this is a test &^";
String expected = "this%20is%20a%20test%20%26%5E";
assertEquals(expected, URLUtils.percentEncode(toEncode));
}
@Test
public void shouldPercentDecodeString()
{
String toDecode = "this+is+a+test+%26%5E";
String expected = "this is a test &^";
assertEquals(expected, URLUtils.percentDecode(toDecode));
}
@Test
public void shouldEncodeAllSpecialCharacters()
{
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));
}
@Test
public void shouldNotEncodeReservedCharacters()
{
String plain = "abcde123456-._~";
String encoded = plain;
assertEquals(encoded, URLUtils.percentEncode(plain));
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfMapIsNull()
{
Map<String, String> nullMap = null;
URLUtils.formURLEncodeMap(nullMap);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfStringToEncodeIsNull()
{
String toEncode = null;
URLUtils.percentEncode(toEncode);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfStringToDecodeIsNull()
{
String toDecode = null;
URLUtils.percentDecode(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%20with%20spaces";
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%20with%20spaces";
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);
}
}