From 5d391a8e65bfd5639a7e87b553efc059fa16195e Mon Sep 17 00:00:00 2001 From: Marcus Thiesen Date: Sat, 15 Oct 2011 11:03:28 +0200 Subject: [PATCH 1/3] Added possibility to remove callback paramter completely, as the Google Appengine OAuth Implentation does behave differently for a set callback parameter and a not set one --- .../org/scribe/builder/ServiceBuilder.java | 18 ++++- .../org/scribe/builder/api/FacebookApi.java | 6 +- .../scribe/builder/api/Foursquare2Api.java | 4 +- .../java/org/scribe/builder/api/LiveApi.java | 6 +- .../org/scribe/builder/api/VkontakteApi.java | 6 +- src/main/java/org/scribe/model/Callback.java | 81 +++++++++++++++++++ .../java/org/scribe/model/OAuthConfig.java | 8 +- .../org/scribe/oauth/OAuth10aServiceImpl.java | 6 +- .../org/scribe/oauth/OAuth20ServiceImpl.java | 6 +- .../java/org/scribe/utils/Preconditions.java | 2 +- .../scribe/builder/ServiceBuilderTest.java | 4 +- .../org/scribe/model/OAuthConfigTest.java | 6 +- 12 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/scribe/model/Callback.java diff --git a/src/main/java/org/scribe/builder/ServiceBuilder.java b/src/main/java/org/scribe/builder/ServiceBuilder.java index 10d080282..de6fcca8e 100644 --- a/src/main/java/org/scribe/builder/ServiceBuilder.java +++ b/src/main/java/org/scribe/builder/ServiceBuilder.java @@ -17,7 +17,7 @@ public class ServiceBuilder { private String apiKey; private String apiSecret; - private String callback; + private Callback callback; private Api api; private String scope; private SignatureType signatureType; @@ -27,7 +27,7 @@ public class ServiceBuilder */ public ServiceBuilder() { - this.callback = OAuthConstants.OUT_OF_BAND; + this.callback = Callback.outOfBand(); } /** @@ -80,8 +80,18 @@ public ServiceBuilder provider(Api api) */ public ServiceBuilder callback(String callback) { - Preconditions.checkValidOAuthCallback(callback, "Callback must be a valid URL or 'oob'"); - this.callback = callback; + this.callback = Callback.from( callback ); + return this; + } + + /** + * Removes the callback parameter completely + * + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder noCallback() + { + this.callback = Callback.none(); return this; } diff --git a/src/main/java/org/scribe/builder/api/FacebookApi.java b/src/main/java/org/scribe/builder/api/FacebookApi.java index d85ff3b65..ead58dba0 100644 --- a/src/main/java/org/scribe/builder/api/FacebookApi.java +++ b/src/main/java/org/scribe/builder/api/FacebookApi.java @@ -19,16 +19,16 @@ public String getAccessTokenEndpoint() @Override public String getAuthorizationUrl(OAuthConfig config) { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB"); + Preconditions.check(config.getCallback().hasValidUrl(), "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(), formURLEncode(config.getCallback()), formURLEncode(config.getScope())); + return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(),config.getCallback().makeURLEncodedValue(), formURLEncode(config.getScope())); } else { - return String.format(AUTHORIZE_URL, config.getApiKey(), formURLEncode(config.getCallback())); + return String.format(AUTHORIZE_URL, config.getApiKey(), config.getCallback().makeURLEncodedValue()); } } } diff --git a/src/main/java/org/scribe/builder/api/Foursquare2Api.java b/src/main/java/org/scribe/builder/api/Foursquare2Api.java index 5bb0fdcd0..dbeb63b89 100644 --- a/src/main/java/org/scribe/builder/api/Foursquare2Api.java +++ b/src/main/java/org/scribe/builder/api/Foursquare2Api.java @@ -17,8 +17,8 @@ public String getAccessTokenEndpoint() @Override public String getAuthorizationUrl(OAuthConfig config) { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Foursquare2 does not support OOB"); - return String.format(AUTHORIZATION_URL, config.getApiKey(), URLUtils.formURLEncode(config.getCallback())); + Preconditions.check(config.getCallback().hasValidUrl(), "Must provide a valid url as callback. Foursquare2 does not support OOB"); + return String.format(AUTHORIZATION_URL, config.getApiKey(),config.getCallback().makeURLEncodedValue()); } @Override diff --git a/src/main/java/org/scribe/builder/api/LiveApi.java b/src/main/java/org/scribe/builder/api/LiveApi.java index 789631fea..85cca424b 100644 --- a/src/main/java/org/scribe/builder/api/LiveApi.java +++ b/src/main/java/org/scribe/builder/api/LiveApi.java @@ -23,15 +23,15 @@ public String getAccessTokenEndpoint() @Override public String getAuthorizationUrl(OAuthConfig config) { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Live does not support OOB"); + Preconditions.check(config.getCallback().hasValidUrl(), "Must provide a valid url as callback. Live does not support OOB"); // Append scope if present if (config.hasScope()) { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), formURLEncode(config.getCallback()), formURLEncode(config.getScope())); + return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), config.getCallback().makeURLEncodedValue(), formURLEncode(config.getScope())); } else { - return String.format(AUTHORIZE_URL, config.getApiKey(), formURLEncode(config.getCallback())); + return String.format(AUTHORIZE_URL, config.getApiKey(), config.getCallback().makeURLEncodedValue()); } } diff --git a/src/main/java/org/scribe/builder/api/VkontakteApi.java b/src/main/java/org/scribe/builder/api/VkontakteApi.java index 6bb4b6bf2..016c80477 100644 --- a/src/main/java/org/scribe/builder/api/VkontakteApi.java +++ b/src/main/java/org/scribe/builder/api/VkontakteApi.java @@ -22,14 +22,14 @@ public String getAccessTokenEndpoint() @Override public String getAuthorizationUrl(OAuthConfig config) { - Preconditions.checkValidUrl(config.getCallback(), "Valid url is required for a callback. Vkontakte does not support OOB"); + Preconditions.check(config.getCallback().hasValidUrl(), "Valid url is required for a callback. Vkontakte does not support OOB"); if(config.hasScope())// Appending scope if present { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), URLUtils.formURLEncode(config.getCallback()),URLUtils.formURLEncode(config.getScope())); + return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), config.getCallback().makeURLEncodedValue(),URLUtils.formURLEncode(config.getScope())); } else { - return String.format(AUTHORIZE_URL, config.getApiKey(), URLUtils.formURLEncode(config.getCallback())); + return String.format(AUTHORIZE_URL, config.getApiKey(), config.getCallback().makeURLEncodedValue()); } } diff --git a/src/main/java/org/scribe/model/Callback.java b/src/main/java/org/scribe/model/Callback.java new file mode 100644 index 000000000..d755e8487 --- /dev/null +++ b/src/main/java/org/scribe/model/Callback.java @@ -0,0 +1,81 @@ +package org.scribe.model; + +import org.scribe.utils.Preconditions; +import org.scribe.utils.URLUtils; + + +public class Callback { + + private final static Callback OUT_OF_BAND = new Callback( OAuthConstants.OUT_OF_BAND ); + private final static Callback NONE = new Callback( null ); + + private final String callbackValue; + + private Callback( final String value ) { + callbackValue = value; + } + + public static Callback from( final String callback ) { + if ( OUT_OF_BAND.equals( callback ) ) { + return outOfBand(); + } + if ( null == callback || "".equals( callback ) ) { + return none(); + } + Preconditions.checkValidUrl( callback, "Callback must be a valid URL"); + return new Callback( callback ); + } + + public static Callback outOfBand() { + return OUT_OF_BAND; + } + + public static Callback none() { + return NONE; + } + + public String getCallbackValue() { + return callbackValue; + } + + public String makeURLEncodedValue() { + return URLUtils.formURLEncode(callbackValue); + } + + public boolean addToRequest() { + return this != NONE && this.callbackValue != null; + } + + public boolean hasValidUrl() { + return this != NONE && this != OUT_OF_BAND; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((callbackValue == null) ? 0 : callbackValue.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Callback other = (Callback) obj; + if (callbackValue == null) { + if (other.callbackValue != null) + return false; + } else if (!callbackValue.equals(other.callbackValue)) + return false; + return true; + } + + + +} diff --git a/src/main/java/org/scribe/model/OAuthConfig.java b/src/main/java/org/scribe/model/OAuthConfig.java index 314d2d9b4..261468251 100644 --- a/src/main/java/org/scribe/model/OAuthConfig.java +++ b/src/main/java/org/scribe/model/OAuthConfig.java @@ -9,7 +9,7 @@ public class OAuthConfig { private final String apiKey; private final String apiSecret; - private final String callback; + private final Callback callback; private final SignatureType signatureType; private final String scope; @@ -18,11 +18,11 @@ public OAuthConfig(String key, String secret) this(key, secret, null, null, null); } - public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope) + public OAuthConfig(String key, String secret, Callback callback, SignatureType type, String scope) { this.apiKey = key; this.apiSecret = secret; - this.callback = callback != null ? callback : OAuthConstants.OUT_OF_BAND; + this.callback = callback != null ? callback : Callback.outOfBand(); this.signatureType = (type != null) ? type : SignatureType.Header; this.scope = scope; } @@ -37,7 +37,7 @@ public String getApiSecret() return apiSecret; } - public String getCallback() + public Callback getCallback() { return callback; } diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 91e7b710a..1baec9c0c 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -35,7 +35,11 @@ public OAuth10aServiceImpl(DefaultApi10a api, OAuthConfig config) public Token getRequestToken() { OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); - request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback()); + final Callback callback = config.getCallback(); + + if ( callback.addToRequest() ) { + request.addOAuthParameter(OAuthConstants.CALLBACK, callback.getCallbackValue() ); + } addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); addSignature(request); Response response = request.send(); diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java index 6262c3700..66ccc6d94 100644 --- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java @@ -31,7 +31,11 @@ public Token getAccessToken(Token requestToken, Verifier verifier) 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()); + final Callback callback = config.getCallback(); + + if ( callback.addToRequest() ) { + request.addOAuthParameter(OAuthConstants.REDIRECT_URI, callback.getCallbackValue() ); + } if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope()); Response response = request.send(); return api.getAccessTokenExtractor().extract(response.getBody()); diff --git a/src/main/java/org/scribe/utils/Preconditions.java b/src/main/java/org/scribe/utils/Preconditions.java index d7a06c347..26a2b54c6 100644 --- a/src/main/java/org/scribe/utils/Preconditions.java +++ b/src/main/java/org/scribe/utils/Preconditions.java @@ -72,7 +72,7 @@ private static boolean isUrl(String url) return URL_PATTERN.matcher(url).matches(); } - private static void check(boolean requirements, String error) + public static void check(boolean requirements, String error) { String message = (error == null || error.trim().length() <= 0) ? DEFAULT_MESSAGE : error; if (!requirements) diff --git a/src/test/java/org/scribe/builder/ServiceBuilderTest.java b/src/test/java/org/scribe/builder/ServiceBuilderTest.java index fca633be8..d3f912d3d 100644 --- a/src/test/java/org/scribe/builder/ServiceBuilderTest.java +++ b/src/test/java/org/scribe/builder/ServiceBuilderTest.java @@ -23,7 +23,7 @@ public void shouldReturnConfigDefaultValues() builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").build(); assertEquals(ApiMock.config.getApiKey(), "key"); assertEquals(ApiMock.config.getApiSecret(), "secret"); - assertEquals(ApiMock.config.getCallback(), OAuthConstants.OUT_OF_BAND); + assertEquals(ApiMock.config.getCallback(), Callback.outOfBand()); assertEquals(ApiMock.config.getSignatureType(), SignatureType.Header); } @@ -33,7 +33,7 @@ public void shouldAcceptValidCallbackUrl() builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").callback("http://example.com").build(); assertEquals(ApiMock.config.getApiKey(), "key"); assertEquals(ApiMock.config.getApiSecret(), "secret"); - assertEquals(ApiMock.config.getCallback(), "http://example.com"); + assertEquals( ApiMock.config.getCallback(), Callback.from( "http://example.com" ) ); } @Test diff --git a/src/test/java/org/scribe/model/OAuthConfigTest.java b/src/test/java/org/scribe/model/OAuthConfigTest.java index 973d40112..08762f7e9 100644 --- a/src/test/java/org/scribe/model/OAuthConfigTest.java +++ b/src/test/java/org/scribe/model/OAuthConfigTest.java @@ -11,7 +11,7 @@ public class OAuthConfigTest public void shouldReturnDefaultValuesIfNotSet() { OAuthConfig config = new OAuthConfig("key", "secret"); - assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback()); + assertEquals(Callback.outOfBand(), config.getCallback()); assertEquals(SignatureType.Header, config.getSignatureType()); assertFalse(config.hasScope()); } @@ -19,8 +19,8 @@ public void shouldReturnDefaultValuesIfNotSet() @Test public void shouldOverrideDefaultsIfSet() { - OAuthConfig config = new OAuthConfig("key", "secret", "http://callback", SignatureType.Header, "scope"); - assertEquals("http://callback", config.getCallback()); + OAuthConfig config = new OAuthConfig("key", "secret", Callback.from( "http://callback" ), SignatureType.Header, "scope"); + assertEquals( Callback.from( "http://callback" ), config.getCallback()); assertEquals("key", config.getApiKey()); assertEquals("secret", config.getApiSecret()); } From 25eba20027151c778d663a3e9714a0e2f07d6de1 Mon Sep 17 00:00:00 2001 From: Marcus Thiesen Date: Sat, 15 Oct 2011 11:12:33 +0200 Subject: [PATCH 2/3] Add support for non verified access tokens --- src/main/java/org/scribe/model/Verifier.java | 14 ++++++++++++++ .../java/org/scribe/oauth/OAuth10aServiceImpl.java | 4 +++- .../java/org/scribe/oauth/OAuth20ServiceImpl.java | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/scribe/model/Verifier.java b/src/main/java/org/scribe/model/Verifier.java index 45f0e4ea3..0462ff2e0 100644 --- a/src/main/java/org/scribe/model/Verifier.java +++ b/src/main/java/org/scribe/model/Verifier.java @@ -10,6 +10,8 @@ public class Verifier { + private final static Verifier NONE = new Verifier(); + private final String value; /** @@ -22,9 +24,21 @@ public Verifier(String value) Preconditions.checkNotNull(value, "Must provide a valid string as verifier"); this.value = value; } + + private Verifier() { + this.value = null; + } public String getValue() { return value; } + + public static Verifier none() { + return NONE; + } + + public boolean isDefined() { + return this != NONE; + } } diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 1baec9c0c..6ae052296 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -64,7 +64,9 @@ public Token getAccessToken(Token requestToken, Verifier verifier) { OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); - request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); + if ( verifier.isDefined() ) { + request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); + } addOAuthParams(request, requestToken); addSignature(request); Response response = request.send(); diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java index 66ccc6d94..ca7a3b093 100644 --- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java @@ -30,7 +30,9 @@ public Token getAccessToken(Token requestToken, Verifier verifier) OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); - request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); + if ( verifier.isDefined() ) { + request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); + } final Callback callback = config.getCallback(); if ( callback.addToRequest() ) { From e4b51d63cee4c2095f695108f789ad7770ed4ad3 Mon Sep 17 00:00:00 2001 From: Marcus Thiesen Date: Mon, 28 Nov 2011 12:27:21 +0100 Subject: [PATCH 3/3] Fixed whitespace error introduced with my patches --- .../java/org/scribe/builder/api/LiveApi.java | 2 +- src/main/java/org/scribe/model/Callback.java | 46 +++++++++---------- .../org/scribe/oauth/OAuth10aServiceImpl.java | 2 +- .../org/scribe/oauth/OAuth20ServiceImpl.java | 4 +- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/scribe/builder/api/LiveApi.java b/src/main/java/org/scribe/builder/api/LiveApi.java index 85cca424b..c957050a2 100644 --- a/src/main/java/org/scribe/builder/api/LiveApi.java +++ b/src/main/java/org/scribe/builder/api/LiveApi.java @@ -23,7 +23,7 @@ public String getAccessTokenEndpoint() @Override public String getAuthorizationUrl(OAuthConfig config) { - Preconditions.check(config.getCallback().hasValidUrl(), "Must provide a valid url as callback. Live does not support OOB"); + Preconditions.check(config.getCallback().hasValidUrl(), "Must provide a valid url as callback. Live does not support OOB"); // Append scope if present if (config.hasScope()) diff --git a/src/main/java/org/scribe/model/Callback.java b/src/main/java/org/scribe/model/Callback.java index d755e8487..4bab27bbd 100644 --- a/src/main/java/org/scribe/model/Callback.java +++ b/src/main/java/org/scribe/model/Callback.java @@ -39,43 +39,41 @@ public String getCallbackValue() { } public String makeURLEncodedValue() { - return URLUtils.formURLEncode(callbackValue); + return URLUtils.formURLEncode(callbackValue); } public boolean addToRequest() { - return this != NONE && this.callbackValue != null; + return this != NONE && this.callbackValue != null; } public boolean hasValidUrl() { - return this != NONE && this != OUT_OF_BAND; + return this != NONE && this != OUT_OF_BAND; } @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((callbackValue == null) ? 0 : callbackValue.hashCode()); - return result; + final int prime = 31; + int result = 1; + result = prime * result + + ((callbackValue == null) ? 0 : callbackValue.hashCode()); + return result; } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Callback other = (Callback) obj; - if (callbackValue == null) { - if (other.callbackValue != null) - return false; - } else if (!callbackValue.equals(other.callbackValue)) - return false; - return true; - } - - + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Callback other = (Callback) obj; + if (callbackValue == null) { + if (other.callbackValue != null) + return false; + } else if (!callbackValue.equals(other.callbackValue)) + return false; + return true; + } } diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 6ae052296..42158cffc 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -65,7 +65,7 @@ public Token getAccessToken(Token requestToken, Verifier verifier) OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); if ( verifier.isDefined() ) { - request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); + request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); } addOAuthParams(request, requestToken); addSignature(request); diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java index ca7a3b093..f80b59eb9 100644 --- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java @@ -31,12 +31,12 @@ public Token getAccessToken(Token requestToken, Verifier verifier) request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); if ( verifier.isDefined() ) { - request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); + request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); } final Callback callback = config.getCallback(); if ( callback.addToRequest() ) { - request.addOAuthParameter(OAuthConstants.REDIRECT_URI, callback.getCallbackValue() ); + request.addOAuthParameter(OAuthConstants.REDIRECT_URI, callback.getCallbackValue() ); } if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope()); Response response = request.send();