diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..0a2df9277 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ['https://www.paypal.com/paypalme/algr453'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/README.md b/README.md index cfa482f90..b90ef2e5f 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Who said OAuth/OAuth2 was difficult? Configuring ScribeJava is __so easy your grandma can do it__! check it out: ```java -OAuthService service = new ServiceBuilder(YOUR_API_KEY) - .apiSecret(YOUR_API_SECRET) +OAuthService service = new ServiceBuilder(YOUR_CLIENT_ID) + .apiSecret(YOUR_CLIENT_SECRET) .build(LinkedInApi20.instance()); ``` @@ -77,6 +77,7 @@ ScribeJava support out-of-box several HTTP clients: * HeadHunter ХэдХантер (https://hh.ru/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HHExample.java) * HiOrg-Server (https://www.hiorg-server.de/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HiOrgServerExample.java) * Imgur (http://imgur.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ImgurExample.java) +* Instagram (https://www.instagram.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/InstagramExample.java) * Kaixin 开心网 (http://www.kaixin001.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Kaixin20Example.java) * Kakao (https://kakao.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KakaoExample.java) * Keycloak (https://www.keycloak.org/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KeycloakExample.java) @@ -136,7 +137,7 @@ You can pull ScribeJava from the central maven repository, just add these to you com.github.scribejava scribejava-apis - 8.2.0 + 8.3.3 ``` @@ -145,7 +146,7 @@ And in case you need just core classes (that's it, without any external API (FB, com.github.scribejava scribejava-core - 8.2.0 + 8.3.3 ``` diff --git a/changelog b/changelog index ee6336655..e962e073b 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,20 @@ +[8.3.3] + * update dependencies, including security updates in libraries + +[8.3.2] + * minor fixes and enhances + * update dependencies + * while using async HTTP client, you could miss some Throwables, now they will be thrown + +[8.3.1] + * fix java.lang.NoClassDefFoundError for non-java8 runtimes (e.g. Android 7.1.1) + (thanks to https://github.com/ChristopherGittner) + +[8.3.0] + * add Instagram (https://www.instagram.com/) API (thanks to https://github.com/faent) + * add getErrorMessage method to FacebookAccessTokenErrorResponse. Should be used instead of general getMessage method + from the parent Exception + [8.2.0] * add ScopeBuilder to easily specify multiple scopes while requesting OAuth2.0 Access Tokens * make Base64 en/de-coding not dependent from java8 implementation (use three optional implementation diff --git a/checkstyle.xml b/checkstyle.xml index c9b0fac9b..f7efbad65 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -96,7 +96,9 @@ - + diff --git a/donate.md b/donate.md index ee6a1a6e7..99d3686dc 100644 --- a/donate.md +++ b/donate.md @@ -1,12 +1,10 @@ You can now help ScribeJava not only by Pull Requests. -You can use [https://paypal.me/kullfar](https://paypal.me/kullfar) directly - -or try donation button from PayPal: [![Donate with PayPal button](https://www.paypalobjects.com/en_US/RU/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=E3XAUM2ET2R3Y&source=url) +You can use [https://www.paypal.com/paypalme/algr453](https://www.paypal.com/paypalme/algr453) directly. Thanks in advance! -ps.If you can't for any reason use above methods, let me know, we will find the way out. +ps.If you can't for any reason use above method, let me know, we will find the way out. Hall of fame "Donors" (in alphabetical order, if you don't want to be here, just put a note along with the donation):
1.Douglas Ross from USA
diff --git a/pmd.xml b/pmd.xml index 7b5314710..5d93d340b 100644 --- a/pmd.xml +++ b/pmd.xml @@ -17,7 +17,6 @@ - @@ -34,8 +33,6 @@ - - @@ -48,6 +45,7 @@ + @@ -91,7 +89,6 @@ - diff --git a/pom.xml b/pom.xml index db2978831..b484b6a71 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.github.scribejava scribejava pom - 8.2.0 + 8.3.4-SNAPSHOT ScribeJava OAuth Library The best OAuth library out there https://github.com/scribejava/scribejava @@ -33,10 +33,10 @@ - scm:git:git://github.com/scribejava/scribejava.git - scm:git:git@github.com:scribejava/scribejava.git + scm:git:https://github.com/scribejava/scribejava + scm:git:https://github.com/scribejava/scribejava https://github.com/scribejava/scribejava - scribejava-8.2.0 + HEAD @@ -55,7 +55,7 @@ com.fasterxml.jackson.core jackson-databind - 2.12.3 + 2.14.0 junit @@ -66,7 +66,7 @@ com.squareup.okhttp3 mockwebserver - 4.9.1 + 4.10.0 test @@ -76,7 +76,7 @@ org.apache.felix maven-bundle-plugin - 5.1.2 + 5.1.8 bundle-manifest @@ -90,7 +90,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.0 + 3.3.0 ${project.build.outputDirectory}/META-INF/MANIFEST.MF @@ -100,12 +100,12 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.1.2 + 3.2.0 com.puppycrawl.tools checkstyle - 8.41.1 + 10.4 @@ -125,19 +125,19 @@ org.apache.maven.plugins maven-clean-plugin - 3.1.0 + 3.2.0 org.apache.maven.plugins maven-install-plugin - 2.5.2 + 3.0.1 maven-compiler-plugin - 3.8.1 + 3.10.1 UTF-8 ${java.release} @@ -149,7 +149,7 @@ maven-deploy-plugin - 2.8.2 + 3.0.0 default-deploy @@ -163,7 +163,7 @@ org.apache.maven.plugins maven-resources-plugin - 3.2.0 + 3.3.0 UTF-8 @@ -184,7 +184,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.4.1 ${java.home}/bin/javadoc UTF-8 @@ -208,7 +208,6 @@ validate validate - main/java/com/github/scribejava/core/java8/* ${basedir}/src @@ -225,7 +224,7 @@ org.apache.maven.plugins maven-pmd-plugin - 3.14.0 + 3.19.0 net.sourceforge.pmd @@ -271,7 +270,7 @@ 7 - 6.33.0 + 6.51.0 @@ -288,7 +287,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.0.1 sign-artifacts diff --git a/scribejava-apis/pom.xml b/scribejava-apis/pom.xml index e0ca099eb..4e51bb8b5 100644 --- a/scribejava-apis/pom.xml +++ b/scribejava-apis/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml @@ -50,6 +50,12 @@ ${project.version} test + + io.netty + netty-resolver + 4.1.84.Final + test + diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/FacebookApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/FacebookApi.java index 9c3ee7a46..d688248d6 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/FacebookApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/FacebookApi.java @@ -13,9 +13,6 @@ import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; -/** - * Facebook API - */ public class FacebookApi extends DefaultApi20 { private final String version; diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/InstagramApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/InstagramApi.java new file mode 100644 index 000000000..85e408113 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/InstagramApi.java @@ -0,0 +1,59 @@ +package com.github.scribejava.apis; + +import java.io.OutputStream; +import com.github.scribejava.apis.instagram.InstagramAccessTokenJsonExtractor; +import com.github.scribejava.apis.instagram.InstagramService; +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.extractors.TokenExtractor; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; +import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; + +public class InstagramApi extends DefaultApi20 { + + public static final String LONG_LIVED_ACCESS_TOKEN_ENDPOINT = "https://graph.instagram.com/access_token"; + + private static class InstanceHolder { + + private static final InstagramApi INSTANCE = new InstagramApi(); + } + + public static InstagramApi instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://api.instagram.com/oauth/access_token"; + } + + @Override + public String getRefreshTokenEndpoint() { + return "https://graph.instagram.com/refresh_access_token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://api.instagram.com/oauth/authorize"; + } + + @Override + public TokenExtractor getAccessTokenExtractor() { + return InstagramAccessTokenJsonExtractor.instance(); + } + + @Override + public ClientAuthentication getClientAuthentication() { + return RequestBodyAuthenticationScheme.instance(); + } + + @Override + public InstagramService createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new InstagramService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenErrorResponse.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenErrorResponse.java index 36cc4a504..ea5053931 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenErrorResponse.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenErrorResponse.java @@ -1,6 +1,6 @@ package com.github.scribejava.apis.facebook; -import com.github.scribejava.core.exceptions.OAuthException; +import com.github.scribejava.core.model.OAuthResponseException; import com.github.scribejava.core.model.Response; import java.io.IOException; import java.util.Objects; @@ -16,39 +16,27 @@ * '{"error":{"message":"Error validating application. Invalid application * ID.","type":"OAuthException","code":101,"fbtrace_id":"CvDR+X4WWIx"}}' */ -public class FacebookAccessTokenErrorResponse extends OAuthException { +public class FacebookAccessTokenErrorResponse extends OAuthResponseException { private static final long serialVersionUID = -1277129766099856895L; + private final String errorMessage; private final String type; private final int codeInt; private final String fbtraceId; - private final Response response; - public FacebookAccessTokenErrorResponse(String message, String type, int code, String fbtraceId, - Response response) { - super(message); + public FacebookAccessTokenErrorResponse(String errorMessage, String type, int code, String fbtraceId, + Response response) + throws IOException { + super(response); + this.errorMessage = errorMessage; this.type = type; this.codeInt = code; this.fbtraceId = fbtraceId; - this.response = response; } - /** - * - * @param message message - * @param type type - * @param code code - * @param fbtraceId fbtraceId - * @param rawResponse rawResponse - * @deprecated use {@link #FacebookAccessTokenErrorResponse(java.lang.String, java.lang.String, - * int, java.lang.String, com.github.scribejava.core.model.Response) - * } - */ - @Deprecated - public FacebookAccessTokenErrorResponse(String message, String type, int code, String fbtraceId, - String rawResponse) { - this(message, type, code, fbtraceId, new Response(-1, null, null, rawResponse)); + public String getErrorMessage() { + return errorMessage; } public String getType() { @@ -63,26 +51,10 @@ public String getFbtraceId() { return fbtraceId; } - /** - * - * @return body of response - * @throws IOException IOException - * @deprecated use {@link #getResponse()} and then {@link Response#getBody()} - */ - @Deprecated - public String getRawResponse() throws IOException { - return response.getBody(); - } - - public Response getResponse() { - return response; - } - @Override public int hashCode() { - int hash = 5; - hash = 83 * hash + Objects.hashCode(response); - hash = 83 * hash + Objects.hashCode(getMessage()); + int hash = super.hashCode(); + hash = 83 * hash + Objects.hashCode(errorMessage); hash = 83 * hash + Objects.hashCode(type); hash = 83 * hash + Objects.hashCode(codeInt); hash = 83 * hash + Objects.hashCode(fbtraceId); @@ -100,11 +72,13 @@ public boolean equals(Object obj) { if (getClass() != obj.getClass()) { return false; } - final FacebookAccessTokenErrorResponse other = (FacebookAccessTokenErrorResponse) obj; - if (!Objects.equals(response, other.getResponse())) { + if (!super.equals(obj)) { return false; } - if (!Objects.equals(getMessage(), other.getMessage())) { + + final FacebookAccessTokenErrorResponse other = (FacebookAccessTokenErrorResponse) obj; + + if (!Objects.equals(errorMessage, other.getErrorMessage())) { return false; } if (!Objects.equals(type, other.getType())) { @@ -119,7 +93,7 @@ public boolean equals(Object obj) { @Override public String toString() { return "FacebookAccessTokenErrorResponse{'type'='" + type + "', 'codeInt'='" + codeInt - + "', 'fbtraceId'='" + fbtraceId + "', 'response'='" + response - + "', 'message'='" + getMessage() + "'}"; + + "', 'fbtraceId'='" + fbtraceId + "', 'response'='" + getResponse() + + "', 'errorMessage'='" + errorMessage + "'}"; } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramAccessTokenErrorResponse.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramAccessTokenErrorResponse.java new file mode 100644 index 000000000..bae3454a2 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramAccessTokenErrorResponse.java @@ -0,0 +1,84 @@ +package com.github.scribejava.apis.instagram; + +import com.github.scribejava.core.model.OAuthResponseException; +import java.io.IOException; +import java.util.Objects; +import com.github.scribejava.core.model.Response; + +/** + * non standard Instagram replace for {@link com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse} + * + * examples:
+ * + * '{"error_type": "OAuthException", "code": 400, "error_message": "Missing required field client_id"}' + */ +public class InstagramAccessTokenErrorResponse extends OAuthResponseException { + + private static final long serialVersionUID = -1277129706699856895L; + + private final String errorType; + private final int code; + private final String errorMessage; + private final transient Response response; + + public InstagramAccessTokenErrorResponse(String errorType, int code, String errorMessage, Response response) + throws IOException { + super(response); + this.errorType = errorType; + this.code = code; + this.errorMessage = errorMessage; + this.response = response; + } + + public String getErrorType() { + return errorType; + } + + public int getCode() { + return code; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + if (!super.equals(obj)) { + return false; + } + + final InstagramAccessTokenErrorResponse that = (InstagramAccessTokenErrorResponse) obj; + if (!Objects.equals(errorMessage, that.getErrorMessage())) { + return false; + } + return code == that.code && Objects.equals(errorType, that.errorType) + && Objects.equals(response, that.response); + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 83 * hash + Objects.hashCode(response); + hash = 83 * hash + Objects.hashCode(errorMessage); + hash = 83 * hash + Objects.hashCode(errorType); + hash = 83 * hash + Objects.hashCode(code); + return hash; + } + + @Override + public String toString() { + return "InstagramAccessTokenErrorResponse{" + + "errorType='" + errorType + + "', code=" + code + + "', errorMessage='" + errorMessage + + "', response=" + response + + '}'; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramAccessTokenJsonExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramAccessTokenJsonExtractor.java new file mode 100644 index 000000000..8f30b2e96 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramAccessTokenJsonExtractor.java @@ -0,0 +1,55 @@ +package com.github.scribejava.apis.instagram; + +import java.io.IOException; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.scribejava.apis.facebook.FacebookAccessTokenJsonExtractor; +import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; +import com.github.scribejava.core.model.Response; + +/** + * non standard Instagram Extractor + */ +public class InstagramAccessTokenJsonExtractor extends OAuth2AccessTokenJsonExtractor { + + protected InstagramAccessTokenJsonExtractor() { + } + + private static class InstanceHolder { + + private static final InstagramAccessTokenJsonExtractor INSTANCE = new InstagramAccessTokenJsonExtractor(); + } + + public static InstagramAccessTokenJsonExtractor instance() { + return InstanceHolder.INSTANCE; + } + + /** + * Non standard error message. Could be Instagram or Facebook specific. Usually Instagram type is used for getting + * access tokens. Facebook type is used for refreshing tokens. + * + * examples:
+ * + * Instagram specific: '{"error_type": "OAuthException", "code": 400, "error_message": "Missing required field + * client_id"}' + * + * Facebook specific: '{"error":{"message":"Error validating application. Invalid application + * ID.","type":"OAuthException","code":101,"fbtrace_id":"CvDR+X4WWIx"}}' + * + * @param response response + */ + @Override + public void generateError(Response response) throws IOException { + final JsonNode errorNode = OAuth2AccessTokenJsonExtractor.OBJECT_MAPPER.readTree(response.getBody()); + final JsonNode error = errorNode.get("error"); + if (error != null) { + FacebookAccessTokenJsonExtractor.instance().generateError(response); + } else { + throw new InstagramAccessTokenErrorResponse( + errorNode.get("error_type").asText(), + errorNode.get("code").asInt(), + errorNode.get("error_message").asText(), + response + ); + } + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramService.java new file mode 100644 index 000000000..5de1f3782 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/instagram/InstagramService.java @@ -0,0 +1,105 @@ +package com.github.scribejava.apis.instagram; + +import com.github.scribejava.apis.InstagramApi; +import java.io.IOException; +import java.io.OutputStream; +import java.util.concurrent.ExecutionException; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthAsyncRequestCallback; +import com.github.scribejava.core.model.OAuthConstants; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; +import java.util.concurrent.Future; + +public class InstagramService extends OAuth20Service { + + public InstagramService(InstagramApi api, String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + super(api, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, + httpClient); + } + + /** + * Refresh a long-lived Instagram User Access Token that is at least 24 hours old but has not expired. Refreshed + * tokens are valid for 60 days from the date at which they are refreshed. + * + * @param accessToken long-lived access token + * @param scope (not used) + * @return refresh token request + */ + @Override + protected OAuthRequest createRefreshTokenRequest(String accessToken, String scope) { + if (accessToken == null || accessToken.isEmpty()) { + throw new IllegalArgumentException("The accessToken cannot be null or empty"); + } + final OAuthRequest request = new OAuthRequest(Verb.GET, getApi().getRefreshTokenEndpoint()); + + request.addParameter(OAuthConstants.GRANT_TYPE, "ig_refresh_token"); + request.addParameter(OAuthConstants.ACCESS_TOKEN, accessToken); + + logRequestWithParams("refresh token", request); + + return request; + } + + public Future getLongLivedAccessTokenAsync(OAuth2AccessToken accessToken) { + return getLongLivedAccessToken(accessToken.getAccessToken(), null); + } + + public Future getLongLivedAccessTokenAsync(String shortLivedAccessToken) { + return getLongLivedAccessToken(shortLivedAccessToken, null); + } + + public Future getLongLivedAccessToken(String shortLivedAccessToken, + OAuthAsyncRequestCallback callback) { + return sendAccessTokenRequestAsync(createLongLivedAccessTokenRequest(shortLivedAccessToken), callback); + } + + public Future getLongLivedAccessToken(OAuth2AccessToken accessToken, + OAuthAsyncRequestCallback callback) { + return getLongLivedAccessToken(accessToken.getAccessToken(), callback); + } + + /** + * Get long-lived access token. + * + * Initial accessToken is valid for 1 hour so one can get long-lived access token. Long-lived access token is valid + * for 60 days. + * + * @param accessToken short-lived access token + * @return long-lived access token with filled expireIn and refreshToken + * @throws java.lang.InterruptedException + * @throws java.util.concurrent.ExecutionException + * @throws java.io.IOException + */ + public OAuth2AccessToken getLongLivedAccessToken(OAuth2AccessToken accessToken) + throws InterruptedException, ExecutionException, IOException { + return getLongLivedAccessToken(accessToken.getAccessToken()); + } + + public OAuth2AccessToken getLongLivedAccessToken(String shortLivedAccessToken) + throws InterruptedException, ExecutionException, IOException { + final OAuthRequest request = createLongLivedAccessTokenRequest(shortLivedAccessToken); + return sendAccessTokenRequestSync(request); + } + + private OAuthRequest createLongLivedAccessTokenRequest(String shortLivedAccessToken) { + final OAuthRequest request = new OAuthRequest(Verb.GET, InstagramApi.LONG_LIVED_ACCESS_TOKEN_ENDPOINT); + + getApi().getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + + request.addParameter(OAuthConstants.GRANT_TYPE, "ig_exchange_token"); + request.addParameter(OAuthConstants.ACCESS_TOKEN, shortLivedAccessToken); + + if (isDebug()) { + log("created long-lived access token request with body params [%s], query string params [%s]", + request.getBodyParams().asFormUrlEncodedString(), + request.getQueryStringParams().asFormUrlEncodedString()); + } + return request; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuthService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuthService.java index e0b0af6f1..c016d6ac7 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuthService.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuthService.java @@ -1,6 +1,6 @@ package com.github.scribejava.apis.polar; -import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.apis.PolarAPI; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; import com.github.scribejava.core.model.OAuthConstants; @@ -13,7 +13,7 @@ public class PolarOAuthService extends OAuth20Service { - public PolarOAuthService(DefaultApi20 api, String apiKey, String apiSecret, String callback, String defaultScope, + public PolarOAuthService(PolarAPI api, String apiKey, String apiSecret, String callback, String defaultScope, String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { super(api, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/InstagramExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/InstagramExample.java new file mode 100644 index 000000000..9694ba909 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/InstagramExample.java @@ -0,0 +1,97 @@ +package com.github.scribejava.apis.examples; + +import java.io.IOException; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; +import com.github.scribejava.apis.InstagramApi; +import com.github.scribejava.apis.instagram.InstagramService; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; + +public class InstagramExample { + + private static final String NETWORK_NAME = "Instagram"; + private static final String PROTECTED_RESOURCE_URL + = "https://graph.instagram.com/me/media?fields=id,caption,media_type,media_url,username"; + + private InstagramExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your client id and secret + final String clientId = "client-id"; + final String clientSecret = "client-secret"; + final String secretState = "secret" + new Random().nextInt(999_999); + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .defaultScope("user_profile,user_media") + .callback("http://example.com") + .build(InstagramApi.instance()); + + final Scanner in = new Scanner(System.in, "UTF-8"); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(secretState); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize ScribeJava here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final String code = in.nextLine(); + System.out.println(); + + System.out.println("And paste the state from server here. We have set 'secretState'='" + secretState + "'."); + System.out.print(">>"); + final String value = in.nextLine(); + if (secretState.equals(value)) { + System.out.println("State value does match!"); + } else { + System.out.println("Ooops, state value does not match!"); + System.out.println("Expected = " + secretState); + System.out.println("Got = " + value); + System.out.println(); + } + + System.out.println("Trading the Authorization Code for an Access Token..."); + final OAuth2AccessToken accessToken = service.getAccessToken(code); + System.out.println("Got the Access Token!"); + System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); + 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..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + try (Response response = service.execute(request)) { + 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 ScribeJava! :)"); + + final InstagramService instagramService = (InstagramService) service; + System.out.println("Now let's exchange our short-lived token to long-lived access token..."); + final OAuth2AccessToken longLivedAccessToken = instagramService.getLongLivedAccessToken(accessToken); + System.out.println("Got the Access Token!"); + System.out.println("(The access token raw response looks like this: " + longLivedAccessToken.getRawResponse() + + "')"); + + System.out.println("Now it's time to refresh long-lived token..."); + final OAuth2AccessToken refreshAccessToken = service.refreshAccessToken(longLivedAccessToken.getAccessToken()); + System.out.println("Got the refreshed Access Token!"); + System.out.println("(The refreshed access token raw response looks like this: " + + refreshAccessToken.getRawResponse() + "')"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncApacheExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteAsyncApacheExample.java similarity index 89% rename from scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncApacheExample.java rename to scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteAsyncApacheExample.java index 29d8dba96..392348b2b 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncApacheExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteAsyncApacheExample.java @@ -3,7 +3,7 @@ import java.util.Random; import java.util.Scanner; import java.util.concurrent.ExecutionException; -import com.github.scribejava.apis.FacebookApi; +import com.github.scribejava.apis.VkontakteApi; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuthRequest; @@ -13,12 +13,13 @@ import com.github.scribejava.httpclient.apache.ApacheHttpClientConfig; import java.io.IOException; -public class FacebookAsyncApacheExample { +public class VkontakteAsyncApacheExample { - private static final String NETWORK_NAME = "Facebook"; - private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/v3.2/me"; + private static final String NETWORK_NAME = "vk.com"; + private static final String PROTECTED_RESOURCE_URL = "https://api.vk.com/method/users.get?v=" + + VkontakteApi.VERSION; - private FacebookAsyncApacheExample() { + private VkontakteAsyncApacheExample() { } @SuppressWarnings("PMD.SystemPrintln") @@ -28,11 +29,11 @@ public static void main(String... args) throws InterruptedException, ExecutionEx final String clientSecret = "your client secret"; final String secretState = "secret" + new Random().nextInt(999_999); - try (OAuth20Service service = new ServiceBuilder(clientId) + try ( OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) .callback("http://www.example.com/oauth_callback/") .httpClientConfig(ApacheHttpClientConfig.defaultConfig()) - .build(FacebookApi.instance())) { + .build(VkontakteApi.instance())) { final Scanner in = new Scanner(System.in, "UTF-8"); System.out.println("=== " + NETWORK_NAME + "'s Async OAuth Workflow ==="); @@ -73,7 +74,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx System.out.println("Now we're going to access a protected resource..."); final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - try (Response response = service.execute(request)) { + try ( Response response = service.execute(request)) { System.out.println("Got it! Lets see what we found..."); System.out.println(); System.out.println(response.getCode()); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncNingExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteAsyncNingExample.java similarity index 90% rename from scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncNingExample.java rename to scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteAsyncNingExample.java index 29c52cbad..bfb80d1a9 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncNingExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteAsyncNingExample.java @@ -5,7 +5,7 @@ import java.util.Random; import java.util.Scanner; import java.util.concurrent.ExecutionException; -import com.github.scribejava.apis.FacebookApi; +import com.github.scribejava.apis.VkontakteApi; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuthRequest; @@ -14,12 +14,13 @@ import com.github.scribejava.core.oauth.OAuth20Service; import java.io.IOException; -public class FacebookAsyncNingExample { +public class VkontakteAsyncNingExample { - private static final String NETWORK_NAME = "Facebook"; - private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/v3.2/me"; + private static final String NETWORK_NAME = "vk.com"; + private static final String PROTECTED_RESOURCE_URL = "https://api.vk.com/method/users.get?v=" + + VkontakteApi.VERSION; - private FacebookAsyncNingExample() { + private VkontakteAsyncNingExample() { } @SuppressWarnings("PMD.SystemPrintln") @@ -36,11 +37,11 @@ public static void main(String... args) throws InterruptedException, ExecutionEx .setReadTimeout(1_000) .build()); - try (OAuth20Service service = new ServiceBuilder(clientId) + try ( OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) .callback("http://www.example.com/oauth_callback/") .httpClientConfig(clientConfig) - .build(FacebookApi.instance())) { + .build(VkontakteApi.instance())) { final Scanner in = new Scanner(System.in, "UTF-8"); System.out.println("=== " + NETWORK_NAME + "'s Async OAuth Workflow ==="); @@ -81,7 +82,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx System.out.println("Now we're going to access a protected resource..."); final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - try (Response response = service.execute(request)) { + try ( Response response = service.execute(request)) { System.out.println("Got it! Lets see what we found..."); System.out.println(); System.out.println(response.getCode()); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteClientCredentialsGrantExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteClientCredentialsGrantExample.java index 2b6e2d4f7..3e4d2d363 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteClientCredentialsGrantExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteClientCredentialsGrantExample.java @@ -9,7 +9,7 @@ public class VkontakteClientCredentialsGrantExample { - private static final String NETWORK_NAME = "Vkontakte.ru"; + private static final String NETWORK_NAME = "vk.com>"; private VkontakteClientCredentialsGrantExample() { } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExample.java index baa4dae91..ca1a698bf 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExample.java @@ -15,7 +15,7 @@ public class VkontakteExample { - private static final String NETWORK_NAME = "Vkontakte.ru"; + private static final String NETWORK_NAME = "vk.com"; private static final String PROTECTED_RESOURCE_URL = "https://api.vk.com/method/users.get?v=" + VkontakteApi.VERSION; @@ -66,7 +66,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println("Now we're going to access a protected resource..."); final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - try (Response response = service.execute(request)) { + try ( Response response = service.execute(request)) { System.out.println("Got it! Lets see what we found..."); System.out.println(); System.out.println(response.getCode()); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExternalHttpExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExternalHttpExample.java index 7f9e0c969..fe5340294 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExternalHttpExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExternalHttpExample.java @@ -16,7 +16,7 @@ public class VkontakteExternalHttpExample { - private static final String NETWORK_NAME = "Vkontakte.ru"; + private static final String NETWORK_NAME = "vk.com"; private static final String PROTECTED_RESOURCE_URL = "https://api.vk.com/method/users.get?v=" + VkontakteApi.VERSION; @@ -37,7 +37,7 @@ public static void main(String... args) throws IOException, InterruptedException .setReadTimeout(1_000) .build(); //wrap it - try (DefaultAsyncHttpClient ahcHttpClient = new DefaultAsyncHttpClient(httpClientConfig)) { + try ( DefaultAsyncHttpClient ahcHttpClient = new DefaultAsyncHttpClient(httpClientConfig)) { //wrap it final AhcHttpClient wrappedAHCHttpClient = new AhcHttpClient(ahcHttpClient); @@ -74,7 +74,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println("Now we're going to access a protected resource..."); final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - try (Response response = service.execute(request)) { + try ( Response response = service.execute(request)) { System.out.println("Got it! Lets see what we found..."); System.out.println(); System.out.println(response.getCode()); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractorTest.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractorTest.java index 45b68353b..240f08b81 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractorTest.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractorTest.java @@ -29,7 +29,7 @@ public void run() throws Throwable { } }); - assertEquals("This authorization code has been used.", fateR.getMessage()); + assertEquals("This authorization code has been used.", fateR.getErrorMessage()); assertEquals("OAuthException", fateR.getType()); assertEquals(100, fateR.getCodeInt()); assertEquals("DtxvtGRaxbB", fateR.getFbtraceId()); diff --git a/scribejava-core/pom.xml b/scribejava-core/pom.xml index 0730794bf..d5fbfc488 100644 --- a/scribejava-core/pom.xml +++ b/scribejava-core/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml @@ -29,7 +29,7 @@ jakarta.xml.bind jakarta.xml.bind-api - 3.0.0 + 4.0.0 true diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/base64/CommonsCodecBase64.java b/scribejava-core/src/main/java/com/github/scribejava/core/base64/CommonsCodecBase64.java index 196a6c4f0..bb172d720 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/base64/CommonsCodecBase64.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/CommonsCodecBase64.java @@ -2,10 +2,18 @@ public class CommonsCodecBase64 extends Base64 { - private static final org.apache.commons.codec.binary.Base64 BASE64_ENCODER - = new org.apache.commons.codec.binary.Base64(); - private static final org.apache.commons.codec.binary.Base64 BASE64_URL_ENCODER_WITHOUT_PADDING - = new org.apache.commons.codec.binary.Base64(0, null, true); + private static final org.apache.commons.codec.binary.Base64 BASE64_ENCODER; + private static final org.apache.commons.codec.binary.Base64 BASE64_URL_ENCODER_WITHOUT_PADDING; + + static { + if (isAvailable()) { + BASE64_ENCODER = new org.apache.commons.codec.binary.Base64(); + BASE64_URL_ENCODER_WITHOUT_PADDING = new org.apache.commons.codec.binary.Base64(0, null, true); + } else { + BASE64_ENCODER = null; + BASE64_URL_ENCODER_WITHOUT_PADDING = null; + } + } @Override protected String internalEncode(byte[] bytes) { diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/base64/Java8Base64.java b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Java8Base64.java index a5cea8755..8e4c6c990 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/base64/Java8Base64.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Java8Base64.java @@ -3,7 +3,7 @@ public class Java8Base64 extends Base64 { private static final com.github.scribejava.java8.base64.Java8Base64 JAVA8_BASE64 - = new com.github.scribejava.java8.base64.Java8Base64(); + = isAvailable() ? new com.github.scribejava.java8.base64.Java8Base64() : null; @Override protected String internalEncode(byte[] bytes) { diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/DeviceAuthorizationJsonExtractor.java b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/DeviceAuthorizationJsonExtractor.java index 0dc0ce931..5b4fa248b 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/DeviceAuthorizationJsonExtractor.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/DeviceAuthorizationJsonExtractor.java @@ -28,17 +28,6 @@ public DeviceAuthorization extract(Response response) throws IOException { return createDeviceAuthorization(response.getBody()); } - /** - * - * @param rawResponse rawResponse - * @throws java.io.IOException IOException - * @deprecated use {@link #generateError(com.github.scribejava.core.model.Response) } - */ - @Deprecated - public void generateError(String rawResponse) throws IOException { - generateError(new Response(-1, null, null, rawResponse)); - } - public void generateError(Response response) throws IOException { OAuth2AccessTokenJsonExtractor.instance().generateError(response); } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractor.java b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractor.java index 982c7e499..b9bfd6cba 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractor.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractor.java @@ -39,17 +39,6 @@ public OAuth2AccessToken extract(Response response) throws IOException { return createToken(body); } - /** - * - * @param rawResponse rawResponse - * @throws java.io.IOException IOException - * @deprecated use {@link #generateError(com.github.scribejava.core.model.Response) } - */ - @Deprecated - public void generateError(String rawResponse) throws IOException { - generateError(new Response(-1, null, null, rawResponse)); - } - /** * Related documentation: https://tools.ietf.org/html/rfc6749#section-5.2 * diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/AbstractAsyncOnlyHttpClient.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/AbstractAsyncOnlyHttpClient.java index 48917eb60..10b3d5faa 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/AbstractAsyncOnlyHttpClient.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/AbstractAsyncOnlyHttpClient.java @@ -1,6 +1,6 @@ package com.github.scribejava.core.httpclient; -import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.Response; import com.github.scribejava.core.model.Verb; import java.io.File; @@ -14,8 +14,17 @@ public abstract class AbstractAsyncOnlyHttpClient implements HttpClient { public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, byte[] bodyContents) throws InterruptedException, ExecutionException, IOException { - return executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, null, - (OAuthRequest.ResponseConverter) null).get(); + final OAuthAsyncRequestThrowableHolderCallback oAuthAsyncRequestThrowableHolderCallback + = new OAuthAsyncRequestThrowableHolderCallback(); + + final Response response = executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, + oAuthAsyncRequestThrowableHolderCallback, null).get(); + + final Throwable throwable = oAuthAsyncRequestThrowableHolderCallback.getThrowable(); + if (throwable != null) { + throw new ExecutionException(throwable); + } + return response; } @Override @@ -23,23 +32,71 @@ public Response execute(String userAgent, Map headers, Verb http com.github.scribejava.core.httpclient.multipart.MultipartPayload bodyContents) throws InterruptedException, ExecutionException, IOException { - return executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, null, - (OAuthRequest.ResponseConverter) null).get(); + final OAuthAsyncRequestThrowableHolderCallback oAuthAsyncRequestThrowableHolderCallback + = new OAuthAsyncRequestThrowableHolderCallback(); + + final Response response = executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, + oAuthAsyncRequestThrowableHolderCallback, null).get(); + + final Throwable throwable = oAuthAsyncRequestThrowableHolderCallback.getThrowable(); + if (throwable != null) { + throw new ExecutionException(throwable); + } + + return response; } @Override public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, String bodyContents) throws InterruptedException, ExecutionException, IOException { - return executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, null, - (OAuthRequest.ResponseConverter) null).get(); + final OAuthAsyncRequestThrowableHolderCallback oAuthAsyncRequestThrowableHolderCallback + = new OAuthAsyncRequestThrowableHolderCallback(); + + final Response response = executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, + oAuthAsyncRequestThrowableHolderCallback, null).get(); + + final Throwable throwable = oAuthAsyncRequestThrowableHolderCallback.getThrowable(); + if (throwable != null) { + throw new ExecutionException(throwable); + } + + return response; } @Override public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, File bodyContents) throws InterruptedException, ExecutionException, IOException { - return executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, null, - (OAuthRequest.ResponseConverter) null).get(); + final OAuthAsyncRequestThrowableHolderCallback oAuthAsyncRequestThrowableHolderCallback + = new OAuthAsyncRequestThrowableHolderCallback(); + + final Response response = executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, + oAuthAsyncRequestThrowableHolderCallback, null).get(); + + final Throwable throwable = oAuthAsyncRequestThrowableHolderCallback.getThrowable(); + if (throwable != null) { + throw new ExecutionException(throwable); + } + + return response; + } + + private class OAuthAsyncRequestThrowableHolderCallback implements OAuthAsyncRequestCallback { + + private Throwable throwable; + + @Override + public void onCompleted(Response response) { + } + + @Override + public void onThrowable(Throwable t) { + throwable = t; + } + + public Throwable getThrowable() { + return throwable; + } } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpFuture.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpFuture.java index 1922d3aef..c4443cc87 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpFuture.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpFuture.java @@ -8,6 +8,8 @@ /** * Fake Future. Just to have Future API for the default JDK Http client. It's NOT Async in any way. Just facade.
* That's it. Sync execution with Async methods. This class does NOT provide any async executions. + * + * @param */ public class JDKHttpFuture implements Future { diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessToken.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessToken.java index 00d5b1636..f02bc57c6 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessToken.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessToken.java @@ -5,11 +5,9 @@ /** * Represents an OAuth 2 Access token. - *

* http://tools.ietf.org/html/rfc6749#section-5.1 * * @see OAuth 2 Access Token Specification - *

*/ public class OAuth2AccessToken extends Token { diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessTokenErrorResponse.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessTokenErrorResponse.java index c64a3d005..5c4a65a19 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessTokenErrorResponse.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuth2AccessTokenErrorResponse.java @@ -1,6 +1,5 @@ package com.github.scribejava.core.model; -import com.github.scribejava.core.exceptions.OAuthException; import com.github.scribejava.core.oauth2.OAuth2Error; import java.io.IOException; @@ -9,39 +8,20 @@ /** * Representing "5.2. Error Response" */ -public class OAuth2AccessTokenErrorResponse extends OAuthException { +public class OAuth2AccessTokenErrorResponse extends OAuthResponseException { private static final long serialVersionUID = 2309424849700276816L; private final OAuth2Error error; private final String errorDescription; private final URI errorUri; - private final Response response; public OAuth2AccessTokenErrorResponse(OAuth2Error error, String errorDescription, URI errorUri, Response rawResponse) throws IOException { - super(rawResponse.getBody()); + super(rawResponse); this.error = error; this.errorDescription = errorDescription; this.errorUri = errorUri; - this.response = rawResponse; - } - - /** - * - * @param error error - * @param errorDescription errorDescription - * @param errorUri errorUri - * @param rawResponse rawResponse - * @throws java.io.IOException IOException - * @deprecated use {@link #OAuth2AccessTokenErrorResponse(com.github.scribejava.core.oauth2.OAuth2Error, - * java.lang.String, java.net.URI, com.github.scribejava.core.model.Response) - * } - */ - @Deprecated - public OAuth2AccessTokenErrorResponse(OAuth2Error error, String errorDescription, URI errorUri, - String rawResponse) throws IOException { - this(error, errorDescription, errorUri, new Response(-1, null, null, rawResponse)); } public OAuth2Error getError() { @@ -56,19 +36,4 @@ public URI getErrorUri() { return errorUri; } - /** - * - * @return body of response - * @throws IOException IOException - * @deprecated use {@link #getResponse()} and then {@link Response#getBody()} - */ - @Deprecated - public String getRawResponse() throws IOException { - return response.getBody(); - } - - public Response getResponse() { - return response; - } - } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthResponseException.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthResponseException.java new file mode 100644 index 000000000..5b6da25cf --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthResponseException.java @@ -0,0 +1,44 @@ +package com.github.scribejava.core.model; + +import com.github.scribejava.core.exceptions.OAuthException; +import java.io.IOException; +import java.util.Objects; + +public class OAuthResponseException extends OAuthException { + + private static final long serialVersionUID = 1309424849700276816L; + + private final transient Response response; + + public OAuthResponseException(Response rawResponse) throws IOException { + super(rawResponse.getBody()); + this.response = rawResponse; + } + + public Response getResponse() { + return response; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 29 * hash + Objects.hashCode(response); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final OAuthResponseException other = (OAuthResponseException) obj; + return Objects.equals(this.response, other.response); + } + +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth10aService.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth10aService.java index 89fd279b1..f48308b2e 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth10aService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth10aService.java @@ -39,7 +39,7 @@ public OAuth1RequestToken getRequestToken() throws IOException, InterruptedExcep final OAuthRequest request = prepareRequestTokenRequest(); log("sending request..."); - try (Response response = execute(request)) { + try ( Response response = execute(request)) { if (isDebug()) { final String body = response.getBody(); log("response status code: %s", response.getCode()); @@ -105,7 +105,7 @@ public OAuth1AccessToken getAccessToken(OAuth1RequestToken requestToken, String log("obtaining access token from %s", api.getAccessTokenEndpoint()); } final OAuthRequest request = prepareAccessTokenRequest(requestToken, oauthVerifier); - try (Response response = execute(request)) { + try ( Response response = execute(request)) { return api.getAccessTokenExtractor().extract(response); } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth20Service.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth20Service.java index 4b4bb6adb..82052e351 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth20Service.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuth20Service.java @@ -40,6 +40,108 @@ public OAuth20Service(DefaultApi20 api, String apiKey, String apiSecret, String this.defaultScope = defaultScope; } + // ===== common OAuth methods ===== + /** + * {@inheritDoc} + */ + @Override + public String getVersion() { + return VERSION; + } + + public void signRequest(String accessToken, OAuthRequest request) { + api.getBearerSignature().signRequest(accessToken, request); + } + + public void signRequest(OAuth2AccessToken accessToken, OAuthRequest request) { + signRequest(accessToken == null ? null : accessToken.getAccessToken(), request); + } + + /** + * Returns the URL where you should redirect your users to authenticate your application. + * + * @return the URL where you should redirect your users + */ + public String getAuthorizationUrl() { + return createAuthorizationUrlBuilder().build(); + } + + public String getAuthorizationUrl(String state) { + return createAuthorizationUrlBuilder() + .state(state) + .build(); + } + + /** + * Returns the URL where you should redirect your users to authenticate your application. + * + * @param additionalParams any additional GET params to add to the URL + * @return the URL where you should redirect your users + */ + public String getAuthorizationUrl(Map additionalParams) { + return createAuthorizationUrlBuilder() + .additionalParams(additionalParams) + .build(); + } + + public String getAuthorizationUrl(PKCE pkce) { + return createAuthorizationUrlBuilder() + .pkce(pkce) + .build(); + } + + public AuthorizationUrlBuilder createAuthorizationUrlBuilder() { + return new AuthorizationUrlBuilder(this); + } + + public DefaultApi20 getApi() { + return api; + } + + public OAuth2Authorization extractAuthorization(String redirectLocation) { + final OAuth2Authorization authorization = new OAuth2Authorization(); + int end = redirectLocation.indexOf('#'); + if (end == -1) { + end = redirectLocation.length(); + } + for (String param : redirectLocation.substring(redirectLocation.indexOf('?') + 1, end).split("&")) { + final String[] keyValue = param.split("="); + if (keyValue.length == 2) { + try { + switch (keyValue[0]) { + case "code": + authorization.setCode(URLDecoder.decode(keyValue[1], "UTF-8")); + break; + case "state": + authorization.setState(URLDecoder.decode(keyValue[1], "UTF-8")); + break; + default: //just ignore any other param; + } + } catch (UnsupportedEncodingException ueE) { + throw new IllegalStateException("jvm without UTF-8, really?", ueE); + } + } + } + return authorization; + } + + public String getResponseType() { + return responseType; + } + + public String getDefaultScope() { + return defaultScope; + } + + protected void logRequestWithParams(String requestDescription, OAuthRequest request) { + if (isDebug()) { + log("created " + requestDescription + " request with body params [%s], query string params [%s]", + request.getBodyParams().asFormUrlEncodedString(), + request.getQueryStringParams().asFormUrlEncodedString()); + } + } + + // ===== common AccessToken request methods ===== //protected to facilitate mocking protected OAuth2AccessToken sendAccessTokenRequestSync(OAuthRequest request) throws IOException, InterruptedException, ExecutionException { @@ -83,6 +185,41 @@ public OAuth2AccessToken convert(Response response) throws IOException { }); } + // ===== get AccessToken authorisation code flow methods ===== + protected OAuthRequest createAccessTokenRequest(AccessTokenRequestParams params) { + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); + + api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + + request.addParameter(OAuthConstants.CODE, params.getCode()); + final String callback = getCallback(); + if (callback != null) { + request.addParameter(OAuthConstants.REDIRECT_URI, callback); + } + final String scope = params.getScope(); + if (scope != null) { + request.addParameter(OAuthConstants.SCOPE, scope); + } else if (defaultScope != null) { + request.addParameter(OAuthConstants.SCOPE, defaultScope); + } + request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE); + + final String pkceCodeVerifier = params.getPkceCodeVerifier(); + if (pkceCodeVerifier != null) { + request.addParameter(PKCE.PKCE_CODE_VERIFIER_PARAM, pkceCodeVerifier); + } + + final Map extraParameters = params.getExtraParameters(); + if (extraParameters != null && !extraParameters.isEmpty()) { + for (Map.Entry extraParameter : extraParameters.entrySet()) { + request.addParameter(extraParameter.getKey(), extraParameter.getValue()); + } + } + + logRequestWithParams("access token", request); + return request; + } + public Future getAccessTokenAsync(String code) { return getAccessToken(AccessTokenRequestParams.create(code), null); } @@ -118,37 +255,26 @@ public Future getAccessToken(String code, return getAccessToken(AccessTokenRequestParams.create(code), callback); } - protected OAuthRequest createAccessTokenRequest(AccessTokenRequestParams params) { - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); + // ===== refresh AccessToken methods ===== + protected OAuthRequest createRefreshTokenRequest(String refreshToken, String scope) { + if (refreshToken == null || refreshToken.isEmpty()) { + throw new IllegalArgumentException("The refreshToken cannot be null or empty"); + } + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getRefreshTokenEndpoint()); api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); - request.addParameter(OAuthConstants.CODE, params.getCode()); - final String callback = getCallback(); - if (callback != null) { - request.addParameter(OAuthConstants.REDIRECT_URI, callback); - } - final String scope = params.getScope(); if (scope != null) { request.addParameter(OAuthConstants.SCOPE, scope); } else if (defaultScope != null) { request.addParameter(OAuthConstants.SCOPE, defaultScope); } - request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE); - final String pkceCodeVerifier = params.getPkceCodeVerifier(); - if (pkceCodeVerifier != null) { - request.addParameter(PKCE.PKCE_CODE_VERIFIER_PARAM, pkceCodeVerifier); - } + request.addParameter(OAuthConstants.REFRESH_TOKEN, refreshToken); + request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.REFRESH_TOKEN); - final Map extraParameters = params.getExtraParameters(); - if (extraParameters != null && !extraParameters.isEmpty()) { - for (Map.Entry extraParameter : extraParameters.entrySet()) { - request.addParameter(extraParameter.getKey(), extraParameter.getValue()); - } - } + logRequestWithParams("refresh token", request); - logRequestWithParams("access token", request); return request; } @@ -186,13 +312,11 @@ public Future refreshAccessToken(String refreshToken, String return sendAccessTokenRequestAsync(request, callback); } - protected OAuthRequest createRefreshTokenRequest(String refreshToken, String scope) { - if (refreshToken == null || refreshToken.isEmpty()) { - throw new IllegalArgumentException("The refreshToken cannot be null or empty"); - } - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getRefreshTokenEndpoint()); - - api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + // ===== get AccessToken password grant flow methods ===== + protected OAuthRequest createAccessTokenPasswordGrantRequest(String username, String password, String scope) { + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); + request.addParameter(OAuthConstants.USERNAME, username); + request.addParameter(OAuthConstants.PASSWORD, password); if (scope != null) { request.addParameter(OAuthConstants.SCOPE, scope); @@ -200,10 +324,11 @@ protected OAuthRequest createRefreshTokenRequest(String refreshToken, String sco request.addParameter(OAuthConstants.SCOPE, defaultScope); } - request.addParameter(OAuthConstants.REFRESH_TOKEN, refreshToken); - request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.REFRESH_TOKEN); + request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.PASSWORD); - logRequestWithParams("refresh token", request); + api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + + logRequestWithParams("access token password grant", request); return request; } @@ -253,22 +378,20 @@ public Future getAccessTokenPasswordGrantAsync(String usernam return sendAccessTokenRequestAsync(request, callback); } - protected OAuthRequest createAccessTokenPasswordGrantRequest(String username, String password, String scope) { + // ===== get AccessToken client credentials flow methods ===== + protected OAuthRequest createAccessTokenClientCredentialsGrantRequest(String scope) { final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); - request.addParameter(OAuthConstants.USERNAME, username); - request.addParameter(OAuthConstants.PASSWORD, password); + + api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); if (scope != null) { request.addParameter(OAuthConstants.SCOPE, scope); } else if (defaultScope != null) { request.addParameter(OAuthConstants.SCOPE, defaultScope); } + request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.CLIENT_CREDENTIALS); - request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.PASSWORD); - - api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); - - logRequestWithParams("access token password grant", request); + logRequestWithParams("access token client credentials grant", request); return request; } @@ -316,80 +439,7 @@ public Future getAccessTokenClientCredentialsGrant(String sco return sendAccessTokenRequestAsync(request, callback); } - protected OAuthRequest createAccessTokenClientCredentialsGrantRequest(String scope) { - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); - - api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); - - if (scope != null) { - request.addParameter(OAuthConstants.SCOPE, scope); - } else if (defaultScope != null) { - request.addParameter(OAuthConstants.SCOPE, defaultScope); - } - request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.CLIENT_CREDENTIALS); - - logRequestWithParams("access token client credentials grant", request); - - return request; - } - - /** - * {@inheritDoc} - */ - @Override - public String getVersion() { - return VERSION; - } - - public void signRequest(String accessToken, OAuthRequest request) { - api.getBearerSignature().signRequest(accessToken, request); - } - - public void signRequest(OAuth2AccessToken accessToken, OAuthRequest request) { - signRequest(accessToken == null ? null : accessToken.getAccessToken(), request); - } - - /** - * Returns the URL where you should redirect your users to authenticate your application. - * - * @return the URL where you should redirect your users - */ - public String getAuthorizationUrl() { - return createAuthorizationUrlBuilder().build(); - } - - public String getAuthorizationUrl(String state) { - return createAuthorizationUrlBuilder() - .state(state) - .build(); - } - - /** - * Returns the URL where you should redirect your users to authenticate your application. - * - * @param additionalParams any additional GET params to add to the URL - * @return the URL where you should redirect your users - */ - public String getAuthorizationUrl(Map additionalParams) { - return createAuthorizationUrlBuilder() - .additionalParams(additionalParams) - .build(); - } - - public String getAuthorizationUrl(PKCE pkce) { - return createAuthorizationUrlBuilder() - .pkce(pkce) - .build(); - } - - public AuthorizationUrlBuilder createAuthorizationUrlBuilder() { - return new AuthorizationUrlBuilder(this); - } - - public DefaultApi20 getApi() { - return api; - } - + // ===== revoke AccessToken methods ===== protected OAuthRequest createRevokeTokenRequest(String tokenToRevoke, TokenTypeHint tokenTypeHint) { final OAuthRequest request = new OAuthRequest(Verb.POST, api.getRevokeTokenEndpoint()); @@ -450,41 +500,7 @@ private void checkForErrorRevokeToken(Response response) throws IOException { } } - public OAuth2Authorization extractAuthorization(String redirectLocation) { - final OAuth2Authorization authorization = new OAuth2Authorization(); - int end = redirectLocation.indexOf('#'); - if (end == -1) { - end = redirectLocation.length(); - } - for (String param : redirectLocation.substring(redirectLocation.indexOf('?') + 1, end).split("&")) { - final String[] keyValue = param.split("="); - if (keyValue.length == 2) { - try { - switch (keyValue[0]) { - case "code": - authorization.setCode(URLDecoder.decode(keyValue[1], "UTF-8")); - break; - case "state": - authorization.setState(URLDecoder.decode(keyValue[1], "UTF-8")); - break; - default: //just ignore any other param; - } - } catch (UnsupportedEncodingException ueE) { - throw new IllegalStateException("jvm without UTF-8, really?", ueE); - } - } - } - return authorization; - } - - public String getResponseType() { - return responseType; - } - - public String getDefaultScope() { - return defaultScope; - } - + // ===== device Authorisation codes methods ===== protected OAuthRequest createDeviceAuthorizationCodesRequest(String scope) { final OAuthRequest request = new OAuthRequest(Verb.POST, api.getDeviceAuthorizationEndpoint()); request.addParameter(OAuthConstants.CLIENT_ID, getApiKey()); @@ -566,6 +582,7 @@ public Future getDeviceAuthorizationCodesAsync(String scope return getDeviceAuthorizationCodes(scope, null); } + // ===== get AccessToken Device Authorisation grant flow methods ===== protected OAuthRequest createAccessTokenDeviceAuthorizationGrantRequest(DeviceAuthorization deviceAuthorization) { final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addParameter(OAuthConstants.GRANT_TYPE, "urn:ietf:params:oauth:grant-type:device_code"); @@ -656,12 +673,4 @@ public OAuth2AccessToken pollAccessTokenDeviceAuthorizationGrant(DeviceAuthoriza Thread.sleep(intervalMillis); } } - - private void logRequestWithParams(String requestDescription, OAuthRequest request) { - if (isDebug()) { - log("created " + requestDescription + " request with body params [%s], query string params [%s]", - request.getBodyParams().asFormUrlEncodedString(), - request.getQueryStringParams().asFormUrlEncodedString()); - } - } } diff --git a/scribejava-httpclient-ahc/pom.xml b/scribejava-httpclient-ahc/pom.xml index d1a174281..fabd225c3 100644 --- a/scribejava-httpclient-ahc/pom.xml +++ b/scribejava-httpclient-ahc/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml @@ -20,6 +20,12 @@ scribejava-core ${project.version}
+ + org.slf4j + slf4j-simple + 2.0.3 + test + org.asynchttpclient async-http-client diff --git a/scribejava-httpclient-apache/pom.xml b/scribejava-httpclient-apache/pom.xml index 45e2113c3..1dc9dd53c 100644 --- a/scribejava-httpclient-apache/pom.xml +++ b/scribejava-httpclient-apache/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml @@ -28,7 +28,7 @@ org.apache.httpcomponents httpasyncclient - 4.1.4 + 4.1.5 com.github.scribejava diff --git a/scribejava-httpclient-armeria/pom.xml b/scribejava-httpclient-armeria/pom.xml index 7048bbd16..54e58c619 100644 --- a/scribejava-httpclient-armeria/pom.xml +++ b/scribejava-httpclient-armeria/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml @@ -20,10 +20,16 @@ scribejava-core ${project.version} + + org.slf4j + slf4j-simple + 2.0.3 + test + com.linecorp.armeria armeria - 1.6.0 + 1.20.2 com.github.scribejava diff --git a/scribejava-httpclient-ning/pom.xml b/scribejava-httpclient-ning/pom.xml index bdc15a132..39696d698 100644 --- a/scribejava-httpclient-ning/pom.xml +++ b/scribejava-httpclient-ning/pom.xml @@ -5,10 +5,10 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml - + com.github.scribejava scribejava-httpclient-ning ScribeJava Ning Async Http Client support @@ -20,6 +20,12 @@ scribejava-core ${project.version} + + org.slf4j + slf4j-simple + 2.0.3 + test + com.ning async-http-client diff --git a/scribejava-httpclient-okhttp/pom.xml b/scribejava-httpclient-okhttp/pom.xml index fcce1cd32..59bc2bffc 100644 --- a/scribejava-httpclient-okhttp/pom.xml +++ b/scribejava-httpclient-okhttp/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml @@ -23,7 +23,7 @@ com.squareup.okhttp3 okhttp - 4.9.1 + 4.10.0 com.github.scribejava diff --git a/scribejava-java8/pom.xml b/scribejava-java8/pom.xml index 4e9a12186..b75f6d2de 100644 --- a/scribejava-java8/pom.xml +++ b/scribejava-java8/pom.xml @@ -5,7 +5,7 @@ com.github.scribejava scribejava - 8.2.0 + 8.3.4-SNAPSHOT ../pom.xml