diff --git a/.gitignore b/.gitignore
index a9a50de0e..fb123fe4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
.classpath
.project
.settings
+*.iml
# IntelliJ Idea settings
@@ -12,4 +13,4 @@ scribe.iml
# Binaries
-target
\ No newline at end of file
+target
diff --git a/bundle b/bundle
old mode 100755
new mode 100644
diff --git a/pom.xml b/pom.xml
index 7418220ef..2c26155b7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
org.scribe
scribe
jar
- 1.3.4
+ 1.3.4-patched
Scribe OAuth Library
The best OAuth library out there
http://github.com/fernandezpablo85/scribe-java
@@ -66,7 +66,7 @@
org.apache.maven.plugins
maven-gpg-plugin
1.4
-
+
org.codehaus.mojo
diff --git a/src/main/java/org/scribe/builder/ServiceBuilder.java b/src/main/java/org/scribe/builder/ServiceBuilder.java
index 27f3c8f63..a25e6ca59 100644
--- a/src/main/java/org/scribe/builder/ServiceBuilder.java
+++ b/src/main/java/org/scribe/builder/ServiceBuilder.java
@@ -22,8 +22,10 @@ public class ServiceBuilder
private Api api;
private String scope;
private SignatureType signatureType;
+ private String grantType;
+ private String accessType;
private OutputStream debugStream;
-
+
/**
* Default constructor
*/
@@ -127,6 +129,18 @@ public ServiceBuilder scope(String scope)
this.scope = scope;
return this;
}
+
+ /**
+ * Configures the OAuth access type. This is only necessary in some APIs (like Google's).
+ *
+ * @param accessType the OAuth access type, e.g. online or offline
+ * @return the {@link ServiceBuilder} instance for method chaining
+ */
+ public ServiceBuilder accessType(String accessType) {
+ Preconditions.checkEmptyString(accessType, "Invalid OAuth access type");
+ this.accessType = accessType;
+ return this;
+ }
/**
* Configures the signature type, choose between header, querystring, etc. Defaults to Header
@@ -154,6 +168,19 @@ public ServiceBuilder debug()
return this;
}
+ /**
+ * Configures the grant type
+ *
+ * @param grant type
+ * @return the {@link ServiceBuilder} instance for method chaining
+ */
+ public ServiceBuilder grantType(String grantType)
+ {
+ Preconditions.checkEmptyString(grantType, "Invalid OAuth Grant Type");
+ this.grantType = grantType;
+ return this;
+ }
+
/**
* Returns the fully configured {@link OAuthService}
*
@@ -164,6 +191,6 @@ 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(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, debugStream));
+ return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, debugStream, grantType, accessType));
}
}
diff --git a/src/main/java/org/scribe/builder/api/BistriApi.java b/src/main/java/org/scribe/builder/api/BistriApi.java
new file mode 100644
index 000000000..d5b9615a0
--- /dev/null
+++ b/src/main/java/org/scribe/builder/api/BistriApi.java
@@ -0,0 +1,40 @@
+package org.scribe.builder.api;
+
+import org.scribe.model.Token;
+import org.scribe.model.Verb;
+
+public class BistriApi
+ extends DefaultApi10a
+{
+ private static final String AUTHORIZATION_URL = "http://localhost:8080/oauth/authorize?oauth_token=%s";
+
+ @Override
+ public String getRequestTokenEndpoint()
+ {
+ return "http://localhost:8080/oauth/request_token";
+ }
+
+ @Override
+ public String getAccessTokenEndpoint()
+ {
+ return "http://localhost:8080/oauth/access_token";
+ }
+
+ @Override
+ public Verb getAccessTokenVerb()
+ {
+ return Verb.GET;
+ }
+
+ @Override
+ public Verb getRequestTokenVerb()
+ {
+ return Verb.GET;
+ }
+
+ @Override
+ public String getAuthorizationUrl( Token requestToken )
+ {
+ return String.format( AUTHORIZATION_URL, requestToken.getToken() );
+ }
+}
diff --git a/src/main/java/org/scribe/builder/api/DefaultApi20.java b/src/main/java/org/scribe/builder/api/DefaultApi20.java
index ffb620702..46fface96 100644
--- a/src/main/java/org/scribe/builder/api/DefaultApi20.java
+++ b/src/main/java/org/scribe/builder/api/DefaultApi20.java
@@ -6,65 +6,77 @@
/**
* Default implementation of the OAuth protocol, version 2.0 (draft 11)
- *
+ *
* This class is meant to be extended by concrete implementations of the API,
* providing the endpoints and endpoint-http-verbs.
- *
+ *
* If your Api adheres to the 2.0 (draft 11) protocol correctly, you just need to extend
* this class and define the getters for your endpoints.
- *
+ *
* If your Api does something a bit different, you can override the different
* extractors or services, in order to fine-tune the process. Please read the
* javadocs of the interfaces to get an idea of what to do.
*
* @author Diego Silveira
- *
*/
-public abstract class DefaultApi20 implements Api
+public abstract class DefaultApi20
+ implements Api
{
- /**
- * Returns the access token extractor.
- *
- * @return access token extractor
- */
- public AccessTokenExtractor getAccessTokenExtractor()
- {
- return new TokenExtractor20Impl();
- }
-
- /**
- * Returns the verb for the access token endpoint (defaults to GET)
- *
- * @return access token endpoint verb
- */
- public Verb getAccessTokenVerb()
- {
- return Verb.GET;
- }
-
- /**
- * Returns the URL that receives the access token requests.
- *
- * @return access token URL
- */
- public abstract String getAccessTokenEndpoint();
-
- /**
- * Returns the URL where you should redirect your users to authenticate
- * your application.
- *
- * @param config OAuth 2.0 configuration param object
- * @return the URL where you should redirect your users
- */
- public abstract String getAuthorizationUrl(OAuthConfig config);
+ public String getTokenParameterName()
+ {
+ return OAuthConstants.ACCESS_TOKEN;
+ }
+
+ /**
+ * Returns the access token extractor.
+ *
+ * @return access token extractor
+ */
+ public AccessTokenExtractor getAccessTokenExtractor()
+ {
+ return new TokenExtractor20Impl();
+ }
+
+ /**
+ * Returns the verb for the access token endpoint (defaults to GET)
+ *
+ * @return access token endpoint verb
+ */
+ public Verb getAccessTokenVerb()
+ {
+ return Verb.GET;
+ }
+
+ /**
+ * Returns the URL that receives the access token requests.
+ *
+ * @return access token URL
+ */
+ public abstract String getAccessTokenEndpoint();
+
+ /**
+ * Returns the URL where you should redirect your users to authenticate
+ * your application.
+ *
+ * @param config OAuth 2.0 configuration param object
+ * @return the URL where you should redirect your users
+ */
+ public abstract String getAuthorizationUrl( OAuthConfig config );
+
+ /**
+ * {@inheritDoc}
+ */
+ public OAuthService createService( OAuthConfig config )
+ {
+ return new OAuth20ServiceImpl( this, config );
+ }
/**
- * {@inheritDoc}
+ * @return the parameter needed to refresh a access token.
*/
- public OAuthService createService(OAuthConfig config)
+ public String getRefreshTokenParameterName()
{
- return new OAuth20ServiceImpl(this, config);
+ throw new UnsupportedOperationException("Refresh token is not implemented for "+getClass().getSimpleName());
}
-
}
diff --git a/src/main/java/org/scribe/builder/api/FacebookApi.java b/src/main/java/org/scribe/builder/api/FacebookApi.java
index 996a651e1..f19310cbf 100644
--- a/src/main/java/org/scribe/builder/api/FacebookApi.java
+++ b/src/main/java/org/scribe/builder/api/FacebookApi.java
@@ -1,33 +1,63 @@
package org.scribe.builder.api;
-import org.scribe.model.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
-import org.scribe.utils.*;
+import org.scribe.extractors.AccessTokenExtractor;
+import org.scribe.extractors.TokenExtractor20Impl;
+import org.scribe.model.OAuthConfig;
+import org.scribe.model.Token;
+import org.scribe.utils.OAuthEncoder;
+import org.scribe.utils.Preconditions;
-public class FacebookApi extends DefaultApi20
-{
- private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s";
+public class FacebookApi extends DefaultApi20 {
+ private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";
+ private static class FacebookTokenExtractor extends TokenExtractor20Impl {
+
+ private static final String TOKEN_REGEX = "expires=([0-9]+)";
+
+ @Override
+ public Token extract(String response) {
+ Token token = super.extract(response);
+
+ Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
+ if (matcher.find()) {
+ int expires = Integer.valueOf(OAuthEncoder.decode(matcher.group(1)));
+ token.setExpiresIn(expires);
+ }
+
+ return token;
+ }
+ }
+
@Override
- public String getAccessTokenEndpoint()
- {
+ public String getAccessTokenEndpoint() {
return "https://graph.facebook.com/oauth/access_token";
}
@Override
- public String getAuthorizationUrl(OAuthConfig config)
- {
- Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB");
+ public String getAuthorizationUrl(OAuthConfig config) {
+ Preconditions.checkValidUrl(config.getCallback(),
+ "Must provide a valid url as callback. Facebook does not support OOB");
// Append scope if present
- if(config.hasScope())
- {
- return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope()));
- }
- else
- {
+ if (config.hasScope()) {
+ return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()),
+ OAuthEncoder.encode(config.getScope()));
+ } else {
return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()));
}
}
-}
+
+ @Override
+ public AccessTokenExtractor getAccessTokenExtractor() {
+ return new FacebookTokenExtractor();
+ }
+
+ @Override
+ public String getRefreshTokenParameterName() {
+ return "fb_exchange_token";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/scribe/builder/api/GoogleApi20.java b/src/main/java/org/scribe/builder/api/GoogleApi20.java
new file mode 100755
index 000000000..3fcdb3eb0
--- /dev/null
+++ b/src/main/java/org/scribe/builder/api/GoogleApi20.java
@@ -0,0 +1,145 @@
+package org.scribe.builder.api;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.scribe.exceptions.OAuthException;
+import org.scribe.extractors.AccessTokenExtractor;
+import org.scribe.model.OAuthConfig;
+import org.scribe.model.OAuthConstants;
+import org.scribe.model.OAuthRequest;
+import org.scribe.model.Response;
+import org.scribe.model.Token;
+import org.scribe.model.Verb;
+import org.scribe.model.Verifier;
+import org.scribe.oauth.OAuth20ServiceImpl;
+import org.scribe.oauth.OAuthService;
+import org.scribe.utils.OAuthEncoder;
+import org.scribe.utils.Preconditions;
+
+public class GoogleApi20 extends DefaultApi20 {
+ private static final String AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%s&redirect_uri=%s";
+ private static final String SCOPE = "&scope=%s";
+ private static final String ACCESS_TYPE = "&access_type=%s";
+
+ @Override
+ public String getAccessTokenEndpoint() {
+ return "https://accounts.google.com/o/oauth2/token";
+ }
+
+ @Override
+ public AccessTokenExtractor getAccessTokenExtractor() {
+ return new AccessTokenExtractor() {
+
+ public Token extract(String response) {
+ Preconditions.checkEmptyString(response,
+ "Response body is incorrect. Can't extract a token from an empty string");
+
+ Matcher matcher = Pattern.compile("\"access_token\" : \"([^&\"]+)\"").matcher(response);
+ Matcher refreshMatcher = Pattern.compile("\"refresh_token\" : \"([^&\"]+)\"").matcher(response);
+ Matcher expiryMatcher = Pattern.compile("\"expires_in\" : ([0-9]+)").matcher(response);
+ if (matcher.find()) {
+ String token = OAuthEncoder.decode(matcher.group(1));
+ Token refreshToken = null;
+ int expiresIn = -1;
+
+ if (refreshMatcher.find()) {
+ String refreshTokenString = OAuthEncoder.decode(refreshMatcher.group(1));
+ refreshToken = new Token(refreshTokenString, "", response);
+ }
+
+ if (expiryMatcher.find()) {
+ String expiryString = OAuthEncoder.decode(expiryMatcher.group(1));
+ expiresIn = Integer.parseInt(expiryString);
+ }
+
+ return new Token(token, "", response, refreshToken, expiresIn);
+ } else {
+ throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'",
+ null);
+ }
+ }
+ };
+ }
+
+ @Override
+ public String getAuthorizationUrl(OAuthConfig config) {
+ String url = String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()));
+ if (config.hasScope()) {
+ // Append scope if present
+ url = url.concat(String.format(SCOPE, OAuthEncoder.encode(config.getScope())));
+ }
+ if (config.hasAccessType()) {
+ // Append access type if present
+ url = url.concat(String.format(ACCESS_TYPE, OAuthEncoder.encode(config.getAccessType())));
+ }
+ return url;
+
+ }
+
+ @Override
+ public Verb getAccessTokenVerb() {
+ return Verb.POST;
+ }
+
+ @Override
+ public OAuthService createService(OAuthConfig config) {
+ return new GoogleOAuth2Service(this, config);
+ }
+
+ private static class GoogleOAuth2Service extends OAuth20ServiceImpl {
+
+ private static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
+ private static final String GRANT_TYPE = "grant_type";
+ private DefaultApi20 api;
+ private OAuthConfig config;
+
+ public GoogleOAuth2Service(DefaultApi20 api, OAuthConfig config) {
+ super(api, config);
+ this.api = api;
+ this.config = config;
+ }
+
+ @Override
+ public Token getAccessToken(Token requestToken, Verifier verifier) {
+ OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
+ switch (api.getAccessTokenVerb()) {
+ case POST:
+ request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
+ request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
+ request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
+ request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
+ request.addBodyParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
+ break;
+ case GET:
+ default:
+ request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
+ request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
+ request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
+ request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
+ if (config.hasScope())
+ request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
+ }
+ Response response = request.send();
+ return api.getAccessTokenExtractor().extract(response.getBody());
+ }
+
+ @Override
+ public Token refreshAccessToken(Token accessToken) {
+ String accessTokenEndpoint = api.getAccessTokenEndpoint();
+ OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), accessTokenEndpoint);
+ request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
+ request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
+ request.addBodyParameter(OAuthConstants.GRANT_TYPE, api.getRefreshTokenParameterName());
+ request.addBodyParameter(api.getRefreshTokenParameterName(), accessToken.getToken());
+ Response response = request.send();
+ return api.getAccessTokenExtractor().extract(response.getBody());
+ }
+ }
+
+ @Override
+ public String getRefreshTokenParameterName() {
+ return "refresh_token";
+ }
+
+}
diff --git a/src/main/java/org/scribe/builder/api/LiveApi.java b/src/main/java/org/scribe/builder/api/LiveApi.java
index 18140f603..f3db6acc2 100644
--- a/src/main/java/org/scribe/builder/api/LiveApi.java
+++ b/src/main/java/org/scribe/builder/api/LiveApi.java
@@ -37,4 +37,10 @@ public AccessTokenExtractor getAccessTokenExtractor()
{
return new JsonTokenExtractor();
}
+
+ @Override
+ public String getRefreshTokenParameterName()
+ {
+ return "refresh_token";
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/scribe/model/OAuthConfig.java b/src/main/java/org/scribe/model/OAuthConfig.java
index 374c95894..51cde94dc 100644
--- a/src/main/java/org/scribe/model/OAuthConfig.java
+++ b/src/main/java/org/scribe/model/OAuthConfig.java
@@ -1,10 +1,10 @@
package org.scribe.model;
-import java.io.*;
+import java.io.OutputStream;
/**
* Parameter object that groups OAuth config values
- *
+ *
* @author Pablo Fernandez
*/
public class OAuthConfig
@@ -14,21 +14,31 @@ public class OAuthConfig
private final String callback;
private final SignatureType signatureType;
private final String scope;
+ private final String grantType;
private final OutputStream debugStream;
-
- public OAuthConfig(String key, String secret)
+ private final String accessType;
+
+ public OAuthConfig(String key, String secret )
{
this(key, secret, null, null, null, null);
}
public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope, OutputStream stream)
+ {
+ this(key, secret, callback, type, scope, stream, null, null);
+ }
+
+ public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope, OutputStream stream,
+ String grantType, String accessType)
{
this.apiKey = key;
this.apiSecret = secret;
- this.callback = callback;
- this.signatureType = type;
+ this.callback = callback != null ? callback : OAuthConstants.OUT_OF_BAND;
+ this.signatureType = (type != null) ? type : SignatureType.Header;
this.scope = scope;
+ this.grantType = grantType;
this.debugStream = stream;
+ this.accessType = accessType;
}
public String getApiKey()
@@ -55,12 +65,32 @@ public String getScope()
{
return scope;
}
+
+ public String getAccessType()
+ {
+ return accessType;
+ }
+
+ public String getGrantType()
+ {
+ return grantType;
+ }
public boolean hasScope()
{
return scope != null;
}
+ public boolean hasGrantType()
+ {
+ return grantType != null;
+ }
+
+ public boolean hasAccessType()
+ {
+ return accessType != null;
+ }
+
public void log(String message)
{
if (debugStream != null)
diff --git a/src/main/java/org/scribe/model/OAuthConstants.java b/src/main/java/org/scribe/model/OAuthConstants.java
index 1719c54d5..c811e8a7b 100644
--- a/src/main/java/org/scribe/model/OAuthConstants.java
+++ b/src/main/java/org/scribe/model/OAuthConstants.java
@@ -47,5 +47,10 @@ private OAuthConstants(){}
public static final String CLIENT_SECRET = "client_secret";
public static final String REDIRECT_URI = "redirect_uri";
public static final String CODE = "code";
+ public static final String GRANT_TYPE = "grant_type";
+ // GrantType
+ public static final String AUTHORIZATION_CODE = "authorization_code";
+ public static final String RESOURCE_OWNER_PASSWORD_CREDENTIALS = "password";
+ public static final String CLIENT_CREDENTIALS = "client_credentials";
}
diff --git a/src/main/java/org/scribe/model/Response.java b/src/main/java/org/scribe/model/Response.java
index d433922c6..aa3eb45c1 100644
--- a/src/main/java/org/scribe/model/Response.java
+++ b/src/main/java/org/scribe/model/Response.java
@@ -38,6 +38,11 @@ public class Response
}
}
+ public Response()
+ {
+
+ }
+
private String parseBodyContents()
{
body = StreamUtils.getStreamContents(getStream());
@@ -123,4 +128,4 @@ public String getHeader(String name)
return headers.get(name);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/scribe/model/Token.java b/src/main/java/org/scribe/model/Token.java
index 4d8c0eeb5..135dbc4f9 100644
--- a/src/main/java/org/scribe/model/Token.java
+++ b/src/main/java/org/scribe/model/Token.java
@@ -8,91 +8,105 @@
*
* @author Pablo Fernandez
*/
-public class Token implements Serializable
-{
- private static final long serialVersionUID = 715000866082812683L;
-
- private final String token;
- private final String secret;
- private final String rawResponse;
-
- /**
- * Default constructor
- *
- * @param token token value. Can't be null.
- * @param secret token secret. Can't be null.
- */
- public Token(String token, String secret)
- {
- this(token, secret, null);
- }
-
- public Token(String token, String secret, String rawResponse)
- {
- Preconditions.checkNotNull(token, "Token can't be null");
- Preconditions.checkNotNull(secret, "Secret can't be null");
-
- this.token = token;
- this.secret = secret;
- this.rawResponse = rawResponse;
- }
-
- public String getToken()
- {
- return token;
- }
-
- public String getSecret()
- {
- return secret;
- }
-
- public String getRawResponse()
- {
- if (rawResponse == null)
- {
- throw new IllegalStateException("This token object was not constructed by scribe and does not have a rawResponse");
- }
- return rawResponse;
- }
-
- @Override
- public String toString()
- {
- return String.format("Token[%s , %s]", token, secret);
- }
-
- /**
- * Returns true if the token is empty (token = "", secret = "")
- */
- public boolean isEmpty()
- {
- return "".equals(this.token) && "".equals(this.secret);
- }
-
- /**
- * Factory method that returns an empty token (token = "", secret = "").
- *
- * Useful for two legged OAuth.
- */
- public static Token empty()
- {
- return new Token("", "");
- }
-
- @Override
- public boolean equals(Object o)
- {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Token that = (Token) o;
- return token.equals(that.token) && secret.equals(that.secret);
- }
-
- @Override
- public int hashCode()
- {
- return 31 * token.hashCode() + secret.hashCode();
- }
+public class Token implements Serializable {
+ private static final long serialVersionUID = 715000866082812683L;
+
+ private final String token;
+ private final String secret;
+ private final String rawResponse;
+ private Token refreshToken = null;
+ private int expiresIn = 0;
+
+ /**
+ * Default constructor
+ *
+ * @param token
+ * token value. Can't be null.
+ * @param secret
+ * token secret. Can't be null.
+ */
+ public Token(String token, String secret) {
+ this(token, secret, null);
+ }
+
+ public Token(String token, String secret, String rawResponse) {
+ Preconditions.checkNotNull(token, "Token can't be null");
+ Preconditions.checkNotNull(secret, "Secret can't be null");
+
+ this.token = token;
+ this.secret = secret;
+ this.rawResponse = rawResponse;
+ }
+
+ public Token(String token, String secret, String rawResponse,
+ Token refreshToken, int expiresIn) {
+ this(token, secret, rawResponse);
+ this.refreshToken = refreshToken;
+ this.expiresIn = expiresIn;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ public String getRawResponse() {
+ if (rawResponse == null) {
+ throw new IllegalStateException(
+ "This token object was not constructed by scribe and does not have a rawResponse");
+ }
+ return rawResponse;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Token[%s , %s]", token, secret);
+ }
+
+ public Token getRefreshToken() {
+ return refreshToken;
+ }
+
+ public int getExpiresIn() {
+ return expiresIn;
+ }
+
+ public void setExpiresIn(int expiresIn) {
+ this.expiresIn = expiresIn;
+ }
+
+ /**
+ * Returns true if the token is empty (token = "", secret = "")
+ */
+ public boolean isEmpty() {
+ return "".equals(this.token) && "".equals(this.secret);
+ }
+
+ /**
+ * Factory method that returns an empty token (token = "", secret = "").
+ *
+ * Useful for two legged OAuth.
+ */
+ public static Token empty() {
+ return new Token("", "");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ Token that = (Token) o;
+ return token.equals(that.token) && secret.equals(that.secret);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * token.hashCode() + secret.hashCode();
+ }
}
diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java
index abde25399..fa5d1fae9 100644
--- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java
+++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java
@@ -15,127 +15,132 @@
*/
public class OAuth10aServiceImpl implements OAuthService
{
- private static final String VERSION = "1.0";
-
- private OAuthConfig config;
- private DefaultApi10a api;
-
- /**
- * Default constructor
- *
- * @param api OAuth1.0a api information
- * @param config OAuth 1.0a configuration param object
- */
- public OAuth10aServiceImpl(DefaultApi10a api, OAuthConfig config)
- {
- this.api = api;
- this.config = config;
- }
-
- /**
- * {@inheritDoc}
- */
- public Token getRequestToken(int timeout, TimeUnit unit)
- {
- return getRequestToken(new TimeoutTuner(timeout, unit));
- }
-
- public Token getRequestToken()
- {
- return getRequestToken(2, TimeUnit.SECONDS);
- }
-
- public Token getRequestToken(RequestTuner tuner)
- {
- config.log("obtaining request token from " + api.getRequestTokenEndpoint());
- OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());
-
- config.log("setting oauth_callback to " + config.getCallback());
- request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
- addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
- appendSignature(request);
-
- config.log("sending request...");
- Response response = request.send(tuner);
- String body = response.getBody();
-
- config.log("response status code: " + response.getCode());
- config.log("response body: " + body);
- return api.getRequestTokenExtractor().extract(body);
- }
-
- private void addOAuthParams(OAuthRequest request, Token token)
- {
- request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds());
- request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce());
- request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
- request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
- request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
- if(config.hasScope()) request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
- request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
-
- config.log("appended additional OAuth parameters: " + MapUtils.toString(request.getOauthParameters()));
- }
-
- /**
- * {@inheritDoc}
- */
- public Token getAccessToken(Token requestToken, Verifier verifier, int timeout, TimeUnit unit)
- {
- return getAccessToken(requestToken, verifier, new TimeoutTuner(timeout, unit));
- }
-
- public Token getAccessToken(Token requestToken, Verifier verifier)
- {
- return getAccessToken(requestToken, verifier, 2, TimeUnit.SECONDS);
- }
-
- public Token getAccessToken(Token requestToken, Verifier verifier, RequestTuner tuner)
- {
- config.log("obtaining access token from " + api.getAccessTokenEndpoint());
- OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
- request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken());
- request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue());
-
- config.log("setting token to: " + requestToken + " and verifier to: " + verifier);
- addOAuthParams(request, requestToken);
- appendSignature(request);
- Response response = request.send(tuner);
- return api.getAccessTokenExtractor().extract(response.getBody());
- }
-
- /**
- * {@inheritDoc}
- */
- public void signRequest(Token token, OAuthRequest request)
- {
- config.log("signing request: " + request.getCompleteUrl());
-
- // Do not append the token if empty. This is for two legged OAuth calls.
- if (!token.isEmpty())
- {
- request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken());
- }
- config.log("setting token to: " + token);
- addOAuthParams(request, token);
- appendSignature(request);
- }
-
- /**
- * {@inheritDoc}
- */
- public String getVersion()
- {
- return VERSION;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getAuthorizationUrl(Token requestToken)
- {
- return api.getAuthorizationUrl(requestToken);
- }
+ private static final String VERSION = "1.0";
+
+ private OAuthConfig config;
+ private DefaultApi10a api;
+
+ /**
+ * Default constructor
+ *
+ * @param api
+ * OAuth1.0a api information
+ * @param config
+ * OAuth 1.0a configuration param object
+ */
+ public OAuth10aServiceImpl(DefaultApi10a api, OAuthConfig config) {
+ this.api = api;
+ this.config = config;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Token getRequestToken(int timeout, TimeUnit unit) {
+ return getRequestToken(new TimeoutTuner(timeout, unit));
+ }
+
+ public Token getRequestToken() {
+ return getRequestToken(2, TimeUnit.SECONDS);
+ }
+
+ public Token getRequestToken(RequestTuner tuner) {
+ config.log("obtaining request token from "
+ + api.getRequestTokenEndpoint());
+ OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(),
+ api.getRequestTokenEndpoint());
+
+ config.log("setting oauth_callback to " + config.getCallback());
+ request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback());
+ addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
+ appendSignature(request);
+
+ config.log("sending request...");
+ Response response = request.send(tuner);
+ String body = response.getBody();
+
+ config.log("response status code: " + response.getCode());
+ config.log("response body: " + body);
+ return api.getRequestTokenExtractor().extract(body);
+ }
+
+ private void addOAuthParams(OAuthRequest request, Token token) {
+ request.addOAuthParameter(OAuthConstants.TIMESTAMP, api
+ .getTimestampService().getTimestampInSeconds());
+ request.addOAuthParameter(OAuthConstants.NONCE, api
+ .getTimestampService().getNonce());
+ request.addOAuthParameter(OAuthConstants.CONSUMER_KEY,
+ config.getApiKey());
+ request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api
+ .getSignatureService().getSignatureMethod());
+ request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
+ if (config.hasScope())
+ request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
+ request.addOAuthParameter(OAuthConstants.SIGNATURE,
+ getSignature(request, token));
+
+ config.log("appended additional OAuth parameters: "
+ + MapUtils.toString(request.getOauthParameters()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Token getAccessToken(Token requestToken, Verifier verifier,
+ int timeout, TimeUnit unit) {
+ return getAccessToken(requestToken, verifier, new TimeoutTuner(timeout,
+ unit));
+ }
+
+ public Token getAccessToken(Token requestToken, Verifier verifier) {
+ return getAccessToken(requestToken, verifier, 2, TimeUnit.SECONDS);
+ }
+
+ public Token getAccessToken(Token requestToken, Verifier verifier,
+ RequestTuner tuner) {
+ config.log("obtaining access token from "
+ + api.getAccessTokenEndpoint());
+ OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(),
+ api.getAccessTokenEndpoint());
+ request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken());
+ request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue());
+
+ config.log("setting token to: " + requestToken + " and verifier to: "
+ + verifier);
+ addOAuthParams(request, requestToken);
+ appendSignature(request);
+ Response response = request.send(tuner);
+ return api.getAccessTokenExtractor().extract(response.getBody());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void signRequest(Token token, OAuthRequest request) {
+ config.log("signing request: " + request.getCompleteUrl());
+
+ // Do not append the token if empty. This is for two legged OAuth calls.
+ if (!token.isEmpty()) {
+ request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken());
+ }
+ config.log("setting token to: " + token);
+ addOAuthParams(request, token);
+ appendSignature(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getVersion() {
+ return VERSION;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getAuthorizationUrl(Token requestToken) {
+ return api.getAuthorizationUrl(requestToken);
+ }
private String getSignature(OAuthRequest request, Token token)
{
@@ -149,42 +154,43 @@ private String getSignature(OAuthRequest request, Token token)
return signature;
}
- private void appendSignature(OAuthRequest request)
- {
- switch (config.getSignatureType())
- {
- case Header:
- config.log("using Http Header signature");
-
- String oauthHeader = api.getHeaderExtractor().extract(request);
- request.addHeader(OAuthConstants.HEADER, oauthHeader);
- break;
- case QueryString:
- config.log("using Querystring signature");
-
- for (Map.Entry entry : request.getOauthParameters().entrySet())
- {
- request.addQuerystringParameter(entry.getKey(), entry.getValue());
- }
- break;
- }
- }
-
- private static class TimeoutTuner extends RequestTuner
- {
- private final int duration;
- private final TimeUnit unit;
-
- public TimeoutTuner(int duration, TimeUnit unit)
- {
- this.duration = duration;
- this.unit = unit;
- }
-
- @Override
- public void tune(Request request)
- {
- request.setReadTimeout(duration, unit);
- }
- }
+ private void appendSignature(OAuthRequest request) {
+ switch (config.getSignatureType()) {
+ case Header:
+ config.log("using Http Header signature");
+
+ String oauthHeader = api.getHeaderExtractor().extract(request);
+ request.addHeader(OAuthConstants.HEADER, oauthHeader);
+ break;
+ case QueryString:
+ config.log("using Querystring signature");
+
+ for (Map.Entry entry : request.getOauthParameters()
+ .entrySet()) {
+ request.addQuerystringParameter(entry.getKey(),
+ entry.getValue());
+ }
+ break;
+ }
+ }
+
+ private static class TimeoutTuner extends RequestTuner {
+ private final int duration;
+ private final TimeUnit unit;
+
+ public TimeoutTuner(int duration, TimeUnit unit) {
+ this.duration = duration;
+ this.unit = unit;
+ }
+
+ @Override
+ public void tune(Request request) {
+ request.setReadTimeout(duration, unit);
+ }
+ }
+
+ public Token refreshAccessToken(Token accessToken) {
+ throw new UnsupportedOperationException(
+ "Refresh token is not supported in Scribe OAuth 1.0");
+ }
}
diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java
index 6262c3700..e238d789b 100644
--- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java
+++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java
@@ -1,18 +1,18 @@
package org.scribe.oauth;
-import org.scribe.builder.api.*;
+import org.scribe.builder.api.DefaultApi20;
import org.scribe.model.*;
public class OAuth20ServiceImpl implements OAuthService
{
private static final String VERSION = "2.0";
-
+
private final DefaultApi20 api;
private final OAuthConfig config;
-
+
/**
* Default constructor
- *
+ *
* @param api OAuth2.0 api information
* @param config OAuth 2.0 configuration param object
*/
@@ -32,7 +32,30 @@ public Token getAccessToken(Token requestToken, Verifier verifier)
request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
- if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
+ if (config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
+ if (config.hasGrantType()) request.addQuerystringParameter(OAuthConstants.GRANT_TYPE, config.getGrantType());
+ Response response = request.send();
+ return api.getAccessTokenExtractor().extract(response.getBody());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Token refreshAccessToken(Token accessToken)
+ {
+
+ String accessTokenEndpoint = api.getAccessTokenEndpoint();
+ if (accessTokenEndpoint.contains("?grant_type="))
+ {
+ // handle the ugly case where the grant_type parameter is already hardcoded in the constant url
+ accessTokenEndpoint = accessTokenEndpoint.substring(0, accessTokenEndpoint.indexOf("?"));
+ }
+ OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), accessTokenEndpoint);
+ request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
+ request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
+ request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
+ request.addQuerystringParameter(OAuthConstants.GRANT_TYPE, api.getRefreshTokenParameterName());
+ request.addQuerystringParameter(api.getRefreshTokenParameterName(), accessToken.getToken());
Response response = request.send();
return api.getAccessTokenExtractor().extract(response.getBody());
}
diff --git a/src/main/java/org/scribe/oauth/OAuthService.java b/src/main/java/org/scribe/oauth/OAuthService.java
index 0c9c57e9b..f7467f95d 100644
--- a/src/main/java/org/scribe/oauth/OAuthService.java
+++ b/src/main/java/org/scribe/oauth/OAuthService.java
@@ -27,6 +27,19 @@ public interface OAuthService
*/
public Token getAccessToken(Token requestToken, Verifier verifier);
+ /**
+ * Refresh the access token to extend its expiration date.
+ *
+ * For the token in parameter, Facebook needs the access_token, while Live
+ * needs the refresh_token (which can be found only in the
+ * {@link org.scribe.model.Token#getRawResponse()} returned by
+ * {@link #getAccessToken(org.scribe.model.Token, org.scribe.model.Verifier)})
+ *
+ * @param accessToken access or refresh token, depending on the OAuth provider
+ * @return fresh access token
+ */
+ public Token refreshAccessToken(Token accessToken);
+
/**
* Signs am OAuth request
*
diff --git a/src/test/java/org/scribe/builder/ServiceBuilderTest.java b/src/test/java/org/scribe/builder/ServiceBuilderTest.java
index 8112d79b3..04e7c0ea0 100644
--- a/src/test/java/org/scribe/builder/ServiceBuilderTest.java
+++ b/src/test/java/org/scribe/builder/ServiceBuilderTest.java
@@ -59,6 +59,15 @@ public void shouldAcceptAnScope()
assertEquals(ApiMock.config.getApiSecret(), "secret");
assertEquals(ApiMock.config.getScope(), "rss-api");
}
+ @Test
+ public void shouldAcceptAGrantType()
+ {
+ builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").grantType("client_credentials").build();
+ assertEquals(ApiMock.config.getApiKey(), "key");
+ assertEquals(ApiMock.config.getApiSecret(), "secret");
+ assertEquals(ApiMock.config.getGrantType(), "client_credentials");
+ }
+
public static class ApiMock implements Api
{
diff --git a/src/test/java/org/scribe/examples/BistriExample.java b/src/test/java/org/scribe/examples/BistriExample.java
new file mode 100644
index 000000000..e13510c3b
--- /dev/null
+++ b/src/test/java/org/scribe/examples/BistriExample.java
@@ -0,0 +1,66 @@
+package org.scribe.examples;
+
+import org.scribe.builder.ServiceBuilder;
+import org.scribe.builder.api.BistriApi;
+import org.scribe.model.OAuthRequest;
+import org.scribe.model.Response;
+import org.scribe.model.Token;
+import org.scribe.model.Verb;
+import org.scribe.model.Verifier;
+import org.scribe.oauth.OAuthService;
+
+import java.util.Scanner;
+
+public class BistriExample
+{
+ private static final String NETWORK_NAME = "Bistri";
+
+ private static final String AUTHORIZE_URL = "http://localhost:8080/oauth/authorize?oauth_token=";
+
+ private static final String PROTECTED_RESOURCE_URL = "http://localhost:8080/static/supportedlanguages";
+
+ public static void main( String[] args )
+ {
+ OAuthService service =
+ new ServiceBuilder().provider( BistriApi.class ).apiKey( "testUser" ).apiSecret( "testSecret" ).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 );
+ 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! :)" );
+
+ }
+}
diff --git a/src/test/java/org/scribe/examples/FacebookAppLoginExample.java b/src/test/java/org/scribe/examples/FacebookAppLoginExample.java
new file mode 100644
index 000000000..c4e6df770
--- /dev/null
+++ b/src/test/java/org/scribe/examples/FacebookAppLoginExample.java
@@ -0,0 +1,55 @@
+package org.scribe.examples;
+
+import org.scribe.builder.ServiceBuilder;
+import org.scribe.builder.api.FacebookApi;
+import org.scribe.model.OAuthConstants;
+import org.scribe.model.OAuthRequest;
+import org.scribe.model.Response;
+import org.scribe.model.Token;
+import org.scribe.model.Verb;
+import org.scribe.oauth.OAuthService;
+
+public class FacebookAppLoginExample
+{
+ private static final String NETWORK_NAME = "Facebook";
+ private static final Token EMPTY_TOKEN = null;
+ private static final String PROTECTED_RESOURCE_URL ="https://graph.facebook.com/%s/insights";
+
+ public static void main(String[] args)
+ {
+ // Replace these with your own api key and secret
+
+ String apiKey = "your_app_id";
+ String apiSecret = "your_api_secret";
+ String callbackURL = "your_call_back";
+ OAuthService service = new ServiceBuilder()
+ .provider(FacebookApi.class)
+ .apiKey(apiKey)
+ .apiSecret(apiSecret)
+ .callback(callbackURL)
+ .grantType(OAuthConstants.CLIENT_CREDENTIALS)
+ .build();
+
+ System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
+ System.out.println();
+ System.out.println("Getting an access Token with Client Credentials (a.k.a App Login as Facebook defines)");
+ Token accessToken = service.getAccessToken(EMPTY_TOKEN, null);
+ 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, String.format(PROTECTED_RESOURCE_URL,apiKey));
+ 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! :)");
+
+ }
+}
diff --git a/src/test/java/org/scribe/examples/GoogleExample20.java b/src/test/java/org/scribe/examples/GoogleExample20.java
new file mode 100755
index 000000000..ac1bfdbb7
--- /dev/null
+++ b/src/test/java/org/scribe/examples/GoogleExample20.java
@@ -0,0 +1,66 @@
+package org.scribe.examples;
+
+import org.scribe.builder.ServiceBuilder;
+import org.scribe.builder.api.GoogleApi20;
+import org.scribe.model.OAuthConstants;
+import org.scribe.model.OAuthRequest;
+import org.scribe.model.Response;
+import org.scribe.model.Token;
+import org.scribe.model.Verb;
+import org.scribe.model.Verifier;
+import org.scribe.oauth.OAuthService;
+
+import java.util.Scanner;
+
+public class GoogleExample20
+{
+ private static final String NETWORK_NAME = "Google 2.0";
+
+ 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 )
+ {
+ // Replace these with your own api key, secret and callback
+ String apiKey = "apiKey";
+ String apiSecret = "apiSecret";
+ String callback = "http://www.example.com/google/back";
+
+ OAuthService service =
+ new ServiceBuilder().provider( GoogleApi20.class ).apiKey( apiKey ).apiSecret( apiSecret ).callback(
+ callback ).scope( SCOPE ).grantType( OAuthConstants.AUTHORIZATION_CODE ).build();
+
+ System.out.println( "=== " + NETWORK_NAME + "'s OAuth Workflow ===" );
+ System.out.println();
+
+ // Obtain the authorization url
+ String url = service.getAuthorizationUrl( null );
+
+ System.out.println( "go there : " + url );
+ System.out.println( "paste the authorization code >>" );
+ Scanner in = new Scanner( System.in );
+ Verifier verifier = new Verifier( in.nextLine() );
+
+ Token accessToken = service.getAccessToken( null, 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! :)" );
+
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/scribe/model/OAuthConfigTest.java b/src/test/java/org/scribe/model/OAuthConfigTest.java
new file mode 100644
index 000000000..2689220d4
--- /dev/null
+++ b/src/test/java/org/scribe/model/OAuthConfigTest.java
@@ -0,0 +1,29 @@
+package org.scribe.model;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+public class OAuthConfigTest
+{
+
+ @Test
+ public void shouldReturnDefaultValuesIfNotSet()
+ {
+ OAuthConfig config = new OAuthConfig("key", "secret");
+ assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback());
+ assertEquals(SignatureType.Header, config.getSignatureType());
+ assertFalse(config.hasScope());
+ assertFalse(config.hasGrantType());
+ }
+
+ @Test
+ public void shouldOverrideDefaultsIfSet()
+ {
+ OAuthConfig config = new OAuthConfig("key", "secret", "http://callback", SignatureType.Header, "scope", System.out);
+ assertEquals("http://callback", config.getCallback());
+ assertEquals("key", config.getApiKey());
+ assertEquals("secret", config.getApiSecret());
+ }
+
+}