Initial commit
This commit is contained in:
commit
bfbe536886
59 files changed
+2540
No files matched your search
+10
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
# Eclipse specific settings
|
||||||
|
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
|
||||||
|
target
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
!http://img411.imageshack.us/img411/2851/scribelogo.png!
|
||||||
|
|
||||||
|
h1. Welcome
|
||||||
|
|
||||||
|
h3. Welcome to the *new* home of **Scribe**
|
||||||
|
|
||||||
|
h1. Why use Scribe?
|
||||||
|
|
||||||
|
h3. Dead Simple
|
||||||
|
|
||||||
|
Who said OAuth was difficult? Configuring scribe is so easy your grandma can do it! check it out:
|
||||||
|
|
||||||
|
OAuthService service = new ServiceBuilder()
|
||||||
|
.provider(LinkedInApi.class)
|
||||||
|
.apiKey(YOUR_API_KEY)
|
||||||
|
.apiSecret(YOUR_API_SECRET)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
That **single line** (added newlines for readability) is the only thing you need to configure scribe with LinkedIn's OAuth API for example.
|
||||||
|
|
||||||
|
h3. Threadsafe
|
||||||
|
|
||||||
|
Hit Scribe as hard and with many threads as you like.
|
||||||
|
|
||||||
|
h3. Supports all major OAuth APIs out-of-the-box
|
||||||
|
|
||||||
|
logos here
|
||||||
|
|
||||||
|
h3. Small and modular
|
||||||
|
|
||||||
|
Scribe's code is small (about 1k LOC) and simple to understand. No smart-ass or "clever" hacks here.
|
||||||
|
|
||||||
|
h3. Stable & bulletproof
|
||||||
|
|
||||||
|
Test coverage of about x% to keep you safe from harm.
|
||||||
|
|
||||||
|
When something bad actually happens, Scribe's meaningful error messages will tell you exactly what went wrong, when and where.
|
||||||
|
|
||||||
|
h1. Getting started in less than 2 minutes
|
||||||
|
|
||||||
|
Check the "Getting Started":http://wiki.github.com/fernandezpablo85/scribe/getting-started page and start rocking!
|
||||||
|
|
||||||
|
h1. Please Read the "FAQ":http://wiki.github.com/fernandezpablo85/scribe/faq before creating an issue :)
|
||||||
|
|
||||||
|
h1. About me
|
||||||
|
|
||||||
|
LinkedIn "profile":http://linkedinprofile
|
||||||
|
|
||||||
|
Email me: fernandezpablo85 at gmail.com
|
||||||
|
|
||||||
|
Follow me: "@fernandezpablo":http://twitter.com/fernandezpablo
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.scribe</groupId>
|
||||||
|
<artifactId>scribe</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>OAuth Library</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.8.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package org.scribe.builder;
|
||||||
|
|
||||||
|
import org.scribe.builder.api.*;
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.oauth.*;
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the Builder pattern, with a fluent interface that creates a
|
||||||
|
* {@link OAuthService}
|
||||||
|
*
|
||||||
|
* @author Pablo Fernandez
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServiceBuilder
|
||||||
|
{
|
||||||
|
private String apiKey;
|
||||||
|
private String apiSecret;
|
||||||
|
private String callback;
|
||||||
|
private Api api;
|
||||||
|
|
||||||
|
public ServiceBuilder()
|
||||||
|
{
|
||||||
|
this.callback = OAuthConstants.OUT_OF_BAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link Api}
|
||||||
|
*
|
||||||
|
* @param apiClass the class of one of the existent {@link Api}s on org.scribe.api package
|
||||||
|
* @return the {@link ServiceBuilder} instance for method chaining
|
||||||
|
*/
|
||||||
|
public ServiceBuilder provider(Class<? extends Api> apiClass)
|
||||||
|
{
|
||||||
|
this.api = createApi(apiClass);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Api createApi(Class<? extends Api> apiClass)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(apiClass, "Api class cannot be null");
|
||||||
|
Api api;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
api = apiClass.newInstance();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new OAuthException("Error while creating the Api object", e);
|
||||||
|
}
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an OAuth callback url
|
||||||
|
*
|
||||||
|
* @param callback callback url. Must be a valid url or 'oob' for out of band OAuth
|
||||||
|
* @return the {@link ServiceBuilder} instance for method chaining
|
||||||
|
*/
|
||||||
|
public ServiceBuilder callback(String callback)
|
||||||
|
{
|
||||||
|
Preconditions.checkValidOAuthCallback(callback, "Callback must be a valid URL or 'oob'");
|
||||||
|
this.callback = callback;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the api key
|
||||||
|
*
|
||||||
|
* @param apiKey The api key for your application
|
||||||
|
* @return the {@link ServiceBuilder} instance for method chaining
|
||||||
|
*/
|
||||||
|
public ServiceBuilder apiKey(String apiKey)
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString(apiKey, "Invalid Api key");
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the api secret
|
||||||
|
*
|
||||||
|
* @param apiSecret The api secret for your application
|
||||||
|
* @return the {@link ServiceBuilder} instance for method chaining
|
||||||
|
*/
|
||||||
|
public ServiceBuilder apiSecret(String apiSecret)
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString(apiSecret, "Invalid Api secret");
|
||||||
|
this.apiSecret = apiSecret;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fully configured {@link OAuthService}
|
||||||
|
*
|
||||||
|
* @return fully configured {@link OAuthService}
|
||||||
|
*/
|
||||||
|
public OAuthService build()
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(api, "You must specify a valid api through the provider() method");
|
||||||
|
Preconditions.checkEmptyString(apiKey, "You must provide an api key");
|
||||||
|
Preconditions.checkEmptyString(apiSecret, "You must provide an api secret");
|
||||||
|
return api.createService(apiKey, apiSecret, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
import org.scribe.oauth.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all the configuration needed to instantiate a valid {@link OAuthService}
|
||||||
|
*
|
||||||
|
* @author Pablo Fernandez
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Api
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates an {@link OAuthService}
|
||||||
|
*
|
||||||
|
* @param apiKey your application api key
|
||||||
|
* @param apiSecret your application api secret
|
||||||
|
* @param callback the callback url (or 'oob' for out of band OAuth)
|
||||||
|
*
|
||||||
|
* @return fully configured {@link OAuthService}
|
||||||
|
*/
|
||||||
|
OAuthService createService(String apiKey, String apiSecret, String callback);
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
import org.scribe.extractors.*;
|
||||||
|
import org.scribe.model.OAuthConfig;
|
||||||
|
import org.scribe.model.Request.Verb;
|
||||||
|
import org.scribe.oauth.OAuth10aServiceImpl;
|
||||||
|
import org.scribe.oauth.OAuthService;
|
||||||
|
import org.scribe.services.*;
|
||||||
|
|
||||||
|
public abstract class DefaultApi10a implements Api
|
||||||
|
{
|
||||||
|
public AccessTokenExtractor getAccessTokenExtractor()
|
||||||
|
{
|
||||||
|
return new TokenExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseStringExtractor getBaseStringExtractor()
|
||||||
|
{
|
||||||
|
return new BaseStringExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HeaderExtractor getHeaderExtractor()
|
||||||
|
{
|
||||||
|
return new HeaderExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestTokenExtractor getRequestTokenExtractor()
|
||||||
|
{
|
||||||
|
return new TokenExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignatureService getSignatureService()
|
||||||
|
{
|
||||||
|
return new HMACSha1SignatureService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimestampService getTimestampService()
|
||||||
|
{
|
||||||
|
return new TimestampServiceImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Verb getAccessTokenVerb()
|
||||||
|
{
|
||||||
|
return Verb.POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Verb getRequestTokenVerb()
|
||||||
|
{
|
||||||
|
return Verb.POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getRequestTokenEndpoint();
|
||||||
|
public abstract String getAccessTokenEndpoint();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuthService createService(String apiKey, String apiSecret, String callback)
|
||||||
|
{
|
||||||
|
return new OAuth10aServiceImpl( getSignatureService(),
|
||||||
|
getTimestampService(),
|
||||||
|
getBaseStringExtractor(),
|
||||||
|
getHeaderExtractor(),
|
||||||
|
getRequestTokenExtractor(),
|
||||||
|
getAccessTokenExtractor(),
|
||||||
|
createConfig(apiKey, apiSecret, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OAuthConfig createConfig(String apiKey, String apiSecret, String callback)
|
||||||
|
{
|
||||||
|
OAuthConfig config = new OAuthConfig();
|
||||||
|
config.setRequestTokenVerb(getRequestTokenVerb());
|
||||||
|
config.setRequestTokenEndpoint(getRequestTokenEndpoint());
|
||||||
|
config.setAccessTokenVerb(getAccessTokenVerb());
|
||||||
|
config.setAccessTokenEndpoint(getAccessTokenEndpoint());
|
||||||
|
config.setApiKey(apiKey);
|
||||||
|
config.setApiSecret(apiSecret);
|
||||||
|
config.setCallback(callback);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
public class FoursquareApi extends DefaultApi10a
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
public class GoogleApi extends DefaultApi10a
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
import org.scribe.extensions.linkedin.*;
|
||||||
|
import org.scribe.extractors.*;
|
||||||
|
|
||||||
|
public class LinkedInApi extends DefaultApi10a
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "https://api.linkedin.com/uas/oauth/accessToken";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "https://api.linkedin.com/uas/oauth/requestToken";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseStringExtractor getBaseStringExtractor()
|
||||||
|
{
|
||||||
|
return new LinkedInBaseStringExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
public class SalesForceApi extends DefaultApi10a
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "https://login.salesforce.com/_nc_external/system/security/oauth/AccessTokenHandler";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "https://login.salesforce.com/_nc_external/system/security/oauth/RequestTokenHandler";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
public class TwitterApi extends DefaultApi10a
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "http://twitter.com/oauth/access_token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "http://twitter.com/oauth/request_token";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.scribe.builder.api;
|
||||||
|
|
||||||
|
public class YahooApi extends DefaultApi10a
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "https://api.login.yahoo.com/oauth/v2/get_token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
return "https://api.login.yahoo.com/oauth/v2/get_request_token";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.scribe.exceptions;
|
||||||
|
|
||||||
|
public class OAuthException extends RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
public OAuthException(String message, Exception e)
|
||||||
|
{
|
||||||
|
super(message, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OAuthException(String message)
|
||||||
|
{
|
||||||
|
super(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.scribe.exceptions;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public class OAuthParametersMissingException extends OAuthException
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1745308760111976671L;
|
||||||
|
private static final String MSG = "Could not find oauth parameters in request: %s. "
|
||||||
|
+ "OAuth parameters must be specified with the addOAuthParameter() method";
|
||||||
|
|
||||||
|
public OAuthParametersMissingException(OAuthRequest request)
|
||||||
|
{
|
||||||
|
super(String.format(MSG, request));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.scribe.exceptions;
|
||||||
|
|
||||||
|
public class OAuthSignatureException extends OAuthException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public OAuthSignatureException(String stringToSign, Exception e)
|
||||||
|
{
|
||||||
|
super("Error while signing string: " + stringToSign, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.scribe.extensions.linkedin;
|
||||||
|
|
||||||
|
import org.scribe.extractors.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public class LinkedInBaseStringExtractorImpl extends BaseStringExtractorImpl
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String extract(OAuthRequest request)
|
||||||
|
{
|
||||||
|
String baseString = super.extract(request);
|
||||||
|
return baseString.replace("%7E", "~");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public interface AccessTokenExtractor
|
||||||
|
{
|
||||||
|
public Token extract(String response);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public interface BaseStringExtractor
|
||||||
|
{
|
||||||
|
String extract(OAuthRequest request);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
public class BaseStringExtractorImpl implements BaseStringExtractor
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String AMPERSAND_SEPARATED_STRING = "%s&%s&%s";
|
||||||
|
|
||||||
|
public String extract(OAuthRequest request)
|
||||||
|
{
|
||||||
|
checkPreconditions(request);
|
||||||
|
String verb = URLUtils.percentEncode(request.getVerb().name());
|
||||||
|
String url = URLUtils.percentEncode(request.getSanitizedUrl());
|
||||||
|
String params = getSortedAndEncodedParams(request);
|
||||||
|
return String.format(AMPERSAND_SEPARATED_STRING, verb, url, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSortedAndEncodedParams(OAuthRequest request)
|
||||||
|
{
|
||||||
|
Map<String, String> params = new HashMap<String, String>();
|
||||||
|
params.putAll(request.getQueryStringParams());
|
||||||
|
params.putAll(request.getBodyParams());
|
||||||
|
params.putAll(request.getOauthParameters());
|
||||||
|
params = MapUtils.sort(params);
|
||||||
|
return URLUtils.percentEncode(URLUtils.formURLEncodeMap(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPreconditions(OAuthRequest request)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(request, "Cannot extract base string from null object");
|
||||||
|
|
||||||
|
if (request.getOauthParameters() == null || request.getOauthParameters().size() <= 0)
|
||||||
|
{
|
||||||
|
throw new OAuthParametersMissingException(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public interface HeaderExtractor
|
||||||
|
{
|
||||||
|
String extract(OAuthRequest request);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
public class HeaderExtractorImpl implements HeaderExtractor
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String PREAMBLE = "OAuth ";
|
||||||
|
|
||||||
|
public String extract(OAuthRequest request)
|
||||||
|
{
|
||||||
|
checkPreconditions(request);
|
||||||
|
Map<String, String> parameters = request.getOauthParameters();
|
||||||
|
StringBuffer header = new StringBuffer();
|
||||||
|
header.append(PREAMBLE);
|
||||||
|
for (String key : parameters.keySet())
|
||||||
|
{
|
||||||
|
addToHeader(header, key, parameters.get(key));
|
||||||
|
}
|
||||||
|
return removeTrail(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPreconditions(OAuthRequest request)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(request, "Cannot extract a header from a null object");
|
||||||
|
|
||||||
|
if (request.getOauthParameters() == null || request.getOauthParameters().size() <= 0)
|
||||||
|
{
|
||||||
|
throw new OAuthParametersMissingException(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToHeader(StringBuffer header, String name, String value)
|
||||||
|
{
|
||||||
|
header.append(String.format("%s=\"%s\", ", name, URLUtils.percentEncode(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String removeTrail(StringBuffer header)
|
||||||
|
{
|
||||||
|
return header.toString().substring(0, header.length() - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public interface RequestTokenExtractor
|
||||||
|
{
|
||||||
|
|
||||||
|
public Token extract(String response);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import java.util.regex.*;
|
||||||
|
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExtractor
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String TOKEN_REGEX = "oauth_token=(\\S*)&oauth_token_secret=(\\S*?)(&(.*))?";
|
||||||
|
|
||||||
|
public Token extract(String response)
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString(response, "Cant extract a token from null object or an empty string.");
|
||||||
|
|
||||||
|
Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
|
||||||
|
if (matcher.matches())
|
||||||
|
{
|
||||||
|
String token = URLUtils.percentDecode(matcher.group(1));
|
||||||
|
String secret = URLUtils.percentDecode(matcher.group(2));
|
||||||
|
return new Token(token, secret);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new OAuthException("Could not find request token or secret in response: " + response, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
|
||||||
|
public class OAuthConfig
|
||||||
|
{
|
||||||
|
private String apiKey;
|
||||||
|
private String apiSecret;
|
||||||
|
private String callback;
|
||||||
|
private String requestTokenEndpoint;
|
||||||
|
private String accessTokenEndpoint;
|
||||||
|
private Verb requestTokenVerb;
|
||||||
|
private Verb accessTokenVerb;
|
||||||
|
|
||||||
|
public String getApiKey()
|
||||||
|
{
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiKey(String apiKey)
|
||||||
|
{
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiSecret()
|
||||||
|
{
|
||||||
|
return apiSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiSecret(String apiSecret)
|
||||||
|
{
|
||||||
|
this.apiSecret = apiSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCallback()
|
||||||
|
{
|
||||||
|
return callback != null ? callback : OAuthConstants.OUT_OF_BAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallback(String callback)
|
||||||
|
{
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRequestTokenEndpoint()
|
||||||
|
{
|
||||||
|
return requestTokenEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestTokenEndpoint(String requestTokenEndpoint)
|
||||||
|
{
|
||||||
|
this.requestTokenEndpoint = requestTokenEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccessTokenEndpoint()
|
||||||
|
{
|
||||||
|
return accessTokenEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessTokenEndpoint(String accessTokenEndpoint)
|
||||||
|
{
|
||||||
|
this.accessTokenEndpoint = accessTokenEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Verb getRequestTokenVerb()
|
||||||
|
{
|
||||||
|
return requestTokenVerb != null ? requestTokenVerb : Verb.GET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestTokenVerb(Verb requestTokenVerb)
|
||||||
|
{
|
||||||
|
this.requestTokenVerb = requestTokenVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Verb getAccessTokenVerb()
|
||||||
|
{
|
||||||
|
return accessTokenVerb != null ? accessTokenVerb : Verb.GET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessTokenVerb(Verb accessTokenVerb)
|
||||||
|
{
|
||||||
|
this.accessTokenVerb = accessTokenVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Pablo Fernandez
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class contains OAuth constants, used project-wide
|
||||||
|
*
|
||||||
|
* @author Pablo Fernandez
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class OAuthConstants
|
||||||
|
{
|
||||||
|
public static final String TIMESTAMP = "oauth_timestamp";
|
||||||
|
public static final String SIGN_METHOD = "oauth_signature_method";
|
||||||
|
public static final String SIGNATURE = "oauth_signature";
|
||||||
|
public static final String CONSUMER_SECRET = "oauth_consumer_secret";
|
||||||
|
public static final String CONSUMER_KEY = "oauth_consumer_key";
|
||||||
|
public static final String CALLBACK = "oauth_callback";
|
||||||
|
public static final String VERSION = "oauth_version";
|
||||||
|
public static final String NONCE = "oauth_nonce";
|
||||||
|
public static final String PARAM_PREFIX = "oauth_";
|
||||||
|
public static final String TOKEN = "oauth_token";
|
||||||
|
public static final String TOKEN_SECRET = "oauth_token_secret";
|
||||||
|
public static final String OUT_OF_BAND = "oob";
|
||||||
|
public static final String VERIFIER = "oauth_verifier";
|
||||||
|
public static final String HEADER = "Authorization";
|
||||||
|
public static final Token EMPTY_TOKEN = new Token("", "");
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
public class OAuthParams
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class OAuthRequest extends Request
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String OAUTH_PREFIX = "oauth_";
|
||||||
|
private Map<String, String> oauthParameters;
|
||||||
|
|
||||||
|
public OAuthRequest(Verb verb, String url)
|
||||||
|
{
|
||||||
|
super(verb, url);
|
||||||
|
this.oauthParameters = new HashMap<String, String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addOAuthParameter(String key, String value)
|
||||||
|
{
|
||||||
|
oauthParameters.put(checkKey(key), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String checkKey(String key)
|
||||||
|
{
|
||||||
|
if (!key.startsWith(OAUTH_PREFIX))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format("OAuth parameters must start with '%s'", OAUTH_PREFIX));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getOauthParameters()
|
||||||
|
{
|
||||||
|
return oauthParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("@OAuthRequest(%s, %s)", getVerb(), getUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an HTTP Request object
|
||||||
|
*
|
||||||
|
* @author Pablo Fernandez
|
||||||
|
*/
|
||||||
|
public class Request
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String CONTENT_LENGTH = "Content-Length";
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
private Verb verb;
|
||||||
|
private Map<String, String> bodyParams;
|
||||||
|
private Map<String, String> headers;
|
||||||
|
private String payload = null;
|
||||||
|
private HttpURLConnection connection;
|
||||||
|
|
||||||
|
public Request(Verb verb, String url)
|
||||||
|
{
|
||||||
|
this.verb = verb;
|
||||||
|
this.url = url;
|
||||||
|
this.bodyParams = new HashMap<String, String>();
|
||||||
|
this.headers = new HashMap<String, String>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.connection = (HttpURLConnection) new URL(url).openConnection();
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
throw new OAuthException("Could not open connection to: " + url, ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the request and return a {@link Response}
|
||||||
|
*
|
||||||
|
* @return Http Response
|
||||||
|
* @throws RuntimeException
|
||||||
|
* if the connection cannot be created.
|
||||||
|
*/
|
||||||
|
public Response send()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return doSend();
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
throw new OAuthException("Problems while creating connection", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Response doSend() throws IOException
|
||||||
|
{
|
||||||
|
connection.setRequestMethod(this.verb.name());
|
||||||
|
addHeaders(connection);
|
||||||
|
if (verb.equals(Verb.PUT) || verb.equals(Verb.POST))
|
||||||
|
{
|
||||||
|
addBody(connection, getBodyContents());
|
||||||
|
}
|
||||||
|
return new Response(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addHeaders(HttpURLConnection conn)
|
||||||
|
{
|
||||||
|
for (String key : headers.keySet())
|
||||||
|
conn.setRequestProperty(key, headers.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addBody(HttpURLConnection conn, String content) throws IOException
|
||||||
|
{
|
||||||
|
conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.getBytes().length));
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
conn.getOutputStream().write(content.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an HTTP Header to the Request
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void addHeader(String key, String value)
|
||||||
|
{
|
||||||
|
this.headers.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a body Parameter (for POST/ PUT Requests)
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void addBodyParameter(String key, String value)
|
||||||
|
{
|
||||||
|
this.bodyParams.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add body payload.
|
||||||
|
*
|
||||||
|
* This method is used when the HTTP body is not a form-url-encoded string,
|
||||||
|
* but another thing. Like for example XML.
|
||||||
|
*
|
||||||
|
* Note: The contents are not part of the OAuth signature
|
||||||
|
*
|
||||||
|
* @param payload
|
||||||
|
*/
|
||||||
|
public void addPayload(String payload)
|
||||||
|
{
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link Map} of the query string parameters.
|
||||||
|
*
|
||||||
|
* @return a map containing the query string parameters
|
||||||
|
*/
|
||||||
|
public Map<String, String> getQueryStringParams()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Map<String, String> params = new HashMap<String, String>();
|
||||||
|
String query = new URL(url).getQuery();
|
||||||
|
if (query != null)
|
||||||
|
{
|
||||||
|
for (String param : query.split("&"))
|
||||||
|
{
|
||||||
|
String pair[] = param.split("=");
|
||||||
|
params.put(pair[0], pair[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
} catch (MalformedURLException mue)
|
||||||
|
{
|
||||||
|
throw new OAuthException("Malformed URL", mue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a {@link Map} of the body parameters.
|
||||||
|
*
|
||||||
|
* @return a map containing the body parameters.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getBodyParams()
|
||||||
|
{
|
||||||
|
return bodyParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the URL of the HTTP Request.
|
||||||
|
*
|
||||||
|
* @return the original URL of the HTTP Request
|
||||||
|
*/
|
||||||
|
public String getUrl()
|
||||||
|
{
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL without the port and the query string part.
|
||||||
|
*
|
||||||
|
* @return the OAuth-sanitized URL
|
||||||
|
*/
|
||||||
|
public String getSanitizedUrl()
|
||||||
|
{
|
||||||
|
return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBodyContents()
|
||||||
|
{
|
||||||
|
return (payload != null) ? payload : URLUtils.formURLEncodeMap(bodyParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP Verb
|
||||||
|
*
|
||||||
|
* @return the verb
|
||||||
|
*/
|
||||||
|
public Verb getVerb()
|
||||||
|
{
|
||||||
|
return verb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getHeaders()
|
||||||
|
{
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setConnection(HttpURLConnection connection)
|
||||||
|
{
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("@Request(%s %s)", getVerb(), getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enumeration containing the most common HTTP Verbs.
|
||||||
|
*
|
||||||
|
* @author Pablo Fernandez
|
||||||
|
*/
|
||||||
|
public static enum Verb
|
||||||
|
{
|
||||||
|
GET, POST, PUT, DELETE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an HTTP Response.
|
||||||
|
*
|
||||||
|
* @author Pablo Fernandez
|
||||||
|
*/
|
||||||
|
public class Response
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String EMPTY = "";
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
private String body;
|
||||||
|
private InputStream stream;
|
||||||
|
private Map<String, String> headers;
|
||||||
|
|
||||||
|
Response(HttpURLConnection connection) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connection.connect();
|
||||||
|
code = connection.getResponseCode();
|
||||||
|
headers = parseHeaders(connection);
|
||||||
|
stream = wasSuccessful() ? connection.getInputStream() : connection.getErrorStream();
|
||||||
|
} catch (UnknownHostException e)
|
||||||
|
{
|
||||||
|
code = 404;
|
||||||
|
body = EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseBodyContents()
|
||||||
|
{
|
||||||
|
body = StreamUtils.getStreamContents(getStream());
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> parseHeaders(HttpURLConnection conn)
|
||||||
|
{
|
||||||
|
Map<String, String> headers = new HashMap<String, String>();
|
||||||
|
for (String key : conn.getHeaderFields().keySet())
|
||||||
|
{
|
||||||
|
headers.put(key, conn.getHeaderFields().get(key).get(0));
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the code is in the successful or redirect range.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
private boolean wasSuccessful()
|
||||||
|
{
|
||||||
|
return getCode() >= 200 && getCode() < 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the HTTP Response body
|
||||||
|
*
|
||||||
|
* @return response body
|
||||||
|
*/
|
||||||
|
public String getBody()
|
||||||
|
{
|
||||||
|
return body != null ? body : parseBodyContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the meaningful stream of the HttpUrlConnection, either inputStream
|
||||||
|
* or errorInputStream, depending on the status code
|
||||||
|
*
|
||||||
|
* @return input stream / error stream
|
||||||
|
*/
|
||||||
|
public InputStream getStream()
|
||||||
|
{
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the HTTP status code
|
||||||
|
*
|
||||||
|
* @return the status code
|
||||||
|
*/
|
||||||
|
public int getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a {@link Map} containing the HTTP Response Headers
|
||||||
|
*
|
||||||
|
* @return headers
|
||||||
|
*/
|
||||||
|
public Map<String, String> getHeaders()
|
||||||
|
{
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a single HTTP Header value, or null if undefined
|
||||||
|
*
|
||||||
|
* @param header
|
||||||
|
* name
|
||||||
|
*
|
||||||
|
* @return header value or null
|
||||||
|
*/
|
||||||
|
public String getHeader(String name)
|
||||||
|
{
|
||||||
|
return headers.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
public class Token
|
||||||
|
{
|
||||||
|
|
||||||
|
private final String token;
|
||||||
|
private final String secret;
|
||||||
|
|
||||||
|
public Token(String token, String secret)
|
||||||
|
{
|
||||||
|
this.token = token;
|
||||||
|
this.secret = secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken()
|
||||||
|
{
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSecret()
|
||||||
|
{
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("Token[%s , %s]", token, secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
public class Verifier
|
||||||
|
{
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public Verifier(String value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package org.scribe.oauth;
|
||||||
|
|
||||||
|
import org.scribe.extractors.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.services.*;
|
||||||
|
|
||||||
|
public class OAuth10aServiceImpl implements OAuthService
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String VERSION = "1.0";
|
||||||
|
|
||||||
|
private OAuthConfig config;
|
||||||
|
private SignatureService signatureService;
|
||||||
|
private TimestampService timestampService;
|
||||||
|
private BaseStringExtractor baseStringExtractor;
|
||||||
|
private HeaderExtractor headerExtractor;
|
||||||
|
private RequestTokenExtractor rtExtractor;
|
||||||
|
private AccessTokenExtractor atExtractor;
|
||||||
|
|
||||||
|
public OAuth10aServiceImpl(SignatureService signatureService, TimestampService timestampService, BaseStringExtractor baseStringExtractor,
|
||||||
|
HeaderExtractor headerExtractor, RequestTokenExtractor rtExtractor, AccessTokenExtractor atExtractor, OAuthConfig config)
|
||||||
|
{
|
||||||
|
this.signatureService = signatureService;
|
||||||
|
this.timestampService = timestampService;
|
||||||
|
this.baseStringExtractor = baseStringExtractor;
|
||||||
|
this.headerExtractor = headerExtractor;
|
||||||
|
this.rtExtractor = rtExtractor;
|
||||||
|
this.atExtractor = atExtractor;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Token getRequestToken()
|
||||||
|
{
|
||||||
|
OAuthRequest request = new OAuthRequest(config.getRequestTokenVerb(), config.getRequestTokenEndpoint());
|
||||||
|
addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
|
||||||
|
addOAuthHeader(request);
|
||||||
|
Response response = request.send();
|
||||||
|
return rtExtractor.extract(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOAuthParams(OAuthRequest request, Token token)
|
||||||
|
{
|
||||||
|
request.addOAuthParameter(OAuthConstants.TIMESTAMP, timestampService.getTimestampInSeconds());
|
||||||
|
request.addOAuthParameter(OAuthConstants.NONCE, timestampService.getNonce());
|
||||||
|
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
|
||||||
|
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, signatureService.getSignatureMethod());
|
||||||
|
request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
|
||||||
|
request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
|
||||||
|
request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Token getAccessToken(Token requestToken, Verifier verifier)
|
||||||
|
{
|
||||||
|
OAuthRequest request = new OAuthRequest(config.getAccessTokenVerb(), config.getAccessTokenEndpoint());
|
||||||
|
request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken());
|
||||||
|
request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue());
|
||||||
|
addOAuthParams(request, requestToken);
|
||||||
|
addOAuthHeader(request);
|
||||||
|
Response response = request.send();
|
||||||
|
return atExtractor.extract(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void signRequest(Token token, OAuthRequest request)
|
||||||
|
{
|
||||||
|
request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken());
|
||||||
|
addOAuthParams(request, token);
|
||||||
|
addOAuthHeader(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion()
|
||||||
|
{
|
||||||
|
return VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSignature(OAuthRequest request, Token token)
|
||||||
|
{
|
||||||
|
String baseString = baseStringExtractor.extract(request);
|
||||||
|
return signatureService.getSignature(baseString, config.getApiSecret(), token.getSecret());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOAuthHeader(OAuthRequest request)
|
||||||
|
{
|
||||||
|
String oauthHeader = headerExtractor.extract(request);
|
||||||
|
request.addHeader(OAuthConstants.HEADER, oauthHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.scribe.oauth;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public interface OAuthService
|
||||||
|
{
|
||||||
|
public Token getRequestToken();
|
||||||
|
|
||||||
|
public Token getAccessToken(Token requestToken, Verifier verifier);
|
||||||
|
|
||||||
|
public void signRequest(Token accessToken, OAuthRequest request);
|
||||||
|
|
||||||
|
public String getVersion();
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.scribe.services;
|
||||||
|
|
||||||
|
import javax.crypto.*;
|
||||||
|
import javax.crypto.spec.*;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.*;
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.utils.*;
|
||||||
|
|
||||||
|
public class HMACSha1SignatureService implements SignatureService
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String EMPTY_STRING = "";
|
||||||
|
private static final String CARRIAGE_RETURN = "\r\n";
|
||||||
|
private static final String UTF8 = "UTF-8";
|
||||||
|
private static final String HMAC_SHA1 = "HmacSHA1";
|
||||||
|
private static final String METHOD = "HMAC-SHA1";
|
||||||
|
|
||||||
|
public String getSignature(String baseString, String apiSecret, String tokenSecret)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string");
|
||||||
|
Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string");
|
||||||
|
return doSign(baseString, apiSecret + '&' + tokenSecret);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new OAuthSignatureException(baseString, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String doSign(String toSign, String keyString) throws Exception
|
||||||
|
{
|
||||||
|
SecretKeySpec key = new SecretKeySpec((keyString).getBytes(UTF8), HMAC_SHA1);
|
||||||
|
Mac mac = Mac.getInstance(HMAC_SHA1);
|
||||||
|
mac.init(key);
|
||||||
|
byte[] bytes = mac.doFinal(toSign.getBytes(UTF8));
|
||||||
|
return new String(Base64.encodeBase64(bytes)).replace(CARRIAGE_RETURN, EMPTY_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignatureMethod()
|
||||||
|
{
|
||||||
|
return METHOD;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.scribe.services;
|
||||||
|
|
||||||
|
public interface SignatureService
|
||||||
|
{
|
||||||
|
public String getSignature(String baseString, String apiSecret, String tokenSecret);
|
||||||
|
|
||||||
|
public String getSignatureMethod();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.scribe.services;
|
||||||
|
|
||||||
|
public interface TimestampService
|
||||||
|
{
|
||||||
|
|
||||||
|
public String getTimestampInSeconds();
|
||||||
|
|
||||||
|
public String getNonce();
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package org.scribe.services;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TimestampServiceImpl implements TimestampService
|
||||||
|
{
|
||||||
|
|
||||||
|
private Timer timer;
|
||||||
|
|
||||||
|
public TimestampServiceImpl()
|
||||||
|
{
|
||||||
|
timer = new Timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce()
|
||||||
|
{
|
||||||
|
Long ts = getTs();
|
||||||
|
return String.valueOf(ts + timer.getRandomInteger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimestampInSeconds()
|
||||||
|
{
|
||||||
|
return String.valueOf(getTs());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getTs()
|
||||||
|
{
|
||||||
|
return timer.getMilis() / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTimer(Timer timer)
|
||||||
|
{
|
||||||
|
this.timer = timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Timer
|
||||||
|
{
|
||||||
|
public Long getMilis()
|
||||||
|
{
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRandomInteger()
|
||||||
|
{
|
||||||
|
return new Random().nextInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final Map<String, String> sort(Map<String, String> map)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(map, "Cannot sort a null object.");
|
||||||
|
|
||||||
|
Map<String, String> sorted = new LinkedHashMap<String, String>();
|
||||||
|
for (String key : getSortedKeys(map))
|
||||||
|
{
|
||||||
|
sorted.put(key, map.get(key));
|
||||||
|
}
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,48 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import org.scribe.model.OAuthConstants;
|
||||||
|
|
||||||
|
public class Preconditions
|
||||||
|
{
|
||||||
|
private static final String DEFAULT_MESSAGE = "Received an invalid parameter";
|
||||||
|
|
||||||
|
public static void checkNotNull(Object object, String errorMsg)
|
||||||
|
{
|
||||||
|
check(object != null, errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkEmptyString(String string, String errorMsg)
|
||||||
|
{
|
||||||
|
check(string != null && !string.trim().isEmpty(), errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkValidUrl(String url, String errorMsg)
|
||||||
|
{
|
||||||
|
checkEmptyString(url, errorMsg);
|
||||||
|
check(isUrl(url), errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkValidOAuthCallback(String url, String errorMsg)
|
||||||
|
{
|
||||||
|
checkEmptyString(url, errorMsg);
|
||||||
|
if(url.toLowerCase().compareToIgnoreCase(OAuthConstants.OUT_OF_BAND) != 0)
|
||||||
|
{
|
||||||
|
check(isUrl(url), errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isUrl(String url)
|
||||||
|
{
|
||||||
|
return url.startsWith("http://") || url.startsWith("https://");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void check(boolean requirements, String error)
|
||||||
|
{
|
||||||
|
String message = (error == null || error.trim().isEmpty()) ? DEFAULT_MESSAGE : error;
|
||||||
|
if (!requirements)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class StreamUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
public static String getStreamContents(InputStream is)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(is, "Cannot get String from a null object");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final char[] buffer = new char[0x10000];
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
Reader in = new InputStreamReader(is, "UTF-8");
|
||||||
|
int read;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
read = in.read(buffer, 0, buffer.length);
|
||||||
|
if (read > 0)
|
||||||
|
{
|
||||||
|
out.append(buffer, 0, read);
|
||||||
|
}
|
||||||
|
} while (read >= 0);
|
||||||
|
in.close();
|
||||||
|
return out.toString();
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Error while reading response body", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
|
||||||
|
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 String ERROR_MSG = String.format("Cannot find specified encoding: %s", UTF_8);
|
||||||
|
|
||||||
|
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();
|
||||||
|
for (String key : map.keySet())
|
||||||
|
{
|
||||||
|
encodedString.append(percentEncode(key)).append(PAIR_SEPARATOR).append(percentEncode(map.get(key))).append(PARAM_SEPARATOR);
|
||||||
|
}
|
||||||
|
return removeTrailingSeparator(encodedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String removeTrailingSeparator(StringBuffer buffer)
|
||||||
|
{
|
||||||
|
return buffer.toString().substring(0, buffer.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String percentEncode(String string)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(string, "Cannot encode null string");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return URLEncoder.encode(string, UTF_8);
|
||||||
|
} catch (UnsupportedEncodingException uee)
|
||||||
|
{
|
||||||
|
throw new OAuthException(ERROR_MSG, uee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 OAuthException(ERROR_MSG, uee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
import org.scribe.test.helpers.*;
|
||||||
|
|
||||||
|
public class BaseStringExtractorTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private BaseStringExtractorImpl extractor;
|
||||||
|
private OAuthRequest request;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
request = ObjectMother.createSampleOAuthRequest();
|
||||||
|
extractor = new BaseStringExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldExtractBaseStringFromOAuthRequest()
|
||||||
|
{
|
||||||
|
String expected = "GET&http%3A%2F%2Fexample.com&oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E*%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456";
|
||||||
|
String baseString = extractor.extract(request);
|
||||||
|
assertEquals(expected, baseString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionIfRquestIsNull()
|
||||||
|
{
|
||||||
|
OAuthRequest nullRequest = null;
|
||||||
|
extractor.extract(nullRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthParametersMissingException.class)
|
||||||
|
public void shouldThrowExceptionIfRquestHasNoOAuthParameters()
|
||||||
|
{
|
||||||
|
OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com");
|
||||||
|
extractor.extract(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
import org.scribe.test.helpers.*;
|
||||||
|
|
||||||
|
public class HeaderExtractorTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private HeaderExtractorImpl extractor;
|
||||||
|
private OAuthRequest request;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
request = ObjectMother.createSampleOAuthRequest();
|
||||||
|
extractor = new HeaderExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldExtractStandardHeader()
|
||||||
|
{
|
||||||
|
String expected = "OAuth oauth_callback=\"http%3A%2F%2Fexample%2Fcallback\", " + "oauth_signature=\"OAuth-Signature\", "
|
||||||
|
+ "oauth_consumer_key=\"AS%23%24%5E*%40%26\", " + "oauth_timestamp=\"123456\"";
|
||||||
|
String header = extractor.extract(request);
|
||||||
|
assertEquals(expected, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldExceptionIfRequestIsNull()
|
||||||
|
{
|
||||||
|
OAuthRequest nullRequest = null;
|
||||||
|
extractor.extract(nullRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthParametersMissingException.class)
|
||||||
|
public void shouldExceptionIfRequestHasNoOAuthParams()
|
||||||
|
{
|
||||||
|
OAuthRequest emptyRequest = new OAuthRequest(Verb.GET, "http://example.com");
|
||||||
|
extractor.extract(emptyRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package org.scribe.extractors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.exceptions.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
|
||||||
|
public class TokenExtractorTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private TokenExtractorImpl extractor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
extractor = new TokenExtractorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldExtractTokenFromOAuthStandardResponse()
|
||||||
|
{
|
||||||
|
String response = "oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03";
|
||||||
|
Token extracted = extractor.extract(response);
|
||||||
|
assertEquals("hh5s93j4hdidpola", extracted.getToken());
|
||||||
|
assertEquals("hdhd0244k9j7ao03", extracted.getSecret());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldExtractTokenFromResponseWithCallbackConfirmed()
|
||||||
|
{
|
||||||
|
String response = "oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03&callback_confirmed=true";
|
||||||
|
Token extracted = extractor.extract(response);
|
||||||
|
assertEquals("hh5s93j4hdidpola", extracted.getToken());
|
||||||
|
assertEquals("hdhd0244k9j7ao03", extracted.getSecret());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthException.class)
|
||||||
|
public void shouldThrowExceptionIfTokenIsAbsent()
|
||||||
|
{
|
||||||
|
String response = "oauth_secret=hh5s93j4hdidpola&callback_confirmed=true";
|
||||||
|
extractor.extract(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthException.class)
|
||||||
|
public void shouldThrowExceptionIfSecretIsAbsent()
|
||||||
|
{
|
||||||
|
String response = "oauth_token=hh5s93j4hdidpola&callback_confirmed=true";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ConnectionStub extends HttpURLConnection
|
||||||
|
{
|
||||||
|
|
||||||
|
private Map<String, String> headers = new HashMap<String, String>();
|
||||||
|
private Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
|
||||||
|
private int inputStreamCalled = 0;
|
||||||
|
|
||||||
|
public ConnectionStub() throws Exception
|
||||||
|
{
|
||||||
|
super(new URL("http://example.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRequestProperty(String key, String value)
|
||||||
|
{
|
||||||
|
headers.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getHeaders()
|
||||||
|
{
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getResponseCode() throws IOException
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException
|
||||||
|
{
|
||||||
|
inputStreamCalled++;
|
||||||
|
return new ByteArrayInputStream("contents".getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTimesCalledInpuStream()
|
||||||
|
{
|
||||||
|
return inputStreamCalled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputStream getOutputStream() throws IOException
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
baos.write("contents".getBytes());
|
||||||
|
return baos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getHeaderFields()
|
||||||
|
{
|
||||||
|
return responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addResponseHeader(String key, String value)
|
||||||
|
{
|
||||||
|
responseHeaders.put(key, Arrays.asList(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean usingProxy()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
|
||||||
|
public class OAuthConfigTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnDefaultValuesIfNotSet()
|
||||||
|
{
|
||||||
|
OAuthConfig config = new OAuthConfig();
|
||||||
|
assertEquals(Verb.GET, config.getAccessTokenVerb());
|
||||||
|
assertEquals(Verb.GET, config.getRequestTokenVerb());
|
||||||
|
assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldOverrideDefaultsIfSet()
|
||||||
|
{
|
||||||
|
OAuthConfig config = new OAuthConfig();
|
||||||
|
config.setCallback("http://callback");
|
||||||
|
config.setAccessTokenVerb(Verb.POST);
|
||||||
|
config.setRequestTokenVerb(Verb.POST);
|
||||||
|
assertEquals("http://callback", config.getCallback());
|
||||||
|
assertEquals(Verb.POST, config.getAccessTokenVerb());
|
||||||
|
assertEquals(Verb.POST, config.getRequestTokenVerb());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
|
||||||
|
public class OAuthRequestTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private OAuthRequest request;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
request = new OAuthRequest(Verb.GET, "http://example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAddOAuthParamters()
|
||||||
|
{
|
||||||
|
request.addOAuthParameter(OAuthConstants.TOKEN, "token");
|
||||||
|
request.addOAuthParameter(OAuthConstants.NONCE, "nonce");
|
||||||
|
request.addOAuthParameter(OAuthConstants.TIMESTAMP, "ts");
|
||||||
|
|
||||||
|
assertEquals(3, request.getOauthParameters().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionIfParameterIsNotOAuth()
|
||||||
|
{
|
||||||
|
request.addOAuthParameter("otherParam", "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
|
||||||
|
public class RequestTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private Request getRequest;
|
||||||
|
private Request postRequest;
|
||||||
|
private ConnectionStub connection;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception
|
||||||
|
{
|
||||||
|
connection = new ConnectionStub();
|
||||||
|
postRequest = new Request(Verb.POST, "http://example.com");
|
||||||
|
postRequest.setConnection(connection);
|
||||||
|
getRequest = new Request(Verb.GET, "http://example.com?qsparam=value&other=value+with+spaces");
|
||||||
|
getRequest.setConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSetRequestVerb()
|
||||||
|
{
|
||||||
|
getRequest.send();
|
||||||
|
assertEquals("GET", connection.getRequestMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldGetQueryStringParameters()
|
||||||
|
{
|
||||||
|
assertEquals(2, getRequest.getQueryStringParams().size());
|
||||||
|
assertEquals(0, postRequest.getQueryStringParams().size());
|
||||||
|
assertTrue(getRequest.getQueryStringParams().containsKey("qsparam"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAddRequestHeaders()
|
||||||
|
{
|
||||||
|
getRequest.addHeader("Header", "1");
|
||||||
|
getRequest.addHeader("Header2", "2");
|
||||||
|
getRequest.send();
|
||||||
|
assertEquals(2, getRequest.getHeaders().size());
|
||||||
|
assertEquals(2, connection.getHeaders().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSetBodyParamsAndHeaders()
|
||||||
|
{
|
||||||
|
postRequest.addBodyParameter("param", "value");
|
||||||
|
postRequest.addBodyParameter("param two", "value with spaces");
|
||||||
|
postRequest.send();
|
||||||
|
assertEquals("param+two=value+with+spaces¶m=value", postRequest.getBodyContents());
|
||||||
|
assertTrue(connection.getHeaders().containsKey("Content-Length"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSetPayloadAndHeaders()
|
||||||
|
{
|
||||||
|
postRequest.addPayload("PAYLOAD");
|
||||||
|
postRequest.send();
|
||||||
|
assertEquals("PAYLOAD", postRequest.getBodyContents());
|
||||||
|
assertTrue(connection.getHeaders().containsKey("Content-Length"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package org.scribe.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
public class ResponseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private Response response;
|
||||||
|
private ConnectionStub connection;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception
|
||||||
|
{
|
||||||
|
connection = new ConnectionStub();
|
||||||
|
connection.addResponseHeader("one", "one");
|
||||||
|
connection.addResponseHeader("two", "two");
|
||||||
|
response = new Response(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPopulateResponseHeaders()
|
||||||
|
{
|
||||||
|
assertEquals(2, response.getHeaders().size());
|
||||||
|
assertEquals("one", response.getHeader("one"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldParseBodyContents()
|
||||||
|
{
|
||||||
|
assertEquals("contents", response.getBody());
|
||||||
|
assertEquals(1, connection.getTimesCalledInpuStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldParseBodyContentsOnlyOnce()
|
||||||
|
{
|
||||||
|
assertEquals("contents", response.getBody());
|
||||||
|
assertEquals("contents", response.getBody());
|
||||||
|
assertEquals("contents", response.getBody());
|
||||||
|
assertEquals(1, connection.getTimesCalledInpuStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleAConnectionWithErrors() throws Exception
|
||||||
|
{
|
||||||
|
Response errResponse = new Response(new FaultyConnection());
|
||||||
|
assertEquals(400, errResponse.getCode());
|
||||||
|
assertEquals("errors", errResponse.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FaultyConnection extends ConnectionStub
|
||||||
|
{
|
||||||
|
|
||||||
|
public FaultyConnection() throws Exception
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getErrorStream()
|
||||||
|
{
|
||||||
|
return new ByteArrayInputStream("errors".getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getResponseCode() throws IOException
|
||||||
|
{
|
||||||
|
return 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.scribe.services;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.scribe.exceptions.OAuthException;
|
||||||
|
|
||||||
|
public class HMACSha1SignatureServiceTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private HMACSha1SignatureService service;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
service = new HMACSha1SignatureService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnSignatureMethodString()
|
||||||
|
{
|
||||||
|
String expected = "HMAC-SHA1";
|
||||||
|
assertEquals(expected, service.getSignatureMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnSignature()
|
||||||
|
{
|
||||||
|
String apiSecret = "api secret";
|
||||||
|
String tokenSecret = "token secret";
|
||||||
|
String baseString = "base string";
|
||||||
|
String signature = "cyxvUDZY/5cQBcBiKulaNgnhN/w=";
|
||||||
|
assertEquals(signature, service.getSignature(baseString, apiSecret, tokenSecret));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthException.class)
|
||||||
|
public void shouldThrowExceptionIfBaseStringIsNull()
|
||||||
|
{
|
||||||
|
service.getSignature(null, "apiSecret", "tokenSecret");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthException.class)
|
||||||
|
public void shouldThrowExceptionIfBaseStringIsEmpty()
|
||||||
|
{
|
||||||
|
service.getSignature(" ", "apiSecret", "tokenSecret");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthException.class)
|
||||||
|
public void shouldThrowExceptionIfApiSecretIsNull()
|
||||||
|
{
|
||||||
|
service.getSignature("base string", null, "tokenSecret");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = OAuthException.class)
|
||||||
|
public void shouldThrowExceptionIfApiSecretIsEmpty()
|
||||||
|
{
|
||||||
|
service.getSignature("base string", " ", "tokenSecret");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.scribe.services;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
public class TimestampServiceTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private TimestampServiceImpl service;
|
||||||
|
private TimestampServiceImpl.Timer timerStub;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
service = new TimestampServiceImpl();
|
||||||
|
timerStub = new TimerStub();
|
||||||
|
service.setTimer(timerStub);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnTimestampInSeconds()
|
||||||
|
{
|
||||||
|
String expected = "1000";
|
||||||
|
assertEquals(expected, service.getTimestampInSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnNonce()
|
||||||
|
{
|
||||||
|
String expected = "1042";
|
||||||
|
assertEquals(expected, service.getNonce());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TimerStub extends TimestampServiceImpl.Timer
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getMilis()
|
||||||
|
{
|
||||||
|
return 1000000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getRandomInteger()
|
||||||
|
{
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.scribe.specs;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import org.scribe.builder.*;
|
||||||
|
import org.scribe.builder.api.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
import org.scribe.oauth.*;
|
||||||
|
|
||||||
|
public class LinkedInSpec
|
||||||
|
{
|
||||||
|
private static final String AUTHORIZE_URL = "https://api.linkedin.com/uas/oauth/authorize?oauth_token=";
|
||||||
|
private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)";
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
OAuthService service = new ServiceBuilder()
|
||||||
|
.provider(LinkedInApi.class)
|
||||||
|
.apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV")
|
||||||
|
.apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Scanner in = new Scanner(System.in);
|
||||||
|
System.out.println("=== LinkedIn's OAuth Workflow ===");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
// Obtain the Request Token
|
||||||
|
System.out.println("Fetching the Request Token...");
|
||||||
|
Token requestToken = service.getRequestToken();
|
||||||
|
System.out.println("Got the Request Token!");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
System.out.println("Now go and authorize Scribe here:");
|
||||||
|
System.out.println(AUTHORIZE_URL + requestToken.getToken());
|
||||||
|
System.out.println("And paste the verifier 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.getBody());
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
|
||||||
|
|
||||||
|
System.out.println(service.getRequestToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package org.scribe.specs;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import org.scribe.builder.*;
|
||||||
|
import org.scribe.builder.api.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
import org.scribe.oauth.*;
|
||||||
|
|
||||||
|
public class TwitterSpec
|
||||||
|
{
|
||||||
|
private static final String AUTHORIZE_URL = "https://twitter.com/oauth/authorize?oauth_token=";
|
||||||
|
private static final String PROTECTED_RESOURCE_URL = "http://api.twitter.com/1/account/verify_credentials.xml";
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
OAuthService service = new ServiceBuilder()
|
||||||
|
.provider(TwitterApi.class)
|
||||||
|
.apiKey("6icbcAXyZx67r8uTAUM5Qw")
|
||||||
|
.apiSecret("SCCAdUUc6LXxiazxH3N0QfpNUvlUy84mZ2XZKiv39s")
|
||||||
|
.build();
|
||||||
|
Scanner in = new Scanner(System.in);
|
||||||
|
|
||||||
|
System.out.println("=== Twitter's OAuth Workflow ===");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
// Obtain the Request Token
|
||||||
|
System.out.println("Fetching the Request Token...");
|
||||||
|
Token requestToken = service.getRequestToken();
|
||||||
|
System.out.println("Got the Request Token!");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
System.out.println("Now go and authorize Resin here:");
|
||||||
|
System.out.println(AUTHORIZE_URL + requestToken.getToken());
|
||||||
|
System.out.println("And paste the verifier 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.getBody());
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("Thats it man! Go and build something awesome with Resin! :)");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.scribe.specs;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import org.scribe.builder.*;
|
||||||
|
import org.scribe.builder.api.*;
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
import org.scribe.oauth.*;
|
||||||
|
|
||||||
|
public class YahooSpec
|
||||||
|
{
|
||||||
|
private static final String NETWORK_NAME = "Yahoo";
|
||||||
|
private static final String AUTHORIZE_URL = "https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token=";
|
||||||
|
private static final String PROTECTED_RESOURCE_URL = "http://social.yahooapis.com/v1/user/A6ROU63MXWDCW3Y5MGCYWVHDJI/profile/status?format=json";
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
OAuthService service = new ServiceBuilder()
|
||||||
|
.provider(YahooApi.class)
|
||||||
|
.apiKey("dj0yJmk9TXZDWVpNVVdGaVFmJmQ9WVdrOWMweHZXbkZLTkhVbWNHbzlNVEl5TWprd05qUTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0wMw--")
|
||||||
|
.apiSecret("262be559f92a2be20c4c039419018f2b48cdfce9")
|
||||||
|
.build();
|
||||||
|
Scanner in = new Scanner(System.in);
|
||||||
|
|
||||||
|
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
// Obtain the Request Token
|
||||||
|
System.out.println("Fetching the Request Token...");
|
||||||
|
Token requestToken = service.getRequestToken();
|
||||||
|
System.out.println("Got the Request Token!");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
System.out.println("Now go and authorize Scribe here:");
|
||||||
|
System.out.println(AUTHORIZE_URL + requestToken.getToken());
|
||||||
|
System.out.println("And paste the verifier 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,18 @@
|
|||||||
|
package org.scribe.test.helpers;
|
||||||
|
|
||||||
|
import org.scribe.model.*;
|
||||||
|
import org.scribe.model.Request.*;
|
||||||
|
|
||||||
|
public class ObjectMother
|
||||||
|
{
|
||||||
|
|
||||||
|
public static OAuthRequest createSampleOAuthRequest()
|
||||||
|
{
|
||||||
|
OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com");
|
||||||
|
request.addOAuthParameter(OAuthConstants.TIMESTAMP, "123456");
|
||||||
|
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "AS#$^*@&");
|
||||||
|
request.addOAuthParameter(OAuthConstants.CALLBACK, "http://example/callback");
|
||||||
|
request.addOAuthParameter(OAuthConstants.SIGNATURE, "OAuth-Signature");
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
public class MapUtilsTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private Map<String, String> unsorted;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
unsorted = new LinkedHashMap<String, String>();
|
||||||
|
unsorted.put("d", "fourth");
|
||||||
|
unsorted.put("a", "first");
|
||||||
|
unsorted.put("c", "third");
|
||||||
|
unsorted.put("b", "second");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSortMap()
|
||||||
|
{
|
||||||
|
Map<String, String> sorted = MapUtils.sort(unsorted);
|
||||||
|
List<String> values = new ArrayList<String>(sorted.values());
|
||||||
|
assertEquals("first", values.get(0));
|
||||||
|
assertEquals("second", values.get(1));
|
||||||
|
assertEquals("third", values.get(2));
|
||||||
|
assertEquals("fourth", values.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotModifyTheOriginalMap()
|
||||||
|
{
|
||||||
|
Map<String, String> sorted = MapUtils.sort(unsorted);
|
||||||
|
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,60 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
public class PreconditionsTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String ERROR_MSG = "";
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionForNullObjects()
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(null, ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionForNullStrings()
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString(null, ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionForEmptyStrings()
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString("", ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionForSpacesOnlyStrings()
|
||||||
|
{
|
||||||
|
Preconditions.checkEmptyString(" ", ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionForInvalidUrls()
|
||||||
|
{
|
||||||
|
Preconditions.checkValidUrl("this/is/not/a/valid/url", ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionForNullUrls()
|
||||||
|
{
|
||||||
|
Preconditions.checkValidUrl(null, ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shouldAllowValidUrls()
|
||||||
|
{
|
||||||
|
Preconditions.checkValidUrl("http://www.example.com", ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shouldAllowSSLUrls()
|
||||||
|
{
|
||||||
|
Preconditions.checkValidUrl("https://www.example.com", ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shouldAllowOutOfBandAsValidCallbackValue()
|
||||||
|
{
|
||||||
|
Preconditions.checkValidOAuthCallback("oob", ERROR_MSG);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class StreamUtilsTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCorrectlyDecodeAStream()
|
||||||
|
{
|
||||||
|
String value = "expected";
|
||||||
|
InputStream is = new ByteArrayInputStream(value.getBytes());
|
||||||
|
String decoded = StreamUtils.getStreamContents(is);
|
||||||
|
assertEquals("expected", decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldFailForNullParameter()
|
||||||
|
{
|
||||||
|
InputStream is = null;
|
||||||
|
StreamUtils.getStreamContents(is);
|
||||||
|
fail("Must throw exception before getting here");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package org.scribe.utils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
public class URLUtilsTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@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+with+spaces=value+with+spaces&%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+is+a+test+%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(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in new issue
Block a user