13 Commits
16 changed files with 175 additions and 69 deletions

No files matched your search

+7
View File
@@ -6,3 +6,10 @@
* FEATURE: Added support for Yammer and Evernote ( thanks oparrsih )
* FIX: Fixed bug that preventing setting the scope param on Google Api
[1.0.8]
* FEATURE: Added setConnectTimeout and setReadTimeout for the Request Object
* FIX: Fixed Evernote Api (uses GET for request and access tokens)
* REFACTOR: URLEncoding stuff. LinkedIn specific decoder is no longer needed
* FEATURE: Added Google example
+1 -1
View File
@@ -4,7 +4,7 @@
<groupId>org.scribe</groupId>
<artifactId>scribe</artifactId>
<packaging>jar</packaging>
<version>1.0.7</version>
<version>1.0.8</version>
<name>Scribe OAuth Library</name>
<description>The best OAuth library out there</description>
<url>http://github.com/fernandezpablo85/scribe-java</url>
@@ -1,7 +1,14 @@
package org.scribe.builder.api;
import org.scribe.model.Verb;
public class EvernoteApi extends DefaultApi10a
{
@Override
protected Verb getRequestTokenVerb()
{
return Verb.GET;
}
@Override
public String getRequestTokenEndpoint()
@@ -10,9 +17,14 @@ public class EvernoteApi extends DefaultApi10a
}
@Override
public String getAccessTokenEndpoint()
{
return "https://www.evernote.com/oauth";
protected Verb getAccessTokenVerb()
{
return Verb.GET;
}
@Override
public String getAccessTokenEndpoint()
{
return "https://www.evernote.com/oauth";
}
}
@@ -1,11 +1,7 @@
package org.scribe.builder.api;
import org.scribe.extensions.linkedin.*;
import org.scribe.extractors.*;
public class LinkedInApi extends DefaultApi10a
{
@Override
protected String getAccessTokenEndpoint()
{
@@ -17,11 +13,4 @@ public class LinkedInApi extends DefaultApi10a
{
return "https://api.linkedin.com/uas/oauth/requestToken";
}
@Override
protected BaseStringExtractor getBaseStringExtractor()
{
return new LinkedInBaseStringExtractorImpl();
}
}
@@ -5,12 +5,12 @@ public class TwitterApi extends DefaultApi10a
@Override
protected String getAccessTokenEndpoint()
{
return "http://twitter.com/oauth/access_token";
return "http://api.twitter.com/oauth/access_token";
}
@Override
protected String getRequestTokenEndpoint()
{
return "http://twitter.com/oauth/request_token";
return "http://api.twitter.com/oauth/request_token";
}
}
@@ -1,23 +0,0 @@
package org.scribe.extensions.linkedin;
import org.scribe.extractors.*;
import org.scribe.model.*;
/**
* LinkedIn's specific extractor that does not encode the tilde character.
*
* @author Pablo Fernandez
*/
public class LinkedInBaseStringExtractorImpl extends BaseStringExtractorImpl
{
/**
* {@inheritDoc}
*/
@Override
public String extract(OAuthRequest request)
{
String baseString = super.extract(request);
return baseString.replace("%7E", "~");
}
}
@@ -22,7 +22,7 @@ public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExt
*/
public Token extract(String response)
{
Preconditions.checkEmptyString(response, "Cant extract a token from null object or an empty string.");
Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string");
Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
if (matcher.matches())
@@ -32,7 +32,7 @@ public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExt
return new Token(token, secret);
} else
{
throw new OAuthException("Could not find request token or secret in response: " + response, null);
throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
}
}
}
+24 -11
View File
@@ -3,6 +3,7 @@ package org.scribe.model;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.scribe.exceptions.*;
import org.scribe.utils.*;
@@ -21,7 +22,6 @@ class Request
private Map<String, String> bodyParams;
private Map<String, String> headers;
private String payload = null;
private Integer timeout = null;
private HttpURLConnection connection;
/**
@@ -39,7 +39,6 @@ class Request
try
{
connection = (HttpURLConnection) new URL(url).openConnection();
if(timeout != null) connection.setConnectTimeout(timeout);
} catch (IOException ioe)
{
throw new OAuthException("Could not open connection to: " + url, ioe);
@@ -91,8 +90,8 @@ class Request
/**
* Add an HTTP Header to the Request
*
* @param name
* @param value
* @param key the header name
* @param value the header value
*/
public void addHeader(String key, String value)
{
@@ -102,8 +101,8 @@ class Request
/**
* Add a body Parameter (for POST/ PUT Requests)
*
* @param name
* @param value
* @param key the parameter name
* @param value the parameter value
*/
public void addBodyParameter(String key, String value)
{
@@ -118,7 +117,7 @@ class Request
*
* Note: The contents are not part of the OAuth signature
*
* @param payload
* @param payload the body of the request
*/
public void addPayload(String payload)
{
@@ -212,13 +211,27 @@ class Request
}
/**
* Sets the connection timeout in milliseconds for the underlying {@link HttpURLConnection}
* Sets the connect timeout for the underlying {@link HttpURLConnection}
*
* @param timeout in milliseconds
* @param duration duration of the timeout
*
* @param unit unit of time (milliseconds, seconds, etc)
*/
public void setTimeout(int timeout)
public void setConnectTimeout(int duration, TimeUnit unit)
{
this.timeout = timeout;
this.connection.setConnectTimeout((int) unit.toMillis(duration));
}
/**
* Sets the read timeout for the underlying {@link HttpURLConnection}
*
* @param duration duration of the timeout
*
* @param unit unit of time (milliseconds, seconds, etc)
*/
public void setReadTimeout(int duration, TimeUnit unit)
{
this.connection.setReadTimeout((int) unit.toMillis(duration));
}
/*
+35 -2
View File
@@ -20,6 +20,17 @@ public class URLUtils
private static final String ERROR_MSG = String.format("Cannot find specified encoding: %s", UTF_8);
private static final Set<EncodingRule> ENCODING_RULES;
static
{
Set<EncodingRule> rules = new HashSet<EncodingRule>();
rules.add(new EncodingRule("*","%2A"));
rules.add(new EncodingRule("+","%20"));
rules.add(new EncodingRule("%7E", "~"));
ENCODING_RULES = Collections.unmodifiableSet(rules);
}
/**
* Turns a map into a form-url-encoded string (key=value&key2=value2)
*
@@ -57,7 +68,12 @@ public class URLUtils
Preconditions.checkNotNull(string, "Cannot encode null string");
try
{
return URLEncoder.encode(string, UTF_8).replaceAll("\\+", "%20");
String encoded = URLEncoder.encode(string, UTF_8);
for(EncodingRule rule : ENCODING_RULES)
{
encoded = rule.apply(encoded);
}
return encoded;
}
catch (UnsupportedEncodingException uee)
{
@@ -77,9 +93,26 @@ public class URLUtils
try
{
return URLDecoder.decode(string, UTF_8);
} catch (UnsupportedEncodingException uee)
}
catch (UnsupportedEncodingException uee)
{
throw new OAuthException(ERROR_MSG, uee);
}
}
private static final class EncodingRule
{
private final String ch;
private final String toCh;
EncodingRule(String ch, String toCh)
{
this.ch = ch;
this.toCh = toCh;
}
String apply(String string) {
return string.replace(ch, toCh);
}
}
}
@@ -0,0 +1,66 @@
package org.scribe.examples;
import java.util.*;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class GoogleExample
{
private static final String NETWORK_NAME = "Google";
private static final String AUTHORIZE_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=";
private static final String PROTECTED_RESOURCE_URL = "https://docs.google.com/feeds/default/private/full/";
private static final String SCOPE = "https://docs.google.com/feeds/";
public static void main(String[] args)
{
OAuthService service = new ServiceBuilder()
.provider(GoogleApi.class)
.apiKey("anonymous")
.apiSecret("anonymous")
.scope(SCOPE)
.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("(if your curious it looks like this: " + requestToken + " )");
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);
request.addHeader("GData-Version", "3.0");
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! :)");
}
}
@@ -55,8 +55,6 @@ public class LinkedInExample
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
System.out.println(service.getRequestToken());
}
}
@@ -9,7 +9,7 @@ import org.scribe.oauth.*;
public class TwitterExample
{
private static final String AUTHORIZE_URL = "https://twitter.com/oauth/authorize?oauth_token=";
private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token=";
private static final String PROTECTED_RESOURCE_URL = "http://api.twitter.com/1/account/verify_credentials.xml";
public static void main(String[] args)
@@ -23,7 +23,7 @@ public class BaseStringExtractorTest
@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 expected = "GET&http%3A%2F%2Fexample.com&oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456";
String baseString = extractor.extract(request);
assertEquals(expected, baseString);
}
@@ -45,7 +45,7 @@ public class BaseStringExtractorTest
@Test
public void shouldProperlyEncodeSpaces()
{
String expected = "GET&http%3A%2F%2Fexample.com&body%3Dthis%2520param%2520has%2520whitespace%26oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E*%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456";
String expected = "GET&http%3A%2F%2Fexample.com&body%3Dthis%2520param%2520has%2520whitespace%26oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456";
request.addBodyParameter("body", "this param has whitespace");
assertEquals(expected, extractor.extract(request));
}
@@ -24,7 +24,7 @@ public class HeaderExtractorTest
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\"";
+ "oauth_consumer_key=\"AS%23%24%5E%2A%40%26\", " + "oauth_timestamp=\"123456\"";
String header = extractor.extract(request);
assertEquals(expected, header);
}
@@ -21,8 +21,9 @@ public class OAuthRequestTest
request.addOAuthParameter(OAuthConstants.TOKEN, "token");
request.addOAuthParameter(OAuthConstants.NONCE, "nonce");
request.addOAuthParameter(OAuthConstants.TIMESTAMP, "ts");
request.addOAuthParameter(OAuthConstants.SCOPE, "feeds");
assertEquals(3, request.getOauthParameters().size());
assertEquals(4, request.getOauthParameters().size());
}
@Test(expected = IllegalArgumentException.class)
@@ -8,13 +8,6 @@ import org.junit.*;
public class URLUtilsTest
{
@Before
public void setup()
{
}
@Test
public void shouldPercentEncodeMap()
{
@@ -51,6 +44,23 @@ public class URLUtilsTest
assertEquals(expected, URLUtils.percentDecode(toDecode));
}
@Test
public void shouldEncodeAllSpecialCharacters()
{
String plain = "!*'();:@&=+$,/?#[]";
String encoded = "%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%23%5B%5D";
assertEquals(encoded, URLUtils.percentEncode(plain));
assertEquals(plain, URLUtils.percentDecode(encoded));
}
@Test
public void shouldNotEncodeReservedCharacters()
{
String plain = "abcde123456-._~";
String encoded = plain;
assertEquals(encoded, URLUtils.percentEncode(plain));
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionIfMapIsNull()
{