Initial commit

This commit is contained in:
Pablo Fernandez committed 2010-09-05 17:01:30 -03:00
commit bfbe536886
59 files changed
+2540

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
# Eclipse specific settings
.classpath
.project
.settings
# Binaries
target
+51
View File
@@ -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
+35
View File
@@ -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());
}
}
+217
View File
@@ -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);
}
}
+30
View File
@@ -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&param=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);
}
}