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/.travis.yml b/.travis.yml deleted file mode 100644 index 1420112b3..000000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -dist: trusty -language: java -script: mvn clean package -jdk: - - openjdk7 -os: - - linux diff --git a/LICENSE.txt b/LICENSE.txt index 8cde51fa9..6085098bc 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,5 @@ The MIT License -Copyright (c) 2013 hh.ru Copyright (c) 2010 Pablo Fernandez Permission is hereby granted, free of charge, to any person obtaining a copy @@ -19,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/README.md b/README.md index 29d1833dd..b90ef2e5f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Welcome to the home of ScribeJava, the simple OAuth client Java lib! -[![Build Status](https://travis-ci.org/scribejava/scribejava.svg?branch=master)](https://travis-ci.org/scribejava/scribejava) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.scribejava/scribejava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.scribejava/scribejava) +[![Donate](https://www.paypalobjects.com/en_US/RU/i/btn/btn_donateCC_LG.gif)](https://github.com/scribejava/scribejava/blob/master/donate.md) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.scribejava/scribejava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.scribejava/scribejava) # Why use ScribeJava? @@ -11,14 +10,15 @@ 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()); ``` That **single line** (added newlines for readability) is the only thing you need to configure ScribeJava with LinkedIn's OAuth API for example. -Working runnable examples are [here](https://github.com/scribejava/scribejava/tree/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples) +Working executable examples are [here](https://github.com/scribejava/scribejava/tree/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples) +Common usage: [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java) ### Threadsafe @@ -27,64 +27,91 @@ Hit ScribeJava as hard and with many threads as you like. ### Java 7 compatible That's it. You can use it in old environments and in android apps. +note: To compile from sources you will need Java 9 or newer ### Async and other HTTP clients ScribeJava support out-of-box several HTTP clients: - * ning async http client 1.9.x (maven module scribejava-httpclient-ning) - * Async Http Client asynchttpclient 2.x (maven module scribejava-httpclient-ahc) - * OkHttp (maven module scribejava-httpclient-okhttp) - * Apache HttpComponents HttpClient (maven module scribejava-httpclient-apache) + * ning async http client 1.9.x (maven module scribejava-httpclient-ning) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncNingExample.java) + * Async Http Client asynchttpclient 2.x (maven module scribejava-httpclient-ahc) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20AsyncAHCExample.java) + * OkHttp (maven module scribejava-httpclient-okhttp) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubAsyncOkHttpExample.java) + * Apache HttpComponents HttpClient (maven module scribejava-httpclient-apache) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncApacheExample.java) + * Armeria HTTP client (required >= java 8) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20ArmeriaExample.java) + * any externally created HTTP client [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExternalHttpExample.java) just add corresponding maven modules to your pom -### Supports all major 1.0a and 2.0 OAuth APIs out-of-the-box - -* Automatic (https://www.automatic.com/) -* AWeber (http://www.aweber.com/) -* Box (https://www.box.com/) -* Dataporten (https://docs.dataporten.no/) -* Digg (http://digg.com/) +### Supports many flows and additional features + + * [RFC 6749](https://tools.ietf.org/html/rfc6749) The OAuth 2.0 Authorization Framework, [Authorization Code Authorization Grant](https://tools.ietf.org/html/rfc6749#section-4.1), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java) + * [RFC 6749](https://tools.ietf.org/html/rfc6749) The OAuth 2.0 Authorization Framework, [Resource Owner Password Credentials Authorization Grant](https://tools.ietf.org/html/rfc6749#section-4.3) + * [RFC 6749](https://tools.ietf.org/html/rfc6749) The OAuth 2.0 Authorization Framework, [Client Credentials Authorization Grant](https://tools.ietf.org/html/rfc6749#section-4.4), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteClientCredentialsGrantExample.java) + * [RFC 6749](https://tools.ietf.org/html/rfc6749) The OAuth 2.0 Authorization Framework, [Refreshing an Access Token](https://tools.ietf.org/html/rfc6749#section-6), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java#L77) + * [RFC 6750](https://tools.ietf.org/html/rfc6750) The OAuth 2.0 Authorization Framework: Bearer Token Usage + * [RFC 7636](https://tools.ietf.org/html/rfc7636) Proof Key for Code Exchange by OAuth Public Clients (PKCE), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20WithPKCEExample.java) + * [RFC 7009](https://tools.ietf.org/html/rfc7009) OAuth 2.0 Token Revocation, [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20RevokeExample.java) + * [RFC 8628](https://tools.ietf.org/html/rfc8628) OAuth 2.0 Device Authorization Grant [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20DeviceAuthorizationGrantExample.java) + * [RFC 5849](https://tools.ietf.org/html/rfc5849) The OAuth 1.0 Protocol, [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TwitterExample.java) + +### Supports all (50+) major 1.0a and 2.0 OAuth APIs out-of-the-box + +* Asana (https://asana.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AsanaExample.java) +* Automatic (https://www.automatic.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AutomaticExample.java) +* AWeber (http://www.aweber.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AWeberExample.java) +* Box (https://www.box.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Box20Example.java) +* Dataporten (https://docs.dataporten.no/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DataportenExample.java) +* Digg (http://digg.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiggExample.java) +* Discord (https://discordapp.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiscordExample.java) * Доктор на работе (https://www.doktornarabote.ru/) -* Etsy (https://www.etsy.com/) -* Facebook (https://www.facebook.com/) -* Fitbit (https://www.fitbit.com/) -* Flickr (https://www.flickr.com/) -* Foursquare (https://foursquare.com/) -* Frappe (https://github.com/frappe/frappe) -* Freelancer (https://www.freelancer.com/) -* Genius (http://genius.com/) -* GitHub (https://github.com/) -* Google (https://www.google.com/) -* HeadHunter ХэдХантер (https://hh.ru/) -* Imgur (http://imgur.com/) -* Kaixin 开心网 (http://www.kaixin001.com/) -* LinkedIn (https://www.linkedin.com/) -* Microsoft Azure Active Directory (Azure AD) (http://azure.microsoft.com/) -* Microsoft Live (https://login.live.com/) -* Mail.Ru (https://mail.ru/) -* MediaWiki (https://www.mediawiki.org/) -* Meetup (http://www.meetup.com/) -* NAVER (http://www.naver.com/) -* Odnoklassniki Одноклассники (http://ok.ru/) -* Pinterest (https://www.pinterest.com/) -* 500px (https://500px.com/) -* Renren (http://renren.com/) -* Salesforce (https://www.salesforce.com/) -* Sina (http://www.sina.com.cn/ http://weibo.com/login.php) -* Skyrock (http://skyrock.com/) -* StackExchange (http://stackexchange.com/) -* The Things Network (v1-staging and v2-preview) (https://www.thethingsnetwork.org/) -* Trello (https://trello.com/) -* Tumblr (https://www.tumblr.com/) -* TUT.BY (http://www.tut.by/) -* Twitter (https://twitter.com/) -* uCoz (https://www.ucoz.com/) -* Viadeo (http://viadeo.com/) -* VK ВКонтакте (http://vk.com/) -* XING (https://www.xing.com/) -* Yahoo (https://www.yahoo.com/) -* Misfit (http://misfit.com/) +* Dropbox (https://www.dropbox.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DropboxExample.java) +* Etsy (https://www.etsy.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/EtsyExample.java) +* Facebook (https://www.facebook.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookExample.java), [example with Async Apache HTTP client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncApacheExample.java), [example with Async Ning HTTP client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncNingExample.java) +* Fitbit (https://www.fitbit.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FitbitApi20Example.java) +* Flickr (https://www.flickr.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FlickrExample.java) +* Foursquare (https://foursquare.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Foursquare2Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FoursquareExample.java) +* Frappe (https://github.com/frappe/frappe) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FrappeExample.java) +* Freelancer (https://www.freelancer.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FreelancerExample.java) +* Genius (http://genius.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GeniusExample.java) +* GitHub (https://github.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubExample.java), [example with OkHttp HTTP client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubAsyncOkHttpExample.java) +* Google (https://www.google.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java), [example with Async Http Client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20AsyncAHCExample.java), [example Revoke](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20RevokeExample.java), [example with PKCEE](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20WithPKCEExample.java) +* 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) +* LinkedIn (https://www.linkedin.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedIn20Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExample.java), [example with custom scopes](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExampleWithScopes.java) +* Mail.Ru (https://mail.ru/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruExample.java), [example with Async Ning HTTP Client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruAsyncExample.java) +* MediaWiki (https://www.mediawiki.org/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MediaWikiExample.java) +* Meetup (https://www.meetup.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Meetup20Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MeetupExample.java) +* Microsoft Azure Active Directory (Azure AD) (http://azure.microsoft.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectoryExample.java) +* Microsoft Azure Active Directory (Azure AD) 2.0 (http://azure.microsoft.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectory20Example.java) +* Microsoft Live (https://login.live.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LiveExample.java) +* Misfit (http://misfit.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MisfitExample.java) +* NAVER (http://www.naver.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/NaverExample.java) +* Odnoklassniki Одноклассники (http://ok.ru/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/OdnoklassnikiExample.java) +* Polar (https://www.polar.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PolarAPIExample.java) +* Pinterest (https://www.pinterest.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PinterestExample.java) +* 500px (https://500px.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Px500Example.java) +* Renren (http://renren.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/RenrenExample.java) +* Salesforce (https://www.salesforce.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceExample.java), [example with Async Ning HTTP Client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceNingAsyncExample.java) +* Sina (http://www.sina.com.cn/ http://weibo.com/login.php) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeibo2Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeiboExample.java) +* Skyrock (http://skyrock.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SkyrockExample.java) +* Slack (https://slack.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SlackExample.java) +* StackExchange (http://stackexchange.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/StackExchangeExample.java) +* The Things Network (v1-staging and v2-preview) (https://www.thethingsnetwork.org/) [example v1](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV1StagingExample.java), [example v2 preview](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV2PreviewExample.java) +* Trello (https://trello.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TrelloExample.java) +* Tumblr (https://www.tumblr.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TumblrExample.java) +* TUT.BY (http://www.tut.by/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TutByExample.java) +* Twitter (https://twitter.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TwitterExample.java) +* uCoz (https://www.ucoz.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/UcozExample.java) +* Viadeo (http://viadeo.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ViadeoExample.java) +* VK ВКонтакте (http://vk.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExample.java), [example Client Credentials Grant](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteClientCredentialsGrantExample.java), [example with External HTTP Client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/VkontakteExternalHttpExample.java) +* Wunderlist (https://www.wunderlist.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/WunderlistExample.java) +* Xero (https://www.xero.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XeroExample.java) +* XING (https://www.xing.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XingExample.java) +* Yahoo (https://www.yahoo.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Yahoo20Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/YahooExample.java) * check the [examples folder](https://github.com/scribejava/scribejava/tree/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples) ### Small and modular @@ -110,7 +137,7 @@ You can pull ScribeJava from the central maven repository, just add these to you com.github.scribejava scribejava-apis - 5.5.0 + 8.3.3 ``` @@ -119,14 +146,29 @@ And in case you need just core classes (that's it, without any external API (FB, com.github.scribejava scribejava-core - 5.5.0 + 8.3.3 ``` +## How can I help ScribeJava + +First of all, Pull Requests are welcome, the second option is [donations](https://github.com/scribejava/scribejava/blob/master/donate.md). + +## When will ScribeJava support XXX (new RFC, custom functionality, new API etc.) + +When you will send the pull request. That's the way for a majority of changes here. +Or you can ask someone to make the paid job for you. +In some cases, when I'm interested in changes (technically or financially), I can implement the request myself. + +## Paid consulting +If you or your business depends on the Scribejava and you need any specific improvement or new feature not currently implemented in the Scribejava, consider contacting me about a paid job. + ## Getting started in less than 2 minutes Check the [Getting Started](https://github.com/scribejava/scribejava/wiki/getting-started) page and start rocking! Please Read the [FAQ](https://github.com/scribejava/scribejava/wiki/faq) before creating an issue :) +Some useful info and answers you can find on the [wiki](https://github.com/scribejava/scribejava/wiki) + Also, remember to read the [fantastic tutorial](http://akoskm.github.io/2015/07/31/twitter-sign-in-for-web-apps.html) that [@akoskm](https://twitter.com/akoskm) wrote to easily integrate a server side app with an API (twitter in this case). ## Questions? diff --git a/changelog b/changelog index 9b63227d1..e962e073b 100644 --- a/changelog +++ b/changelog @@ -1,10 +1,127 @@ -[SNAPSHOT] - * remove support for obsolete NetEase (http://www.163.com/) and sohu 搜狐 (http://www.sohu.com/) (thanks to https://github.com/zawn) +[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 + (internal java 8+, Apache Commons Codec, JAXB) detected in runtime) (thanks to https://github.com/CodingFabian) + * implement possibility to add extra parameters to Access Token Request + (AccessTokenRequestParams#*ExtraParameters methods), https://github.com/scribejava/scribejava/issues/980 + (thanks to https://github.com/pmorch) + +[8.1.0] + * add raw Response (with HTTP response code and body) as member to the OAuth2AccessTokenErrorResponse + * add possibility to set "" (empty string) as apiSecret + * add Slack API (https://slack.com/) (thanks to https://github.com/petrkopotev) + +[8.0.0] + * add Kakao API (https://kakao.com/) (thanks to https://github.com/v0o0v) + * support chunks in JDKHttpClient's Multipart (thanks to https://github.com/eos1d3) + * add support for OAuth 2.0 Device Authorization Grant (RFC 8628) (thanks to https://github.com/rebarbora-mckvak) + * update Google API URLs + +[7.1.1] + * add Proxy support (via config's option) to internal JDKHttpClient (thanks to https://github.com/bjournaud) + * fix typo (change "Verfier" to "Verifier") (thanks to https://github.com/afkbrb) + * fix Multipart support in JDKHttpClient (thanks to https://github.com/eos1d3) + +[7.0.0] + * Add Polar API (https://www.polar.com/) (thanks to https://github.com/vidi42) + * make Response accept resources to autoclose and autoclose it (thanks to https://github.com/drei01) + * fix url encoding in POST payload (it's needed for 'application/x-www-form-urlencoded' Content-Type) + + unit tests (thanks to https://github.com/max904-github) + * Add Armeria HTTP client (thanks to https://github.com/max904-github) + +[6.9.0] + * Add Xero API (https://www.xero.com/) (thanks to https://github.com/SidneyAllen) + +[6.8.1] + * make Response implements Closeable (thanks to https://github.com/omaric) + * fix Type resolution for builder pattern in ServiceBuilderOAuth10a (thanks to https://github.com/mgyucht) + * fix no Content-length errors (thanks to https://github.com/mikita-herasiutsin and https://github.com/iankurverma) + +[6.8.0] + * Add debug output to OAuth2Service (thanks to https://github.com/rbarbey) + * Add Dropbox API (https://www.dropbox.com/) (thanks to https://github.com/petrkopotev) + +[6.7.0] + * Add OAuth2 support for Meetup.com (thanks to https://github.com/stevedes77) + * upgrade okhttp to 4.0.1 and security fix for jackson-databind 2.9.9.1 + +[6.6.3] + * fix NPE for OpenId providers + +[6.6.2] + * add PMD checks on compile + * add all OAuth error codes from supported RFCs (incl. "invalid_token") (thanks to https://github.com/echorebel) + * Update LinkedIn Example to API v2 (thanks to https://github.com/peternees) + * switch to jackson dependency to parse json responses (thanks to https://github.com/galimru) + +[6.5.1] + * cleanup deprecates methods + +[6.5.0] + * separate OAuth1.0a and OAuth2.0 ServiceBuilders, + introduce AuthorizationUrlBuilder (along with deprecation of AuthorizationUrlWithPKCE) + add possibility to provide different scopes for each Access Token request + * upgrade Facebook API from v2.11 to v3.2 + * upgrade VkontakteApi from 5.73 to 5.92 + +[6.4.1] + * support TLS 1.3 in JDK 11 for Salesforce + * fix NPE in Apache HTTP client in case of empty body in HTTP response (e.g. with 204 response code) + (thanks to https://github.com/SainagNeelamPatnaik) + * separate OAuth1.0a and OAuth2.0 classes + +[6.3.0] + * fix Muplipart request model and implement it for a jdk HTTP client (thanks to https://github.com/NTPape) + * remove any Google+ mention (switch to clean Google OAuth2) (thanks to https://github.com/fvasco) + * fix Microsoft Azure AD v1.0 and v2.0 (thanks to https://github.com/kenpusney and https://github.com/oscararias) + * add new API Asana (https://asana.com/) (thanks to https://github.com/joestazak) + * state param should be used only for authorization url generation, for v2 only, for Authorization Code Grant only, + and it should be set per request, not per created OAuthService + +[6.2.0] + * add new API Microsoft Azure Active Directory (Azure AD) 2.0 + (thanks to https://github.com/rzukow and https://github.com/dgrudenic) + +[6.1.0] + * add new API Keycloak (https://www.keycloak.org/) (thanks to https://github.com/JureZelic) + * add new API Discord (https://discordapp.com/) (thanks to https://github.com/Jokuni) + +[6.0.0] + * make redirect_uri optional while Access Token requesting on OAuth 2.0 (thanks to https://github.com/computerlove) + * switch to java 9+ (from java 7 only) for compilation. Runtime is still java 7+. + Complement README with links and RFC descriptions. + * switch OAuth2 Bearer Token Usage from enum OAuth2SignatureType to interface BearerSignature to be extensible + * add new API Wunderlist (https://www.wunderlist.com/) (thanks to https://github.com/M-F-K) + +[5.6.0] + * remove support for obsolete NetEase (http://www.163.com/) and sohu 搜狐 (http://www.sohu.com/) + (thanks to https://github.com/zawn) * add Multipart functionality to JDK Http Client (thanks to https://github.com/eos1d3) - * switch OAuth2 ClientAuthenticationType from enum to interface to be extensible according to + * switch OAuth2 ClientAuthenticationType from enum to interface ClientAuthentication to be extensible according to https://tools.ietf.org/html/rfc6749#section-2.3.2 (thanks to https://github.com/zawn) - * add RuntimeException processing in async http clients (delivered to onError callbacks) (thanks to https://github.com/jochen314) + * add RuntimeException processing in async http clients (delivered to onError callbacks) + (thanks to https://github.com/jochen314) * check 200 status code from response in OAuth2AccessTokenExtractor (thanks to https://github.com/jochen314) + * fix case sensitive Http Headers comparison and sending Content-Type header along with content-type + (thanks to https://github.com/marnix) + * add HiOrg-Server (https://www.hiorg-server.de/) API (thanks to https://github.com/MartinBoehmer) [5.5.0] * fix error parsing for Fitbit (thanks to https://github.com/danmana) @@ -16,7 +133,8 @@ * fix missing support for scope for refresh_token grant_type (thanks to https://github.com/tlxtellef) * add email field to VKOAuth2AccessToken (thanks to https://github.com/grouzen) * add new API - Automatic (https://www.automatic.com/) (thanks to https://github.com/ramsrib) - * add new API - Fitbit (https://www.fitbit.com/) (thanks to https://github.com/JustinLawler and https://github.com/alexthered) + * add new API - Fitbit (https://www.fitbit.com/) + (thanks to https://github.com/JustinLawler and https://github.com/alexthered) * deprecate OAuthConfig * OAuth1.0: send "oob" instead of null callback while requesting RequestToken (thanks to https://github.com/Rafaelsk) @@ -30,7 +148,8 @@ * add required param version to VK ВКонтакте (http://vk.com/) urls [5.2.0-java7again] - * allow 'null' as callback. It's an optional parameter. Remove "oob" as default (thanks to https://github.com/massongit) + * allow 'null' as callback. It's an optional parameter. Remove "oob" as default + (thanks to https://github.com/massongit) * java7 compatible again! [5.1.0] @@ -40,20 +159,23 @@ * fix LinkedInApi20 (thanks to https://github.com/jhorowitz-firedrum) [5.0.0] - * drop Java 7 backward compatibility support, become Java 8 only + * drop Java 7 backward compatibility support, become Java 8 only (was reverted in v5.2.0-java7again) * add JSON token extractor for OAuth 1.0a (thanks to https://github.com/evstropovv) * add new API - uCoz (https://www.ucoz.com/) (thanks to https://github.com/evstropovv) - * add PKCE (RFC 7636) support (Proof Key for Code Exchange by OAuth Public Clients) (thanks for suggesting to https://github.com/dieseldjango) + * add PKCE (RFC 7636) support (Proof Key for Code Exchange by OAuth Public Clients) + (thanks for suggesting to https://github.com/dieseldjango) * switch to use HTTP Basic Authorization by default in requests with need of (2.3. Client Authentication) https://tools.ietf.org/html/rfc6749#section-2.3 Can be overrided in API class * add support for client_credentials grant type (thanks to https://github.com/vivin) * add support for RFC 7009 OAuth 2.0 Token Revocation (thanks to https://github.com/vivin) * add OAuth2Service signRequest method accepting just String, not OAuth2 Access Token Object. Remove signRequest from abstract OAuthService. 2.0 and 1.0a will be a bit more different now. - * drop toString method from *Tokens to prevent leak of sensible data (token ans secrets) (thanks to https://github.com/rcaa) + * drop toString method from *Tokens to prevent leak of sensible data (token ans secrets) + (thanks to https://github.com/rcaa) * add Apache HttpComponents HttpClient support in separate module (thanks to https://github.com/sschwieb) * add support for appsecret_proof in Facebook - * update Facebook v2.8 -> v2.11 (version can be configured while constructing OAuthService - use FacebookApi.customVersion("2.11")) + * update Facebook v2.8 -> v2.11 + (version can be configured while constructing OAuthService - use FacebookApi.customVersion("2.11")) [4.2.0] * DELETE in JdkClient permits, but not requires payload (thanks to https://github.com/miguelD73) @@ -66,21 +188,27 @@ * update Live API (thanks to https://github.com/typhoon17) [4.1.1] - * omit the client_secret parameter if it is an empty string while refreshing token (thanks to https://github.com/KungfuPancake) + * omit the client_secret parameter if it is an empty string while refreshing token + (thanks to https://github.com/KungfuPancake) * allow perms to be specified in Flickr Api (read, write, or delete) (thanks to https://github.com/rogerhu) - * OdnoklassnikiService should consider params in a body while signing the request (thanks to https://github.com/MrNeuronix) + * OdnoklassnikiService should consider params in a body while signing the request + (thanks to https://github.com/MrNeuronix) * do not open OutputStream for output while sending empty body in HTTP requests in the default JDK Http client [4.1.0] - * make client_secret optional in OAuth2 while requesting AccessToken (if set to null, it's not required by OAuth2 specs) + * make client_secret optional in OAuth2 while requesting AccessToken + (if set to null, it's not required by OAuth2 specs) * move OAuth1 SignatureType from ServiceBuilder to API * add body for PATCH HTTP method - * make addOAuthParams appendSignature methods protected in OAuth10aService (to override them in case of need) (thanks to https://github.com/vivin) + * make addOAuthParams appendSignature methods protected in OAuth10aService (to override them in case of need) + (thanks to https://github.com/vivin) [4.0.0] - * Remove OAuthRequestAsync, just OAuthRequest. Request should know about sync vs async. Move default Http engine to JDKHttpClient. + * Remove OAuthRequestAsync, just OAuthRequest. Request should know about sync vs async. + Move default Http engine to JDKHttpClient. * introduce SignatureType for OAuth2.0 to implement Bearer signing for the requests - * switch Google, GitHub, Facebook OAuth2.0 oauth requests signing to more secured recommended variant (GET-param -> header Bearer) + * switch Google, GitHub, Facebook OAuth2.0 oauth requests signing to more secured recommended variant + (GET-param -> header Bearer) * introduce custom nonstandard Facebook AccessTokenErrorResponse [3.4.1] @@ -93,14 +221,16 @@ * add support for byte[] and File (async only) payload in OAuth Requests (thanks to https://github.com/keijohyttinen) * add support for HTTP verbs (thanks to https://github.com/keijohyttinen) * add OkHttp http client support (thanks to https://github.com/arcao) - * add default HTTP client configs (to use like 'new ServiceBuilder().httpClientConfig(OkHttpHttpClientConfig.defaultConfig())') + * add default HTTP client configs + (to use like 'new ServiceBuilder().httpClientConfig(OkHttpHttpClientConfig.defaultConfig())') * you can use your own impl of AsyncHttpClient [3.3.0] * update Facebook v2.6 -> v2.8 * add The Things Network API (v1-staging and v2-preview) (thanks to https://github.com/jpmeijers) * add Box (thanks to https://github.com/MclaughlinSteve) - * fix: OAuth20Service::refreshAccessToken should use RefreshTokenEndpoint, not AccessTokenEndpoint (thanks to https://github.com/vivin) + * fix: OAuth20Service::refreshAccessToken should use RefreshTokenEndpoint, not AccessTokenEndpoint + (thanks to https://github.com/vivin) * move signRequest method to OAuthService (common for OAuth1 and OAuth2) (thanks to https://github.com/apomelov) * drop deprecated setConnectionKeepAlive method @@ -109,14 +239,17 @@ * handle OAuth2 error response for Issuing an Access Token (thanks to juherr) [3.1.0] - * fix OdnoklassnikiServiceImpl signature, params for hash must be sorted in lexicographic order, see http://new.apiok.ru/dev/methods/ + * fix OdnoklassnikiServiceImpl signature, params for hash must be sorted in lexicographic order, + see http://new.apiok.ru/dev/methods/ * add posibility to use externally created http client * make ScribeJava compilable under jdk7 (checkstyle downgraded for jdk 1.7) * add travis CI (check [oracle|open]jdk7 oraclejdk8) [3.0.0] - * create abstract HTTP Client layer to support different HTTP clients as plugins (AHC and Ning support becames maven submodules) - * remove changing global JVM property http.keepAlive, deprecate controlling this property inside of ScribeJava (thanks to wldaunfr and rockihack) + * create abstract HTTP Client layer to support different HTTP clients as plugins + (AHC and Ning support becames maven submodules) + * remove changing global JVM property http.keepAlive, deprecate controlling this property inside of ScribeJava + (thanks to wldaunfr and rockihack) [2.8.1] * add Salesforce sandbox API support @@ -157,8 +290,10 @@ [2.5.2] * add Google Async Exmaple (with bugfix for it to work) * add OSGI manifest metadata - * apiSecret is not mandatory parameter in config (to use on client sides and other flows without need of the API secret) - * implement OAuth2 Authorization Response parsing in the OAuth20Service (to extract code and state from url, useful for Android) + * apiSecret is not mandatory parameter in config + (to use on client sides and other flows without need of the API secret) + * implement OAuth2 Authorization Response parsing in the OAuth20Service + (to extract code and state from url, useful for Android) * update ok.ru API urls, add 'state' support, add refresh token to the example [2.4.0] @@ -200,8 +335,7 @@ [2.0] * merge back SubScribe fork to the ScribeJava - + for previous changes see v1-changelog - changelog for 1.x version v2pre-changelog - changelog for SubScribe fork - diff --git a/checkstyle.xml b/checkstyle.xml index f3befc8a5..f7efbad65 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -93,20 +93,22 @@ - - - - - + + + + + diff --git a/donate.md b/donate.md new file mode 100644 index 000000000..99d3686dc --- /dev/null +++ b/donate.md @@ -0,0 +1,12 @@ +You can now help ScribeJava not only by Pull Requests. + +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 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
+2.Ian Strachan
+3.Your name can be here. diff --git a/pmd.xml b/pmd.xml new file mode 100644 index 000000000..5d93d340b --- /dev/null +++ b/pmd.xml @@ -0,0 +1,124 @@ + + + + + This ruleset defines the PMD rules for project "ScribeJava". + + + + + + + true + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 7fd7e0dd9..b484b6a71 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.github.scribejava scribejava pom - 5.5.1-SNAPSHOT + 8.3.4-SNAPSHOT ScribeJava OAuth Library The best OAuth library out there https://github.com/scribejava/scribejava @@ -16,11 +16,13 @@ scribejava-core + scribejava-java8 scribejava-apis scribejava-httpclient-ahc scribejava-httpclient-ning scribejava-httpclient-okhttp scribejava-httpclient-apache + scribejava-httpclient-armeria @@ -31,47 +33,40 @@ - 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 - HEAD - + HEAD + kullfar - Stas Gromov - s.gromov@hh.ru - hh.ru - http://hh.ru + Stanislav Gromov + kullfar@gmail.com all +3 - - kullfar@gmail.com - +7-909-677-11-16 - - junit - junit - 4.12 - test + com.fasterxml.jackson.core + jackson-databind + 2.14.0 - com.google.code.gson - gson - 2.8.5 + junit + junit + 4.13.2 test com.squareup.okhttp3 mockwebserver - 3.11.0 + 4.10.0 test @@ -81,7 +76,7 @@ org.apache.felix maven-bundle-plugin - 3.5.1 + 5.1.8 bundle-manifest @@ -95,7 +90,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.1.0 + 3.3.0 ${project.build.outputDirectory}/META-INF/MANIFEST.MF @@ -105,38 +100,56 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.0.0 + 3.2.0 com.puppycrawl.tools checkstyle - 6.19 + 10.4 + org.apache.maven.plugins maven-release-plugin 2.5.3 true + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-clean-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-install-plugin + 3.0.1 + maven-compiler-plugin - 3.8.0 + 3.10.1 UTF-8 - 1.7 - 1.7 + ${java.release} true + + -Xlint:-options + maven-deploy-plugin - 2.8.2 + 3.0.0 default-deploy @@ -150,7 +163,7 @@ org.apache.maven.plugins maven-resources-plugin - 3.1.0 + 3.3.0 UTF-8 @@ -158,7 +171,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.2.1 attach-sources @@ -171,9 +184,12 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.1 + 3.4.1 + ${java.home}/bin/javadoc UTF-8 + -html5 + all,-missing @@ -192,7 +208,6 @@ validate validate - main/java/com/github/scribejava/core/java8/* ${basedir}/src @@ -208,27 +223,56 @@ org.apache.maven.plugins - maven-enforcer-plugin - 1.4.1 + maven-pmd-plugin + 3.19.0 + + + net.sourceforge.pmd + pmd-core + ${pmdVersion} + + + net.sourceforge.pmd + pmd-java + ${pmdVersion} + + + net.sourceforge.pmd + pmd-javascript + ${pmdVersion} + + + net.sourceforge.pmd + pmd-jsp + ${pmdVersion} + + + + 1.${java.release} + false + + ../pmd.xml + + true + true + true + - enforce-java - enforce + check - - - - (,1.8) - - - + + 7 + 6.51.0 + + release-sign-artifacts @@ -243,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 e92f60e67..4e51bb8b5 100644 --- a/scribejava-apis/pom.xml +++ b/scribejava-apis/pom.xml @@ -5,10 +5,10 @@ com.github.scribejava scribejava - 5.5.1-SNAPSHOT + 8.3.4-SNAPSHOT ../pom.xml - + com.github.scribejava scribejava-apis ScribeJava APIs @@ -44,6 +44,18 @@ ${project.version} test + + com.github.scribejava + scribejava-httpclient-armeria + ${project.version} + test + + + io.netty + netty-resolver + 4.1.84.Final + test + diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/AWeberApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/AWeberApi.java index 84e5117df..9ad3a185a 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/AWeberApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/AWeberApi.java @@ -12,6 +12,7 @@ protected AWeberApi() { } private static class InstanceHolder { + private static final AWeberApi INSTANCE = new AWeberApi(); } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/Asana20Api.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/Asana20Api.java new file mode 100644 index 000000000..5e769aab8 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/Asana20Api.java @@ -0,0 +1,27 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; + +public class Asana20Api extends DefaultApi20 { + + protected Asana20Api() { + } + + private static class InstanceHolder { + private static final Asana20Api INSTANCE = new Asana20Api(); + } + + public static Asana20Api instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://app.asana.com/-/oauth_token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://app.asana.com/-/oauth_authorize"; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/BoxApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/BoxApi20.java index d21cc39be..91a4b7c16 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/BoxApi20.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/BoxApi20.java @@ -1,7 +1,8 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; /** * Box.com Api @@ -31,7 +32,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/DiscordApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/DiscordApi.java new file mode 100644 index 000000000..0583b6dc5 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/DiscordApi.java @@ -0,0 +1,32 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; + +public class DiscordApi extends DefaultApi20 { + + private DiscordApi() { + } + + private static class InstanceHolder { + private static final DiscordApi INSTANCE = new DiscordApi(); + } + + public static DiscordApi instance() { + return DiscordApi.InstanceHolder.INSTANCE; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://discordapp.com/api/oauth2/authorize"; + } + + @Override + public String getRevokeTokenEndpoint() { + return "https://discordapp.com/api/oauth2/token/revoke"; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://discordapp.com/api/oauth2/token"; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/DropboxApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/DropboxApi.java new file mode 100644 index 000000000..8bbd646f5 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/DropboxApi.java @@ -0,0 +1,31 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; + +/** + * Dropbox.com Api + */ +public class DropboxApi extends DefaultApi20 { + + protected DropboxApi() { + } + + private static class InstanceHolder { + + private static final DropboxApi INSTANCE = new DropboxApi(); + } + + public static DropboxApi instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://api.dropbox.com/oauth2/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://www.dropbox.com/oauth2/authorize"; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/EtsyApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/EtsyApi.java index 289f83588..00ca72918 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/EtsyApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/EtsyApi.java @@ -23,6 +23,7 @@ private EtsyApi(String... scopes) { } private static class InstanceHolder { + private static final EtsyApi INSTANCE = new EtsyApi(); } 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 fb0668eb1..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 @@ -1,7 +1,9 @@ package com.github.scribejava.apis; +import java.io.OutputStream; + import com.github.scribejava.apis.facebook.FacebookAccessTokenJsonExtractor; -import com.github.scribejava.apis.service.FacebookService; +import com.github.scribejava.apis.facebook.FacebookService; import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.extractors.TokenExtractor; import com.github.scribejava.core.httpclient.HttpClient; @@ -10,17 +12,13 @@ import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; -import java.io.OutputStream; -/** - * Facebook API - */ public class FacebookApi extends DefaultApi20 { private final String version; protected FacebookApi() { - this("2.11"); + this("3.2"); } protected FacebookApi(String version) { @@ -71,10 +69,10 @@ public ClientAuthentication getClientAuthentication() { } @Override - public FacebookService createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new FacebookService(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, - httpClientConfig, httpClient); + public FacebookService createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new FacebookService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/FlickrApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/FlickrApi.java index 33432f2bb..eedb89890 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/FlickrApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/FlickrApi.java @@ -29,6 +29,7 @@ protected FlickrApi(FlickrPerm perm) { } private static class InstanceHolder { + private static final FlickrApi INSTANCE = new FlickrApi(); } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/Foursquare2Api.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/Foursquare2Api.java index 321554af2..a90547f3a 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/Foursquare2Api.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/Foursquare2Api.java @@ -1,8 +1,9 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; public class Foursquare2Api extends DefaultApi20 { @@ -33,7 +34,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/FreelancerApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/FreelancerApi.java index b5c302ffc..33844d193 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/FreelancerApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/FreelancerApi.java @@ -21,7 +21,7 @@ public static FreelancerApi instance() { @Override public OAuth1SignatureType getSignatureType() { - return OAuth1SignatureType.QueryString; + return OAuth1SignatureType.QUERY_STRING; } @Override diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/GoogleApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/GoogleApi20.java index b4ab24d39..e3de4c746 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/GoogleApi20.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/GoogleApi20.java @@ -1,7 +1,9 @@ package com.github.scribejava.apis; +import com.github.scribejava.apis.google.GoogleDeviceAuthorizationJsonExtractor; import com.github.scribejava.apis.openid.OpenIdJsonTokenExtractor; import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.extractors.DeviceAuthorizationJsonExtractor; import com.github.scribejava.core.extractors.TokenExtractor; import com.github.scribejava.core.model.OAuth2AccessToken; @@ -11,6 +13,7 @@ protected GoogleApi20() { } private static class InstanceHolder { + private static final GoogleApi20 INSTANCE = new GoogleApi20(); } @@ -20,12 +23,12 @@ public static GoogleApi20 instance() { @Override public String getAccessTokenEndpoint() { - return "https://www.googleapis.com/oauth2/v4/token"; + return "https://oauth2.googleapis.com/token"; } @Override protected String getAuthorizationBaseUrl() { - return "https://accounts.google.com/o/oauth2/auth"; + return "https://accounts.google.com/o/oauth2/v2/auth"; } @Override @@ -35,6 +38,16 @@ public TokenExtractor getAccessTokenExtractor() { @Override public String getRevokeTokenEndpoint() { - return "https://accounts.google.com/o/oauth2/revoke"; + return "https://oauth2.googleapis.com/revoke"; + } + + @Override + public String getDeviceAuthorizationEndpoint() { + return "https://oauth2.googleapis.com/device/code"; + } + + @Override + public DeviceAuthorizationJsonExtractor getDeviceAuthorizationExtractor() { + return GoogleDeviceAuthorizationJsonExtractor.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/HHApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/HHApi.java index bd1224fe6..61476eaef 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/HHApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/HHApi.java @@ -10,6 +10,7 @@ protected HHApi() { } private static class InstanceHolder { + private static final HHApi INSTANCE = new HHApi(); } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/HiOrgServerApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/HiOrgServerApi20.java new file mode 100644 index 000000000..a69673a25 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/HiOrgServerApi20.java @@ -0,0 +1,44 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; + +/** + * OAuth2 API for HiOrg-Server + * + * @see HiOrg-Server OAuth API documentation + */ +public class HiOrgServerApi20 extends DefaultApi20 { + + private final String version; + + protected HiOrgServerApi20() { + this("v1"); + } + + protected HiOrgServerApi20(String version) { + this.version = version; + } + + private static class InstanceHolder { + + private static final HiOrgServerApi20 INSTANCE = new HiOrgServerApi20(); + } + + public static HiOrgServerApi20 instance() { + return InstanceHolder.INSTANCE; + } + + public static HiOrgServerApi20 customVersion(String version) { + return new HiOrgServerApi20(version); + } + + @Override + public String getAccessTokenEndpoint() { + return "https://www.hiorg-server.de/api/oauth2/" + version + "/token.php"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://www.hiorg-server.de/api/oauth2/" + version + "/authorize.php"; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/ImgurApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/ImgurApi.java index b8c802647..845fd95cb 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/ImgurApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/ImgurApi.java @@ -1,11 +1,12 @@ package com.github.scribejava.apis; -import com.github.scribejava.apis.service.ImgurOAuthService; +import com.github.scribejava.apis.imgur.ImgurOAuthService; import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.ParameterList; + import java.io.OutputStream; import java.util.Map; @@ -15,6 +16,7 @@ protected ImgurApi() { } private static class InstanceHolder { + private static final ImgurApi INSTANCE = new ImgurApi(); } @@ -55,11 +57,11 @@ protected String getAuthorizationBaseUrl() { } @Override - public ImgurOAuthService createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new ImgurOAuthService(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, - httpClientConfig, httpClient); + public ImgurOAuthService createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new ImgurOAuthService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); } public static boolean isOob(String callback) { 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/KaixinApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/KaixinApi20.java index 927813535..b94e8e1a3 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/KaixinApi20.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/KaixinApi20.java @@ -1,8 +1,9 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; /** * Kaixin(http://www.kaixin001.com/) open platform api based on OAuth 2.0. @@ -36,7 +37,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/KakaoApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/KakaoApi.java new file mode 100644 index 000000000..6587fe32f --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/KakaoApi.java @@ -0,0 +1,35 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; +import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; + +public class KakaoApi extends DefaultApi20 { + + protected KakaoApi() { + } + + private static class InstanceHolder { + + private static final KakaoApi INSTANCE = new KakaoApi(); + } + + public static KakaoApi instance() { + return KakaoApi.InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://kauth.kakao.com/oauth/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://kauth.kakao.com/oauth/authorize"; + } + + @Override + public ClientAuthentication getClientAuthentication() { + return RequestBodyAuthenticationScheme.instance(); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/KeycloakApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/KeycloakApi.java new file mode 100644 index 000000000..ed713b4d0 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/KeycloakApi.java @@ -0,0 +1,63 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.apis.openid.OpenIdJsonTokenExtractor; +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.extractors.TokenExtractor; +import com.github.scribejava.core.model.OAuth2AccessToken; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class KeycloakApi extends DefaultApi20 { + + private static final ConcurrentMap INSTANCES = new ConcurrentHashMap<>(); + + private final String baseUrlWithRealm; + + protected KeycloakApi(String baseUrlWithRealm) { + this.baseUrlWithRealm = baseUrlWithRealm; + } + + public static KeycloakApi instance() { + return instance("http://localhost:8080/", "master"); + } + + public static KeycloakApi instance(String baseUrl, String realm) { + final String defaultBaseUrlWithRealm = composeBaseUrlWithRealm(baseUrl, realm); + + //java8: switch to ConcurrentMap::computeIfAbsent + KeycloakApi api = INSTANCES.get(defaultBaseUrlWithRealm); + if (api == null) { + api = new KeycloakApi(defaultBaseUrlWithRealm); + final KeycloakApi alreadyCreatedApi = INSTANCES.putIfAbsent(defaultBaseUrlWithRealm, api); + if (alreadyCreatedApi != null) { + return alreadyCreatedApi; + } + } + return api; + } + + protected static String composeBaseUrlWithRealm(String baseUrl, String realm) { + return baseUrl + (baseUrl.endsWith("/") ? "" : "/") + "auth/realms/" + realm; + } + + @Override + public String getAccessTokenEndpoint() { + return baseUrlWithRealm + "/protocol/openid-connect/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return baseUrlWithRealm + "/protocol/openid-connect/auth"; + } + + @Override + public TokenExtractor getAccessTokenExtractor() { + return OpenIdJsonTokenExtractor.instance(); + } + + @Override + public String getRevokeTokenEndpoint() { + throw new RuntimeException("Not implemented yet"); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/LiveApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/LiveApi.java index 83cd89780..7a0a64ea5 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/LiveApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/LiveApi.java @@ -1,7 +1,8 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; public class LiveApi extends DefaultApi20 { @@ -27,7 +28,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/MailruApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/MailruApi.java index 05ae5cb8a..b48091594 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/MailruApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/MailruApi.java @@ -1,10 +1,11 @@ package com.github.scribejava.apis; +import java.io.OutputStream; + +import com.github.scribejava.apis.mailru.MailruOAuthService; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.apis.service.MailruOAuthService; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; -import java.io.OutputStream; public class MailruApi extends DefaultApi20 { @@ -12,6 +13,7 @@ protected MailruApi() { } private static class InstanceHolder { + private static final MailruApi INSTANCE = new MailruApi(); } @@ -30,10 +32,10 @@ protected String getAuthorizationBaseUrl() { } @Override - public MailruOAuthService createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new MailruOAuthService(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, - httpClientConfig, httpClient); + public MailruOAuthService createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new MailruOAuthService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/MediaWikiApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/MediaWikiApi.java index 8426d1924..3bb18001d 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/MediaWikiApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/MediaWikiApi.java @@ -40,6 +40,8 @@ public MediaWikiApi(String indexUrl, String niceUrlBase) { * * Special:OAuthConsumerRegistration/propose * . + * + * @return instance */ public static MediaWikiApi instance() { return InstanceHolder.INSTANCE; @@ -50,6 +52,8 @@ public static MediaWikiApi instance() { * * Special:OAuthConsumerRegistration/propose * . + * + * @return instanceBeta */ public static MediaWikiApi instanceBeta() { return BetaInstanceHolder.BETA_INSTANCE; diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/MeetupApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/MeetupApi20.java new file mode 100644 index 000000000..ce09e931d --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/MeetupApi20.java @@ -0,0 +1,34 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; +import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; + +public class MeetupApi20 extends DefaultApi20 { + + protected MeetupApi20() { + } + + private static class InstanceHolder { + private static final MeetupApi20 INSTANCE = new MeetupApi20(); + } + + public static MeetupApi20 instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://secure.meetup.com/oauth2/access"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://secure.meetup.com/oauth2/authorize"; + } + + @Override + public ClientAuthentication getClientAuthentication() { + return RequestBodyAuthenticationScheme.instance(); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectory20Api.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectory20Api.java new file mode 100644 index 000000000..399cf54c9 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectory20Api.java @@ -0,0 +1,48 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.apis.microsoftazureactivedirectory.BaseMicrosoftAzureActiveDirectoryApi; +import com.github.scribejava.apis.microsoftazureactivedirectory.MicrosoftAzureActiveDirectory20BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; + +/** + * Microsoft Azure Active Directory Api v 2.0 + * + * @see + * Understand the OAuth 2.0 authorization code flow in Azure AD | Microsoft Docs + * @see + * Microsoft Graph REST API v1.0 reference + * @see https://portal.azure.com + */ +public class MicrosoftAzureActiveDirectory20Api extends BaseMicrosoftAzureActiveDirectoryApi { + + protected MicrosoftAzureActiveDirectory20Api() { + this(COMMON_TENANT); + } + + protected MicrosoftAzureActiveDirectory20Api(String tenant) { + super(tenant); + } + + private static class InstanceHolder { + + private static final MicrosoftAzureActiveDirectory20Api INSTANCE = new MicrosoftAzureActiveDirectory20Api(); + } + + public static MicrosoftAzureActiveDirectory20Api instance() { + return InstanceHolder.INSTANCE; + } + + public static MicrosoftAzureActiveDirectory20Api custom(String tenant) { + return new MicrosoftAzureActiveDirectory20Api(tenant); + } + + @Override + public BearerSignature getBearerSignature() { + return MicrosoftAzureActiveDirectory20BearerSignature.instance(); + } + + @Override + protected String getEndpointVersionPath() { + return "/v2.0"; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectoryApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectoryApi.java index 2c793ae14..9ab4aa291 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectoryApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/MicrosoftAzureActiveDirectoryApi.java @@ -1,12 +1,8 @@ package com.github.scribejava.apis; -import com.github.scribejava.apis.service.MicrosoftAzureActiveDirectoryService; -import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.HttpClientConfig; -import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; -import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; -import java.io.OutputStream; +import com.github.scribejava.apis.microsoftazureactivedirectory.BaseMicrosoftAzureActiveDirectoryApi; +import com.github.scribejava.apis.microsoftazureactivedirectory.MicrosoftAzureActiveDirectoryBearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; /** * Microsoft Azure Active Directory Api @@ -20,15 +16,18 @@ * Azure AD Graph API Operations on the Signed-in User * @see https://portal.azure.com */ -public class MicrosoftAzureActiveDirectoryApi extends DefaultApi20 { +public class MicrosoftAzureActiveDirectoryApi extends BaseMicrosoftAzureActiveDirectoryApi { - private static final String MSFT_GRAPH_URL = "https://graph.windows.net"; + private final String resource; - private static final String MSFT_LOGIN_URL = "https://login.microsoftonline.com"; - private static final String SLASH = "/"; - private static final String COMMON = "common"; - private static final String TOKEN_URI = "oauth2/token"; - private static final String AUTH_URI = "oauth2/authorize?resource=" + MSFT_GRAPH_URL; + protected MicrosoftAzureActiveDirectoryApi() { + this(COMMON_TENANT, null); + } + + protected MicrosoftAzureActiveDirectoryApi(String tenant, String resource) { + super(tenant); + this.resource = resource; + } private static class InstanceHolder { @@ -39,26 +38,27 @@ public static MicrosoftAzureActiveDirectoryApi instance() { return InstanceHolder.INSTANCE; } - @Override - public String getAccessTokenEndpoint() { - return MSFT_LOGIN_URL + SLASH + COMMON + SLASH + TOKEN_URI; + public static MicrosoftAzureActiveDirectoryApi customTenant(String tenant) { + return new MicrosoftAzureActiveDirectoryApi(tenant, null); } - @Override - protected String getAuthorizationBaseUrl() { - return MSFT_LOGIN_URL + SLASH + COMMON + SLASH + AUTH_URI; + public static MicrosoftAzureActiveDirectoryApi customResource(String resource) { + return new MicrosoftAzureActiveDirectoryApi(COMMON_TENANT, resource); + } + + public static MicrosoftAzureActiveDirectoryApi custom(String tenant, String resource) { + return new MicrosoftAzureActiveDirectoryApi(tenant, resource); } @Override - public MicrosoftAzureActiveDirectoryService createService(String apiKey, String apiSecret, String callback, - String scope, OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new MicrosoftAzureActiveDirectoryService(this, apiKey, apiSecret, callback, scope, state, responseType, - userAgent, httpClientConfig, httpClient); + protected String getAuthorizationBaseUrl() { + final String authorizationBaseUrl = super.getAuthorizationBaseUrl(); + return resource == null || resource.isEmpty() ? authorizationBaseUrl + : authorizationBaseUrl + "?resource=" + resource; } @Override - public ClientAuthentication getClientAuthentication() { - return RequestBodyAuthenticationScheme.instance(); + public BearerSignature getBearerSignature() { + return MicrosoftAzureActiveDirectoryBearerSignature.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/MisfitApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/MisfitApi.java index c34d2cc15..051de70c1 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/MisfitApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/MisfitApi.java @@ -1,7 +1,8 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; public class MisfitApi extends DefaultApi20 { @@ -28,7 +29,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/NaverApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/NaverApi.java index a3028ae11..f60871735 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/NaverApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/NaverApi.java @@ -1,7 +1,8 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; public class NaverApi extends DefaultApi20 { protected NaverApi() { @@ -9,9 +10,6 @@ protected NaverApi() { private static class InstanceHolder { private static final NaverApi INSTANCE = new NaverApi(); - - private InstanceHolder() { - } } public static NaverApi instance() { @@ -29,7 +27,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/OdnoklassnikiApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/OdnoklassnikiApi.java index e7db8838d..b87eaa072 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/OdnoklassnikiApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/OdnoklassnikiApi.java @@ -1,13 +1,15 @@ package com.github.scribejava.apis; -import com.github.scribejava.apis.service.OdnoklassnikiOAuthService; +import java.io.OutputStream; + +import com.github.scribejava.apis.odnoklassniki.OdnoklassnikiOAuthService; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; -import java.io.OutputStream; public class OdnoklassnikiApi extends DefaultApi20 { @@ -15,6 +17,7 @@ protected OdnoklassnikiApi() { } private static class InstanceHolder { + private static final OdnoklassnikiApi INSTANCE = new OdnoklassnikiApi(); } @@ -33,16 +36,16 @@ protected String getAuthorizationBaseUrl() { } @Override - public OdnoklassnikiOAuthService createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, + public OdnoklassnikiOAuthService createService(String apiKey, String apiSecret, String callback, + String defaultScope, String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new OdnoklassnikiOAuthService(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, - httpClientConfig, httpClient); + return new OdnoklassnikiOAuthService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } @Override diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/PolarAPI.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/PolarAPI.java new file mode 100644 index 000000000..01e1651c6 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/PolarAPI.java @@ -0,0 +1,53 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.apis.polar.PolarJsonTokenExtractor; +import com.github.scribejava.apis.polar.PolarOAuthService; +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 java.io.OutputStream; + +/** + * Polar's OAuth2 client's implementation source: https://www.polar.com/accesslink-api/#authentication + */ +public class PolarAPI extends DefaultApi20 { + + protected PolarAPI() { + } + + private static class InstanceHolder { + + private static final PolarAPI INSTANCE = new PolarAPI(); + } + + public static PolarAPI instance() { + return PolarAPI.InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://polarremote.com/v2/oauth2/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://flow.polar.com/oauth2/authorization"; + } + + @Override + public PolarOAuthService createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + + return new PolarOAuthService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); + } + + @Override + public TokenExtractor getAccessTokenExtractor() { + return PolarJsonTokenExtractor.instance(); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/RenrenApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/RenrenApi.java index cc475440e..d4ade9fad 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/RenrenApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/RenrenApi.java @@ -1,8 +1,9 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; /** * Renren(http://www.renren.com/) OAuth 2.0 based api. @@ -36,7 +37,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/SalesforceApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/SalesforceApi.java index afd2eae5f..8760a7fff 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/SalesforceApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/SalesforceApi.java @@ -12,14 +12,14 @@ import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import javax.net.ssl.SSLSocket; /** * This class is an implementation of the Salesforce OAuth2 API. - * The default implementation connects to the Salesforce - * production environment. - * If you want to connect to a Sandbox environment you've to use {@link #sandbox()} method to - * get sandbox instance of this API + * + * The default implementation connects to the Salesforce production environment. If you want to connect to a Sandbox + * environment you've to use {@link #sandbox()} method to get sandbox instance of this API */ public class SalesforceApi extends DefaultApi20 { @@ -51,6 +51,7 @@ protected SalesforceApi(String hostName) { } private static class InstanceHolder { + private static final SalesforceApi INSTANCE = new SalesforceApi(PRODUCTION_HOST); } @@ -84,7 +85,7 @@ public TokenExtractor getAccessTokenExtractor() { private static boolean isTLSv11orUpperEnabled(final SSLSocket socket) { for (String protocol : socket.getEnabledProtocols()) { - if ("TLSv1.2".equals(protocol) || "TLSv1.1".equals(protocol)) { + if (protocol.startsWith("TLSv1.")) { return true; } } @@ -97,7 +98,7 @@ private static boolean isTLSv11orUpperEnabled(final SSLSocket socket) { * Java 8 have TLS 1.2 enabled by default. java 7 - no, you should invoke this method or turn TLS>=1.1 somehow * else

* - * @throws java.security.NoSuchAlgorithmException in case your jvm doesn't support TLSv1.1 and TLSv1.2 + * @throws java.security.NoSuchAlgorithmException in case your jvm doesn't support TLSv1.1 or higher * @throws java.security.KeyManagementException unexpected Exception from * {@link SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom)} * @throws java.io.IOException unexpected Exception from {@link javax.net.ssl.SSLSocketFactory#createSocket()} @@ -107,29 +108,19 @@ public static void initTLSv11orUpper() throws NoSuchAlgorithmException, KeyManag if (isTLSv11orUpperEnabled(socket)) { return; } - boolean supportTLSv11 = false; - boolean supportTLSv12 = false; - for (String protocol : socket.getSupportedProtocols()) { - if ("TLSv1.2".equals(protocol)) { - supportTLSv12 = true; - break; - } - if ("TLSv1.1".equals(protocol)) { - supportTLSv11 = true; + final String[] supportedProtocols = socket.getSupportedProtocols(); + Arrays.sort(supportedProtocols); + for (int i = supportedProtocols.length - 1; i >= 0; i--) { + final String supportedProtocol = supportedProtocols[i]; + if (supportedProtocol.startsWith("TLSv1.")) { + final SSLContext context = SSLContext.getInstance(supportedProtocol); + context.init(null, null, null); + SSLContext.setDefault(context); + return; } } - final SSLContext context; - if (supportTLSv12) { - context = SSLContext.getInstance("TLSv1.2"); - } else if (supportTLSv11) { - context = SSLContext.getInstance("TLSv1.1"); - } else { - throw new NoSuchAlgorithmException("for Salesforce API to work you need jvm with TLS 1.1 or 1.2 support"); - } - - context.init(null, null, null); - SSLContext.setDefault(context); + throw new NoSuchAlgorithmException("for Salesforce API to work you need jvm with TLS 1.1 or higher support"); } @Override diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/SinaWeiboApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/SinaWeiboApi20.java index edd316f87..19aa9f356 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/SinaWeiboApi20.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/SinaWeiboApi20.java @@ -1,7 +1,8 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; /** * SinaWeibo OAuth 2.0 api. @@ -30,7 +31,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/SlackApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/SlackApi.java new file mode 100644 index 000000000..4d834fff1 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/SlackApi.java @@ -0,0 +1,37 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.apis.slack.SlackJsonTokenExtractor; +import com.github.scribejava.core.builder.api.DefaultApi20; + +/** + * Slack.com API + */ +public class SlackApi extends DefaultApi20 { + + protected SlackApi() { + } + + private static class InstanceHolder { + + private static final SlackApi INSTANCE = new SlackApi(); + } + + public static SlackApi instance() { + return SlackApi.InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://slack.com/api/oauth.v2.access"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://slack.com/oauth/v2/authorize"; + } + + @Override + public SlackJsonTokenExtractor getAccessTokenExtractor() { + return SlackJsonTokenExtractor.instance(); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/StackExchangeApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/StackExchangeApi.java index 554c97b33..3ba195460 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/StackExchangeApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/StackExchangeApi.java @@ -1,10 +1,11 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.extractors.OAuth2AccessTokenExtractor; import com.github.scribejava.core.extractors.TokenExtractor; import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; /** * Stack Exchange authentication via OAuth 2.0 (stackoverflow.com, @@ -39,7 +40,7 @@ public TokenExtractor getAccessTokenExtractor() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/TutByApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/TutByApi.java index 377bc9046..41f71b307 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/TutByApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/TutByApi.java @@ -1,10 +1,8 @@ package com.github.scribejava.apis; -import com.github.scribejava.apis.service.TutByOAuthService; +import com.github.scribejava.apis.tutby.TutByBearerSignature; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.HttpClientConfig; -import java.io.OutputStream; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; public class TutByApi extends DefaultApi20 { @@ -30,10 +28,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public TutByOAuthService createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new TutByOAuthService(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, - httpClientConfig, httpClient); + public BearerSignature getBearerSignature() { + return TutByBearerSignature.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/ViadeoApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/ViadeoApi.java index 30c0ffcfe..fb70de258 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/ViadeoApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/ViadeoApi.java @@ -1,8 +1,9 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; public class ViadeoApi extends DefaultApi20 { @@ -33,7 +34,7 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/VkontakteApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/VkontakteApi.java index ff11d902c..dfc96275b 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/VkontakteApi.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/VkontakteApi.java @@ -2,16 +2,17 @@ import com.github.scribejava.apis.vk.VKJsonTokenExtractor; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.extractors.TokenExtractor; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; public class VkontakteApi extends DefaultApi20 { - public static final String VERSION = "5.73"; + public static final String VERSION = "5.92"; protected VkontakteApi() { } @@ -41,8 +42,8 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } @Override diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/WunderlistAPI.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/WunderlistAPI.java new file mode 100644 index 000000000..abf19db92 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/WunderlistAPI.java @@ -0,0 +1,58 @@ +package com.github.scribejava.apis; + +import java.io.OutputStream; + +import com.github.scribejava.apis.wunderlist.WunderlistOAuthService; +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; +import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; +import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; + +/** + * Wunderlist.com Api + */ +public class WunderlistAPI extends DefaultApi20 { + + protected WunderlistAPI() { + } + + private static class InstanceHolder { + + private static final WunderlistAPI INSTANCE = new WunderlistAPI(); + } + + public static WunderlistAPI instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://www.wunderlist.com/oauth/access_token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://www.wunderlist.com/oauth/authorize"; + } + + @Override + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); + } + + @Override + public ClientAuthentication getClientAuthentication() { + return RequestBodyAuthenticationScheme.instance(); + } + + @Override + public WunderlistOAuthService createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new WunderlistOAuthService(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/XeroApi20.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/XeroApi20.java new file mode 100644 index 000000000..2141ed007 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/XeroApi20.java @@ -0,0 +1,31 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; + +/** + * Xero.com Api + */ +public class XeroApi20 extends DefaultApi20 { + + protected XeroApi20() { + } + + private static class InstanceHolder { + + private static final XeroApi20 INSTANCE = new XeroApi20(); + } + + public static XeroApi20 instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://identity.xero.com/connect/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://login.xero.com/identity/connect/authorize"; + } +} 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 30c049a3f..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,8 @@ 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; /** @@ -14,47 +16,47 @@ * '{"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 String code; + private final int codeInt; private final String fbtraceId; - private final String rawResponse; - public FacebookAccessTokenErrorResponse(String message, String type, String code, String fbtraceId, - String rawResponse) { - 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.code = code; + this.codeInt = code; this.fbtraceId = fbtraceId; - this.rawResponse = rawResponse; + } + + public String getErrorMessage() { + return errorMessage; } public String getType() { return type; } - public String getCode() { - return code; + public int getCodeInt() { + return codeInt; } public String getFbtraceId() { return fbtraceId; } - public String getRawResponse() { - return rawResponse; - } - @Override public int hashCode() { - int hash = 5; - hash = 83 * hash + Objects.hashCode(rawResponse); - 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(code); + hash = 83 * hash + Objects.hashCode(codeInt); hash = 83 * hash + Objects.hashCode(fbtraceId); return hash; } @@ -70,17 +72,19 @@ public boolean equals(Object obj) { if (getClass() != obj.getClass()) { return false; } - final FacebookAccessTokenErrorResponse other = (FacebookAccessTokenErrorResponse) obj; - if (!Objects.equals(rawResponse, other.getRawResponse())) { + 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())) { return false; } - if (!Objects.equals(code, other.getCode())) { + if (codeInt != other.getCodeInt()) { return false; } return Objects.equals(fbtraceId, other.getFbtraceId()); @@ -88,8 +92,8 @@ public boolean equals(Object obj) { @Override public String toString() { - return "FacebookAccessTokenErrorResponse{'type'='" + type + "', 'code'='" + code - + "', 'fbtraceId'='" + fbtraceId + "', 'rawResponse'='" + rawResponse - + "', 'message'='" + getMessage() + "'}"; + return "FacebookAccessTokenErrorResponse{'type'='" + type + "', 'codeInt'='" + codeInt + + "', 'fbtraceId'='" + fbtraceId + "', 'response'='" + getResponse() + + "', 'errorMessage'='" + errorMessage + "'}"; } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractor.java index 62326e099..f51935436 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractor.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractor.java @@ -1,18 +1,15 @@ package com.github.scribejava.apis.facebook; +import com.fasterxml.jackson.databind.JsonNode; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; -import java.util.regex.Pattern; +import com.github.scribejava.core.model.Response; +import java.io.IOException; /** * non standard Facebook Extractor */ public class FacebookAccessTokenJsonExtractor extends OAuth2AccessTokenJsonExtractor { - private static final Pattern MESSAGE_REGEX_PATTERN = Pattern.compile("\"message\"\\s*:\\s*\"([^\"]*?)\""); - private static final Pattern TYPE_REGEX_PATTERN = Pattern.compile("\"type\"\\s*:\\s*\"([^\"]*?)\""); - private static final Pattern CODE_REGEX_PATTERN = Pattern.compile("\"code\"\\s*:\\s*\"?([^\",}]*?)[\",}]"); - private static final Pattern FBTRACE_ID_REGEX_PATTERN = Pattern.compile("\"fbtrace_id\"\\s*:\\s*\"([^\"]*?)\""); - protected FacebookAccessTokenJsonExtractor() { } @@ -33,15 +30,17 @@ public static FacebookAccessTokenJsonExtractor instance() { * * '{"error":{"message":"Error validating application. Invalid application * ID.","type":"OAuthException","code":101,"fbtrace_id":"CvDR+X4WWIx"}}' + * + * @param response response */ @Override - public void generateError(String response) { - extractParameter(response, MESSAGE_REGEX_PATTERN, false); + public void generateError(Response response) throws IOException { + final JsonNode errorNode = OAuth2AccessTokenJsonExtractor.OBJECT_MAPPER + .readTree(response.getBody()) + .get("error"); - throw new FacebookAccessTokenErrorResponse(extractParameter(response, MESSAGE_REGEX_PATTERN, false), - extractParameter(response, TYPE_REGEX_PATTERN, false), - extractParameter(response, CODE_REGEX_PATTERN, false), - extractParameter(response, FBTRACE_ID_REGEX_PATTERN, false), response); + throw new FacebookAccessTokenErrorResponse(errorNode.get("message").asText(), errorNode.get("type").asText(), + errorNode.get("code").asInt(), errorNode.get("fbtrace_id").asText(), response); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/FacebookService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookService.java similarity index 73% rename from scribejava-apis/src/main/java/com/github/scribejava/apis/service/FacebookService.java rename to scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookService.java index 51e282310..efb53a4f3 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/FacebookService.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/facebook/FacebookService.java @@ -1,10 +1,12 @@ -package com.github.scribejava.apis.service; +package com.github.scribejava.apis.facebook; -import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.apis.FacebookApi; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.oauth.OAuth20Service; + +import java.io.OutputStream; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Formatter; @@ -13,10 +15,11 @@ public class FacebookService extends OAuth20Service { - public FacebookService(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, + public FacebookService(FacebookApi api, String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); + super(api, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, + httpClient); } @Override diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractor.java index fad86fc53..24ed6025a 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractor.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractor.java @@ -1,15 +1,15 @@ package com.github.scribejava.apis.fitbit; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; - -import java.util.regex.Pattern; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.oauth2.OAuth2Error; +import java.io.IOException; public class FitBitJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { - private static final Pattern USER_ID_REGEX_PATTERN = Pattern.compile("\"user_id\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern ERROR_REGEX_PATTERN = Pattern.compile("\"errorType\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern ERROR_DESCRIPTION_REGEX_PATTERN = Pattern.compile("\"message\"\\s*:\\s*\"([^\"]*?)\""); protected FitBitJsonTokenExtractor() { } @@ -24,27 +24,32 @@ public static FitBitJsonTokenExtractor instance() { @Override protected FitBitOAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, - String refreshToken, String scope, String response) { + String refreshToken, String scope, JsonNode response, String rawResponse) { return new FitBitOAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, - extractParameter(response, USER_ID_REGEX_PATTERN, false), response); + response.get("user_id").asText(), rawResponse); } /** * Related documentation: https://dev.fitbit.com/build/reference/web-api/oauth2/ */ @Override - public void generateError(String response) { - final String errorInString = extractParameter(response, ERROR_REGEX_PATTERN, true); - final String errorDescription = extractParameter(response, ERROR_DESCRIPTION_REGEX_PATTERN, false); + public void generateError(Response response) throws IOException { + final JsonNode errorNode; + try { + errorNode = OAuth2AccessTokenJsonExtractor.OBJECT_MAPPER.readTree(response.getBody()).get("errors").get(0); + } catch (JsonProcessingException ex) { + throw new OAuth2AccessTokenErrorResponse(null, null, null, response); + } - OAuth2AccessTokenErrorResponse.ErrorCode errorCode; + OAuth2Error errorCode; try { - errorCode = OAuth2AccessTokenErrorResponse.ErrorCode.valueOf(errorInString); + errorCode = OAuth2Error + .parseFrom(extractRequiredParameter(errorNode, "errorType", response.getBody()).asText()); } catch (IllegalArgumentException iaE) { //non oauth standard error code errorCode = null; } - throw new OAuth2AccessTokenErrorResponse(errorCode, errorDescription, null, response); + throw new OAuth2AccessTokenErrorResponse(errorCode, errorNode.get("message").asText(), null, response); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/google/GoogleDeviceAuthorizationJsonExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/google/GoogleDeviceAuthorizationJsonExtractor.java new file mode 100644 index 000000000..d3dd77772 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/google/GoogleDeviceAuthorizationJsonExtractor.java @@ -0,0 +1,25 @@ +package com.github.scribejava.apis.google; + +import com.github.scribejava.core.extractors.DeviceAuthorizationJsonExtractor; + +public class GoogleDeviceAuthorizationJsonExtractor extends DeviceAuthorizationJsonExtractor { + + protected GoogleDeviceAuthorizationJsonExtractor() { + } + + private static class InstanceHolder { + + private static final GoogleDeviceAuthorizationJsonExtractor INSTANCE + = new GoogleDeviceAuthorizationJsonExtractor(); + } + + public static GoogleDeviceAuthorizationJsonExtractor instance() { + return GoogleDeviceAuthorizationJsonExtractor.InstanceHolder.INSTANCE; + } + + @Override + protected String getVerificationUriParamName() { + return "verification_url"; + } + +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/ImgurOAuthService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/imgur/ImgurOAuthService.java similarity index 55% rename from scribejava-apis/src/main/java/com/github/scribejava/apis/service/ImgurOAuthService.java rename to scribejava-apis/src/main/java/com/github/scribejava/apis/imgur/ImgurOAuthService.java index e1b146846..317934e35 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/ImgurOAuthService.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/imgur/ImgurOAuthService.java @@ -1,4 +1,6 @@ -package com.github.scribejava.apis.service; +package com.github.scribejava.apis.imgur; + +import java.io.OutputStream; import com.github.scribejava.apis.ImgurApi; import com.github.scribejava.core.builder.api.DefaultApi20; @@ -6,23 +8,27 @@ import com.github.scribejava.core.httpclient.HttpClientConfig; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.oauth.AccessTokenRequestParams; import com.github.scribejava.core.oauth.OAuth20Service; +import com.github.scribejava.core.pkce.PKCE; public class ImgurOAuthService extends OAuth20Service { - public ImgurOAuthService(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, + public ImgurOAuthService(ImgurApi api, String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); + super(api, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, + httpClient); } @Override - protected OAuthRequest createAccessTokenRequest(String oauthVerifier) { + protected OAuthRequest createAccessTokenRequest(AccessTokenRequestParams params) { final DefaultApi20 api = getApi(); final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addBodyParameter(OAuthConstants.CLIENT_ID, getApiKey()); request.addBodyParameter(OAuthConstants.CLIENT_SECRET, getApiSecret()); + final String oauthVerifier = params.getCode(); if (ImgurApi.isOob(getCallback())) { request.addBodyParameter(OAuthConstants.GRANT_TYPE, "pin"); request.addBodyParameter("pin", oauthVerifier); @@ -30,11 +36,18 @@ protected OAuthRequest createAccessTokenRequest(String oauthVerifier) { request.addBodyParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE); request.addBodyParameter(OAuthConstants.CODE, oauthVerifier); } + + final String pkceCodeVerifier = params.getPkceCodeVerifier(); + if (pkceCodeVerifier != null) { + request.addParameter(PKCE.PKCE_CODE_VERIFIER_PARAM, pkceCodeVerifier); + } + return request; } @Override public void signRequest(String accessToken, OAuthRequest request) { - request.addHeader("Authorization", accessToken == null ? "Client-ID " + getApiKey() : "Bearer " + accessToken); + request.addHeader(OAuthConstants.HEADER, + accessToken == null ? "Client-ID " + getApiKey() : "Bearer " + accessToken); } } 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/service/MailruOAuthService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/mailru/MailruOAuthService.java similarity index 84% rename from scribejava-apis/src/main/java/com/github/scribejava/apis/service/MailruOAuthService.java rename to scribejava-apis/src/main/java/com/github/scribejava/apis/mailru/MailruOAuthService.java index f40727f53..a9ff7d77b 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/MailruOAuthService.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/mailru/MailruOAuthService.java @@ -1,13 +1,15 @@ -package com.github.scribejava.apis.service; +package com.github.scribejava.apis.mailru; +import com.github.scribejava.apis.MailruApi; import java.net.URLDecoder; import java.util.Map; import java.util.TreeMap; -import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.oauth.OAuth20Service; + +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.security.MessageDigest; @@ -16,13 +18,13 @@ public class MailruOAuthService extends OAuth20Service { - public MailruOAuthService(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, + public MailruOAuthService(MailruApi api, String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); + super(api, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, + httpClient); } - @Override public void signRequest(String accessToken, OAuthRequest request) { // sig = md5(params + secret_key) diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/BaseMicrosoftAzureActiveDirectoryApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/BaseMicrosoftAzureActiveDirectoryApi.java new file mode 100644 index 000000000..5e4891164 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/BaseMicrosoftAzureActiveDirectoryApi.java @@ -0,0 +1,41 @@ +package com.github.scribejava.apis.microsoftazureactivedirectory; + +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; +import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; + +public abstract class BaseMicrosoftAzureActiveDirectoryApi extends DefaultApi20 { + + protected static final String COMMON_TENANT = "common"; + + private static final String MSFT_LOGIN_URL = "https://login.microsoftonline.com/"; + private static final String OAUTH_2 = "/oauth2"; + private final String tenant; + + protected BaseMicrosoftAzureActiveDirectoryApi() { + this(COMMON_TENANT); + } + + protected BaseMicrosoftAzureActiveDirectoryApi(String tenant) { + this.tenant = tenant == null || tenant.isEmpty() ? COMMON_TENANT : tenant; + } + + @Override + public String getAccessTokenEndpoint() { + return MSFT_LOGIN_URL + tenant + OAUTH_2 + getEndpointVersionPath() + "/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return MSFT_LOGIN_URL + tenant + OAUTH_2 + getEndpointVersionPath() + "/authorize"; + } + + @Override + public ClientAuthentication getClientAuthentication() { + return RequestBodyAuthenticationScheme.instance(); + } + + protected String getEndpointVersionPath() { + return ""; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/BaseMicrosoftAzureActiveDirectoryBearerSignature.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/BaseMicrosoftAzureActiveDirectoryBearerSignature.java new file mode 100644 index 000000000..ab85674af --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/BaseMicrosoftAzureActiveDirectoryBearerSignature.java @@ -0,0 +1,20 @@ +package com.github.scribejava.apis.microsoftazureactivedirectory; + +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureAuthorizationRequestHeaderField; + +public abstract class BaseMicrosoftAzureActiveDirectoryBearerSignature + extends BearerSignatureAuthorizationRequestHeaderField { + + private final String acceptedFormat; + + protected BaseMicrosoftAzureActiveDirectoryBearerSignature(String acceptedFormat) { + this.acceptedFormat = acceptedFormat; + } + + @Override + public void signRequest(String accessToken, OAuthRequest request) { + super.signRequest(accessToken, request); + request.addHeader("Accept", acceptedFormat); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/MicrosoftAzureActiveDirectory20BearerSignature.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/MicrosoftAzureActiveDirectory20BearerSignature.java new file mode 100644 index 000000000..c554beeff --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/MicrosoftAzureActiveDirectory20BearerSignature.java @@ -0,0 +1,18 @@ +package com.github.scribejava.apis.microsoftazureactivedirectory; + +public class MicrosoftAzureActiveDirectory20BearerSignature extends BaseMicrosoftAzureActiveDirectoryBearerSignature { + + protected MicrosoftAzureActiveDirectory20BearerSignature() { + super("application/json"); + } + + private static class InstanceHolder { + + private static final MicrosoftAzureActiveDirectory20BearerSignature INSTANCE + = new MicrosoftAzureActiveDirectory20BearerSignature(); + } + + public static MicrosoftAzureActiveDirectory20BearerSignature instance() { + return InstanceHolder.INSTANCE; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/MicrosoftAzureActiveDirectoryBearerSignature.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/MicrosoftAzureActiveDirectoryBearerSignature.java new file mode 100644 index 000000000..bfddd523a --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/microsoftazureactivedirectory/MicrosoftAzureActiveDirectoryBearerSignature.java @@ -0,0 +1,18 @@ +package com.github.scribejava.apis.microsoftazureactivedirectory; + +public class MicrosoftAzureActiveDirectoryBearerSignature extends BaseMicrosoftAzureActiveDirectoryBearerSignature { + + protected MicrosoftAzureActiveDirectoryBearerSignature() { + super("application/json; odata=minimalmetadata; streaming=true; charset=utf-8"); + } + + private static class InstanceHolder { + + private static final MicrosoftAzureActiveDirectoryBearerSignature INSTANCE + = new MicrosoftAzureActiveDirectoryBearerSignature(); + } + + public static MicrosoftAzureActiveDirectoryBearerSignature instance() { + return InstanceHolder.INSTANCE; + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/OdnoklassnikiOAuthService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/odnoklassniki/OdnoklassnikiOAuthService.java similarity index 81% rename from scribejava-apis/src/main/java/com/github/scribejava/apis/service/OdnoklassnikiOAuthService.java rename to scribejava-apis/src/main/java/com/github/scribejava/apis/odnoklassniki/OdnoklassnikiOAuthService.java index 34bd0fe89..fd1327a6d 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/OdnoklassnikiOAuthService.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/odnoklassniki/OdnoklassnikiOAuthService.java @@ -1,12 +1,14 @@ -package com.github.scribejava.apis.service; +package com.github.scribejava.apis.odnoklassniki; -import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.apis.OdnoklassnikiApi; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Parameter; import com.github.scribejava.core.model.ParameterList; import com.github.scribejava.core.oauth.OAuth20Service; + +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -19,10 +21,11 @@ public class OdnoklassnikiOAuthService extends OAuth20Service { - public OdnoklassnikiOAuthService(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, - HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); + public OdnoklassnikiOAuthService(OdnoklassnikiApi 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); } @Override diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/openid/OpenIdJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/openid/OpenIdJsonTokenExtractor.java index bec8b0613..1fc441a70 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/openid/OpenIdJsonTokenExtractor.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/openid/OpenIdJsonTokenExtractor.java @@ -1,15 +1,13 @@ package com.github.scribejava.apis.openid; +import com.fasterxml.jackson.databind.JsonNode; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; -import java.util.regex.Pattern; /** * additionally parses OpenID id_token */ public class OpenIdJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { - private static final Pattern ID_TOKEN_REGEX_PATTERN = Pattern.compile("\"id_token\"\\s*:\\s*\"(\\S*?)\""); - protected OpenIdJsonTokenExtractor() { } @@ -24,8 +22,9 @@ public static OpenIdJsonTokenExtractor instance() { @Override protected OpenIdOAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, - String refreshToken, String scope, String response) { + String refreshToken, String scope, JsonNode response, String rawResponse) { + final JsonNode idToken = response.get("id_token"); return new OpenIdOAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, - extractParameter(response, ID_TOKEN_REGEX_PATTERN, false), response); + idToken == null ? null : idToken.asText(), rawResponse); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarJsonTokenExtractor.java new file mode 100644 index 000000000..1258dfe59 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarJsonTokenExtractor.java @@ -0,0 +1,55 @@ +package com.github.scribejava.apis.polar; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; +import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.oauth2.OAuth2Error; +import java.io.IOException; + +/** + * Token related documentation: https://www.polar.com/accesslink-api/#token-endpoint + */ +public class PolarJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { + + protected PolarJsonTokenExtractor() { + } + + private static class InstanceHolder { + + private static final PolarJsonTokenExtractor INSTANCE = new PolarJsonTokenExtractor(); + } + + public static PolarJsonTokenExtractor instance() { + return InstanceHolder.INSTANCE; + } + + @Override + protected PolarOAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, + String refreshToken, String scope, JsonNode response, String rawResponse) { + return new PolarOAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, + response.get("x_user_id").asText(), rawResponse); + } + + @Override + public void generateError(Response response) throws IOException { + final JsonNode errorNode; + try { + errorNode = OAuth2AccessTokenJsonExtractor.OBJECT_MAPPER.readTree(response.getBody()).get("errors").get(0); + } catch (JsonProcessingException ex) { + throw new OAuth2AccessTokenErrorResponse(null, null, null, response); + } + + OAuth2Error errorCode; + try { + errorCode = OAuth2Error + .parseFrom(extractRequiredParameter(errorNode, "errorType", response.getBody()).asText()); + } catch (IllegalArgumentException iaE) { + //non oauth standard error code + errorCode = null; + } + + throw new OAuth2AccessTokenErrorResponse(errorCode, errorNode.get("message").asText(), null, response); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuth2AccessToken.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuth2AccessToken.java new file mode 100644 index 000000000..99710728f --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuth2AccessToken.java @@ -0,0 +1,47 @@ +package com.github.scribejava.apis.polar; + +import com.github.scribejava.core.model.OAuth2AccessToken; + +import java.util.Objects; + +public class PolarOAuth2AccessToken extends OAuth2AccessToken { + + private static final long serialVersionUID = 1L; + + private final String userId; + + public PolarOAuth2AccessToken(String accessToken, String tokenType, Integer expiresIn, String refreshToken, + String scope, String userId, String rawResponse) { + super(accessToken, tokenType, expiresIn, refreshToken, scope, rawResponse); + this.userId = userId; + } + + public String getUserId() { + return userId; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 37 * hash + Objects.hashCode(userId); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + if (!super.equals(obj)) { + return false; + } + + return Objects.equals(userId, ((PolarOAuth2AccessToken) obj).getUserId()); + } +} 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 new file mode 100644 index 000000000..c016d6ac7 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/polar/PolarOAuthService.java @@ -0,0 +1,47 @@ +package com.github.scribejava.apis.polar; + +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; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.oauth.AccessTokenRequestParams; +import com.github.scribejava.core.oauth.OAuth20Service; +import com.github.scribejava.core.pkce.PKCE; + +import java.io.OutputStream; + +public class PolarOAuthService extends OAuth20Service { + + 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, + httpClient); + } + + @Override + protected OAuthRequest createAccessTokenRequest(AccessTokenRequestParams params) { + final OAuthRequest request = new OAuthRequest(getApi().getAccessTokenVerb(), getApi().getAccessTokenEndpoint()); + + getApi().getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + + request.addParameter(OAuthConstants.CODE, params.getCode()); + final String callback = getCallback(); + if (callback != null) { + request.addParameter(OAuthConstants.REDIRECT_URI, callback); + } + request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE); + + final String pkceCodeVerifier = params.getPkceCodeVerifier(); + if (pkceCodeVerifier != null) { + request.addParameter(PKCE.PKCE_CODE_VERIFIER_PARAM, pkceCodeVerifier); + } + if (isDebug()) { + log("created 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/salesforce/SalesforceJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/salesforce/SalesforceJsonTokenExtractor.java index 841276724..62a3294cf 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/salesforce/SalesforceJsonTokenExtractor.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/salesforce/SalesforceJsonTokenExtractor.java @@ -1,7 +1,7 @@ package com.github.scribejava.apis.salesforce; +import com.fasterxml.jackson.databind.JsonNode; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; -import java.util.regex.Pattern; /** * This extractor parses in addition to the standard Extractor the instance_url @@ -9,8 +9,6 @@ */ public class SalesforceJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { - private static final Pattern INSTANCE_URL_REGEX_PATTERN = Pattern.compile("\"instance_url\"\\s*:\\s*\"(\\S*?)\""); - protected SalesforceJsonTokenExtractor() { } @@ -25,8 +23,8 @@ public static SalesforceJsonTokenExtractor instance() { @Override protected SalesforceToken createToken(String accessToken, String tokenType, Integer expiresIn, - String refreshToken, String scope, String response) { + String refreshToken, String scope, JsonNode response, String rawResponse) { return new SalesforceToken(accessToken, tokenType, expiresIn, refreshToken, scope, - extractParameter(response, INSTANCE_URL_REGEX_PATTERN, true), response); + extractRequiredParameter(response, "instance_url", rawResponse).asText(), rawResponse); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/MicrosoftAzureActiveDirectoryService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/service/MicrosoftAzureActiveDirectoryService.java deleted file mode 100644 index bab20d3b7..000000000 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/MicrosoftAzureActiveDirectoryService.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.github.scribejava.apis.service; - -import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.HttpClientConfig; -import com.github.scribejava.core.model.OAuthRequest; -import com.github.scribejava.core.oauth.OAuth20Service; - -public class MicrosoftAzureActiveDirectoryService extends OAuth20Service { - - private static final String ACCEPTED_FORMAT - = "application/json; odata=minimalmetadata; streaming=true; charset=utf-8"; - - public MicrosoftAzureActiveDirectoryService(DefaultApi20 api, String apiKey, String apiSecret, String callback, - String scope, String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, - HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); - } - - @Override - public void signRequest(String accessToken, OAuthRequest request) { - super.signRequest(accessToken, request); - request.addHeader("Accept", ACCEPTED_FORMAT); - } -} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/TutByOAuthService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/service/TutByOAuthService.java deleted file mode 100644 index 82ded6c92..000000000 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/service/TutByOAuthService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.github.scribejava.apis.service; - -import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.HttpClientConfig; -import com.github.scribejava.core.model.OAuthConstants; -import com.github.scribejava.core.model.OAuthRequest; -import com.github.scribejava.core.oauth.OAuth20Service; - -public class TutByOAuthService extends OAuth20Service { - - public TutByOAuthService(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, - HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); - } - - @Override - public void signRequest(String accessToken, OAuthRequest request) { - request.addQuerystringParameter(OAuthConstants.TOKEN, accessToken); - } -} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/slack/SlackJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/slack/SlackJsonTokenExtractor.java new file mode 100644 index 000000000..ca0be7587 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/slack/SlackJsonTokenExtractor.java @@ -0,0 +1,34 @@ +package com.github.scribejava.apis.slack; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; + +public class SlackJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { + + protected SlackJsonTokenExtractor() { + } + + private static class InstanceHolder { + + private static final SlackJsonTokenExtractor INSTANCE = new SlackJsonTokenExtractor(); + } + + public static SlackJsonTokenExtractor instance() { + return SlackJsonTokenExtractor.InstanceHolder.INSTANCE; + } + + @Override + protected SlackOAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, + String refreshToken, String scope, JsonNode response, String rawResponse) { + final String userAccessToken; + final JsonNode userAccessTokenNode = response.get("authed_user").get("access_token"); + if (userAccessTokenNode == null) { + userAccessToken = ""; + } else { + userAccessToken = userAccessTokenNode.asText(); + } + + return new SlackOAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, userAccessToken, + rawResponse); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/slack/SlackOAuth2AccessToken.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/slack/SlackOAuth2AccessToken.java new file mode 100644 index 000000000..d1d28ad7b --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/slack/SlackOAuth2AccessToken.java @@ -0,0 +1,47 @@ +package com.github.scribejava.apis.slack; + +import com.github.scribejava.core.model.OAuth2AccessToken; + +import java.util.Objects; + +public class SlackOAuth2AccessToken extends OAuth2AccessToken { + + private static final long serialVersionUID = 1L; + + private final String userAccessToken; + + public SlackOAuth2AccessToken(String accessToken, String tokenType, Integer expiresIn, String refreshToken, + String scope, String userAccessToken, String rawResponse) { + super(accessToken, tokenType, expiresIn, refreshToken, scope, rawResponse); + this.userAccessToken = userAccessToken; + } + + public String getUserAccessToken() { + return userAccessToken; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 37 * hash + Objects.hashCode(userAccessToken); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + if (!super.equals(obj)) { + return false; + } + + return Objects.equals(userAccessToken, ((SlackOAuth2AccessToken) obj).getUserAccessToken()); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/tutby/TutByBearerSignature.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/tutby/TutByBearerSignature.java new file mode 100644 index 000000000..0c7609073 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/tutby/TutByBearerSignature.java @@ -0,0 +1,25 @@ +package com.github.scribejava.apis.tutby; + +import com.github.scribejava.core.model.OAuthConstants; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; + +public class TutByBearerSignature implements BearerSignature { + + protected TutByBearerSignature() { + } + + private static class InstanceHolder { + + private static final TutByBearerSignature INSTANCE = new TutByBearerSignature(); + } + + public static TutByBearerSignature instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public void signRequest(String accessToken, OAuthRequest request) { + request.addQuerystringParameter(OAuthConstants.TOKEN, accessToken); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/vk/VKJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/vk/VKJsonTokenExtractor.java index 4e658b061..a3d14aacf 100644 --- a/scribejava-apis/src/main/java/com/github/scribejava/apis/vk/VKJsonTokenExtractor.java +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/vk/VKJsonTokenExtractor.java @@ -1,15 +1,13 @@ package com.github.scribejava.apis.vk; +import com.fasterxml.jackson.databind.JsonNode; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; -import java.util.regex.Pattern; /** * additionally parses email */ public class VKJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { - private static final Pattern EMAIL_REGEX_PATTERN = Pattern.compile("\"email\"\\s*:\\s*\"(\\S*?)\""); - protected VKJsonTokenExtractor() { } @@ -24,8 +22,9 @@ public static VKJsonTokenExtractor instance() { @Override protected VKOAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, - String refreshToken, String scope, String response) { + String refreshToken, String scope, JsonNode response, String rawResponse) { + final JsonNode email = response.get("email"); return new VKOAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, - extractParameter(response, EMAIL_REGEX_PATTERN, false), response); + email == null ? null : email.asText(), rawResponse); } } diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/wunderlist/WunderlistOAuthService.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/wunderlist/WunderlistOAuthService.java new file mode 100644 index 000000000..06a248d9c --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/wunderlist/WunderlistOAuthService.java @@ -0,0 +1,25 @@ +package com.github.scribejava.apis.wunderlist; + +import java.io.OutputStream; + +import com.github.scribejava.apis.WunderlistAPI; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.oauth.OAuth20Service; + +public class WunderlistOAuthService extends OAuth20Service { + + public WunderlistOAuthService(WunderlistAPI 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); + } + + @Override + public void signRequest(String accessToken, OAuthRequest request) { + super.signRequest(accessToken, request); + request.addHeader("X-Client-ID", getApiKey()); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/ExampleUtils.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/ExampleUtils.java new file mode 100644 index 000000000..5f60abcb1 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/ExampleUtils.java @@ -0,0 +1,55 @@ +package com.github.scribejava.apis; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public class ExampleUtils { + + private ExampleUtils() { + } + + public static void turnOfSSl() { + try { + final TrustManager[] trustAllCerts = new TrustManager[]{new TrustAllCertsManager() + }; + + final SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + + final HostnameVerifier allHostsValid = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new RuntimeException(e); + } + } + + private static class TrustAllCertsManager implements X509TrustManager { + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AWeberExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AWeberExample.java index 6a35e469b..e61110716 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AWeberExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AWeberExample.java @@ -23,6 +23,7 @@ public class AWeberExample { private AWeberExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder(CONSUMER_KEY) .apiSecret(CONSUMER_SECRET) @@ -46,7 +47,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -57,10 +58,11 @@ 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, ACCOUNT_RESOURCE_URL); service.signRequest(accessToken, request); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with AWeber and ScribeJava! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AsanaExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AsanaExample.java new file mode 100644 index 000000000..1ab4d3d3c --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AsanaExample.java @@ -0,0 +1,82 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.Asana20Api; +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; + +import java.io.IOException; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class AsanaExample { + + private static final String PROTECTED_RESOURCE_URL = "https://app.asana.com/api/1.0/users/me"; + + private AsanaExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + final String apiKey = "your client id"; + final String apiSecret = "your client secret"; + final String secretState = "secret" + new Random().nextInt(999_999); + final OAuth20Service service = new ServiceBuilder(apiKey) + .apiSecret(apiSecret) + .callback("https://localhost/") + .build(Asana20Api.instance()); + final Scanner in = new Scanner(System.in); + + // Obtain Auth URL + System.out.println("Fetching the Authorication URL..."); + System.out.println("Got the Authorization URL!"); + final String authorizationUrl = service.getAuthorizationUrl(secretState); + 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("Trading the Authorization Code for an Access Token..."); + 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(); + + 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("Refreshing the Access Token..."); + accessToken = service.refreshAccessToken(accessToken.getRefreshToken()); + System.out.println("Refreshed the Access Token!"); + System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); + System.out.println(); + + 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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AutomaticExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AutomaticExample.java index 665a5552f..ae0c299f2 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AutomaticExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/AutomaticExample.java @@ -21,6 +21,7 @@ public class AutomaticExample { private AutomaticExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -28,9 +29,8 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") - .scope("scope:user:profile").debug() + .defaultScope("scope:user:profile") .build(AutomaticAPI.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -39,7 +39,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -71,12 +71,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Box20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Box20Example.java index 7f82c9222..11673af20 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Box20Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Box20Example.java @@ -22,6 +22,7 @@ public class Box20Example { private Box20Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { //Replace these with your client id and secret final String clientId = "your client id"; @@ -29,7 +30,6 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "security_token" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("https://example.com/callback") .build(BoxApi20.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -42,9 +42,12 @@ public static void main(String... args) throws IOException, InterruptedException //pass access_type=offline to get refresh token final Map additionalParams = new HashMap<>(); additionalParams.put("access_type", "offline"); - //force to reget refresh token (if usera are asked not the first time) + //force to reget refresh token (if user are asked not the first time) additionalParams.put("prompt", "consent"); - final String authorizationUrl = service.getAuthorizationUrl(additionalParams); + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .state(secretState) + .additionalParams(additionalParams) + .build(); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); System.out.println(authorizationUrl); @@ -65,8 +68,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -77,12 +79,12 @@ 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); - final 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()); - + 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("Thats it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DataportenExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DataportenExample.java index fc0f4d3e2..fe8fada2a 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DataportenExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DataportenExample.java @@ -20,6 +20,7 @@ public class DataportenExample { private DataportenExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -27,7 +28,6 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") .build(DataportenApi.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -37,7 +37,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -58,8 +58,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -69,12 +68,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiggExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiggExample.java index a1f11b196..eb2820683 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiggExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiggExample.java @@ -20,6 +20,7 @@ public class DiggExample { private DiggExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "myKey"; @@ -49,7 +50,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -61,12 +62,12 @@ public static void main(String... args) throws IOException, InterruptedException final OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); request.addBodyParameter("comment_id", "20100729223726:4fef610331ee46a3b5cbd740bf71313e"); service.signRequest(accessToken, request); - final 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()); - + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiscordExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiscordExample.java new file mode 100644 index 000000000..f42bde9ec --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DiscordExample.java @@ -0,0 +1,90 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.DiscordApi; +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; + +import java.io.IOException; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class DiscordExample { + + private static final String NETWORK_NAME = "Discord"; + private static final String PROTECTED_RESOURCE_URL = "https://discordapp.com/api/users/@me"; + + private DiscordExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, ExecutionException, InterruptedException { + // 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("identify") // replace with desired scope + .callback("http://example.com/callback") + .userAgent("ScribeJava") + .build(DiscordApi.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..."); + OAuth2AccessToken accessToken = service.getAccessToken(code); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + + ", 'rawResponse'='" + accessToken.getRawResponse() + "')"); + + System.out.println("Refreshing the Access Token..."); + accessToken = service.refreshAccessToken(accessToken.getRefreshToken()); + System.out.println("Refreshed the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + + ", 'rawResponse'='" + 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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DropboxExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DropboxExample.java new file mode 100644 index 000000000..bcf02624a --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DropboxExample.java @@ -0,0 +1,74 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.DropboxApi; +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; + +import java.io.IOException; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class DropboxExample { + + private static final String NETWORK_NAME = "Dropbox.com"; + private static final String PROTECTED_RESOURCE_URL = "https://api.dropboxapi.com/2/users/get_space_usage"; + private static final String PAYLOAD = "null"; + private static final String CONTENT_TYPE_NAME = "Content-Type"; + private static final String CONTENT_TYPE_VALUE = "application/json"; + + private DropboxExample() { + } + + @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 OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .callback("https://www.example.com/oauth_callback/") + .build(DropboxApi.instance()); + + final Scanner in = new Scanner(System.in); + + 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(); + 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("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(); + + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); + request.addHeader(CONTENT_TYPE_NAME, CONTENT_TYPE_VALUE); + request.setPayload(PAYLOAD); + 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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/EtsyExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/EtsyExample.java index d26adb59a..ad55cb07c 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/EtsyExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/EtsyExample.java @@ -20,6 +20,7 @@ public class EtsyExample { private EtsyExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String[] args) throws InterruptedException, ExecutionException, IOException { // Replace with your api and secret key final OAuth10aService service = new ServiceBuilder("your api key") @@ -54,11 +55,11 @@ public static void main(String[] args) throws InterruptedException, ExecutionExc 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("That's it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookExample.java index 7a0ba726a..db8f6bdea 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookExample.java @@ -15,11 +15,12 @@ public class FacebookExample { private static final String NETWORK_NAME = "Facebook"; - private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/v2.11/me"; + private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/v3.2/me"; private FacebookExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -27,7 +28,6 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") .build(FacebookApi.instance()); @@ -38,7 +38,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -59,8 +59,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -70,12 +69,12 @@ 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); - final 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()); - + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FitbitApi20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FitbitApi20Example.java index 9c17e9054..e5818a92a 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FitbitApi20Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FitbitApi20Example.java @@ -20,6 +20,7 @@ public class FitbitApi20Example { private FitbitApi20Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws Exception { // Replace these with your client id and secret fron your app @@ -27,10 +28,9 @@ public static void main(String... args) throws Exception { final String clientSecret = "your client secret"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("activity profile") // replace with desired scope + .defaultScope("activity profile") // replace with desired scope //your callback URL to store and handle the authorization code sent by Fitbit .callback("http://www.example.com/oauth_callback/") - .state("some_params") .build(FitbitApi20.instance()); final Scanner in = new Scanner(System.in); @@ -39,7 +39,7 @@ public static void main(String... args) throws Exception { // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + final String authorizationUrl = service.getAuthorizationUrl("some_params"); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); System.out.println(authorizationUrl); @@ -48,8 +48,7 @@ public static void main(String... args) throws Exception { final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + System.out.println("Trading the Authorization Code for an Access Token..."); final OAuth2AccessToken oauth2AccessToken = service.getAccessToken(code); System.out.println("Got the Access Token!"); System.out.println("(if your curious it looks like this: " + oauth2AccessToken @@ -72,11 +71,11 @@ public static void main(String... args) throws Exception { service.signRequest(accessToken, request); - final Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } System.out.println(); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FlickrExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FlickrExample.java index 66ddf3fd2..8cdf8a209 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FlickrExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FlickrExample.java @@ -20,6 +20,7 @@ public class FlickrExample { private FlickrExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your_app_id"; @@ -47,7 +48,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -59,11 +60,11 @@ public static void main(String... args) throws IOException, InterruptedException final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); request.addQuerystringParameter("method", "flickr.test.login"); service.signRequest(accessToken, request); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Foursquare2Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Foursquare2Example.java index aae4fe7f8..cdd29180a 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Foursquare2Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Foursquare2Example.java @@ -19,6 +19,7 @@ public class Foursquare2Example { private Foursquare2Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your client id"; @@ -43,8 +44,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -54,12 +54,12 @@ 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 + accessToken.getAccessToken()); service.signRequest(accessToken, request); - final 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()); - + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FoursquareExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FoursquareExample.java index d9ec56652..6aa3c9435 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FoursquareExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FoursquareExample.java @@ -19,6 +19,7 @@ public class FoursquareExample { private FoursquareExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") @@ -41,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -52,11 +53,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FrappeExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FrappeExample.java index ce9012b1c..827f8aacd 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FrappeExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FrappeExample.java @@ -19,6 +19,7 @@ public class FrappeExample { private FrappeExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { //Replace these with your client id and secret final String clientId = "clientId"; @@ -26,7 +27,7 @@ public static void main(String... args) throws IOException, InterruptedException final String clientDomain = "https://example.com"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("openid all") + .defaultScope("openid all") .callback("https://example.com/callback") .build(FrappeApi.instance(clientDomain)); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -56,12 +57,12 @@ 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, clientDomain + PROTECTED_RESOURCE_PATH); service.signRequest(accessToken, request); - final 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()); - + 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("Thats it man! Go and build something awesome with ScribeJava! :)"); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FreelancerExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FreelancerExample.java index 80640d989..023d789c4 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FreelancerExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FreelancerExample.java @@ -23,10 +23,11 @@ public class FreelancerExample { private FreelancerExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") - .scope(SCOPE) + .withScope(SCOPE) .build(FreelancerApi.Sandbox.instance()); final Scanner in = new Scanner(System.in); @@ -47,7 +48,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -59,12 +60,12 @@ public static void main(String... args) throws IOException, InterruptedException final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); request.addHeader("GData-Version", "3.0"); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GeniusExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GeniusExample.java index 8f269657e..9749a168e 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GeniusExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GeniusExample.java @@ -20,6 +20,7 @@ public class GeniusExample { private GeniusExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -27,8 +28,7 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "100"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("me") - .state(secretState) + .defaultScope("me") .callback("com.scribejavatest://callback") .userAgent("ScribeJava") .build(GeniusApi.instance()); @@ -38,7 +38,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -77,12 +77,12 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println("Accessing a protected resource..."); final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - final Response response = service.execute(request); - System.out.println("Got it! Viewing contents..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Viewing contents..."); + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubAsyncOkHttpExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubAsyncOkHttpExample.java index bc05042bf..a0c94792c 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubAsyncOkHttpExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubAsyncOkHttpExample.java @@ -22,6 +22,7 @@ public class GitHubAsyncOkHttpExample { private GitHubAsyncOkHttpExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, ExecutionException, InterruptedException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -29,7 +30,6 @@ public static void main(String... args) throws IOException, ExecutionException, final String secretState = "secret" + new Random().nextInt(999_999); try (OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") .httpClientConfig(OkHttpHttpClientConfig.defaultConfig()) .build(GitHubApi.instance())) { @@ -40,7 +40,7 @@ public static void main(String... args) throws IOException, ExecutionException, // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -62,8 +62,7 @@ public static void main(String... args) throws IOException, ExecutionException, System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() @@ -74,12 +73,12 @@ public static void main(String... args) throws IOException, ExecutionException, 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubExample.java index 6d60957a3..bfd3f2512 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/GitHubExample.java @@ -20,6 +20,7 @@ public class GitHubExample { private GitHubExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -27,7 +28,6 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") .build(GitHubApi.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -37,7 +37,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -58,8 +58,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -69,12 +68,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20ArmeriaExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20ArmeriaExample.java new file mode 100644 index 000000000..04fddb1da --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20ArmeriaExample.java @@ -0,0 +1,118 @@ +package com.github.scribejava.apis.examples; + +import java.util.Random; +import java.util.Scanner; +import com.github.scribejava.apis.GoogleApi20; +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; +import com.github.scribejava.httpclient.armeria.ArmeriaHttpClientConfig; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +public class Google20ArmeriaExample { + + private static final String NETWORK_NAME = "Google Armeria"; + private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/oauth2/v3/userinfo"; + + private Google20ArmeriaExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws InterruptedException, ExecutionException, IOException { + // Replace these with your client id and secret + final String clientId = "your client id"; + final String clientSecret = "your client secret"; + final String secretState = "secret" + new Random().nextInt(999_999); + + try (OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .defaultScope("profile") // replace with desired scope + .callback("http://example.com/callback") + .httpClientConfig(ArmeriaHttpClientConfig.defaultConfig()) + .build(GoogleApi20.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..."); + //pass access_type=offline to get refresh token + //https://developers.google.com/identity/protocols/OAuth2WebServer#preparing-to-start-the-oauth-20-flow + final Map additionalParams = new HashMap<>(); + additionalParams.put("access_type", "offline"); + //force to reget refresh token (if user are asked not the first time) + additionalParams.put("prompt", "consent"); + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .state(secretState) + .additionalParams(additionalParams) + .build(); + 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..."); + 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("Refreshing the Access Token..."); + accessToken = service.refreshAccessToken(accessToken.getRefreshToken()); + System.out.println("Refreshed 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..."); + while (true) { + System.out.println("Paste fieldnames to fetch (leave empty to get profile, 'exit' to stop example)"); + System.out.print(">>"); + final String query = in.nextLine(); + System.out.println(); + + final String requestUrl; + if ("exit".equals(query)) { + break; + } else if (query == null || query.isEmpty()) { + requestUrl = PROTECTED_RESOURCE_URL; + } else { + requestUrl = PROTECTED_RESOURCE_URL + "?fields=" + query; + } + + final OAuthRequest request = new OAuthRequest(Verb.GET, requestUrl); + service.signRequest(accessToken, request); + System.out.println(); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } + System.out.println(); + } + } + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20AsyncAHCExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20AsyncAHCExample.java index d815edce3..a894db2bf 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20AsyncAHCExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20AsyncAHCExample.java @@ -19,12 +19,13 @@ public class Google20AsyncAHCExample { - private static final String NETWORK_NAME = "G+ Async"; - private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/plus/v1/people/me"; + private static final String NETWORK_NAME = "Google Async"; + private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/oauth2/v3/userinfo"; private Google20AsyncAHCExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws InterruptedException, ExecutionException, IOException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -39,8 +40,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx try (OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("profile") // replace with desired scope - .state(secretState) + .defaultScope("profile") // replace with desired scope .callback("http://example.com/callback") .httpClientConfig(clientConfig) .build(GoogleApi20.instance())) { @@ -55,9 +55,12 @@ public static void main(String... args) throws InterruptedException, ExecutionEx //https://developers.google.com/identity/protocols/OAuth2WebServer#preparing-to-start-the-oauth-20-flow final Map additionalParams = new HashMap<>(); additionalParams.put("access_type", "offline"); - //force to reget refresh token (if usera are asked not the first time) + //force to reget refresh token (if user are asked not the first time) additionalParams.put("prompt", "consent"); - final String authorizationUrl = service.getAuthorizationUrl(additionalParams); + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .state(secretState) + .additionalParams(additionalParams) + .build(); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); System.out.println(authorizationUrl); @@ -79,8 +82,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + System.out.println("Trading the Authorization Code for an Access Token..."); OAuth2AccessToken accessToken = service.getAccessToken(code); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() @@ -112,11 +114,11 @@ public static void main(String... args) throws InterruptedException, ExecutionEx final OAuthRequest request = new OAuthRequest(Verb.GET, requestUrl); service.signRequest(accessToken, request); - final Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } System.out.println(); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20DeviceAuthorizationGrantExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20DeviceAuthorizationGrantExample.java new file mode 100644 index 000000000..fc361e13f --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20DeviceAuthorizationGrantExample.java @@ -0,0 +1,82 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.apis.GoogleApi20; +import com.github.scribejava.core.model.DeviceAuthorization; +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; +import java.io.IOException; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class Google20DeviceAuthorizationGrantExample { + + private static final String NETWORK_NAME = "Google"; + private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/oauth2/v3/userinfo"; + + private Google20DeviceAuthorizationGrantExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your client id and secret + final String clientId = "your client id"; + final String clientSecret = "your_client_secret"; + + final OAuth20Service service = new ServiceBuilder(clientId) + .debug() + .apiSecret(clientSecret) + .defaultScope("profile") // replace with desired scope + .build(GoogleApi20.instance()); + final Scanner in = new Scanner(System.in, "UTF-8"); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + System.out.println("Requesting a set of verification codes..."); + + final DeviceAuthorization deviceAuthorization = service.getDeviceAuthorizationCodes(); + System.out.println("Got the Device Authorization Codes!"); + System.out.println(deviceAuthorization); + + System.out.println("Now go and authorize ScribeJava. Visit: " + deviceAuthorization.getVerificationUri() + + " and enter the code: " + deviceAuthorization.getUserCode()); + if (deviceAuthorization.getVerificationUriComplete() != null) { + System.out.println("Or visit " + deviceAuthorization.getVerificationUriComplete()); + } + + System.out.println("Polling for an Access Token..."); + final OAuth2AccessToken accessToken = service.pollAccessTokenDeviceAuthorizationGrant(deviceAuthorization); + + System.out.println("Got the Access Token!"); + System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + while (true) { + System.out.println("Paste fieldnames to fetch (leave empty to get profile, 'exit' to stop the example)"); + System.out.print(">>"); + final String query = in.nextLine(); + System.out.println(); + final String requestUrl; + if ("exit".equals(query)) { + break; + } else if (query == null || query.isEmpty()) { + requestUrl = PROTECTED_RESOURCE_URL; + } else { + requestUrl = PROTECTED_RESOURCE_URL + "?fields=" + query; + } + final OAuthRequest request = new OAuthRequest(Verb.GET, requestUrl); + service.signRequest(accessToken, request); + System.out.println(); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } + System.out.println(); + } + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java index 0cce9f250..ca70409f4 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20Example.java @@ -16,21 +16,21 @@ public class Google20Example { - private static final String NETWORK_NAME = "G+"; - private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/plus/v1/people/me"; + private static final String NETWORK_NAME = "Google"; + private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/oauth2/v3/userinfo"; private Google20Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret - final String clientId = "your client id"; - final String clientSecret = "your client secret"; + final String clientId = "your_client_id"; + final String clientSecret = "your_client_secret"; final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("profile") // replace with desired scope - .state(secretState) + .defaultScope("profile") // replace with desired scope .callback("http://example.com/callback") .build(GoogleApi20.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -44,9 +44,12 @@ public static void main(String... args) throws IOException, InterruptedException //https://developers.google.com/identity/protocols/OAuth2WebServer#preparing-to-start-the-oauth-20-flow final Map additionalParams = new HashMap<>(); additionalParams.put("access_type", "offline"); - //force to reget refresh token (if usera are asked not the first time) + //force to reget refresh token (if user are asked not the first time) additionalParams.put("prompt", "consent"); - final String authorizationUrl = service.getAuthorizationUrl(additionalParams); + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .state(secretState) + .additionalParams(additionalParams) + .build(); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); System.out.println(authorizationUrl); @@ -67,8 +70,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + System.out.println("Trading the Authorization Code for an Access Token..."); OAuth2AccessToken accessToken = service.getAccessToken(code); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); @@ -98,11 +100,11 @@ public static void main(String... args) throws IOException, InterruptedException final OAuthRequest request = new OAuthRequest(Verb.GET, requestUrl); service.signRequest(accessToken, request); - final Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } System.out.println(); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20RevokeExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20RevokeExample.java index f65b07c39..ba513ca52 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20RevokeExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20RevokeExample.java @@ -16,12 +16,13 @@ public class Google20RevokeExample { - private static final String NETWORK_NAME = "G+"; - private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/plus/v1/people/me"; + private static final String NETWORK_NAME = "Google"; + private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/oauth2/v3/userinfo"; private Google20RevokeExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -29,8 +30,7 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("profile") // replace with desired scope - .state(secretState) + .defaultScope("profile") // replace with desired scope .callback("http://example.com/callback") .build(GoogleApi20.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -44,9 +44,12 @@ public static void main(String... args) throws IOException, InterruptedException //https://developers.google.com/identity/protocols/OAuth2WebServer#preparing-to-start-the-oauth-20-flow final Map additionalParams = new HashMap<>(); additionalParams.put("access_type", "offline"); - //force to reget refresh token (if usera are asked not the first time) + //force to reget refresh token (if user are asked not the first time) additionalParams.put("prompt", "consent"); - final String authorizationUrl = service.getAuthorizationUrl(additionalParams); + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .state(secretState) + .additionalParams(additionalParams) + .build(); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); System.out.println(authorizationUrl); @@ -67,8 +70,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -77,12 +79,12 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println("Now we're going to access a protected resource..."); OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } System.out.println(); - System.out.println("Revoking token..."); service.revokeToken(accessToken.getAccessToken()); System.out.println("done."); @@ -90,15 +92,18 @@ public static void main(String... args) throws IOException, InterruptedException in.nextLine(); //Google Note: Following a successful revocation response, //it might take some time before the revocation has full effect. - while (response.getCode() == 200) { + int responseCode; + do { Thread.sleep(1000); request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, request); - response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + responseCode = response.getCode(); + System.out.println(responseCode); + System.out.println(response.getBody()); + } System.out.println(); - } + } while (responseCode == 200); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20WithPKCEExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20WithPKCEExample.java index 54a359291..8c840b8d5 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20WithPKCEExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Google20WithPKCEExample.java @@ -4,12 +4,13 @@ import java.util.Scanner; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.apis.GoogleApi20; +import com.github.scribejava.core.oauth.AuthorizationUrlBuilder; 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.AccessTokenRequestParams; import com.github.scribejava.core.oauth.OAuth20Service; -import com.github.scribejava.core.pkce.AuthorizationUrlWithPKCE; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -17,12 +18,13 @@ public class Google20WithPKCEExample { - private static final String NETWORK_NAME = "G+"; - private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/plus/v1/people/me"; + private static final String NETWORK_NAME = "Google"; + private static final String PROTECTED_RESOURCE_URL = "https://www.googleapis.com/oauth2/v3/userinfo"; private Google20WithPKCEExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -30,8 +32,7 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("profile") // replace with desired scope - .state(secretState) + .defaultScope("profile") // replace with desired scope .callback("http://example.com/callback") .build(GoogleApi20.instance()); @@ -46,14 +47,17 @@ public static void main(String... args) throws IOException, InterruptedException //https://developers.google.com/identity/protocols/OAuth2WebServer#preparing-to-start-the-oauth-20-flow final Map additionalParams = new HashMap<>(); additionalParams.put("access_type", "offline"); - //force to reget refresh token (if usera are asked not the first time) + //force to reget refresh token (if user are asked not the first time) additionalParams.put("prompt", "consent"); - final AuthorizationUrlWithPKCE authUrlWithPKCE = service.getAuthorizationUrlWithPKCE(additionalParams); + final AuthorizationUrlBuilder authorizationUrlBuilder = service.createAuthorizationUrlBuilder() + .state(secretState) + .additionalParams(additionalParams) + .initPKCE(); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); - System.out.println(authUrlWithPKCE.getAuthorizationUrl()); + System.out.println(authorizationUrlBuilder.build()); System.out.println("And paste the authorization code here"); System.out.print(">>"); final String code = in.nextLine(); @@ -71,9 +75,9 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - OAuth2AccessToken accessToken = service.getAccessToken(code, authUrlWithPKCE.getPkce().getCodeVerifier()); + System.out.println("Trading the Authorization Code for an Access Token..."); + OAuth2AccessToken accessToken = service.getAccessToken(AccessTokenRequestParams.create(code) + .pkceCodeVerifier(authorizationUrlBuilder.getPkce().getCodeVerifier())); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); @@ -102,11 +106,11 @@ public static void main(String... args) throws IOException, InterruptedException final OAuthRequest request = new OAuthRequest(Verb.GET, requestUrl); service.signRequest(accessToken, request); - final Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } System.out.println(); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HHExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HHExample.java index 0c1d24b9b..c013b7d2b 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HHExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HHExample.java @@ -21,6 +21,7 @@ public class HHExample { private HHExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own client id and secret final String clientId = "your client id"; @@ -45,8 +46,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -55,12 +55,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HiOrgServerExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HiOrgServerExample.java new file mode 100644 index 000000000..2602d1257 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/HiOrgServerExample.java @@ -0,0 +1,92 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.HiOrgServerApi20; +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; +import java.io.IOException; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class HiOrgServerExample { + + private static final String NETWORK_NAME = "HiOrgServer"; + private static final String PROTECTED_RESOURCE_URL = "https://www.hiorg-server.de/api/oauth2/v1/user.php"; + private static final String CLIENT_ID = "your client id"; + private static final String CLIENT_SECRET = "your client secret"; + private static final String CALLBACK_URL = "http://www.example.com/oauth_callback/"; + + private HiOrgServerExample() { + } + + @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("basic eigenedaten") + .callback(CALLBACK_URL) + .build(HiOrgServerApi20.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..."); + 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(); + + System.out.println("Refreshing the Access Token..."); + accessToken = service.refreshAccessToken(accessToken.getRefreshToken()); + System.out.println("Refreshed 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! :)"); + } + +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ImgurExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ImgurExample.java index ddc67c107..229e3a7ee 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ImgurExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ImgurExample.java @@ -20,6 +20,7 @@ public class ImgurExample { private ImgurExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your client id"; @@ -54,12 +55,12 @@ 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); - final 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()); - + 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! :)"); } 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/Kaixin20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Kaixin20Example.java index dad494e49..482453cb4 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Kaixin20Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Kaixin20Example.java @@ -19,6 +19,7 @@ public class Kaixin20Example { private Kaixin20Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your api key"; @@ -54,12 +55,12 @@ 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); - final 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()); - + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KakaoExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KakaoExample.java new file mode 100644 index 000000000..643182ea8 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KakaoExample.java @@ -0,0 +1,70 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.KakaoApi; +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; + +import java.io.IOException; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class KakaoExample { + + private static final String NETWORK_NAME = "Kakao"; + private static final String PROTECTED_RESOURCE_URL = "https://kapi.kakao.com/v2/user/me"; + + private KakaoExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace this with your client id + final String clientId = "your client id"; + + final OAuth20Service service = new ServiceBuilder(clientId) + .callback("http://www.example.com/oauth_callback/") + .build(KakaoApi.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(); + 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("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! :)"); + + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KeycloakExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KeycloakExample.java new file mode 100644 index 000000000..2d78ffb97 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KeycloakExample.java @@ -0,0 +1,72 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.KeycloakApi; +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; + +import java.io.IOException; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class KeycloakExample { + + private KeycloakExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your own api key, secret, callback, base url and realm + final String apiKey = "your_api_key"; + final String apiSecret = "your_api_secret"; + final String callback = "your_callback"; + final String baseUrl = "your_base_url"; + final String realm = "your_realm"; + + final String protectedResourceUrl = baseUrl + "/auth/realms/" + realm + "/protocol/openid-connect/userinfo"; + + final OAuth20Service service = new ServiceBuilder(apiKey) + .apiSecret(apiSecret) + .defaultScope("openid") + .callback(callback) + .build(KeycloakApi.instance(baseUrl, realm)); + final Scanner in = new Scanner(System.in); + + System.out.println("=== Keyloack's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(); + 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("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, protectedResourceUrl); + 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! :)"); + + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedIn20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedIn20Example.java index d76acb856..05e6733df 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedIn20Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedIn20Example.java @@ -3,31 +3,35 @@ import java.util.Scanner; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.apis.LinkedInApi20; +import com.github.scribejava.core.builder.ScopeBuilder; 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; import java.io.IOException; +import java.util.Random; import java.util.concurrent.ExecutionException; public class LinkedIn20Example { private static final String NETWORK_NAME = "LinkedIn"; - private static final String PROTECTED_RESOURCE_URL = "https://api.linkedin.com/v1/people/~:(%s)"; + private static final String PROTECTED_RESOURCE_URL = "https://api.linkedin.com/v2/me"; + private static final String PROTECTED_EMAIL_RESOURCE_URL + = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"; private LinkedIn20Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; final String clientSecret = "your client secret"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("r_basicprofile r_emailaddress") // replace with desired scope + .defaultScope(new ScopeBuilder("r_liteprofile", "r_emailaddress")) // replace with desired scope .callback("http://example.com/callback") - .state("some_params") .build(LinkedInApi20.instance()); final Scanner in = new Scanner(System.in); @@ -36,7 +40,8 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + final String secretState = "secret" + new Random().nextInt(999_999); + 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); @@ -45,35 +50,36 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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..."); - while (true) { - System.out.println("Paste profile query for fetch (firstName, lastName, etc) or 'exit' to stop example"); - System.out.print(">>"); - final String query = in.nextLine(); - System.out.println(); + System.out.println("Now we're going to get the email of the current user..."); + final OAuthRequest emailRequest = new OAuthRequest(Verb.GET, PROTECTED_EMAIL_RESOURCE_URL); + emailRequest.addHeader("x-li-format", "json"); + emailRequest.addHeader("Accept-Language", "ru-RU"); + service.signRequest(accessToken, emailRequest); + System.out.println(); + try (Response emailResponse = service.execute(emailRequest)) { + System.out.println(emailResponse.getCode()); + System.out.println(emailResponse.getBody()); + } + System.out.println(); - if ("exit".equals(query)) { - break; - } + System.out.println("Now we're going to access a protected profile resource..."); - final OAuthRequest request = new OAuthRequest(Verb.GET, String.format(PROTECTED_RESOURCE_URL, query)); - request.addHeader("x-li-format", "json"); - request.addHeader("Accept-Language", "ru-RU"); - service.signRequest(accessToken, request); - final Response response = service.execute(request); - System.out.println(); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + request.addHeader("x-li-format", "json"); + request.addHeader("Accept-Language", "ru-RU"); + service.signRequest(accessToken, request); + System.out.println(); + try (Response response = service.execute(request)) { System.out.println(response.getCode()); System.out.println(response.getBody()); - - System.out.println(); } + + System.out.println(); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExample.java index 48f9fdcb5..ec1051134 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExample.java @@ -20,6 +20,7 @@ public class LinkedInExample { private LinkedInExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") @@ -42,7 +43,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -53,10 +54,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExampleWithScopes.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExampleWithScopes.java index f90f91ce0..3b795de1f 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExampleWithScopes.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExampleWithScopes.java @@ -20,6 +20,7 @@ public class LinkedInExampleWithScopes { private LinkedInExampleWithScopes() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -46,7 +47,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -57,10 +58,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LiveExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LiveExample.java index 119c5aca1..2c8635a1a 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LiveExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LiveExample.java @@ -18,13 +18,14 @@ public class LiveExample { private LiveExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = ""; final String apiSecret = ""; final OAuth20Service service = new ServiceBuilder(apiKey) .apiSecret(apiSecret) - .scope("wl.basic") + .defaultScope("wl.basic") .callback("http://localhost:9000/") .build(LiveApi.instance()); final Scanner in = new Scanner(System.in); @@ -43,8 +44,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -54,11 +54,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruAsyncExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruAsyncExample.java index 95673747d..1ad9f56cc 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruAsyncExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruAsyncExample.java @@ -22,6 +22,7 @@ public class MailruAsyncExample { private MailruAsyncExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws InterruptedException, ExecutionException, IOException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -56,8 +57,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() @@ -67,12 +67,13 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruExample.java index 372bedd1a..4eb4c7aff 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruExample.java @@ -20,6 +20,7 @@ public class MailruExample { private MailruExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -45,8 +46,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -55,11 +55,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MediaWikiExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MediaWikiExample.java index 6ec9e5b67..621480013 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MediaWikiExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MediaWikiExample.java @@ -24,6 +24,7 @@ public class MediaWikiExample { private MediaWikiExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder(CONSUMER_KEY) .apiSecret(CONSUMER_SECRET) @@ -47,7 +48,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -58,10 +59,11 @@ 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, API_USERINFO_URL); service.signRequest(accessToken, request); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with MediaWiki and ScribeJava! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Meetup20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Meetup20Example.java new file mode 100644 index 000000000..f64ec246b --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Meetup20Example.java @@ -0,0 +1,70 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.MeetupApi20; +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; + +import java.io.IOException; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class Meetup20Example { + + private static final String NETWORK_NAME = "Meetup"; + private static final String PROTECTED_RESOURCE_URL = " https://api.meetup.com/self/groups"; + + private Meetup20Example() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your Meetup consumer id and secret + final String consumerKey = "your consumer key"; + final String consumerSecret = "your consumer secret"; + final OAuth20Service service = new ServiceBuilder(consumerKey) + .apiSecret(consumerSecret) + .defaultScope("basic") // replace with desired scopes + .callback("http://example.com/callback") // replace with appropriate URI for your consumer, + // see https://www.meetup.com/meetup_api/auth/#redirect_uris + .build(MeetupApi20.instance()); + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String secretState = "secret" + new Random().nextInt(999_999); + 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("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(); + + System.out.println("Now we're going to the user's groups...."); + + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + System.out.println(); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } + + System.out.println(); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MeetupExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MeetupExample.java index ff97a734a..e3c7c8e8c 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MeetupExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MeetupExample.java @@ -19,6 +19,7 @@ public class MeetupExample { private MeetupExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") @@ -41,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -52,10 +53,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectory20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectory20Example.java new file mode 100644 index 000000000..71f346bc6 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectory20Example.java @@ -0,0 +1,63 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.MicrosoftAzureActiveDirectory20Api; +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; +import java.io.IOException; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class MicrosoftAzureActiveDirectory20Example { + + private static final String NETWORK_NAME = "Microsoft Azure Active Directory"; + private static final String PROTECTED_RESOURCE_URL = "https://graph.microsoft.com/v1.0/me"; + + private MicrosoftAzureActiveDirectory20Example() { + } + + @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 here"; + final String clientSecret = "client secret here"; + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .defaultScope("openid User.Read") + .callback("http://www.example.com/oauth_callback/") + .build(MicrosoftAzureActiveDirectory20Api.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(); + 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("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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectoryExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectoryExample.java index 51efc5cf8..6c9610f06 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectoryExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MicrosoftAzureActiveDirectoryExample.java @@ -21,13 +21,14 @@ private MicrosoftAzureActiveDirectoryExample() { } + @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 here"; final String clientSecret = "client secret here"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("openid") + .defaultScope("openid") .callback("http://www.example.com/oauth_callback/") .build(MicrosoftAzureActiveDirectoryApi.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -46,8 +47,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -57,11 +57,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MisfitExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MisfitExample.java index 60d5a903c..65e048499 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MisfitExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MisfitExample.java @@ -21,6 +21,7 @@ public class MisfitExample { private MisfitExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your client id"; @@ -28,7 +29,7 @@ public static void main(String... args) throws IOException, InterruptedException final OAuth20Service service = new ServiceBuilder(apiKey) .apiSecret(apiSecret) .callback("http://example.com/callback/") - .scope("public,birthday,email,tracking,session,sleep") + .defaultScope("public,birthday,email,tracking,session,sleep") .build(MisfitApi.instance()); final Scanner in = new Scanner(System.in); @@ -57,11 +58,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/NaverExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/NaverExample.java index bf359c547..7918ebd02 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/NaverExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/NaverExample.java @@ -21,6 +21,7 @@ public class NaverExample { private NaverExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -28,7 +29,6 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") .build(NaverApi.instance()); @@ -39,7 +39,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -60,8 +60,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -71,11 +70,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/OdnoklassnikiExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/OdnoklassnikiExample.java index 4ff6a4933..ff2c05863 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/OdnoklassnikiExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/OdnoklassnikiExample.java @@ -20,9 +20,10 @@ public class OdnoklassnikiExample { private OdnoklassnikiExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret - final String clientId = "your api client id"; + final String clientId = "your api client id"; final String publicKey = "your api public key"; final String secretKey = "your api secret key"; @@ -47,9 +48,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - + System.out.println("Trading the Authorization Code for an Access Token..."); OAuth2AccessToken accessToken = service.getAccessToken(code); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); @@ -65,11 +64,12 @@ 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, String.format(PROTECTED_RESOURCE_URL, publicKey)); service.signRequest(accessToken, request); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PinterestExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PinterestExample.java index 03b3a428a..73ad113d5 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PinterestExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PinterestExample.java @@ -19,13 +19,14 @@ public class PinterestExample { private PinterestExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your_app_id"; final String apiSecret = "your_app_secret"; final OAuth20Service service = new ServiceBuilder(apiKey) .apiSecret(apiSecret) - .scope("read_public,write_public,read_relationships,write_relationships") + .defaultScope("read_public,write_public,read_relationships,write_relationships") .callback("https://localhost/") // Add as valid callback in developer portal .build(PinterestApi.instance()); final Scanner in = new Scanner(System.in); @@ -44,8 +45,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -55,11 +55,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PolarAPIExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PolarAPIExample.java new file mode 100644 index 000000000..501a8e470 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/PolarAPIExample.java @@ -0,0 +1,82 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.PolarAPI; +import com.github.scribejava.apis.polar.PolarOAuth2AccessToken; +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; + +import java.util.Scanner; + +public class PolarAPIExample { + + private static final String NETWORK_NAME = "Polar"; + + private static final String PROTECTED_RESOURCE_URL = "https://www.polaraccesslink.com/v3/users/%s"; + + private PolarAPIExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws Exception { + final String clientId = "your_api_client"; + final String clientSecret = "your_api_secret"; + final String scope = "accesslink.read_all"; + final String callback = "your_api_callback"; + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .defaultScope(scope) + //your callback URL to store and handle the authorization code sent by Polar + .callback(callback) + .build(PolarAPI.instance()); + final Scanner in = new Scanner(System.in); + + 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("some_params"); + 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("Trading the Authorization Code for an Access Token..."); + System.out.println("Got the Access Token!"); + final OAuth2AccessToken oauth2AccessToken = service.getAccessToken(code); + System.out.println("(if your curious it looks like this: " + oauth2AccessToken + + ", 'rawResponse'='" + oauth2AccessToken.getRawResponse() + "')"); + System.out.println(); + + if (!(oauth2AccessToken instanceof PolarOAuth2AccessToken)) { + System.out.println("oauth2AccessToken is not instance of PolarOAuth2AccessToken. Strange enough. exit."); + return; + } + + final PolarOAuth2AccessToken accessToken = (PolarOAuth2AccessToken) oauth2AccessToken; + + // Now let's go and ask for a protected resource! + // This will get the profile for this user + System.out.println("Now we're going to access a protected resource..."); + + final OAuthRequest request = new OAuthRequest(Verb.GET, String.format(PROTECTED_RESOURCE_URL, + accessToken.getUserId())); + request.addHeader("Accept", "application/json"); + + service.signRequest(accessToken, request); + + System.out.println(); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } + System.out.println(); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Px500Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Px500Example.java index 962faaa3d..e441cebdd 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Px500Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Px500Example.java @@ -19,6 +19,7 @@ public class Px500Example { private Px500Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your-api-key") .apiSecret("your-api-secret") @@ -41,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -52,10 +53,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/RenrenExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/RenrenExample.java index 4d9b3bd76..701be48b4 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/RenrenExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/RenrenExample.java @@ -29,13 +29,14 @@ public class RenrenExample { private RenrenExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your api key"; final String apiSecret = "your api secret"; final OAuth20Service service = new ServiceBuilder(apiKey) .apiSecret(apiSecret) - .scope("status_update publish_feed") + .defaultScope("status_update publish_feed") .callback("http://your.doman.com/oauth/renren") .build(RenrenApi.instance()); final Scanner in = new Scanner(System.in); @@ -54,8 +55,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -86,11 +86,12 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println("Sig string: " + sig); request.addQuerystringParameter("sig", md5(sig)); service.signRequest(accessToken, request); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceExample.java index 7d4aa6b10..6e8ce342a 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceExample.java @@ -24,12 +24,13 @@ public class SalesforceExample { private SalesforceExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, NoSuchAlgorithmException, KeyManagementException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; final String clientSecret = "your client secret"; - //IT's important! Salesforce upper require TLS v1.1 or 1.2. + //IT's important! Salesforce upper require TLS v1.1 or higher. //They are enabled in Java 8 by default, but not in Java 7 SalesforceApi.initTLSv11orUpper(); @@ -38,7 +39,6 @@ public static void main(String... args) throws IOException, NoSuchAlgorithmExcep // // When you plan to connect to a Sandbox environment you've to use SalesforceApi.sandbox() API instance // new ServiceBuilder.....build(SalesforceApi.sandbox()); - final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) .callback("https://www.example.com/callback") @@ -95,9 +95,10 @@ public static void main(String... args) throws IOException, NoSuchAlgorithmExcep final OAuthRequest request = new OAuthRequest(Verb.GET, url); service.signRequest(salesforceAccessToken, request); - final Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceNingAsyncExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceNingAsyncExample.java index f5a524026..6c3987046 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceNingAsyncExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SalesforceNingAsyncExample.java @@ -27,7 +27,7 @@ public class SalesforceNingAsyncExample { private SalesforceNingAsyncExample() { } - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings({"unchecked", "rawtypes", "PMD.SystemPrintln"}) public static void main(String... args) throws InterruptedException, ExecutionException, UnsupportedEncodingException, IOException, NoSuchAlgorithmException, KeyManagementException { // Replace these with your client id and secret @@ -42,7 +42,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx .setReadTimeout(10_000) .build()); - //IT's important! Salesforce upper require TLS v1.1 or 1.2 + //IT's important! Salesforce upper require TLS v1.1 or higher SalesforceApi.initTLSv11orUpper(); try (OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) @@ -91,10 +91,11 @@ public static void main(String... args) throws InterruptedException, ExecutionEx System.out.println(); System.out.println("Full URL: " + url); final OAuthRequest request = new OAuthRequest(Verb.GET, url); - final Response response = service.execute(request); System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); + try (Response response = service.execute(request)) { + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } } } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeibo2Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeibo2Example.java index d4ff865de..3ac982efb 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeibo2Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeibo2Example.java @@ -19,6 +19,7 @@ public class SinaWeibo2Example { private SinaWeibo2Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your_api_key"; @@ -54,11 +55,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeiboExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeiboExample.java index 618e8c881..767ccdbab 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeiboExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SinaWeiboExample.java @@ -20,6 +20,7 @@ public class SinaWeiboExample { private SinaWeiboExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your key"; @@ -49,7 +50,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -60,11 +61,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SkyrockExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SkyrockExample.java index 5751538ef..f2c0cf007 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SkyrockExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SkyrockExample.java @@ -19,6 +19,7 @@ public class SkyrockExample { private SkyrockExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your-api-key") .apiSecret("your-api-secret") @@ -41,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -52,11 +53,12 @@ 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); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SlackExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SlackExample.java new file mode 100644 index 000000000..44a952d16 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/SlackExample.java @@ -0,0 +1,102 @@ +package com.github.scribejava.apis.examples; + +import com.github.scribejava.apis.SlackApi; +import com.github.scribejava.apis.slack.SlackOAuth2AccessToken; +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; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; + +public class SlackExample { + + private static final String NETWORK_NAME = "Slack.com"; + private static final String BOT_RESOURCE_URL = "https://slack.com/api/channels.list"; + private static final String BOT_SCOPE = "channels:read"; + private static final String USER_RESOURCE_URL = "https://slack.com/api/users.list"; + private static final String USER_SCOPE = "users:read"; + private static final String PAYLOAD = "null"; + private static final String CONTENT_TYPE_NAME = "Content-Type"; + private static final String CONTENT_TYPE_VALUE = "application/json"; + + private SlackExample() { + } + + @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 OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .callback("https://www.example.com/oauth_callback/") + .defaultScope(BOT_SCOPE) + .build(SlackApi.instance()); + + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + + final Map additionalParams = new HashMap<>(); + // define user scope if any + additionalParams.put("user_scope", USER_SCOPE); + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .additionalParams(additionalParams) + .build(); + 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("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(); + + System.out.println("Getting info using BOT token..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, BOT_RESOURCE_URL); + request.addHeader(CONTENT_TYPE_NAME, CONTENT_TYPE_VALUE); + request.setPayload(PAYLOAD); + 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("Getting info using USER token..."); + final OAuthRequest userRequest = new OAuthRequest(Verb.GET, USER_RESOURCE_URL); + userRequest.addHeader(CONTENT_TYPE_NAME, CONTENT_TYPE_VALUE); + userRequest.setPayload(PAYLOAD); + final SlackOAuth2AccessToken token = (SlackOAuth2AccessToken) accessToken; + service.signRequest(token.getUserAccessToken(), userRequest); + + try (Response response = service.execute(userRequest)) { + 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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/StackExchangeExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/StackExchangeExample.java index 39350cd14..5b4d52bcb 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/StackExchangeExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/StackExchangeExample.java @@ -21,6 +21,7 @@ public class StackExchangeExample { private StackExchangeExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id, secret, application key and // optionally site name @@ -32,7 +33,6 @@ public static void main(String... args) throws IOException, InterruptedException final String secretState = "secret" + new Random().nextInt(999_999); final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback("http://www.example.com/oauth_callback/") .build(StackExchangeApi.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -42,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -63,8 +63,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -75,11 +74,12 @@ public static void main(String... args) throws IOException, InterruptedException final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL + "?site=" + site + "&key=" + key); service.signRequest(accessToken, request); - final 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()); + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV1StagingExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV1StagingExample.java index 427b83f2c..63139e589 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV1StagingExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV1StagingExample.java @@ -22,6 +22,7 @@ public class TheThingsNetworkV1StagingExample { private TheThingsNetworkV1StagingExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your_client_id"; @@ -31,7 +32,6 @@ public static void main(String... args) throws IOException, InterruptedException final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback(redirectURI) .build(TheThingsNetworkV1StagingApi.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -41,7 +41,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -50,7 +50,7 @@ public static void main(String... args) throws IOException, InterruptedException // TTN v1staging does not have URL safe keys, so we have to decode it final String code = URLDecoder.decode(in.nextLine(), "UTF-8"); - System.out.println("Using code: "+code); + System.out.println("Using code: " + code); System.out.println(); System.out.println("And paste the state from server here. We have set 'secretState'='" + secretState + "'."); @@ -78,19 +78,20 @@ public static void main(String... args) throws IOException, InterruptedException service.signRequest(accessToken, request); request.addHeader("Accept", "application/json"); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); - if (response.getCode() == 401) { - System.out.println("Not authorised: "+response.getBody()); - } else { - System.out.println("You should see a JSON array of your registered applications:"); - System.out.println(response.getBody()); + if (response.getCode() == 401) { + System.out.println("Not authorised: " + response.getBody()); + } else { + System.out.println("You should see a JSON array of your registered applications:"); + System.out.println(response.getBody()); - System.out.println(); - System.out.println("That's it man! Go and build something awesome with ScribeJava! :)"); + System.out.println(); + System.out.println("That's it man! Go and build something awesome with ScribeJava! :)"); + } } } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV2PreviewExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV2PreviewExample.java index 19cc96331..25316d6ea 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV2PreviewExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TheThingsNetworkV2PreviewExample.java @@ -16,12 +16,13 @@ public class TheThingsNetworkV2PreviewExample { private static final String NETWORK_NAME = "TTNv2preview"; - private static final String PROTECTED_RESOURCE_URL = - "https://preview.account.thethingsnetwork.org/api/v2/applications"; + private static final String PROTECTED_RESOURCE_URL + = "https://preview.account.thethingsnetwork.org/api/v2/applications"; private TheThingsNetworkV2PreviewExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your_client_id"; @@ -31,7 +32,6 @@ public static void main(String... args) throws IOException, InterruptedException final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .state(secretState) .callback(redirectURI) .build(TheThingsNetworkV2PreviewApi.instance()); final Scanner in = new Scanner(System.in, "UTF-8"); @@ -41,7 +41,7 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -75,19 +75,20 @@ public static void main(String... args) throws IOException, InterruptedException service.signRequest(accessToken, request); request.addHeader("Accept", "application/json"); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); - if (response.getCode() == 401) { - System.out.println("Not authorised: "+response.getBody()); - } else { - System.out.println("You should see a JSON array of your registered applications:"); - System.out.println(response.getBody()); + if (response.getCode() == 401) { + System.out.println("Not authorised: " + response.getBody()); + } else { + System.out.println("You should see a JSON array of your registered applications:"); + System.out.println(response.getBody()); - System.out.println(); - System.out.println("That's it man! Go and build something awesome with ScribeJava! :)"); + System.out.println(); + System.out.println("That's it man! Go and build something awesome with ScribeJava! :)"); + } } } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TrelloExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TrelloExample.java index a73826a34..737bd768e 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TrelloExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TrelloExample.java @@ -21,6 +21,7 @@ public class TrelloExample { private TrelloExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder(API_KEY) .apiSecret(API_SECRET) @@ -43,7 +44,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -54,11 +55,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TumblrExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TumblrExample.java index 6d16ef54f..063b8b9b2 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TumblrExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TumblrExample.java @@ -19,6 +19,7 @@ public class TumblrExample { private TumblrExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("MY_CONSUMER_KEY") .apiSecret("MY_CONSUMER_SECRET") @@ -43,7 +44,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -54,11 +55,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TutByExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TutByExample.java index 70f05e5b2..c6aaf7eab 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TutByExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TutByExample.java @@ -21,6 +21,7 @@ public class TutByExample { private TutByExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -44,8 +45,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -55,12 +55,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TwitterExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TwitterExample.java index 20b95531d..748fa9034 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TwitterExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/TwitterExample.java @@ -19,6 +19,7 @@ public class TwitterExample { private TwitterExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") @@ -41,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -52,11 +53,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("That's it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/UcozExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/UcozExample.java index dcf6e1fd5..5760bb36a 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/UcozExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/UcozExample.java @@ -20,6 +20,7 @@ public class UcozExample { private UcozExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your_api_key") .apiSecret("your_api_secret") @@ -36,7 +37,7 @@ public static void main(String... args) throws IOException, InterruptedException System.out.print(">>"); final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -47,12 +48,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ViadeoExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ViadeoExample.java index 134faf3cc..39dbcff78 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ViadeoExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/ViadeoExample.java @@ -19,6 +19,7 @@ public class ViadeoExample { private ViadeoExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your own api key and secret final String apiKey = "your_app_id"; @@ -43,8 +44,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() + "')"); @@ -54,12 +54,12 @@ 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); - final 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()); - + 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! :)"); 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 79% 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 bf7c6f2ee..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,26 +13,27 @@ 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/v2.11/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") public static void main(String... args) throws InterruptedException, ExecutionException, IOException { // Replace these with your client id and secret final String clientId = "your client id"; 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) - .state(secretState) .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 ==="); @@ -40,7 +41,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -62,8 +63,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + System.out.println("Trading the Authorization Code for an Access Token..."); final OAuth2AccessToken accessToken = service.getAccessTokenAsync(code).get(); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() @@ -74,12 +74,12 @@ 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); - final 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()); - + 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! :)"); } 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 81% 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 81d1dd53a..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,14 +14,16 @@ 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/v2.11/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") public static void main(String... args) throws InterruptedException, ExecutionException, IOException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -35,12 +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) - .state(secretState) .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 ==="); @@ -48,7 +49,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + 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); @@ -70,8 +71,7 @@ public static void main(String... args) throws InterruptedException, ExecutionEx System.out.println(); } - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + System.out.println("Trading the Authorization Code for an Access Token..."); final OAuth2AccessToken accessToken = service.getAccessTokenAsync(code).get(); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() @@ -82,12 +82,12 @@ 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); - final 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()); - + 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! :)"); } 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 ed2fd0fba..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,18 +9,19 @@ public class VkontakteClientCredentialsGrantExample { - private static final String NETWORK_NAME = "Vkontakte.ru"; + private static final String NETWORK_NAME = "vk.com>"; private VkontakteClientCredentialsGrantExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; final String clientSecret = "your client secret"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("wall,offline") // replace with desired scope + .defaultScope("wall,offline") // replace with desired scope .callback("http://your.site.com/callback") .build(VkontakteApi.instance()); 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 bbab9db62..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 @@ -8,26 +8,28 @@ 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.AccessTokenRequestParams; import com.github.scribejava.core.oauth.OAuth20Service; import java.io.IOException; import java.util.concurrent.ExecutionException; 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; private VkontakteExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; final String clientSecret = "your client secret"; final OAuth20Service service = new ServiceBuilder(clientId) .apiSecret(clientSecret) - .scope("wall,offline,email") // replace with desired scope + .defaultScope("wall,offline") // replace with desired scope .callback("http://your.site.com/callback") .build(VkontakteApi.instance()); final Scanner in = new Scanner(System.in); @@ -37,7 +39,10 @@ public static void main(String... args) throws IOException, InterruptedException // Obtain the Authorization URL System.out.println("Fetching the Authorization URL..."); - final String authorizationUrl = service.getAuthorizationUrl(); + final String customScope = "wall,offline,email"; + final String authorizationUrl = service.createAuthorizationUrlBuilder() + .scope(customScope) + .build(); System.out.println("Got the Authorization URL!"); System.out.println("Now go and authorize ScribeJava here:"); System.out.println(authorizationUrl); @@ -46,9 +51,9 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - final OAuth2AccessToken accessToken = service.getAccessToken(code); + System.out.println("Trading the Authorization Code for an Access Token..."); + final OAuth2AccessToken accessToken = service.getAccessToken(AccessTokenRequestParams.create(code) + .scope(customScope)); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); if (accessToken instanceof VKOAuth2AccessToken) { @@ -61,12 +66,12 @@ 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); - final 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()); - + 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! :)"); } 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 eb0958491..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,13 +16,14 @@ 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; private VkontakteExternalHttpExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Replace these with your client id and secret final String clientId = "your client id"; @@ -36,14 +37,14 @@ 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); final OAuth20Service service = new ServiceBuilder(clientId) .httpClient(wrappedAHCHttpClient) .apiSecret(clientSecret) - .scope("wall,offline") // replace with desired scope + .defaultScope("wall,offline") // replace with desired scope .callback("http://your.site.com/callback") .build(VkontakteApi.instance()); final Scanner in = new Scanner(System.in); @@ -62,8 +63,7 @@ public static void main(String... args) throws IOException, InterruptedException final String code = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + 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() @@ -74,12 +74,12 @@ 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); - final 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()); - + 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! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/WunderlistExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/WunderlistExample.java new file mode 100644 index 000000000..5d3ffd562 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/WunderlistExample.java @@ -0,0 +1,73 @@ +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.WunderlistAPI; +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 WunderlistExample { + + private static final String NETWORK_NAME = "Wunderlist"; + private static final String PROTECTED_RESOURCE_URL = "https://a.wunderlist.com/api/v1/user"; + + private WunderlistExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your own values + final String apiKey = "apiKey"; + final String apiSecret = "apiSecret"; + final String callbackUrl = "http://example.com/callback"; + final String secretState = "security_token" + new Random().nextInt(999_999); + + final OAuth20Service service = new ServiceBuilder(apiKey) + .apiSecret(apiSecret) + .callback(callbackUrl) + .build(WunderlistAPI.instance()); + + final String code; + try (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(">>"); + code = in.nextLine(); + } + System.out.println(); + + // Trade the Request Token and Verifier for the Access Token + System.out.println("Trading the Request Token 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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XeroExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XeroExample.java new file mode 100644 index 000000000..d66334e40 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XeroExample.java @@ -0,0 +1,110 @@ +package com.github.scribejava.apis.examples; + +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Scanner; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.scribejava.apis.XeroApi20; +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; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class XeroExample { + + private static final String NETWORK_NAME = "Xero"; + private static final String PROTECTED_RESOURCE_URL = "https://api.xero.com/connections"; + private static final String PROTECTED_ORGANISATION_URL = "https://api.xero.com/api.xro/2.0/Organisation"; + + private XeroExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your client id and secret + final String clientId = "your client id"; + final String clientSecret = "your client secret"; + final String callback = "your callback url"; + + final String secretState = "secret" + new Random().nextInt(999_999); + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + // replace with desired scope + .defaultScope("openid email profile offline_access accounting.settings accounting.transactions") + .callback(callback) + .build(XeroApi20.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(); + + //First GET the Xero Tenant ID + System.out.println("Getting Xero tenant id..."); + final OAuthRequest requestConn = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + requestConn.addHeader("Accept", "application/json"); + service.signRequest(accessToken.getAccessToken(), requestConn); + final Response connResp = service.execute(requestConn); + + final ObjectMapper objectMapper = new ObjectMapper(); + final List> tenantList = objectMapper.readValue(connResp.getBody(), + objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)); + + System.out.println(); + System.out.println(connResp.getCode()); + System.out.println(connResp.getBody()); + System.out.println(); + System.out.println("Your Xero tenant id is ...." + tenantList.get(0).get("tenantId")); + System.out.println(); + + // GET protected Resource + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_ORGANISATION_URL); + request.addHeader("xero-tenant-id", tenantList.get(0).get("tenantId")); + service.signRequest(accessToken.getAccessToken(), request); + final Response response = service.execute(request); + + // Now let's go and ask for a protected resource! + 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! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XingExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XingExample.java index 5cfd1d89d..ebf946db5 100755 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XingExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/XingExample.java @@ -19,6 +19,7 @@ public class XingExample { private XingExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") @@ -41,7 +42,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -52,11 +53,11 @@ 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); - final Response response = service.execute(request); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + } System.out.println(); System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Yahoo20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Yahoo20Example.java index 8102b4ea3..49b655462 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Yahoo20Example.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Yahoo20Example.java @@ -29,6 +29,7 @@ public class Yahoo20Example { private Yahoo20Example() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { // Add your personal information here final String clientId = "ADD CLIENT ID HERE!!!!"; @@ -55,8 +56,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); + System.out.println("Trading the Authorization Code for an Access Token..."); final OAuth2AccessToken accessToken = service.getAccessToken(oauthVerifier); System.out.println("Got the Access Token!"); System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); @@ -66,12 +66,12 @@ 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); - final 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()); - + 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! :)"); diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/YahooExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/YahooExample.java index b75b8a447..acaa42aea 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/YahooExample.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/YahooExample.java @@ -20,6 +20,7 @@ public class YahooExample { private YahooExample() { } + @SuppressWarnings("PMD.SystemPrintln") public static void main(String... args) throws IOException, InterruptedException, ExecutionException { final OAuth10aService service = new ServiceBuilder("your client id") .apiSecret("your client secret") @@ -42,7 +43,7 @@ public static void main(String... args) throws IOException, InterruptedException final String oauthVerifier = in.nextLine(); System.out.println(); - // Trade the Request Token and Verfier for the Access Token + // Trade the Request Token and Verifier for the Access Token System.out.println("Trading the Request Token for an Access Token..."); final OAuth1AccessToken accessToken = service.getAccessToken(requestToken, oauthVerifier); System.out.println("Got the Access Token!"); @@ -53,12 +54,12 @@ 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); - final 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()); - + 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! :)"); 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 new file mode 100644 index 000000000..240f08b81 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/facebook/FacebookAccessTokenJsonExtractorTest.java @@ -0,0 +1,43 @@ +package com.github.scribejava.apis.facebook; + +import com.github.scribejava.core.model.Response; +import java.io.IOException; +import java.util.Collections; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; + +public class FacebookAccessTokenJsonExtractorTest { + + private final FacebookAccessTokenJsonExtractor extractor = FacebookAccessTokenJsonExtractor.instance(); + + @Test + public void shouldThrowExceptionIfResponseIsError() throws IOException { + final String body = "{\"error\":" + + "{\"message\":\"This authorization code has been used.\"," + + "\"type\":\"OAuthException\"," + + "\"code\":100," + + "\"fbtrace_id\":\"DtxvtGRaxbB\"}}"; + try (Response response = error(body)) { + + final FacebookAccessTokenErrorResponse fateR = assertThrows(FacebookAccessTokenErrorResponse.class, + new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + + assertEquals("This authorization code has been used.", fateR.getErrorMessage()); + assertEquals("OAuthException", fateR.getType()); + assertEquals(100, fateR.getCodeInt()); + assertEquals("DtxvtGRaxbB", fateR.getFbtraceId()); + assertEquals(body, fateR.getResponse().getBody()); + } + } + + private static Response error(String body) { + return new Response(400, /* message */ null, /* headers */ Collections.emptyMap(), body); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractorTest.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractorTest.java index a0f5b53a3..836a0d6ba 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractorTest.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/fitbit/FitBitJsonTokenExtractorTest.java @@ -1,60 +1,38 @@ package com.github.scribejava.apis.fitbit; import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; -import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse.ErrorCode; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.oauth2.OAuth2Error; +import java.io.IOException; -import org.hamcrest.FeatureMatcher; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertEquals; +import org.junit.function.ThrowingRunnable; public class FitBitJsonTokenExtractorTest { - private static final String ERROR_DESCRIPTION = "Authorization code invalid: " + - "cbb1c11b23209011e89be71201fa6381464dc0af " + - "Visit https://dev.fitbit.com/docs/oauth2 for more information " + - "on the Fitbit Web API authorization process."; - private static final String ERROR_JSON = "{\"errors\":[{\"errorType\":\"invalid_grant\",\"message\":\"" + - ERROR_DESCRIPTION + "\"}],\"success\":false}"; - - @Rule - public ExpectedException thrown = ExpectedException.none(); + private static final String ERROR_DESCRIPTION = "Authorization code invalid: " + + "cbb1c11b23209011e89be71201fa6381464dc0af " + + "Visit https://dev.fitbit.com/docs/oauth2 for more information " + + "on the Fitbit Web API authorization process."; + private static final String ERROR_JSON = "{\"errors\":[{\"errorType\":\"invalid_grant\",\"message\":\"" + + ERROR_DESCRIPTION + "\"}],\"success\":false}"; @Test - public void testErrorExtraction() { + public void testErrorExtraction() throws IOException { final FitBitJsonTokenExtractor extractor = new FitBitJsonTokenExtractor(); - - thrown.expect(OAuth2AccessTokenErrorResponse.class); - thrown.expect(new ErrorCodeFeatureMatcher(ErrorCode.invalid_grant)); - thrown.expect(new ErrorDescriptionFeatureMatcher(ERROR_DESCRIPTION)); - - extractor.generateError(ERROR_JSON); - } - - private static class ErrorCodeFeatureMatcher extends FeatureMatcher { - - private ErrorCodeFeatureMatcher(ErrorCode expected) { - super(equalTo(expected), "a response with errorCode", "errorCode"); - } - - @Override - protected ErrorCode featureValueOf(OAuth2AccessTokenErrorResponse actual) { - return actual.getErrorCode(); - } - } - - private static class ErrorDescriptionFeatureMatcher extends FeatureMatcher { - - private ErrorDescriptionFeatureMatcher(String expected) { - super(equalTo(expected), "a response with errorDescription", "errorDescription"); - } - - @Override - protected String featureValueOf(OAuth2AccessTokenErrorResponse actual) { - return actual.getErrorDescription(); - } + final OAuth2AccessTokenErrorResponse thrown = assertThrows(OAuth2AccessTokenErrorResponse.class, + new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.generateError(new Response(403, null, null, ERROR_JSON)); + } + }); + assertSame(OAuth2Error.INVALID_GRANT, thrown.getError()); + assertEquals(ERROR_DESCRIPTION, thrown.getErrorDescription()); } } diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/service/OdnoklassnikiServiceTest.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/odnoklassniki/OdnoklassnikiServiceTest.java similarity index 94% rename from scribejava-apis/src/test/java/com/github/scribejava/apis/service/OdnoklassnikiServiceTest.java rename to scribejava-apis/src/test/java/com/github/scribejava/apis/odnoklassniki/OdnoklassnikiServiceTest.java index 0dded23fb..f4bfbccac 100644 --- a/scribejava-apis/src/test/java/com/github/scribejava/apis/service/OdnoklassnikiServiceTest.java +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/odnoklassniki/OdnoklassnikiServiceTest.java @@ -1,4 +1,4 @@ -package com.github.scribejava.apis.service; +package com.github.scribejava.apis.odnoklassniki; import com.github.scribejava.apis.OdnoklassnikiApi; import com.github.scribejava.core.builder.ServiceBuilder; @@ -19,7 +19,7 @@ public class OdnoklassnikiServiceTest { private final OAuth20Service service = new ServiceBuilder("0000000000") .apiSecret("CCCCCCCCCCCCCCCCCCCCCCCC") - .scope("VALUABLE_ACCESS") + .defaultScope("VALUABLE_ACCESS") .callback("http://your.site.com/callback") .build(OdnoklassnikiApi.instance()); diff --git a/scribejava-core/pom.xml b/scribejava-core/pom.xml index 96ea8ad56..d5fbfc488 100644 --- a/scribejava-core/pom.xml +++ b/scribejava-core/pom.xml @@ -5,15 +5,41 @@ com.github.scribejava scribejava - 5.5.1-SNAPSHOT + 8.3.4-SNAPSHOT ../pom.xml - + com.github.scribejava scribejava-core ScribeJava Core jar + + + com.github.scribejava + scribejava-java8 + ${project.version} + + + commons-codec + commons-codec + 1.15 + true + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + true + + + javax.xml.bind + jaxb-api + 2.3.0 + true + + + diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/base64/Base64.java b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Base64.java new file mode 100644 index 000000000..18a8f01a0 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Base64.java @@ -0,0 +1,55 @@ +package com.github.scribejava.core.base64; + +public abstract class Base64 { + + private static volatile Base64 instance; + + public static Base64 getInstance() { + Base64 localInstance = instance; + if (localInstance == null) { + synchronized (Base64.class) { + localInstance = instance; + if (localInstance == null) { + localInstance = createInstance(); + instance = localInstance; + } + } + } + return localInstance; + } + + private static Base64 createInstance() { + if (Java8Base64.isAvailable()) { + return new Java8Base64(); + } + if (Jaxb230Base64.isAvailable()) { + return new Jaxb230Base64(); + } + if (JaxbBase64.isAvailable()) { + return new JaxbBase64(); + } + if (CommonsCodecBase64.isAvailable()) { + return new CommonsCodecBase64(); + } + throw new IllegalStateException( + "No Base64 implementation was provided. Java 8 Base64, Apache Commons Codec or JAXB is needed"); + } + + public static void init(Base64 base64) { + synchronized (Base64.class) { + instance = base64; + } + } + + public static String encode(byte[] bytes) { + return getInstance().internalEncode(bytes); + } + + public static String encodeUrlWithoutPadding(byte[] bytes) { + return getInstance().internalEncodeUrlWithoutPadding(bytes); + } + + protected abstract String internalEncode(byte[] bytes); + + protected abstract String internalEncodeUrlWithoutPadding(byte[] bytes); +} 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 new file mode 100644 index 000000000..bb172d720 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/CommonsCodecBase64.java @@ -0,0 +1,36 @@ +package com.github.scribejava.core.base64; + +public class CommonsCodecBase64 extends Base64 { + + 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) { + return BASE64_ENCODER.encodeToString(bytes); + } + + @Override + protected String internalEncodeUrlWithoutPadding(byte[] bytes) { + return BASE64_URL_ENCODER_WITHOUT_PADDING.encodeToString(bytes); + } + + static boolean isAvailable() { + try { + Class.forName("org.apache.commons.codec.binary.Base64", false, CommonsCodecBase64.class.getClassLoader()); + return true; + } catch (ClassNotFoundException cnfE) { + return false; + } + } +} 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 new file mode 100644 index 000000000..8e4c6c990 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Java8Base64.java @@ -0,0 +1,26 @@ +package com.github.scribejava.core.base64; + +public class Java8Base64 extends Base64 { + + private static final com.github.scribejava.java8.base64.Java8Base64 JAVA8_BASE64 + = isAvailable() ? new com.github.scribejava.java8.base64.Java8Base64() : null; + + @Override + protected String internalEncode(byte[] bytes) { + return JAVA8_BASE64.internalEncode(bytes); + } + + @Override + protected String internalEncodeUrlWithoutPadding(byte[] bytes) { + return JAVA8_BASE64.internalEncodeUrlWithoutPadding(bytes); + } + + static boolean isAvailable() { + try { + Class.forName("java.util.Base64", false, Java8Base64.class.getClassLoader()); + return true; + } catch (ClassNotFoundException cnfE) { + return false; + } + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/base64/Jaxb230Base64.java b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Jaxb230Base64.java new file mode 100644 index 000000000..c4ee4d799 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/Jaxb230Base64.java @@ -0,0 +1,32 @@ +package com.github.scribejava.core.base64; + +import javax.xml.bind.DatatypeConverter; + +/** + * JAXB v2.3.0 (the latest for JRE 7) + */ +public class Jaxb230Base64 extends Base64 { + + @Override + protected String internalEncode(byte[] bytes) { + return DatatypeConverter.printBase64Binary(bytes); + } + + @Override + protected String internalEncodeUrlWithoutPadding(byte[] bytes) { + String string = DatatypeConverter.printBase64Binary(bytes); + while (string.endsWith("=")) { + string = string.substring(0, string.length() - 1); + } + return string.replace('+', '-').replace('/', '_'); + } + + static boolean isAvailable() { + try { + Class.forName("javax.xml.bind.DatatypeConverter", false, Jaxb230Base64.class.getClassLoader()); + return true; + } catch (ClassNotFoundException cnfE) { + return false; + } + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/base64/JaxbBase64.java b/scribejava-core/src/main/java/com/github/scribejava/core/base64/JaxbBase64.java new file mode 100644 index 000000000..85e889501 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/base64/JaxbBase64.java @@ -0,0 +1,29 @@ +package com.github.scribejava.core.base64; + +import jakarta.xml.bind.DatatypeConverter; + +public class JaxbBase64 extends Base64 { + + @Override + protected String internalEncode(byte[] bytes) { + return DatatypeConverter.printBase64Binary(bytes); + } + + @Override + protected String internalEncodeUrlWithoutPadding(byte[] bytes) { + String string = DatatypeConverter.printBase64Binary(bytes); + while (string.endsWith("=")) { + string = string.substring(0, string.length() - 1); + } + return string.replace('+', '-').replace('/', '_'); + } + + static boolean isAvailable() { + try { + Class.forName("jakarta.xml.bind.DatatypeConverter", false, JaxbBase64.class.getClassLoader()); + return true; + } catch (ClassNotFoundException cnfE) { + return false; + } + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/ScopeBuilder.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ScopeBuilder.java new file mode 100644 index 000000000..8bd22e1a4 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ScopeBuilder.java @@ -0,0 +1,56 @@ +package com.github.scribejava.core.builder; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * OAuth2.0 Scope Builder. It allows specifying multiple scopes one by one. It will combine them in the single + * space-delimited string. OAuth 2.0 standard specifies space as a delimiter for scopes + * (https://tools.ietf.org/html/rfc6749#section-3.3). If you found API, that do not support spaces, but support + * something else, let ScribeJava know (submit the issue here https://github.com/scribejava/scribejava/issues) and use + * your own concatenated string as a temporary workaround. + */ +public class ScopeBuilder { + + private final Set scopes = new HashSet<>(); + + public ScopeBuilder() { + } + + public ScopeBuilder(String scope) { + withScope(scope); + } + + public ScopeBuilder(String... scopes) { + withScopes(scopes); + } + + public ScopeBuilder(Collection scopes) { + withScopes(scopes); + } + + public final ScopeBuilder withScope(String scope) { + scopes.add(scope); + return this; + } + + public final ScopeBuilder withScopes(String... scopes) { + this.scopes.addAll(Arrays.asList(scopes)); + return this; + } + + public final ScopeBuilder withScopes(Collection scopes) { + this.scopes.addAll(scopes); + return this; + } + + public String build() { + final StringBuilder scopeBuilder = new StringBuilder(); + for (String scope : scopes) { + scopeBuilder.append(' ').append(scope); + } + return scopeBuilder.substring(1); + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilder.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilder.java index 8c70c4319..eade1ede5 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilder.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilder.java @@ -1,8 +1,11 @@ package com.github.scribejava.core.builder; -import com.github.scribejava.core.builder.api.BaseApi; +import com.github.scribejava.core.builder.api.DefaultApi10a; +import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.oauth.OAuth10aService; +import com.github.scribejava.core.oauth.OAuth20Service; import com.github.scribejava.core.oauth.OAuthService; import com.github.scribejava.core.utils.Preconditions; @@ -11,13 +14,12 @@ /** * Implementation of the Builder pattern, with a fluent interface that creates a {@link OAuthService} */ -public class ServiceBuilder { +public class ServiceBuilder implements ServiceBuilderOAuth10a, ServiceBuilderOAuth20 { private String callback; private String apiKey; private String apiSecret; private String scope; - private String state; private OutputStream debugStream; private String responseType = "code"; private String userAgent; @@ -29,114 +31,100 @@ public ServiceBuilder(String apiKey) { apiKey(apiKey); } - /** - * Adds an OAuth callback url - * - * @param callback callback url. Must be a valid url or 'oob' - * ({@link com.github.scribejava.core.model.OAuthConstants#OOB} for out of band OAuth - * @return the {@link ServiceBuilder} instance for method chaining - */ + @Override public ServiceBuilder callback(String callback) { this.callback = callback; return this; } - /** - * Configures the api key - * - * @param apiKey The api key for your application - * @return the {@link ServiceBuilder} instance for method chaining - */ + @Override public final ServiceBuilder apiKey(String apiKey) { Preconditions.checkEmptyString(apiKey, "Invalid Api key"); this.apiKey = apiKey; return this; } - /** - * Configures the api secret - * - * @param apiSecret The api secret for your application - * @return the {@link ServiceBuilder} instance for method chaining - */ + @Override public ServiceBuilder apiSecret(String apiSecret) { Preconditions.checkEmptyString(apiSecret, "Invalid Api secret"); this.apiSecret = apiSecret; return this; } - /** - * Configures the OAuth scope. This is only necessary in some APIs (like Google's). - * - * @param scope The OAuth scope - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder scope(String scope) { + @Override + public ServiceBuilder apiSecretIsEmptyStringUnsafe() { + apiSecret = ""; + return this; + } + + private ServiceBuilder setScope(String scope) { Preconditions.checkEmptyString(scope, "Invalid OAuth scope"); this.scope = scope; return this; } - /** - * Configures the anti forgery session state. This is available in some APIs (like Google's). - * - * @param state The OAuth state - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder state(String state) { - Preconditions.checkEmptyString(state, "Invalid OAuth state"); - this.state = state; - return this; + @Override + public ServiceBuilderOAuth20 defaultScope(String defaultScope) { + return setScope(defaultScope); + } + + @Override + public ServiceBuilderOAuth20 defaultScope(ScopeBuilder scopeBuilder) { + return setScope(scopeBuilder.build()); } + @Override + public ServiceBuilderOAuth10a withScope(String scope) { + return setScope(scope); + } + + @Override public ServiceBuilder debugStream(OutputStream debugStream) { Preconditions.checkNotNull(debugStream, "debug stream can't be null"); this.debugStream = debugStream; return this; } - public ServiceBuilder responseType(String responseType) { + @Override + public ServiceBuilderOAuth20 responseType(String responseType) { Preconditions.checkEmptyString(responseType, "Invalid OAuth responseType"); this.responseType = responseType; return this; } + @Override public ServiceBuilder httpClientConfig(HttpClientConfig httpClientConfig) { Preconditions.checkNotNull(httpClientConfig, "httpClientConfig can't be null"); this.httpClientConfig = httpClientConfig; return this; } - /** - * takes precedence over httpClientConfig - * - * @param httpClient externally created HTTP client - * @return the {@link ServiceBuilder} instance for method chaining - */ + @Override public ServiceBuilder httpClient(HttpClient httpClient) { this.httpClient = httpClient; return this; } + @Override public ServiceBuilder userAgent(String userAgent) { this.userAgent = userAgent; return this; } + @Override public ServiceBuilder debug() { - debugStream(System.out); - return this; + return debugStream(System.out); + } + + @Override + public OAuth10aService build(DefaultApi10a api) { + return api.createService(apiKey, apiSecret, callback, scope, debugStream, userAgent, httpClientConfig, + httpClient); } - /** - * Returns the fully configured {@link OAuthService} - * - * @param OAuthService implementation (OAuth1/OAuth2/any API specific) - * @param api will build Service for this API - * @return fully configured {@link OAuthService} - */ - public S build(BaseApi api) { - return api.createService(apiKey, apiSecret, callback, scope, debugStream, state, responseType, userAgent, + @Override + public OAuth20Service build(DefaultApi20 api) { + return api.createService(apiKey, apiSecret, callback, scope, responseType, debugStream, userAgent, httpClientConfig, httpClient); } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderCommon.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderCommon.java new file mode 100644 index 000000000..fd71c49d8 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderCommon.java @@ -0,0 +1,63 @@ +package com.github.scribejava.core.builder; + +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.oauth.OAuthService; +import java.io.OutputStream; + +/** + * Implementation of the Builder pattern, with a fluent interface that creates a {@link OAuthService} + */ +public interface ServiceBuilderCommon { + + /** + * Adds an OAuth callback url + * + * @param callback callback url. Must be a valid url or 'oob' + * ({@link com.github.scribejava.core.model.OAuthConstants#OOB} for out of band OAuth + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderCommon callback(String callback); + + /** + * Configures the api key + * + * @param apiKey The api key for your application + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderCommon apiKey(String apiKey); + + /** + * Configures the api secret + * + * @param apiSecret The api secret for your application + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderCommon apiSecret(String apiSecret); + + /** + * Configures the api secret as "" (empty string). + * + * Used usually for a test environments or another strange cases. Not all providers support empty string as api key + * and will throw an Exception in such cases. + * + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderCommon apiSecretIsEmptyStringUnsafe(); + + ServiceBuilderCommon httpClientConfig(HttpClientConfig httpClientConfig); + + /** + * takes precedence over httpClientConfig + * + * @param httpClient externally created HTTP client + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderCommon httpClient(HttpClient httpClient); + + ServiceBuilderCommon userAgent(String userAgent); + + ServiceBuilderCommon debugStream(OutputStream debugStream); + + ServiceBuilderCommon debug(); +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderOAuth10a.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderOAuth10a.java new file mode 100644 index 000000000..8c7027cca --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderOAuth10a.java @@ -0,0 +1,47 @@ +package com.github.scribejava.core.builder; + +import com.github.scribejava.core.builder.api.DefaultApi10a; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.oauth.OAuth10aService; +import java.io.OutputStream; + +public interface ServiceBuilderOAuth10a extends ServiceBuilderCommon { + + @Override + ServiceBuilderOAuth10a callback(String callback); + + @Override + ServiceBuilderOAuth10a apiKey(String apiKey); + + @Override + ServiceBuilderOAuth10a apiSecret(String apiSecret); + + @Override + ServiceBuilderOAuth10a apiSecretIsEmptyStringUnsafe(); + + @Override + ServiceBuilderOAuth10a httpClientConfig(HttpClientConfig httpClientConfig); + + @Override + ServiceBuilderOAuth10a httpClient(HttpClient httpClient); + + @Override + ServiceBuilderOAuth10a userAgent(String userAgent); + + @Override + ServiceBuilderOAuth10a debugStream(OutputStream debugStream); + + @Override + ServiceBuilderOAuth10a debug(); + + /** + * Configures the OAuth 1.0a scope. This is only necessary in some APIs + * + * @param scope The OAuth scope + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderOAuth10a withScope(String scope); + + OAuth10aService build(DefaultApi10a api); +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderOAuth20.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderOAuth20.java new file mode 100644 index 000000000..bcf119db9 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/ServiceBuilderOAuth20.java @@ -0,0 +1,57 @@ +package com.github.scribejava.core.builder; + +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.oauth.OAuth20Service; +import java.io.OutputStream; + +public interface ServiceBuilderOAuth20 extends ServiceBuilderCommon { + + @Override + ServiceBuilderOAuth20 callback(String callback); + + @Override + ServiceBuilderOAuth20 apiKey(String apiKey); + + @Override + ServiceBuilderOAuth20 apiSecret(String apiSecret); + + @Override + ServiceBuilderOAuth20 apiSecretIsEmptyStringUnsafe(); + + @Override + ServiceBuilderOAuth20 httpClientConfig(HttpClientConfig httpClientConfig); + + @Override + ServiceBuilderOAuth20 httpClient(HttpClient httpClient); + + @Override + ServiceBuilderOAuth20 userAgent(String userAgent); + + @Override + ServiceBuilderOAuth20 debugStream(OutputStream debugStream); + + @Override + ServiceBuilderOAuth20 debug(); + + ServiceBuilderOAuth20 responseType(String responseType); + + /** + * Configures the default OAuth 2.0 scope.
+ * + * You can request any uniq scope per each access token request using + * {@link com.github.scribejava.core.oauth.AuthorizationUrlBuilder#scope(java.lang.String) }.

+ * + * In case you're requesting always the same scope,
+ * you can just set it here and do not provide scope param nowhere more. + * + * @param defaultScope The OAuth scope, used as deafult + * @return the {@link ServiceBuilder} instance for method chaining + */ + ServiceBuilderOAuth20 defaultScope(String defaultScope); + + ServiceBuilderOAuth20 defaultScope(ScopeBuilder scopeBuilder); + + OAuth20Service build(DefaultApi20 api); +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/BaseApi.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/BaseApi.java deleted file mode 100644 index bce6192dc..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/BaseApi.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.github.scribejava.core.builder.api; - -import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.HttpClientConfig; -import com.github.scribejava.core.oauth.OAuthService; -import java.io.OutputStream; - -public interface BaseApi { - - T createService(String apiKey, String apiSecret, String callback, String scope, OutputStream debugStream, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, - HttpClient httpClient); -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/ClientAuthenticationType.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/ClientAuthenticationType.java deleted file mode 100644 index 097ba1081..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/ClientAuthenticationType.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.github.scribejava.core.builder.api; - -import com.github.scribejava.core.model.OAuthRequest; -import com.github.scribejava.core.oauth2.clientauthentication.HttpBasicAuthenticationScheme; -import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; - -/** - * Represents
- * 2.3. Client Authentication
- * https://tools.ietf.org/html/rfc6749#section-2.3
- * in it's part 2.3.1. Client Password
- * https://tools.ietf.org/html/rfc6749#section-2.3.1 - * - * @deprecated use {@link com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication} - */ -@Deprecated -public enum ClientAuthenticationType { - /** - * @deprecated use {@link com.github.scribejava.core.oauth2.clientauthentication.HttpBasicAuthenticationScheme} - */ - @Deprecated - HTTP_BASIC_AUTHENTICATION_SCHEME { - - @Override - public void addClientAuthentication(OAuthRequest request, String apiKey, String apiSecret) { - HttpBasicAuthenticationScheme.instance().addClientAuthentication(request, apiKey, apiSecret); - } - }, - /** - * @deprecated use {@link com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme} - */ - @Deprecated - REQUEST_BODY { - @Override - public void addClientAuthentication(OAuthRequest request, String apiKey, String apiSecret) { - RequestBodyAuthenticationScheme.instance().addClientAuthentication(request, apiKey, apiSecret); - } - }; - - public abstract void addClientAuthentication(OAuthRequest request, String apiKey, String apiSecret); -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi10a.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi10a.java index 67bbd181e..2ea470110 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi10a.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi10a.java @@ -34,7 +34,7 @@ * fine-tune the process. Please read the javadocs of the interfaces to get an idea of what to do. * */ -public abstract class DefaultApi10a implements BaseApi { +public abstract class DefaultApi10a { /** * Returns the access token extractor. @@ -85,7 +85,7 @@ public SignatureService getSignatureService() { * @return the signature type, choose between header, querystring, etc. Defaults to Header */ public OAuth1SignatureType getSignatureType() { - return OAuth1SignatureType.Header; + return OAuth1SignatureType.HEADER; } /** @@ -143,10 +143,8 @@ public String getAuthorizationUrl(OAuth1RequestToken requestToken) { return parameters.appendTo(getAuthorizationBaseUrl()); } - @Override public OAuth10aService createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { + OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { return new OAuth10aService(this, apiKey, apiSecret, callback, scope, debugStream, userAgent, httpClientConfig, httpClient); } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi20.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi20.java index b429142a6..76ef6dbce 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi20.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/DefaultApi20.java @@ -1,5 +1,6 @@ package com.github.scribejava.core.builder.api; +import com.github.scribejava.core.extractors.DeviceAuthorizationJsonExtractor; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; import com.github.scribejava.core.extractors.TokenExtractor; import com.github.scribejava.core.httpclient.HttpClient; @@ -9,9 +10,11 @@ import com.github.scribejava.core.model.ParameterList; import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.oauth.OAuth20Service; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureAuthorizationRequestHeaderField; import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; import com.github.scribejava.core.oauth2.clientauthentication.HttpBasicAuthenticationScheme; -import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme; + import java.io.OutputStream; import java.util.Map; @@ -28,7 +31,7 @@ * fine-tune the process. Please read the javadocs of the interfaces to get an idea of what to do. * */ -public abstract class DefaultApi20 implements BaseApi { +public abstract class DefaultApi20 { /** * Returns the access token extractor. @@ -76,7 +79,12 @@ public String getRevokeTokenEndpoint() { /** * Returns the URL where you should redirect your users to authenticate your application. * + * @param responseType responseType + * @param apiKey apiKey * @param additionalParams any additional GET params to add to the URL + * @param callback callback + * @param state state + * @param scope scope * @return the URL where you should redirect your users */ public String getAuthorizationUrl(String responseType, String apiKey, String callback, String scope, String state, @@ -100,34 +108,33 @@ public String getAuthorizationUrl(String responseType, String apiKey, String cal return parameters.appendTo(getAuthorizationBaseUrl()); } - @Override - public OAuth20Service createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new OAuth20Service(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, + public OAuth20Service createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new OAuth20Service(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, httpClient); } - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_AUTHORIZATION_REQUEST_HEADER_FIELD; + public BearerSignature getBearerSignature() { + return BearerSignatureAuthorizationRequestHeaderField.instance(); } public ClientAuthentication getClientAuthentication() { - switch (getClientAuthenticationType()) { - case HTTP_BASIC_AUTHENTICATION_SCHEME: - return HttpBasicAuthenticationScheme.instance(); - case REQUEST_BODY: - return RequestBodyAuthenticationScheme.instance(); - default: - throw new IllegalStateException("there was no such Client Authentication Type"); - } + return HttpBasicAuthenticationScheme.instance(); } /** - * @deprecated use {@link #getClientAuthentication() } + * RFC 8628 OAuth 2.0 Device Authorization Grant + * + * @see RFC 8628 + * @return the device authorization endpoint */ - @Deprecated - public ClientAuthenticationType getClientAuthenticationType() { - return ClientAuthenticationType.HTTP_BASIC_AUTHENTICATION_SCHEME; + public String getDeviceAuthorizationEndpoint() { + throw new UnsupportedOperationException( + "This API doesn't support Device Authorization Grant or we have no info about this"); + } + + public DeviceAuthorizationJsonExtractor getDeviceAuthorizationExtractor() { + return DeviceAuthorizationJsonExtractor.instance(); } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth1SignatureType.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth1SignatureType.java index 7660b5826..7de68ff7b 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth1SignatureType.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth1SignatureType.java @@ -2,6 +2,6 @@ public enum OAuth1SignatureType { - Header, - QueryString + HEADER, + QUERY_STRING } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth2SignatureType.java b/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth2SignatureType.java deleted file mode 100644 index c42b54d98..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/builder/api/OAuth2SignatureType.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.github.scribejava.core.builder.api; - -import com.github.scribejava.core.model.OAuthConstants; -import com.github.scribejava.core.model.OAuthRequest; - -public enum OAuth2SignatureType { - /** - * https://tools.ietf.org/html/rfc6750#section-2.1 - */ - BEARER_AUTHORIZATION_REQUEST_HEADER_FIELD { - @Override - public void signRequest(String accessToken, OAuthRequest request) { - request.addHeader("Authorization", "Bearer " + accessToken); - } - - }, - /** - * https://tools.ietf.org/html/rfc6750#section-2.3 - */ - BEARER_URI_QUERY_PARAMETER { - @Override - public void signRequest(String accessToken, OAuthRequest request) { - request.addQuerystringParameter(OAuthConstants.ACCESS_TOKEN, accessToken); - } - - }; - - public abstract void signRequest(String accessToken, OAuthRequest request); -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractJsonExtractor.java b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractJsonExtractor.java new file mode 100644 index 000000000..4a592a706 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractJsonExtractor.java @@ -0,0 +1,22 @@ +package com.github.scribejava.core.extractors; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.scribejava.core.exceptions.OAuthException; + +public abstract class AbstractJsonExtractor { + + protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + protected static JsonNode extractRequiredParameter(JsonNode errorNode, String parameterName, String rawResponse) + throws OAuthException { + final JsonNode value = errorNode.get(parameterName); + + if (value == null) { + throw new OAuthException("Response body is incorrect. Can't extract a '" + parameterName + + "' from this: '" + rawResponse + "'", null); + } + + return value; + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractOAuth1JSONTokenExtractor.java b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractOAuth1JSONTokenExtractor.java index 16f684855..5c42e812a 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractOAuth1JSONTokenExtractor.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/AbstractOAuth1JSONTokenExtractor.java @@ -1,39 +1,37 @@ package com.github.scribejava.core.extractors; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.scribejava.core.exceptions.OAuthException; import com.github.scribejava.core.model.OAuth1Token; +import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.Response; -import com.github.scribejava.core.utils.OAuthEncoder; import com.github.scribejava.core.utils.Preconditions; import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public abstract class AbstractOAuth1JSONTokenExtractor implements TokenExtractor { - private static final Pattern OAUTH_TOKEN_PATTERN = Pattern.compile("\"oauth_token\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern OAUTH_TOKEN_SECRET_PATTERN - = Pattern.compile("\"oauth_token_secret\"\\s*:\\s*\"(\\S*?)\""); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public T extract(Response response) throws IOException { - final String body = response.getBody(); - Preconditions.checkEmptyString(body, "Response body is incorrect. Can't extract a token from an empty string"); - final String token = extract(body, OAUTH_TOKEN_PATTERN); - final String secret = extract(body, OAUTH_TOKEN_SECRET_PATTERN); - return createToken(token, secret, body); - } + final String rawBody = response.getBody(); + Preconditions.checkEmptyString(rawBody, + "Response body is incorrect. Can't extract a token from an empty string"); + + final JsonNode body = OBJECT_MAPPER.readTree(rawBody); - private String extract(String response, Pattern p) { - final Matcher matcher = p.matcher(response); - if (matcher.find() && matcher.groupCount() >= 1) { - return OAuthEncoder.decode(matcher.group(1)); - } else { + final JsonNode token = body.get(OAuthConstants.TOKEN); + final JsonNode secret = body.get(OAuthConstants.TOKEN_SECRET); + + if (token == null || secret == null) { throw new OAuthException("Response body is incorrect. Can't extract token and secret from this: '" - + response + '\'', null); + + rawBody + '\'', null); } + + return createToken(token.asText(), secret.asText(), rawBody); } protected abstract T createToken(String token, String secret, String response); diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/BaseStringExtractorImpl.java b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/BaseStringExtractorImpl.java index acda30254..3547fbcac 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/extractors/BaseStringExtractorImpl.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/BaseStringExtractorImpl.java @@ -32,6 +32,8 @@ protected String getVerb(OAuthRequest request) { /** * https://tools.ietf.org/html/rfc5849#section-3.4.1.2 + * @param request request + * @return url */ protected String getUrl(OAuthRequest request) { return request.getSanitizedUrl(); 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 new file mode 100644 index 000000000..5b4fa248b --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/extractors/DeviceAuthorizationJsonExtractor.java @@ -0,0 +1,61 @@ +package com.github.scribejava.core.extractors; + +import static com.github.scribejava.core.extractors.AbstractJsonExtractor.OBJECT_MAPPER; +import static com.github.scribejava.core.extractors.AbstractJsonExtractor.extractRequiredParameter; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.scribejava.core.model.DeviceAuthorization; +import java.io.IOException; +import com.github.scribejava.core.model.Response; + +public class DeviceAuthorizationJsonExtractor extends AbstractJsonExtractor { + + protected DeviceAuthorizationJsonExtractor() { + } + + private static class InstanceHolder { + + private static final DeviceAuthorizationJsonExtractor INSTANCE = new DeviceAuthorizationJsonExtractor(); + } + + public static DeviceAuthorizationJsonExtractor instance() { + return InstanceHolder.INSTANCE; + } + + public DeviceAuthorization extract(Response response) throws IOException { + if (response.getCode() != 200) { + generateError(response); + } + return createDeviceAuthorization(response.getBody()); + } + + public void generateError(Response response) throws IOException { + OAuth2AccessTokenJsonExtractor.instance().generateError(response); + } + + private DeviceAuthorization createDeviceAuthorization(String rawResponse) throws IOException { + + final JsonNode response = OBJECT_MAPPER.readTree(rawResponse); + + final DeviceAuthorization deviceAuthorization = new DeviceAuthorization( + extractRequiredParameter(response, "device_code", rawResponse).textValue(), + extractRequiredParameter(response, "user_code", rawResponse).textValue(), + extractRequiredParameter(response, getVerificationUriParamName(), rawResponse).textValue(), + extractRequiredParameter(response, "expires_in", rawResponse).intValue()); + + final JsonNode intervalSeconds = response.get("interval"); + if (intervalSeconds != null) { + deviceAuthorization.setIntervalSeconds(intervalSeconds.asInt(5)); + } + + final JsonNode verificationUriComplete = response.get("verification_uri_complete"); + if (verificationUriComplete != null) { + deviceAuthorization.setVerificationUriComplete(verificationUriComplete.asText()); + } + + return deviceAuthorization; + } + + protected String getVerificationUriParamName() { + return "verification_uri"; + } +} 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 e49831daf..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 @@ -1,29 +1,20 @@ package com.github.scribejava.core.extractors; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.net.URI; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import com.github.scribejava.core.exceptions.OAuthException; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; +import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.oauth2.OAuth2Error; import com.github.scribejava.core.utils.Preconditions; /** * JSON (default) implementation of {@link TokenExtractor} for OAuth 2.0 */ -public class OAuth2AccessTokenJsonExtractor implements TokenExtractor { - - private static final Pattern ACCESS_TOKEN_REGEX_PATTERN = Pattern.compile("\"access_token\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern TOKEN_TYPE_REGEX_PATTERN = Pattern.compile("\"token_type\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern EXPIRES_IN_REGEX_PATTERN = Pattern.compile("\"expires_in\"\\s*:\\s*\"?(\\d*?)\"?\\D"); - private static final Pattern REFRESH_TOKEN_REGEX_PATTERN = Pattern.compile("\"refresh_token\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern SCOPE_REGEX_PATTERN = Pattern.compile("\"scope\"\\s*:\\s*\"([^\"]*?)\""); - private static final Pattern ERROR_REGEX_PATTERN = Pattern.compile("\"error\"\\s*:\\s*\"(\\S*?)\""); - private static final Pattern ERROR_DESCRIPTION_REGEX_PATTERN - = Pattern.compile("\"error_description\"\\s*:\\s*\"([^\"]*?)\""); - private static final Pattern ERROR_URI_REGEX_PATTERN = Pattern.compile("\"error_uri\"\\s*:\\s*\"(\\S*?)\""); +public class OAuth2AccessTokenJsonExtractor extends AbstractJsonExtractor implements TokenExtractor { protected OAuth2AccessTokenJsonExtractor() { } @@ -43,7 +34,7 @@ public OAuth2AccessToken extract(Response response) throws IOException { Preconditions.checkEmptyString(body, "Response body is incorrect. Can't extract a token from an empty string"); if (response.getCode() != 200) { - generateError(body); + generateError(response); } return createToken(body); } @@ -52,62 +43,58 @@ public OAuth2AccessToken extract(Response response) throws IOException { * Related documentation: https://tools.ietf.org/html/rfc6749#section-5.2 * * @param response response + * @throws java.io.IOException IOException + * */ - public void generateError(String response) { - final String errorInString = extractParameter(response, ERROR_REGEX_PATTERN, true); - final String errorDescription = extractParameter(response, ERROR_DESCRIPTION_REGEX_PATTERN, false); - final String errorUriInString = extractParameter(response, ERROR_URI_REGEX_PATTERN, false); + public void generateError(Response response) throws IOException { + final String responseBody = response.getBody(); + final JsonNode responseBodyJson; + try { + responseBodyJson = OBJECT_MAPPER.readTree(responseBody); + } catch (JsonProcessingException ex) { + throw new OAuth2AccessTokenErrorResponse(null, null, null, response); + } + + final JsonNode errorUriInString = responseBodyJson.get("error_uri"); URI errorUri; try { - errorUri = errorUriInString == null ? null : URI.create(errorUriInString); + errorUri = errorUriInString == null ? null : URI.create(errorUriInString.asText()); } catch (IllegalArgumentException iae) { errorUri = null; } - OAuth2AccessTokenErrorResponse.ErrorCode errorCode; + OAuth2Error errorCode; try { - errorCode = OAuth2AccessTokenErrorResponse.ErrorCode.valueOf(errorInString); + errorCode = OAuth2Error + .parseFrom(extractRequiredParameter(responseBodyJson, "error", responseBody).asText()); } catch (IllegalArgumentException iaE) { //non oauth standard error code errorCode = null; } - throw new OAuth2AccessTokenErrorResponse(errorCode, errorDescription, errorUri, response); - } - - private OAuth2AccessToken createToken(String response) { - final String accessToken = extractParameter(response, ACCESS_TOKEN_REGEX_PATTERN, true); - final String tokenType = extractParameter(response, TOKEN_TYPE_REGEX_PATTERN, false); - final String expiresInString = extractParameter(response, EXPIRES_IN_REGEX_PATTERN, false); - Integer expiresIn; - try { - expiresIn = expiresInString == null ? null : Integer.valueOf(expiresInString); - } catch (NumberFormatException nfe) { - expiresIn = null; - } - final String refreshToken = extractParameter(response, REFRESH_TOKEN_REGEX_PATTERN, false); - final String scope = extractParameter(response, SCOPE_REGEX_PATTERN, false); + final JsonNode errorDescription = responseBodyJson.get("error_description"); - return createToken(accessToken, tokenType, expiresIn, refreshToken, scope, response); + throw new OAuth2AccessTokenErrorResponse(errorCode, errorDescription == null ? null : errorDescription.asText(), + errorUri, response); } - protected OAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, - String refreshToken, String scope, String response) { - return new OAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, response); - } + private OAuth2AccessToken createToken(String rawResponse) throws IOException { - protected static String extractParameter(String response, Pattern regexPattern, boolean required) - throws OAuthException { - final Matcher matcher = regexPattern.matcher(response); - if (matcher.find()) { - return matcher.group(1); - } + final JsonNode response = OBJECT_MAPPER.readTree(rawResponse); - if (required) { - throw new OAuthException("Response body is incorrect. Can't extract a '" + regexPattern.pattern() - + "' from this: '" + response + "'", null); - } + final JsonNode expiresInNode = response.get("expires_in"); + final JsonNode refreshToken = response.get(OAuthConstants.REFRESH_TOKEN); + final JsonNode scope = response.get(OAuthConstants.SCOPE); + final JsonNode tokenType = response.get("token_type"); - return null; + return createToken(extractRequiredParameter(response, OAuthConstants.ACCESS_TOKEN, rawResponse).asText(), + tokenType == null ? null : tokenType.asText(), expiresInNode == null ? null : expiresInNode.asInt(), + refreshToken == null ? null : refreshToken.asText(), scope == null ? null : scope.asText(), response, + rawResponse); + } + + protected OAuth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn, + String refreshToken, String scope, JsonNode response, String rawResponse) { + return new OAuth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope, rawResponse); } } 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 6f75ee6c1..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,31 +14,89 @@ 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 public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, - MultipartPayload bodyContents) throws InterruptedException, ExecutionException, IOException { + com.github.scribejava.core.httpclient.multipart.MultipartPayload bodyContents) + throws InterruptedException, ExecutionException, IOException { + + 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 executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, null, - (OAuthRequest.ResponseConverter) null).get(); + 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/BodyPartPayload.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/BodyPartPayload.java deleted file mode 100644 index 3e8c6d47e..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/BodyPartPayload.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.scribejava.core.httpclient; - -public class BodyPartPayload { - - private final String contentDisposition; - private final String contentType; - private final byte[] payload; - - public BodyPartPayload(String contentDisposition, String contentType, byte[] payload) { - this.contentDisposition = contentDisposition; - this.contentType = contentType; - this.payload = payload; - } - - public String getContentDisposition() { - return contentDisposition; - } - - public String getContentType() { - return contentType; - } - - public byte[] getPayload() { - return payload; - } - -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/HttpClient.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/HttpClient.java index 40f9663f5..821c9b194 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/HttpClient.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/HttpClient.java @@ -1,5 +1,6 @@ package com.github.scribejava.core.httpclient; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Response; diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/MultipartPayload.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/MultipartPayload.java deleted file mode 100644 index a1dbb5e7e..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/MultipartPayload.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.github.scribejava.core.httpclient; - -import java.util.ArrayList; -import java.util.List; - -/** - * The class containing more than one payload of multipart/form-data request - */ -public class MultipartPayload { - - private final String boundary; - private final List bodyParts = new ArrayList<>(); - - public MultipartPayload(String boundary) { - this.boundary = boundary; - } - - public byte[] getStartBoundary(BodyPartPayload bodyPart) { - return ("--" + boundary + "\r\n" - + "Content-Disposition: " + bodyPart.getContentDisposition() + "\r\n" - + (bodyPart.getContentType() == null ? "" : "Content-Type: " + bodyPart.getContentType() + "\r\n") - + "\r\n").getBytes(); - } - - public byte[] getEndBoundary() { - return ("\r\n--" + boundary + "--\r\n").getBytes(); - } - - public int getContentLength() { - int contentLength = 0; - for (BodyPartPayload bodyPart : bodyParts) { - contentLength += bodyPart.getPayload().length - + bodyPart.getContentDisposition().length(); - if (bodyPart.getContentType() != null) { - contentLength += 16 //length of constant portions of contentType header - + bodyPart.getContentType().length(); - } - } - - contentLength += (37 //length of constant portions of contentDisposition header, - //see getStartBoundary and getEndBoundary methods - + boundary.length() * 2 //twice. start and end parts - ) * bodyParts.size(); //for every part - return contentLength; - } - - public List getBodyParts() { - return bodyParts; - } - - public void addMultipartPayload(String contentDisposition, String contentType, byte[] payload) { - bodyParts.add(new BodyPartPayload(contentDisposition, contentType, payload)); - } -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClient.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClient.java index 7e87dba0b..b500ba997 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClient.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClient.java @@ -1,14 +1,15 @@ package com.github.scribejava.core.httpclient.jdk; import com.github.scribejava.core.exceptions.OAuthException; -import com.github.scribejava.core.httpclient.BodyPartPayload; import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartUtils; 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.Response; import com.github.scribejava.core.model.Verb; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -113,7 +114,13 @@ public Response execute(String userAgent, Map headers, Verb http private Response doExecute(String userAgent, Map headers, Verb httpVerb, String completeUrl, BodyType bodyType, Object bodyContents) throws IOException { - final HttpURLConnection connection = (HttpURLConnection) new URL(completeUrl).openConnection(); + final URL url = new URL(completeUrl); + final HttpURLConnection connection; + if (config.getProxy() == null) { + connection = (HttpURLConnection) url.openConnection(); + } else { + connection = (HttpURLConnection) url.openConnection(config.getProxy()); + } connection.setInstanceFollowRedirects(config.isFollowRedirects()); connection.setRequestMethod(httpVerb.name()); if (config.getConnectTimeout() != null) { @@ -187,28 +194,30 @@ private static void addHeaders(HttpURLConnection connection, Map } } - /** - * Multipart implementation supporting more than one payload - */ - private static void addBody(HttpURLConnection connection, MultipartPayload multipartPayload, boolean requiresBody) - throws IOException { - - final int contentLength = multipartPayload.getContentLength(); + private static void addBody(HttpURLConnection connection, byte[] content, boolean requiresBody) throws IOException { + final int contentLength = content.length; if (requiresBody || contentLength > 0) { - final OutputStream os = prepareConnectionForBodyAndGetOutputStream(connection, contentLength); - - for (BodyPartPayload bodyPart : multipartPayload.getBodyParts()) { - os.write(multipartPayload.getStartBoundary(bodyPart)); - os.write(bodyPart.getPayload()); - os.write(multipartPayload.getEndBoundary()); + final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength); + if (contentLength > 0) { + outputStream.write(content); } } } - private static void addBody(HttpURLConnection connection, byte[] content, boolean requiresBody) throws IOException { - final int contentLength = content.length; - if (requiresBody || contentLength > 0) { - prepareConnectionForBodyAndGetOutputStream(connection, contentLength).write(content); + private static void addBody(HttpURLConnection connection, MultipartPayload multipartPayload, boolean requiresBody) + throws IOException { + + for (Map.Entry header : multipartPayload.getHeaders().entrySet()) { + connection.setRequestProperty(header.getKey(), header.getValue()); + } + + if (requiresBody) { + final ByteArrayOutputStream os = MultipartUtils.getPayload(multipartPayload); + final int contentLength = os.size(); + final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength); + if (contentLength > 0) { + os.writeTo(outputStream); + } } } @@ -218,10 +227,8 @@ private static OutputStream prepareConnectionForBodyAndGetOutputStream(HttpURLCo connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(contentLength)); if (connection.getRequestProperty(CONTENT_TYPE) == null) { connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); - } connection.setDoOutput(true); return connection.getOutputStream(); } - } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClientConfig.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClientConfig.java index cfb97b359..3b322b0af 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClientConfig.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClientConfig.java @@ -1,5 +1,7 @@ package com.github.scribejava.core.httpclient.jdk; +import java.net.Proxy; + import com.github.scribejava.core.httpclient.HttpClientConfig; public class JDKHttpClientConfig implements HttpClientConfig { @@ -7,6 +9,7 @@ public class JDKHttpClientConfig implements HttpClientConfig { private Integer connectTimeout; private Integer readTimeout; private boolean followRedirects = true; + private Proxy proxy; @Override public JDKHttpClientConfig createDefaultConfig() { @@ -25,6 +28,11 @@ public void setConnectTimeout(Integer connectTimeout) { this.connectTimeout = connectTimeout; } + public JDKHttpClientConfig withConnectTimeout(Integer connectTimeout) { + this.connectTimeout = connectTimeout; + return this; + } + public Integer getReadTimeout() { return readTimeout; } @@ -33,6 +41,24 @@ public void setReadTimeout(Integer readTimeout) { this.readTimeout = readTimeout; } + public JDKHttpClientConfig withReadTimeout(Integer readTimeout) { + this.readTimeout = readTimeout; + return this; + } + + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + + public Proxy getProxy() { + return proxy; + } + + public JDKHttpClientConfig withProxy(Proxy proxy) { + this.proxy = proxy; + return this; + } + public boolean isFollowRedirects() { return followRedirects; } @@ -49,4 +75,19 @@ public boolean isFollowRedirects() { public void setFollowRedirects(boolean followRedirects) { this.followRedirects = followRedirects; } + + /** + * Sets whether the underlying Http Connection follows redirects or not. + * + * Defaults to true (follow redirects) + * + * @see http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects(boolean) + * @param followRedirects boolean + * @return this for chaining methods invocations + */ + public JDKHttpClientConfig withFollowRedirects(boolean followRedirects) { + this.followRedirects = followRedirects; + return this; + } } 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/httpclient/multipart/BodyPartPayload.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/BodyPartPayload.java new file mode 100644 index 000000000..ddd6e9cb2 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/BodyPartPayload.java @@ -0,0 +1,30 @@ +package com.github.scribejava.core.httpclient.multipart; + +import com.github.scribejava.core.httpclient.HttpClient; +import java.util.Collections; +import java.util.Map; + +public abstract class BodyPartPayload { + + private final Map headers; + + public BodyPartPayload() { + this((Map) null); + } + + public BodyPartPayload(String contentType) { + this(convertContentTypeToHeaders(contentType)); + } + + public BodyPartPayload(Map headers) { + this.headers = headers; + } + + public Map getHeaders() { + return headers; + } + + protected static Map convertContentTypeToHeaders(String contentType) { + return contentType == null ? null : Collections.singletonMap(HttpClient.CONTENT_TYPE, contentType); + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/ByteArrayBodyPartPayload.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/ByteArrayBodyPartPayload.java new file mode 100644 index 000000000..c706d7481 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/ByteArrayBodyPartPayload.java @@ -0,0 +1,50 @@ +package com.github.scribejava.core.httpclient.multipart; + +import java.util.Map; + +public class ByteArrayBodyPartPayload extends BodyPartPayload { + + private final byte[] payload; + private final int off; + private final int len; + + public ByteArrayBodyPartPayload(byte[] payload, int off, int len, Map headers) { + super(headers); + this.payload = payload; + this.off = off; + this.len = len; + } + + public ByteArrayBodyPartPayload(byte[] payload, Map headers) { + this(payload, 0, payload.length, headers); + } + + public ByteArrayBodyPartPayload(byte[] payload, String contentType) { + this(payload, convertContentTypeToHeaders(contentType)); + } + + public ByteArrayBodyPartPayload(byte[] payload, int off, int len, String contentType) { + this(payload, off, len, convertContentTypeToHeaders(contentType)); + } + + public ByteArrayBodyPartPayload(byte[] payload) { + this(payload, (Map) null); + } + + public ByteArrayBodyPartPayload(byte[] payload, int off, int len) { + this(payload, off, len, (Map) null); + } + + public byte[] getPayload() { + return payload; + } + + public int getOff() { + return off; + } + + public int getLen() { + return len; + } + +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/FileByteArrayBodyPartPayload.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/FileByteArrayBodyPartPayload.java new file mode 100644 index 000000000..41b3e72bf --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/FileByteArrayBodyPartPayload.java @@ -0,0 +1,77 @@ +package com.github.scribejava.core.httpclient.multipart; + +import com.github.scribejava.core.httpclient.HttpClient; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class FileByteArrayBodyPartPayload extends ByteArrayBodyPartPayload { + + public FileByteArrayBodyPartPayload(byte[] payload) { + this(payload, null); + } + + public FileByteArrayBodyPartPayload(byte[] payload, int off, int len) { + this(payload, off, len, null); + } + + public FileByteArrayBodyPartPayload(byte[] payload, String name) { + this(payload, name, null); + } + + public FileByteArrayBodyPartPayload(byte[] payload, int off, int len, String name) { + this(payload, off, len, name, null); + } + + public FileByteArrayBodyPartPayload(byte[] payload, String name, String filename) { + this(null, payload, name, filename); + } + + public FileByteArrayBodyPartPayload(byte[] payload, int off, int len, String name, String filename) { + this(null, payload, off, len, name, filename); + } + + public FileByteArrayBodyPartPayload(String contentType, byte[] payload) { + this(contentType, payload, null); + } + + public FileByteArrayBodyPartPayload(String contentType, byte[] payload, int off, int len) { + this(contentType, payload, off, len, null); + } + + public FileByteArrayBodyPartPayload(String contentType, byte[] payload, String name) { + this(contentType, payload, name, null); + } + + public FileByteArrayBodyPartPayload(String contentType, byte[] payload, int off, int len, String name) { + this(contentType, payload, off, len, name, null); + } + + public FileByteArrayBodyPartPayload(String contentType, byte[] payload, String name, String filename) { + super(payload, composeHeaders(contentType, name, filename)); + } + + public FileByteArrayBodyPartPayload(String contentType, byte[] payload, int off, int len, String name, + String filename) { + super(payload, off, len, composeHeaders(contentType, name, filename)); + } + + private static Map composeHeaders(String contentType, String name, String filename) { + + String contentDispositionHeader = "form-data"; + if (name != null) { + contentDispositionHeader += "; name=\"" + name + '"'; + } + if (filename != null) { + contentDispositionHeader += "; filename=\"" + filename + '"'; + } + if (contentType == null) { + return Collections.singletonMap("Content-Disposition", contentDispositionHeader); + } else { + final Map headers = new HashMap<>(); + headers.put(HttpClient.CONTENT_TYPE, contentType); + headers.put("Content-Disposition", contentDispositionHeader); + return headers; + } + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/MultipartPayload.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/MultipartPayload.java new file mode 100644 index 000000000..9d60e0caa --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/MultipartPayload.java @@ -0,0 +1,110 @@ +package com.github.scribejava.core.httpclient.multipart; + +import com.github.scribejava.core.httpclient.HttpClient; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class MultipartPayload extends BodyPartPayload { + + private static final String DEFAULT_SUBTYPE = "form-data"; + + private final String boundary; + private String preamble; + private final List bodyParts = new ArrayList<>(); + private String epilogue; + + public MultipartPayload() { + this(null, MultipartUtils.generateDefaultBoundary(), null); + } + + public MultipartPayload(String boundary) { + this(null, boundary, null); + } + + public MultipartPayload(String subtype, String boundary) { + this(subtype, boundary, null); + } + + public MultipartPayload(Map headers) { + this(null, parseOrGenerateBoundary(headers), headers); + } + + public MultipartPayload(String boundary, Map headers) { + this(null, boundary, headers); + } + + public MultipartPayload(String subtype, String boundary, Map headers) { + super(composeHeaders(subtype, boundary, headers)); + this.boundary = boundary; + } + + private static Map composeHeaders(String subtype, String boundary, Map headersIn) + throws IllegalArgumentException { + MultipartUtils.checkBoundarySyntax(boundary); + final Map headersOut; + String contentTypeHeader = headersIn == null ? null : headersIn.get(HttpClient.CONTENT_TYPE); + if (contentTypeHeader == null) { + contentTypeHeader = "multipart/" + (subtype == null ? DEFAULT_SUBTYPE : subtype) + + "; boundary=\"" + boundary + '"'; + if (headersIn == null) { + headersOut = Collections.singletonMap(HttpClient.CONTENT_TYPE, contentTypeHeader); + } else { + headersOut = headersIn; + headersOut.put(HttpClient.CONTENT_TYPE, contentTypeHeader); + } + } else { + headersOut = headersIn; + final String parsedBoundary = MultipartUtils.parseBoundaryFromHeader(contentTypeHeader); + if (parsedBoundary == null) { + headersOut.put(HttpClient.CONTENT_TYPE, contentTypeHeader + "; boundary=\"" + boundary + '"'); + } else if (!parsedBoundary.equals(boundary)) { + throw new IllegalArgumentException( + "Different boundaries was passed in constructors. One as argument, second as header"); + } + } + return headersOut; + } + + private static String parseOrGenerateBoundary(Map headers) { + final String parsedBoundary = MultipartUtils.parseBoundaryFromHeader(headers.get(HttpClient.CONTENT_TYPE)); + return parsedBoundary == null ? MultipartUtils.generateDefaultBoundary() : parsedBoundary; + } + + public void addBodyPart(BodyPartPayload bodyPartPayload) { + bodyParts.add(bodyPartPayload); + } + + public void addBodyPart(MultipartPayload multipartPayload) { + if (multipartPayload.getBoundary().equals(boundary)) { + throw new IllegalArgumentException("{'boundary'}={'" + boundary + + "'} is the same for parent MultipartPayload and child"); + } + bodyParts.add(multipartPayload); + } + + public List getBodyParts() { + return bodyParts; + } + + public String getBoundary() { + return boundary; + } + + public String getPreamble() { + return preamble; + } + + public void setPreamble(String preamble) { + this.preamble = preamble; + } + + public String getEpilogue() { + return epilogue; + } + + public void setEpilogue(String epilogue) { + this.epilogue = epilogue; + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/MultipartUtils.java b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/MultipartUtils.java new file mode 100644 index 000000000..bdbeaf542 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/httpclient/multipart/MultipartUtils.java @@ -0,0 +1,84 @@ +package com.github.scribejava.core.httpclient.multipart; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MultipartUtils { + + private static final String B_CHARS_NO_SPACE_PATTERN = "0-9a-zA-Z'()+_,-./:=?"; + private static final String B_CHARS_PATTERN = B_CHARS_NO_SPACE_PATTERN + " "; + private static final String BOUNDARY_PATTERN = '[' + B_CHARS_PATTERN + "]{0,69}[" + B_CHARS_NO_SPACE_PATTERN + ']'; + private static final Pattern BOUNDARY_REGEXP = Pattern.compile(BOUNDARY_PATTERN); + private static final Pattern BOUNDARY_FROM_HEADER_REGEXP + = Pattern.compile("; boundary=\"?(" + BOUNDARY_PATTERN + ")\"?"); + + private MultipartUtils() { + } + + public static void checkBoundarySyntax(String boundary) { + if (boundary == null || !BOUNDARY_REGEXP.matcher(boundary).matches()) { + throw new IllegalArgumentException("{'boundary'='" + boundary + "'} has invalid syntax. Should be '" + + BOUNDARY_PATTERN + "'."); + } + } + + public static String parseBoundaryFromHeader(String contentTypeHeader) { + if (contentTypeHeader == null) { + return null; + } + final Matcher matcher = BOUNDARY_FROM_HEADER_REGEXP.matcher(contentTypeHeader); + return matcher.find() ? matcher.group(1) : null; + } + + public static String generateDefaultBoundary() { + return "----ScribeJava----" + System.currentTimeMillis(); + } + + public static ByteArrayOutputStream getPayload(MultipartPayload multipartPayload) throws IOException { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + final String preamble = multipartPayload.getPreamble(); + if (preamble != null) { + os.write((preamble + "\r\n").getBytes()); + } + final List bodyParts = multipartPayload.getBodyParts(); + if (!bodyParts.isEmpty()) { + final String boundary = multipartPayload.getBoundary(); + final byte[] startBoundary = ("--" + boundary + "\r\n").getBytes(); + + for (BodyPartPayload bodyPart : bodyParts) { + os.write(startBoundary); + + final Map bodyPartHeaders = bodyPart.getHeaders(); + if (bodyPartHeaders != null) { + for (Map.Entry header : bodyPartHeaders.entrySet()) { + os.write((header.getKey() + ": " + header.getValue() + "\r\n").getBytes()); + } + } + + os.write("\r\n".getBytes()); + if (bodyPart instanceof MultipartPayload) { + getPayload((MultipartPayload) bodyPart).writeTo(os); + } else if (bodyPart instanceof ByteArrayBodyPartPayload) { + final ByteArrayBodyPartPayload byteArrayBodyPart = (ByteArrayBodyPartPayload) bodyPart; + os.write(byteArrayBodyPart.getPayload(), byteArrayBodyPart.getOff(), byteArrayBodyPart.getLen()); + } else { + throw new AssertionError(bodyPart.getClass()); + } + os.write("\r\n".getBytes()); //CRLF for the next (starting or closing) boundary + } + + os.write(("--" + boundary + "--").getBytes()); + final String epilogue = multipartPayload.getEpilogue(); + if (epilogue != null) { + os.write(("\r\n" + epilogue).getBytes()); + } + + } + return os; + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/java8/Base64.java b/scribejava-core/src/main/java/com/github/scribejava/core/java8/Base64.java deleted file mode 100644 index 7e599c6e5..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/java8/Base64.java +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.github.scribejava.core.java8; - -import java.io.FilterOutputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Objects; - -/** - * This class consists exclusively of static methods for obtaining encoders and decoders for the Base64 encoding scheme. - * The implementation of this class supports the following types of Base64 as specified in - * RFC 4648 and - * RFC 2045. - * - *
    - *
  • Basic - *

    - * Uses "The Base64 Alphabet" as specified in Table 1 of RFC 4648 and RFC 2045 for encoding and decoding operation. The - * encoder does not add any line feed (line separator) character. The decoder rejects data that contains characters - * outside the base64 alphabet.

  • - * - *
  • URL and Filename safe - *

    - * Uses the "URL and Filename safe Base64 Alphabet" as specified in Table 2 of RFC 4648 for encoding and decoding. The - * encoder does not add any line feed (line separator) character. The decoder rejects data that contains characters - * outside the base64 alphabet.

  • - * - *
  • MIME - *

    - * Uses the "The Base64 Alphabet" as specified in Table 1 of RFC 2045 for encoding and decoding operation. The encoded - * output must be represented in lines of no more than 76 characters each and uses a carriage return {@code '\r'} - * followed immediately by a linefeed {@code '\n'} as the line separator. No line separator is added to the end of the - * encoded output. All line separators or other characters not found in the base64 alphabet table are ignored in - * decoding operation.

  • - *
- * - *

- * Unless otherwise noted, passing a {@code null} argument to a method of this class will cause a {@link java.lang.NullPointerException - * NullPointerException} to be thrown. - * - * @author Xueming Shen - * @since 1.8 - */ -public class Base64 { - - private Base64() { - } - - /** - * Returns a {@link Encoder} that encodes using the - * Basic type base64 encoding scheme. - * - * @return A Base64 encoder. - */ - public static Encoder getEncoder() { - return Encoder.RFC4648; - } - - /** - * Returns a {@link Encoder} that encodes using the - * URL and Filename safe type base64 encoding scheme. - * - * @return A Base64 encoder. - */ - public static Encoder getUrlEncoder() { - return Encoder.RFC4648_URLSAFE; - } - - /** - * Returns a {@link Encoder} that encodes using the - * MIME type base64 encoding scheme. - * - * @return A Base64 encoder. - */ - public static Encoder getMimeEncoder() { - return Encoder.RFC2045; - } - - /** - * Returns a {@link Encoder} that encodes using the - * MIME type base64 encoding scheme with specified line length and line separators. - * - * @param lineLength the length of each output line (rounded down to nearest multiple of 4). If - * {@code lineLength <= 0} the output will not be separated in lines - * @param lineSeparator the line separator for each output line - * - * @return A Base64 encoder. - * - * @throws IllegalArgumentException if {@code lineSeparator} includes any character of "The Base64 Alphabet" as - * specified in Table 1 of RFC 2045. - */ - public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) { - Objects.requireNonNull(lineSeparator); - int[] base64 = Decoder.FROM_BASE_64; - for (byte b : lineSeparator) { - if (base64[b & 0xff] != -1) { - throw new IllegalArgumentException( - "Illegal base64 line separator character 0x" + Integer.toString(b, 16)); - } - } - if (lineLength <= 0) { - return Encoder.RFC4648; - } - return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true); - } - - /** - * Returns a {@link Decoder} that decodes using the - * Basic type base64 encoding scheme. - * - * @return A Base64 decoder. - */ - public static Decoder getDecoder() { - return Decoder.RFC4648; - } - - /** - * Returns a {@link Decoder} that decodes using the - * URL and Filename safe type base64 encoding scheme. - * - * @return A Base64 decoder. - */ - public static Decoder getUrlDecoder() { - return Decoder.RFC4648_URLSAFE; - } - - /** - * Returns a {@link Decoder} that decodes using the - * MIME type base64 decoding scheme. - * - * @return A Base64 decoder. - */ - public static Decoder getMimeDecoder() { - return Decoder.RFC2045; - } - - /** - * This class implements an encoder for encoding byte data using the Base64 encoding scheme as specified in RFC 4648 - * and RFC 2045. - * - *

- * Instances of {@link Encoder} class are safe for use by multiple concurrent threads. - * - *

- * Unless otherwise noted, passing a {@code null} argument to a method of this class will cause a - * {@link java.lang.NullPointerException NullPointerException} to be thrown. - * - * @see Decoder - * @since 1.8 - */ - public static class Encoder { - - private final byte[] newline; - private final int linemax; - private final boolean isURL; - private final boolean doPadding; - - /** - * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" - * equivalents as specified in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648). - */ - private static final char[] TO_BASE_64 = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' - }; - - /** - * It's the lookup table for "URL and Filename safe Base64" as specified in Table 2 of the RFC 4648, with the - * '+' and '/' changed to '-' and '_'. This table is used when BASE64_URL is specified. - */ - private static final char[] TO_BASE_64_URL = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' - }; - - private static final int MIMELINEMAX = 76; - private static final byte[] CRLF = new byte[]{'\r', '\n'}; - - static final Encoder RFC4648 = new Encoder(false, null, -1, true); - static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true); - static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true); - - private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) { - this.isURL = isURL; - this.newline = newline; - this.linemax = linemax; - this.doPadding = doPadding; - } - - private int outLength(int srclen) { - int len; - if (doPadding) { - len = 4 * ((srclen + 2) / 3); - } else { - int n = srclen % 3; - len = 4 * (srclen / 3) + (n == 0 ? 0 : n + 1); - } - if (linemax > 0) // line separators - { - len += (len - 1) / linemax * newline.length; - } - return len; - } - - /** - * Encodes all bytes from the specified byte array into a newly-allocated byte array using the {@link Base64} - * encoding scheme. The returned byte array is of the length of the resulting bytes. - * - * @param src the byte array to encode - * @return A newly-allocated byte array containing the resulting encoded bytes. - */ - public byte[] encode(byte[] src) { - int len = outLength(src.length); // dst array size - byte[] dst = new byte[len]; - int ret = encode0(src, 0, src.length, dst); - if (ret != dst.length) { - return Arrays.copyOf(dst, ret); - } - return dst; - } - - /** - * Encodes all bytes from the specified byte array using the {@link Base64} encoding scheme, writing the - * resulting bytes to the given output byte array, starting at offset 0. - * - *

- * It is the responsibility of the invoker of this method to make sure the output byte array {@code dst} has - * enough space for encoding all bytes from the input byte array. No bytes will be written to the output byte - * array if the output byte array is not big enough. - * - * @param src the byte array to encode - * @param dst the output byte array - * @return The number of bytes written to the output byte array - * - * @throws IllegalArgumentException if {@code dst} does not have enough space for encoding all input bytes. - */ - public int encode(byte[] src, byte[] dst) { - int len = outLength(src.length); // dst array size - if (dst.length < len) { - throw new IllegalArgumentException( - "Output byte array is too small for encoding all input bytes"); - } - return encode0(src, 0, src.length, dst); - } - - /** - * Encodes the specified byte array into a String using the {@link Base64} encoding scheme. - * - *

- * This method first encodes all input bytes into a base64 encoded byte array and then constructs a new String - * by using the encoded byte array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1 - * ISO-8859-1} charset. - * - *

- * In other words, an invocation of this method has exactly the same effect as invoking - * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}. - * - * @param src the byte array to encode - * @return A String containing the resulting Base64 encoded characters - */ - @SuppressWarnings("deprecation") - public String encodeToString(byte[] src) { - byte[] encoded = encode(src); - return new String(encoded, 0, 0, encoded.length); - } - - /** - * Encodes all remaining bytes from the specified byte buffer into a newly-allocated ByteBuffer using the - * {@link Base64} encoding scheme. - * - * Upon return, the source buffer's position will be updated to its limit; its limit will not have been changed. - * The returned output buffer's position will be zero and its limit will be the number of resulting encoded - * bytes. - * - * @param buffer the source ByteBuffer to encode - * @return A newly-allocated byte buffer containing the encoded bytes. - */ - public ByteBuffer encode(ByteBuffer buffer) { - int len = outLength(buffer.remaining()); - byte[] dst = new byte[len]; - int ret; - if (buffer.hasArray()) { - ret = encode0(buffer.array(), - buffer.arrayOffset() + buffer.position(), - buffer.arrayOffset() + buffer.limit(), - dst); - buffer.position(buffer.limit()); - } else { - byte[] src = new byte[buffer.remaining()]; - buffer.get(src); - ret = encode0(src, 0, src.length, dst); - } - if (ret != dst.length) { - dst = Arrays.copyOf(dst, ret); - } - return ByteBuffer.wrap(dst); - } - - /** - * Wraps an output stream for encoding byte data using the {@link Base64} encoding scheme. - * - *

- * It is recommended to promptly close the returned output stream after use, during which it will flush all - * possible leftover bytes to the underlying output stream. Closing the returned output stream will close the - * underlying output stream. - * - * @param os the output stream. - * @return the output stream for encoding the byte data into the specified Base64 encoded format - */ - public OutputStream wrap(OutputStream os) { - Objects.requireNonNull(os); - return new EncOutputStream(os, isURL ? TO_BASE_64_URL : TO_BASE_64, - newline, linemax, doPadding); - } - - /** - * Returns an encoder instance that encodes equivalently to this one, but without adding any padding character - * at the end of the encoded byte data. - * - *

- * The encoding scheme of this encoder instance is unaffected by this invocation. The returned encoder instance - * should be used for non-padding encoding operation. - * - * @return an equivalent encoder that encodes without adding any padding character at the end - */ - public Encoder withoutPadding() { - if (!doPadding) { - return this; - } - return new Encoder(isURL, newline, linemax, false); - } - - private int encode0(byte[] src, int off, int end, byte[] dst) { - char[] base64 = isURL ? TO_BASE_64_URL : TO_BASE_64; - int sp = off; - int slen = (end - off) / 3 * 3; - int sl = off + slen; - if (linemax > 0 && slen > linemax / 4 * 3) { - slen = linemax / 4 * 3; - } - int dp = 0; - while (sp < sl) { - int sl0 = Math.min(sp + slen, sl); - for (int sp0 = sp, dp0 = dp; sp0 < sl0;) { - int bits = (src[sp0++] & 0xff) << 16 - | (src[sp0++] & 0xff) << 8 - | (src[sp0++] & 0xff); - dst[dp0++] = (byte) base64[(bits >>> 18) & 0x3f]; - dst[dp0++] = (byte) base64[(bits >>> 12) & 0x3f]; - dst[dp0++] = (byte) base64[(bits >>> 6) & 0x3f]; - dst[dp0++] = (byte) base64[bits & 0x3f]; - } - int dlen = (sl0 - sp) / 3 * 4; - dp += dlen; - sp = sl0; - if (dlen == linemax && sp < end) { - for (byte b : newline) { - dst[dp++] = b; - } - } - } - if (sp < end) { // 1 or 2 leftover bytes - int b0 = src[sp++] & 0xff; - dst[dp++] = (byte) base64[b0 >> 2]; - if (sp == end) { - dst[dp++] = (byte) base64[(b0 << 4) & 0x3f]; - if (doPadding) { - dst[dp++] = '='; - dst[dp++] = '='; - } - } else { - int b1 = src[sp++] & 0xff; - dst[dp++] = (byte) base64[(b0 << 4) & 0x3f | (b1 >> 4)]; - dst[dp++] = (byte) base64[(b1 << 2) & 0x3f]; - if (doPadding) { - dst[dp++] = '='; - } - } - } - return dp; - } - } - - /** - * This class implements a decoder for decoding byte data using the Base64 encoding scheme as specified in RFC 4648 - * and RFC 2045. - * - *

- * The Base64 padding character {@code '='} is accepted and interpreted as the end of the encoded byte data, but is - * not required. So if the final unit of the encoded byte data only has two or three Base64 characters (without the - * corresponding padding character(s) padded), they are decoded as if followed by padding character(s). If there is - * a padding character present in the final unit, the correct number of padding character(s) must be present, - * otherwise {@code IllegalArgumentException} ( {@code IOException} when reading from a Base64 stream) is thrown - * during decoding. - * - *

- * Instances of {@link Decoder} class are safe for use by multiple concurrent threads. - * - *

- * Unless otherwise noted, passing a {@code null} argument to a method of this class will cause a - * {@link java.lang.NullPointerException NullPointerException} to be thrown. - * - * @see Encoder - * @since 1.8 - */ - public static class Decoder { - - private final boolean isURL; - private final boolean isMIME; - - /** - * Lookup table for decoding unicode characters drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC - * 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 alphabet but fall - * within the bounds of the array are encoded to -1. - * - */ - private static final int[] FROM_BASE_64 = new int[256]; - static { - Arrays.fill(FROM_BASE_64, -1); - for (int i = 0; i < Encoder.TO_BASE_64.length; i++) { - FROM_BASE_64[Encoder.TO_BASE_64[i]] = i; - } - FROM_BASE_64['='] = -2; - } - - /** - * Lookup table for decoding "URL and Filename safe Base64 Alphabet" as specified in Table2 of the RFC 4648. - */ - private static final int[] FROM_BASE_64_URL = new int[256]; - static { - Arrays.fill(FROM_BASE_64_URL, -1); - for (int i = 0; i < Encoder.TO_BASE_64_URL.length; i++) { - FROM_BASE_64_URL[Encoder.TO_BASE_64_URL[i]] = i; - } - FROM_BASE_64_URL['='] = -2; - } - - static final Decoder RFC4648 = new Decoder(false, false); - static final Decoder RFC4648_URLSAFE = new Decoder(true, false); - static final Decoder RFC2045 = new Decoder(false, true); - - private Decoder(boolean isURL, boolean isMIME) { - this.isURL = isURL; - this.isMIME = isMIME; - } - - /** - * Decodes all bytes from the input byte array using the {@link Base64} encoding scheme, writing the results - * into a newly-allocated output byte array. The returned byte array is of the length of the resulting bytes. - * - * @param src the byte array to decode - * - * @return A newly-allocated byte array containing the decoded bytes. - * - * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme - */ - public byte[] decode(byte[] src) { - byte[] dst = new byte[outLength(src, 0, src.length)]; - int ret = decode0(src, 0, src.length, dst); - if (ret != dst.length) { - dst = Arrays.copyOf(dst, ret); - } - return dst; - } - - /** - * Decodes a Base64 encoded String into a newly-allocated byte array using the {@link Base64} encoding scheme. - * - *

- * An invocation of this method has exactly the same effect as invoking - * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))} - * - * @param src the string to decode - * - * @return A newly-allocated byte array containing the decoded bytes. - * - * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme - */ - public byte[] decode(String src) { - return decode(src.getBytes(StandardCharsets.ISO_8859_1)); - } - - /** - * Decodes all bytes from the input byte array using the {@link Base64} encoding scheme, writing the results - * into the given output byte array, starting at offset 0. - * - *

- * It is the responsibility of the invoker of this method to make sure the output byte array {@code dst} has - * enough space for decoding all bytes from the input byte array. No bytes will be be written to the output byte - * array if the output byte array is not big enough. - * - *

- * If the input byte array is not in valid Base64 encoding scheme then some bytes may have been written to the - * output byte array before IllegalargumentException is thrown. - * - * @param src the byte array to decode - * @param dst the output byte array - * - * @return The number of bytes written to the output byte array - * - * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme, or {@code dst} does not have - * enough space for decoding all input bytes. - */ - public int decode(byte[] src, byte[] dst) { - int len = outLength(src, 0, src.length); - if (dst.length < len) { - throw new IllegalArgumentException( - "Output byte array is too small for decoding all input bytes"); - } - return decode0(src, 0, src.length, dst); - } - - /** - * Decodes all bytes from the input byte buffer using the {@link Base64} encoding scheme, writing the results - * into a newly-allocated ByteBuffer. - * - *

- * Upon return, the source buffer's position will be updated to its limit; its limit will not have been changed. - * The returned output buffer's position will be zero and its limit will be the number of resulting decoded - * bytes - * - *

- * {@code IllegalArgumentException} is thrown if the input buffer is not in valid Base64 encoding scheme. The - * position of the input buffer will not be advanced in this case. - * - * @param buffer the ByteBuffer to decode - * - * @return A newly-allocated byte buffer containing the decoded bytes - * - * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme. - */ - public ByteBuffer decode(ByteBuffer buffer) { - int pos0 = buffer.position(); - try { - byte[] src; - int sp, sl; - if (buffer.hasArray()) { - src = buffer.array(); - sp = buffer.arrayOffset() + buffer.position(); - sl = buffer.arrayOffset() + buffer.limit(); - buffer.position(buffer.limit()); - } else { - src = new byte[buffer.remaining()]; - buffer.get(src); - sp = 0; - sl = src.length; - } - byte[] dst = new byte[outLength(src, sp, sl)]; - return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst)); - } catch (IllegalArgumentException iae) { - buffer.position(pos0); - throw iae; - } - } - - /** - * Returns an input stream for decoding {@link Base64} encoded byte stream. - * - *

- * The {@code read} methods of the returned {@code InputStream} will throw {@code IOException} when reading - * bytes that cannot be decoded. - * - *

- * Closing the returned input stream will close the underlying input stream. - * - * @param is the input stream - * - * @return the input stream for decoding the specified Base64 encoded byte stream - */ - public InputStream wrap(InputStream is) { - Objects.requireNonNull(is); - return new DecInputStream(is, isURL ? FROM_BASE_64_URL : FROM_BASE_64, isMIME); - } - - private int outLength(byte[] src, int sp, int sl) { - int[] base64 = isURL ? FROM_BASE_64_URL : FROM_BASE_64; - int paddings = 0; - int len = sl - sp; - if (len == 0) { - return 0; - } - if (len < 2) { - if (isMIME && base64[0] == -1) { - return 0; - } - throw new IllegalArgumentException( - "Input byte[] should at least have 2 bytes for base64 bytes"); - } - if (isMIME) { - // scan all bytes to fill out all non-alphabet. a performance - // trade-off of pre-scan or Arrays.copyOf - int n = 0; - while (sp < sl) { - int b = src[sp++] & 0xff; - if (b == '=') { - len -= (sl - sp + 1); - break; - } - if ((b = base64[b]) == -1) { - n++; - } - } - len -= n; - } else { - if (src[sl - 1] == '=') { - paddings++; - if (src[sl - 2] == '=') { - paddings++; - } - } - } - if (paddings == 0 && (len & 0x3) != 0) { - paddings = 4 - (len & 0x3); - } - return 3 * ((len + 3) / 4) - paddings; - } - - private int decode0(byte[] src, int sp, int sl, byte[] dst) { - int[] base64 = isURL ? FROM_BASE_64_URL : FROM_BASE_64; - int dp = 0; - int bits = 0; - int shiftto = 18; // pos of first byte of 4-byte atom - while (sp < sl) { - int b = src[sp++] & 0xff; - if ((b = base64[b]) < 0) { - if (b == -2) { // padding byte '=' - // = shiftto==18 unnecessary padding - // x= shiftto==12 a dangling single x - // x to be handled together with non-padding case - // xx= shiftto==6&&sp==sl missing last = - // xx=y shiftto==6 last is not = - if (shiftto == 6 && (sp == sl || src[sp++] != '=') - || shiftto == 18) { - throw new IllegalArgumentException( - "Input byte array has wrong 4-byte ending unit"); - } - break; - } - if (isMIME) // skip if for rfc2045 - { - continue; - } else { - throw new IllegalArgumentException( - "Illegal base64 character " - + Integer.toString(src[sp - 1], 16)); - } - } - bits |= b << shiftto; - shiftto -= 6; - if (shiftto < 0) { - dst[dp++] = (byte) (bits >> 16); - dst[dp++] = (byte) (bits >> 8); - dst[dp++] = (byte) (bits); - shiftto = 18; - bits = 0; - } - } - // reached end of byte array or hit padding '=' characters. - if (shiftto == 6) { - dst[dp++] = (byte) (bits >> 16); - } else if (shiftto == 0) { - dst[dp++] = (byte) (bits >> 16); - dst[dp++] = (byte) (bits >> 8); - } else if (shiftto == 12) { - // dangling single "x", incorrectly encoded. - throw new IllegalArgumentException( - "Last unit does not have enough valid bits"); - } - // anything left is invalid, if is not MIME. - // if MIME, ignore all non-base64 character - while (sp < sl) { - if (isMIME && base64[src[sp++]] < 0) { - continue; - } - throw new IllegalArgumentException( - "Input byte array has incorrect ending byte at " + sp); - } - return dp; - } - } - - /* - * An output stream for encoding bytes into the Base64. - */ - private static class EncOutputStream extends FilterOutputStream { - - private int leftover; - private int b0, b1, b2; - private boolean closed; - - private final char[] base64; // byte->base64 mapping - private final byte[] newline; // line separator, if needed - private final int linemax; - private final boolean doPadding;// whether or not to pad - private int linepos; - - EncOutputStream(OutputStream os, char[] base64, - byte[] newline, int linemax, boolean doPadding) { - super(os); - this.base64 = base64; - this.newline = newline; - this.linemax = linemax; - this.doPadding = doPadding; - } - - @Override - public void write(int b) throws IOException { - byte[] buf = new byte[1]; - buf[0] = (byte) (b & 0xff); - write(buf, 0, 1); - } - - private void checkNewline() throws IOException { - if (linepos == linemax) { - out.write(newline); - linepos = 0; - } - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (closed) { - throw new IOException("Stream is closed"); - } - if (off < 0 || len < 0 || off + len > b.length) { - throw new ArrayIndexOutOfBoundsException(); - } - if (len == 0) { - return; - } - if (leftover != 0) { - if (leftover == 1) { - b1 = b[off++] & 0xff; - len--; - if (len == 0) { - leftover++; - return; - } - } - b2 = b[off++] & 0xff; - len--; - checkNewline(); - out.write(base64[b0 >> 2]); - out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]); - out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]); - out.write(base64[b2 & 0x3f]); - linepos += 4; - } - int nBits24 = len / 3; - leftover = len - (nBits24 * 3); - while (nBits24-- > 0) { - checkNewline(); - int bits = (b[off++] & 0xff) << 16 - | (b[off++] & 0xff) << 8 - | (b[off++] & 0xff); - out.write(base64[(bits >>> 18) & 0x3f]); - out.write(base64[(bits >>> 12) & 0x3f]); - out.write(base64[(bits >>> 6) & 0x3f]); - out.write(base64[bits & 0x3f]); - linepos += 4; - } - if (leftover == 1) { - b0 = b[off++] & 0xff; - } else if (leftover == 2) { - b0 = b[off++] & 0xff; - b1 = b[off++] & 0xff; - } - } - - @Override - public void close() throws IOException { - if (!closed) { - closed = true; - if (leftover == 1) { - checkNewline(); - out.write(base64[b0 >> 2]); - out.write(base64[(b0 << 4) & 0x3f]); - if (doPadding) { - out.write('='); - out.write('='); - } - } else if (leftover == 2) { - checkNewline(); - out.write(base64[b0 >> 2]); - out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]); - out.write(base64[(b1 << 2) & 0x3f]); - if (doPadding) { - out.write('='); - } - } - leftover = 0; - out.close(); - } - } - } - - /* - * An input stream for decoding Base64 bytes - */ - private static class DecInputStream extends InputStream { - - private final InputStream is; - private final boolean isMIME; - private final int[] base64; // base64 -> byte mapping - private int bits; // 24-bit buffer for decoding - private int nextin = 18; // next available "off" in "bits" for input; - // -> 18, 12, 6, 0 - private int nextout = -8; // next available "off" in "bits" for output; - // -> 8, 0, -8 (no byte for output) - private boolean eof; - private boolean closed; - - private final byte[] sbBuf = new byte[1]; - - DecInputStream(InputStream is, int[] base64, boolean isMIME) { - this.is = is; - this.base64 = base64; - this.isMIME = isMIME; - } - - @Override - public int read() throws IOException { - return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if (closed) { - throw new IOException("Stream is closed"); - } - if (eof && nextout < 0) // eof and no leftover - { - return -1; - } - if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } - int oldOff = off; - if (nextout >= 0) { // leftover output byte(s) in bits buf - do { - if (len == 0) { - return off - oldOff; - } - b[off++] = (byte) (bits >> nextout); - len--; - nextout -= 8; - } while (nextout >= 0); - bits = 0; - } - while (len > 0) { - int v = is.read(); - if (v == -1) { - eof = true; - if (nextin != 18) { - if (nextin == 12) { - throw new IOException("Base64 stream has one un-decoded dangling byte."); - } - // treat ending xx/xxx without padding character legal. - // same logic as v == '=' below - b[off++] = (byte) (bits >> (16)); - len--; - if (nextin == 0) { // only one padding byte - if (len == 0) { // no enough output space - bits >>= 8; // shift to lowest byte - nextout = 0; - } else { - b[off++] = (byte) (bits >> 8); - } - } - } - if (off == oldOff) { - return -1; - } else { - return off - oldOff; - } - } - if (v == '=') { // padding byte(s) - // = shiftto==18 unnecessary padding - // x= shiftto==12 dangling x, invalid unit - // xx= shiftto==6 && missing last '=' - // xx=y or last is not '=' - if (nextin == 18 || nextin == 12 - || nextin == 6 && is.read() != '=') { - throw new IOException("Illegal base64 ending sequence:" + nextin); - } - b[off++] = (byte) (bits >> (16)); - len--; - if (nextin == 0) { // only one padding byte - if (len == 0) { // no enough output space - bits >>= 8; // shift to lowest byte - nextout = 0; - } else { - b[off++] = (byte) (bits >> 8); - } - } - eof = true; - break; - } - if ((v = base64[v]) == -1) { - if (isMIME) // skip if for rfc2045 - { - continue; - } else { - throw new IOException("Illegal base64 character " - + Integer.toString(v, 16)); - } - } - bits |= v << nextin; - if (nextin == 0) { - nextin = 18; // clear for next - nextout = 16; - while (nextout >= 0) { - b[off++] = (byte) (bits >> nextout); - len--; - nextout -= 8; - if (len == 0 && nextout >= 0) { // don't clean "bits" - return off - oldOff; - } - } - bits = 0; - } else { - nextin -= 6; - } - } - return off - oldOff; - } - - @Override - public int available() throws IOException { - if (closed) { - throw new IOException("Stream is closed"); - } - return is.available(); // TBD: - } - - @Override - public void close() throws IOException { - if (!closed) { - closed = true; - is.close(); - } - } - } -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/java8/Consumer.java b/scribejava-core/src/main/java/com/github/scribejava/core/java8/Consumer.java deleted file mode 100644 index 83306b7be..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/java8/Consumer.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.github.scribejava.core.java8; - -/** - * Represents an operation that accepts a single input argument and returns no result. Unlike most other functional - * interfaces, {@code Consumer} is expected to operate via side-effects. - * - *

- * This is a functional interface - * whose functional method is {@link #accept(Object)}. - * - * @param the type of the input to the operation - * - * @since 1.8 - */ -public interface Consumer { - - /** - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(T t); -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/model/DeviceAuthorization.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/DeviceAuthorization.java new file mode 100644 index 000000000..dfdc42c36 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/DeviceAuthorization.java @@ -0,0 +1,105 @@ +package com.github.scribejava.core.model; + +/** + * Device Authorization Response + * + * @see rfc8628 + */ +public class DeviceAuthorization { + + /** + * device_code + * + * REQUIRED. The device verification code. + */ + private final String deviceCode; + + /** + * user_code + * + * REQUIRED. The end-user verification code. + */ + private final String userCode; + + /** + * verification_uri + * + * REQUIRED. The end-user verification URI on the authorization server. The URI should be short and easy to remember + * as end users will be asked to manually type it into their user agent. + */ + private final String verificationUri; + + /** + * verification_uri_complete + * + * OPTIONAL. A verification URI that includes the "user_code" (or other information with the same function as the + * "user_code"), which is designed for non-textual transmission. + */ + private String verificationUriComplete; + + /** + * expires_in + * + * REQUIRED. The lifetime in seconds of the "device_code" and "user_code". + */ + private final int expiresInSeconds; + + /** + * interval + * + * OPTIONAL. The minimum amount of time in seconds that the client SHOULD wait between polling requests to the token + * endpoint. If no value is provided, clients MUST use 5 as the default. + */ + private int intervalSeconds = 5; + + public DeviceAuthorization(String deviceCode, String userCode, String verificationUri, int expiresInSeconds) { + this.deviceCode = deviceCode; + this.userCode = userCode; + this.verificationUri = verificationUri; + this.expiresInSeconds = expiresInSeconds; + } + + public void setVerificationUriComplete(String verificationUriComplete) { + this.verificationUriComplete = verificationUriComplete; + } + + public void setIntervalSeconds(int intervalSeconds) { + this.intervalSeconds = intervalSeconds; + } + + public String getDeviceCode() { + return deviceCode; + } + + public String getUserCode() { + return userCode; + } + + public String getVerificationUri() { + return verificationUri; + } + + public String getVerificationUriComplete() { + return verificationUriComplete; + } + + public long getExpiresInSeconds() { + return expiresInSeconds; + } + + public int getIntervalSeconds() { + return intervalSeconds; + } + + @Override + public String toString() { + return "DeviceAuthorization{" + + "'deviceCode'='" + deviceCode + + "', 'userCode'='" + userCode + + "', 'verificationUri'='" + verificationUri + + "', 'verificationUriComplete'='" + verificationUriComplete + + "', 'expiresInSeconds'='" + expiresInSeconds + + "', 'intervalSeconds'='" + intervalSeconds + "'}"; + } + +} 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 37b951f13..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,10 +5,9 @@ /** * Represents an OAuth 2 Access token. - *

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

+ * @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 86ca38d88..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,40 +1,31 @@ package com.github.scribejava.core.model; -import com.github.scribejava.core.exceptions.OAuthException; +import com.github.scribejava.core.oauth2.OAuth2Error; +import java.io.IOException; import java.net.URI; /** * Representing "5.2. Error Response" */ -public class OAuth2AccessTokenErrorResponse extends OAuthException { +public class OAuth2AccessTokenErrorResponse extends OAuthResponseException { private static final long serialVersionUID = 2309424849700276816L; - public enum ErrorCode { - invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope, - /** - * @see RFC 7009, 2.2.1. Error Response - */ - unsupported_token_type - } - - private final ErrorCode errorCode; + private final OAuth2Error error; private final String errorDescription; private final URI errorUri; - private final String rawResponse; - public OAuth2AccessTokenErrorResponse(ErrorCode errorCode, String errorDescription, URI errorUri, - String rawResponse) { + public OAuth2AccessTokenErrorResponse(OAuth2Error error, String errorDescription, URI errorUri, + Response rawResponse) throws IOException { super(rawResponse); - this.errorCode = errorCode; + this.error = error; this.errorDescription = errorDescription; this.errorUri = errorUri; - this.rawResponse = rawResponse; } - public ErrorCode getErrorCode() { - return errorCode; + public OAuth2Error getError() { + return error; } public String getErrorDescription() { @@ -45,7 +36,4 @@ public URI getErrorUri() { return errorUri; } - public String getRawResponse() { - return rawResponse; - } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthAsyncRequestCallback.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthAsyncRequestCallback.java index 10f398fc4..7719314d2 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthAsyncRequestCallback.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthAsyncRequestCallback.java @@ -2,6 +2,11 @@ public interface OAuthAsyncRequestCallback { + /** + * Implementations of this method should close provided response in case it implements {@link java.io.Closeable} + * + * @param response response + */ void onCompleted(T response); void onThrowable(Throwable t); diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthRequest.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthRequest.java index a33ac7d72..ccf26157c 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthRequest.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthRequest.java @@ -1,7 +1,8 @@ package com.github.scribejava.core.model; import com.github.scribejava.core.exceptions.OAuthException; -import com.github.scribejava.core.httpclient.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.BodyPartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -10,6 +11,7 @@ import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; /** * The representation of an OAuth HttpRequest. @@ -22,7 +24,7 @@ public class OAuthRequest { private final Verb verb; private final ParameterList querystringParams = new ParameterList(); private final ParameterList bodyParams = new ParameterList(); - private final Map headers = new HashMap<>(); + private final Map headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); private String charset; @@ -95,7 +97,7 @@ public String getCompleteUrl() { * @param value the header value */ public void addHeader(String key, String value) { - this.headers.put(key, value); + headers.put(key, value); } /** @@ -105,7 +107,7 @@ public void addHeader(String key, String value) { * @param value the parameter value */ public void addBodyParameter(String key, String value) { - this.bodyParams.add(key, value); + bodyParams.add(key, value); } /** @@ -115,7 +117,7 @@ public void addBodyParameter(String key, String value) { * @param value the parameter value */ public void addQuerystringParameter(String key, String value) { - this.querystringParams.add(key, value); + querystringParams.add(key, value); } public void addParameter(String key, String value) { @@ -126,41 +128,45 @@ public void addParameter(String key, String value) { } } - /** - * Set boundary of multipart request - * - * @param boundary can be any string - */ - public void initMultipartBoundary(String boundary) { - multipartPayload = new MultipartPayload(boundary == null - ? Long.toString(System.currentTimeMillis()) - : boundary); + public MultipartPayload getMultipartPayload() { + return multipartPayload; } - /** - * init boundary of multipart request with default boundary - */ - public void initMultipartBoundary() { - initMultipartBoundary(null); + public void setMultipartPayload(MultipartPayload multipartPayload) { + this.multipartPayload = multipartPayload; } - /** - * you can invoke {@link #initMultipartBoundary(java.lang.String) } to set custom boundary - */ - public void addMultipartPayload(String contentDisposition, String contentType, byte[] payload) { - if (multipartPayload == null) { - initMultipartBoundary(); - } - multipartPayload.addMultipartPayload(contentDisposition, contentType, payload); + public void initMultipartPayload() { + this.multipartPayload = new MultipartPayload(); + } + + public void initMultipartPayload(String boundary) { + this.multipartPayload = new MultipartPayload(boundary); } - public void setMultipartPayload(String contentDisposition, String contentType, byte[] payload) { - setMultipartPayload(null, contentDisposition, contentType, payload); + public void initMultipartPayload(String subtype, String boundary) { + this.multipartPayload = new MultipartPayload(subtype, boundary); } - public void setMultipartPayload(String boundary, String contentDisposition, String contentType, byte[] payload) { - initMultipartBoundary(boundary); - multipartPayload.addMultipartPayload(contentDisposition, contentType, payload); + public void initMultipartPayload(Map headers) { + this.multipartPayload = new MultipartPayload(headers); + } + + public void initMultipartPayload(String boundary, Map headers) { + this.multipartPayload = new MultipartPayload(boundary, headers); + } + + public void initMultipartPayload(String subtype, String boundary, Map headers) { + this.multipartPayload = new MultipartPayload(subtype, boundary, headers); + } + + public void setBodyPartPayloadInMultipartPayload(BodyPartPayload bodyPartPayload) { + initMultipartPayload(); + addBodyPartPayloadInMultipartPayload(bodyPartPayload); + } + + public void addBodyPartPayloadInMultipartPayload(BodyPartPayload bodyPartPayload) { + multipartPayload.addBodyPart(bodyPartPayload); } /** @@ -277,10 +283,6 @@ public byte[] getByteArrayPayload() { } } - public MultipartPayload getMultipartPayloads() { - return multipartPayload; - } - public File getFilePayload() { return filePayload; } @@ -313,6 +315,15 @@ public void setCharset(String charsetName) { public interface ResponseConverter { + /** + * Implementations of this method should close provided Response in case response is not included in the return + * Object of type <T> Then responsibility to close response is in on the + * {@link com.github.scribejava.core.model.OAuthAsyncRequestCallback#onCompleted(java.lang.Object) } + * + * @param response response + * @return T + * @throws IOException IOException + */ T convert(Response response) throws IOException; } 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/model/Response.java b/scribejava-core/src/main/java/com/github/scribejava/core/model/Response.java index 4a84c76ef..553c6cda5 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/model/Response.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/model/Response.java @@ -4,14 +4,24 @@ import java.io.InputStream; import java.util.Map; import com.github.scribejava.core.utils.StreamUtils; +import java.io.Closeable; -public class Response { +/** + * An HTTP response. + * + *

+ * This response may contain a non-null body stream of the HttpUrlConnection. If so, this body must be closed to avoid + * leaking resources. Use either {@link #getBody()} or {@link #close()} to close the body. + */ +public class Response implements Closeable { private final int code; private final String message; private final Map headers; private String body; private InputStream stream; + private Closeable[] closeables; + private boolean closed; private Response(int code, String message, Map headers) { this.code = code; @@ -19,9 +29,11 @@ private Response(int code, String message, Map headers) { this.headers = headers; } - public Response(int code, String message, Map headers, InputStream stream) { + public Response(int code, String message, Map headers, InputStream stream, + Closeable... closeables) { this(code, message, headers); this.stream = stream; + this.closeables = closeables; } public Response(int code, String message, Map headers, String body) { @@ -45,6 +57,12 @@ public boolean isSuccessful() { return code >= 200 && code < 400; } + /** + * Returns the response body as a string, closing the stream that backs it. Idempotent. + * + * @return body as string + * @throws IOException IO Exception + */ public String getBody() throws IOException { return body == null ? parseBodyContents() : body; } @@ -100,11 +118,37 @@ public String getHeader(String name) { @Override public String toString() { - return "Response{" + - "code=" + code + - ", message='" + message + '\'' + - ", body='" + body + '\'' + - ", headers=" + headers + - '}'; + return "Response{" + + "code=" + code + + ", message='" + message + '\'' + + ", body='" + body + '\'' + + ", headers=" + headers + + '}'; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + IOException ioException = null; + if (closeables != null) { + for (Closeable closeable : closeables) { + if (closeable == null) { + continue; + } + try { + closeable.close(); + } catch (IOException ioE) { + if (ioException != null) { + ioException = ioE; + } + } + } + } + if (ioException != null) { + throw ioException; + } + closed = true; } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/AccessTokenRequestParams.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/AccessTokenRequestParams.java new file mode 100644 index 000000000..d45377a56 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/AccessTokenRequestParams.java @@ -0,0 +1,79 @@ +package com.github.scribejava.core.oauth; + +import com.github.scribejava.core.builder.ScopeBuilder; +import java.util.HashMap; +import java.util.Map; + +/** + * not thread safe + */ +public class AccessTokenRequestParams { + + private final String code; + private String pkceCodeVerifier; + private String scope; + private Map extraParameters; + + public AccessTokenRequestParams(String code) { + this.code = code; + } + + public static AccessTokenRequestParams create(String code) { + return new AccessTokenRequestParams(code); + } + + public AccessTokenRequestParams pkceCodeVerifier(String pkceCodeVerifier) { + this.pkceCodeVerifier = pkceCodeVerifier; + return this; + } + + public AccessTokenRequestParams scope(String scope) { + this.scope = scope; + return this; + } + + public AccessTokenRequestParams scope(ScopeBuilder scope) { + this.scope = scope.build(); + return this; + } + + public AccessTokenRequestParams addExtraParameters(Map extraParameters) { + if (extraParameters == null || extraParameters.isEmpty()) { + return this; + } + if (this.extraParameters == null) { + extraParameters = new HashMap<>(); + } + this.extraParameters.putAll(extraParameters); + return this; + } + + public AccessTokenRequestParams addExtraParameter(String name, String value) { + if (this.extraParameters == null) { + extraParameters = new HashMap<>(); + } + this.extraParameters.put(name, value); + return this; + } + + public AccessTokenRequestParams setExtraParameters(Map extraParameters) { + this.extraParameters = extraParameters; + return this; + } + + public Map getExtraParameters() { + return extraParameters; + } + + public String getCode() { + return code; + } + + public String getPkceCodeVerifier() { + return pkceCodeVerifier; + } + + public String getScope() { + return scope; + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/AuthorizationUrlBuilder.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/AuthorizationUrlBuilder.java new file mode 100644 index 000000000..fd02f60dd --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/AuthorizationUrlBuilder.java @@ -0,0 +1,61 @@ +package com.github.scribejava.core.oauth; + +import com.github.scribejava.core.pkce.PKCE; +import com.github.scribejava.core.pkce.PKCEService; +import java.util.HashMap; +import java.util.Map; + +public class AuthorizationUrlBuilder { + + private final OAuth20Service oauth20Service; + + private String state; + private Map additionalParams; + private PKCE pkce; + private String scope; + + public AuthorizationUrlBuilder(OAuth20Service oauth20Service) { + this.oauth20Service = oauth20Service; + } + + public AuthorizationUrlBuilder state(String state) { + this.state = state; + return this; + } + + public AuthorizationUrlBuilder additionalParams(Map additionalParams) { + this.additionalParams = additionalParams; + return this; + } + + public AuthorizationUrlBuilder pkce(PKCE pkce) { + this.pkce = pkce; + return this; + } + + public AuthorizationUrlBuilder initPKCE() { + this.pkce = PKCEService.defaultInstance().generatePKCE(); + return this; + } + + public AuthorizationUrlBuilder scope(String scope) { + this.scope = scope; + return this; + } + + public PKCE getPkce() { + return pkce; + } + + public String build() { + final Map params; + if (pkce == null) { + params = additionalParams; + } else { + params = additionalParams == null ? new HashMap() : new HashMap<>(additionalParams); + params.putAll(pkce.getAuthorizationUrlParams()); + } + return oauth20Service.getApi().getAuthorizationUrl(oauth20Service.getResponseType(), oauth20Service.getApiKey(), + oauth20Service.getCallback(), scope == null ? oauth20Service.getDefaultScope() : scope, state, params); + } +} 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 b168a9f2c..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 @@ -22,27 +22,31 @@ public class OAuth10aService extends OAuthService { private static final String VERSION = "1.0"; - private final OutputStream debugStream; private final DefaultApi10a api; + private final String scope; public OAuth10aService(DefaultApi10a api, String apiKey, String apiSecret, String callback, String scope, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - super(apiKey, apiSecret, callback, scope, userAgent, httpClientConfig, httpClient); - this.debugStream = debugStream; + super(apiKey, apiSecret, callback, debugStream, userAgent, httpClientConfig, httpClient); this.api = api; + this.scope = scope; } public OAuth1RequestToken getRequestToken() throws IOException, InterruptedException, ExecutionException { - log("obtaining request token from %s", api.getRequestTokenEndpoint()); + if (isDebug()) { + log("obtaining request token from %s", api.getRequestTokenEndpoint()); + } final OAuthRequest request = prepareRequestTokenRequest(); log("sending request..."); - final Response response = execute(request); - final String body = response.getBody(); - - log("response status code: %s", response.getCode()); - log("response body: %s", body); - return api.getRequestTokenExtractor().extract(response); + try ( Response response = execute(request)) { + if (isDebug()) { + final String body = response.getBody(); + log("response status code: %s", response.getCode()); + log("response body: %s", body); + } + return api.getRequestTokenExtractor().extract(response); + } } public Future getRequestTokenAsync() { @@ -50,12 +54,16 @@ public Future getRequestTokenAsync() { } public Future getRequestTokenAsync(OAuthAsyncRequestCallback callback) { - log("async obtaining request token from %s", api.getRequestTokenEndpoint()); + if (isDebug()) { + log("async obtaining request token from %s", api.getRequestTokenEndpoint()); + } final OAuthRequest request = prepareRequestTokenRequest(); return execute(request, callback, new OAuthRequest.ResponseConverter() { @Override public OAuth1RequestToken convert(Response response) throws IOException { - return getApi().getRequestTokenExtractor().extract(response); + final OAuth1RequestToken token = getApi().getRequestTokenExtractor().extract(response); + response.close(); + return token; } }); } @@ -66,7 +74,9 @@ protected OAuthRequest prepareRequestTokenRequest() { if (callback == null) { callback = OAuthConstants.OOB; } - log("setting oauth_callback to %s", callback); + if (isDebug()) { + log("setting oauth_callback to %s", callback); + } request.addOAuthParameter(OAuthConstants.CALLBACK, callback); addOAuthParams(request, ""); appendSignature(request); @@ -79,21 +89,25 @@ protected void addOAuthParams(OAuthRequest request, String tokenSecret) { request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, getApiKey()); request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod()); request.addOAuthParameter(OAuthConstants.VERSION, getVersion()); - final String scope = getScope(); if (scope != null) { request.addOAuthParameter(OAuthConstants.SCOPE, scope); } request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, tokenSecret)); - log("appended additional OAuth parameters: %s", request.getOauthParameters()); + if (isDebug()) { + log("appended additional OAuth parameters: %s", request.getOauthParameters()); + } } public OAuth1AccessToken getAccessToken(OAuth1RequestToken requestToken, String oauthVerifier) throws IOException, InterruptedException, ExecutionException { - log("obtaining access token from %s", api.getAccessTokenEndpoint()); + if (isDebug()) { + log("obtaining access token from %s", api.getAccessTokenEndpoint()); + } final OAuthRequest request = prepareAccessTokenRequest(requestToken, oauthVerifier); - final Response response = execute(request); - return api.getAccessTokenExtractor().extract(response); + try ( Response response = execute(request)) { + return api.getAccessTokenExtractor().extract(response); + } } public Future getAccessTokenAsync(OAuth1RequestToken requestToken, String oauthVerifier) { @@ -111,12 +125,16 @@ public Future getAccessTokenAsync(OAuth1RequestToken requestT */ public Future getAccessTokenAsync(OAuth1RequestToken requestToken, String oauthVerifier, OAuthAsyncRequestCallback callback) { - log("async obtaining access token from %s", api.getAccessTokenEndpoint()); + if (isDebug()) { + log("async obtaining access token from %s", api.getAccessTokenEndpoint()); + } final OAuthRequest request = prepareAccessTokenRequest(requestToken, oauthVerifier); return execute(request, callback, new OAuthRequest.ResponseConverter() { @Override public OAuth1AccessToken convert(Response response) throws IOException { - return getApi().getAccessTokenExtractor().extract(response); + final OAuth1AccessToken token = getApi().getAccessTokenExtractor().extract(response); + response.close(); + return token; } }); } @@ -125,19 +143,25 @@ protected OAuthRequest prepareAccessTokenRequest(OAuth1RequestToken requestToken final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); request.addOAuthParameter(OAuthConstants.VERIFIER, oauthVerifier); - log("setting token to: %s and verifier to: %s", requestToken, oauthVerifier); + if (isDebug()) { + log("setting token to: %s and verifier to: %s", requestToken, oauthVerifier); + } addOAuthParams(request, requestToken.getTokenSecret()); appendSignature(request); return request; } public void signRequest(OAuth1AccessToken token, OAuthRequest request) { - log("signing request: %s", request.getCompleteUrl()); + if (isDebug()) { + log("signing request: %s", request.getCompleteUrl()); + } if (!token.isEmpty() || api.isEmptyOAuthTokenParamIsRequired()) { request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken()); } - log("setting token to: %s", token); + if (isDebug()) { + log("setting token to: %s", token); + } addOAuthParams(request, token.getTokenSecret()); appendSignature(request); } @@ -162,21 +186,23 @@ private String getSignature(OAuthRequest request, String tokenSecret) { final String baseString = api.getBaseStringExtractor().extract(request); final String signature = api.getSignatureService().getSignature(baseString, getApiSecret(), tokenSecret); - log("base string is: %s", baseString); - log("signature is: %s", signature); + if (isDebug()) { + log("base string is: %s", baseString); + log("signature is: %s", signature); + } return signature; } protected void appendSignature(OAuthRequest request) { final OAuth1SignatureType signatureType = api.getSignatureType(); switch (signatureType) { - case Header: + case HEADER: log("using Http Header signature"); final String oauthHeader = api.getHeaderExtractor().extract(request); request.addHeader(OAuthConstants.HEADER, oauthHeader); break; - case QueryString: + case QUERY_STRING: log("using Querystring signature"); for (Map.Entry oauthParameter : request.getOauthParameters().entrySet()) { @@ -191,15 +217,4 @@ protected void appendSignature(OAuthRequest request) { public DefaultApi10a getApi() { return api; } - - public void log(String messagePattern, Object... params) { - if (debugStream != null) { - final String message = String.format(messagePattern, params) + '\n'; - try { - debugStream.write(message.getBytes("UTF8")); - } catch (IOException | RuntimeException e) { - throw new RuntimeException("there were problems while writting to the debug stream", e); - } - } - } } 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 5b10849af..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 @@ -1,149 +1,262 @@ package com.github.scribejava.core.oauth; -import java.io.IOException; -import java.util.concurrent.Future; import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.github.scribejava.core.model.DeviceAuthorization; import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; import com.github.scribejava.core.model.OAuth2Authorization; 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.Response; import com.github.scribejava.core.model.Verb; -import com.github.scribejava.core.pkce.AuthorizationUrlWithPKCE; +import com.github.scribejava.core.oauth2.OAuth2Error; import com.github.scribejava.core.pkce.PKCE; -import com.github.scribejava.core.pkce.PKCEService; -import java.util.HashMap; +import com.github.scribejava.core.revoke.TokenTypeHint; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.util.Map; import java.util.concurrent.ExecutionException; -import com.github.scribejava.core.revoke.TokenTypeHint; +import java.util.concurrent.Future; public class OAuth20Service extends OAuthService { private static final String VERSION = "2.0"; - private static final PKCEService PKCE_SERVICE = new PKCEService(); private final DefaultApi20 api; private final String responseType; - private final String state; + private final String defaultScope; - public OAuth20Service(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, - String state, String responseType, String userAgent, HttpClientConfig httpClientConfig, + public OAuth20Service(DefaultApi20 api, String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - super(apiKey, apiSecret, callback, scope, userAgent, httpClientConfig, httpClient); + super(apiKey, apiSecret, callback, debugStream, userAgent, httpClientConfig, httpClient); this.responseType = responseType; - this.state = state; this.api = api; + this.defaultScope = defaultScope; } - //protected to facilitate mocking - protected OAuth2AccessToken sendAccessTokenRequestSync(OAuthRequest request) - throws IOException, InterruptedException, ExecutionException { - return api.getAccessTokenExtractor().extract(execute(request)); + // ===== common OAuth methods ===== + /** + * {@inheritDoc} + */ + @Override + public String getVersion() { + return VERSION; } - //protected to facilitate mocking - protected Future sendAccessTokenRequestAsync(OAuthRequest request) { - return sendAccessTokenRequestAsync(request, null); + public void signRequest(String accessToken, OAuthRequest request) { + api.getBearerSignature().signRequest(accessToken, request); } - //protected to facilitate mocking - protected Future sendAccessTokenRequestAsync(OAuthRequest request, - OAuthAsyncRequestCallback callback) { + public void signRequest(OAuth2AccessToken accessToken, OAuthRequest request) { + signRequest(accessToken == null ? null : accessToken.getAccessToken(), request); + } - return execute(request, callback, new OAuthRequest.ResponseConverter() { - @Override - public OAuth2AccessToken convert(Response response) throws IOException { - return getApi().getAccessTokenExtractor().extract(response); + /** + * 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 Future getAccessTokenAsync(String code) { - return getAccessToken(code, null, null); + public String getResponseType() { + return responseType; } - public Future getAccessTokenAsync(String code, String pkceCodeVerifier) { - return getAccessToken(code, null, pkceCodeVerifier); + public String getDefaultScope() { + return defaultScope; } - public OAuth2AccessToken getAccessToken(String code) throws IOException, InterruptedException, ExecutionException { - return getAccessToken(code, (String) null); + 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()); + } } - public OAuth2AccessToken getAccessToken(String code, String pkceCodeVerifier) + // ===== common AccessToken request methods ===== + //protected to facilitate mocking + protected OAuth2AccessToken sendAccessTokenRequestSync(OAuthRequest request) throws IOException, InterruptedException, ExecutionException { - final OAuthRequest request = createAccessTokenRequest(code, pkceCodeVerifier); + if (isDebug()) { + log("send request for access token synchronously to %s", request.getCompleteUrl()); + } + try (Response response = execute(request)) { + if (isDebug()) { + log("response status code: %s", response.getCode()); + log("response body: %s", response.getBody()); + } - return sendAccessTokenRequestSync(request); + return api.getAccessTokenExtractor().extract(response); + } } - /** - * Start the request to retrieve the access token. The optionally provided callback will be called with the Token - * when it is available. - * - * @param code code - * @param callback optional callback - * @param pkceCodeVerifier pkce Code Verifier - * @return Future - */ - public Future getAccessToken(String code, OAuthAsyncRequestCallback callback, - String pkceCodeVerifier) { - final OAuthRequest request = createAccessTokenRequest(code, pkceCodeVerifier); - - return sendAccessTokenRequestAsync(request, callback); + //protected to facilitate mocking + protected Future sendAccessTokenRequestAsync(OAuthRequest request) { + return sendAccessTokenRequestAsync(request, null); } - public Future getAccessToken(String code, + //protected to facilitate mocking + protected Future sendAccessTokenRequestAsync(OAuthRequest request, OAuthAsyncRequestCallback callback) { + if (isDebug()) { + log("send request for access token asynchronously to %s", request.getCompleteUrl()); + } - return getAccessToken(code, callback, null); + return execute(request, callback, new OAuthRequest.ResponseConverter() { + @Override + public OAuth2AccessToken convert(Response response) throws IOException { + log("received response for access token"); + if (isDebug()) { + log("response status code: %s", response.getCode()); + log("response body: %s", response.getBody()); + } + final OAuth2AccessToken token = api.getAccessTokenExtractor().extract(response); + response.close(); + return token; + } + }); } - protected OAuthRequest createAccessTokenRequest(String code) { + // ===== 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, code); - request.addParameter(OAuthConstants.REDIRECT_URI, getCallback()); - final String scope = getScope(); + 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); - return request; - } - protected OAuthRequest createAccessTokenRequest(String code, String pkceCodeVerifier) { - final OAuthRequest request = createAccessTokenRequest(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 refreshAccessTokenAsync(String refreshToken) { - return refreshAccessToken(refreshToken, null); + public Future getAccessTokenAsync(String code) { + return getAccessToken(AccessTokenRequestParams.create(code), null); } - public OAuth2AccessToken refreshAccessToken(String refreshToken) - throws IOException, InterruptedException, ExecutionException { - final OAuthRequest request = createRefreshTokenRequest(refreshToken); + public Future getAccessTokenAsync(AccessTokenRequestParams params) { + return getAccessToken(params, null); + } - return sendAccessTokenRequestSync(request); + public OAuth2AccessToken getAccessToken(String code) throws IOException, InterruptedException, ExecutionException { + return getAccessToken(AccessTokenRequestParams.create(code)); } - public Future refreshAccessToken(String refreshToken, + public OAuth2AccessToken getAccessToken(AccessTokenRequestParams params) + throws IOException, InterruptedException, ExecutionException { + return sendAccessTokenRequestSync(createAccessTokenRequest(params)); + } + + /** + * Start the request to retrieve the access token. The optionally provided callback will be called with the Token + * when it is available. + * + * @param params params + * @param callback optional callback + * @return Future + */ + public Future getAccessToken(AccessTokenRequestParams params, OAuthAsyncRequestCallback callback) { - final OAuthRequest request = createRefreshTokenRequest(refreshToken); + return sendAccessTokenRequestAsync(createAccessTokenRequest(params), callback); + } - return sendAccessTokenRequestAsync(request, callback); + public Future getAccessToken(String code, + OAuthAsyncRequestCallback callback) { + return getAccessToken(AccessTokenRequestParams.create(code), callback); } - protected OAuthRequest createRefreshTokenRequest(String refreshToken) { + // ===== 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"); } @@ -151,160 +264,182 @@ protected OAuthRequest createRefreshTokenRequest(String refreshToken) { api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); - final String scope = getScope(); if (scope != null) { request.addParameter(OAuthConstants.SCOPE, scope); + } else if (defaultScope != null) { + request.addParameter(OAuthConstants.SCOPE, defaultScope); } request.addParameter(OAuthConstants.REFRESH_TOKEN, refreshToken); request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.REFRESH_TOKEN); + + logRequestWithParams("refresh token", request); + return request; } - public OAuth2AccessToken getAccessTokenPasswordGrant(String uname, String password) + public Future refreshAccessTokenAsync(String refreshToken) { + return refreshAccessToken(refreshToken, (OAuthAsyncRequestCallback) null); + } + + public Future refreshAccessTokenAsync(String refreshToken, String scope) { + return refreshAccessToken(refreshToken, scope, null); + } + + public OAuth2AccessToken refreshAccessToken(String refreshToken) throws IOException, InterruptedException, ExecutionException { - final OAuthRequest request = createAccessTokenPasswordGrantRequest(uname, password); + return refreshAccessToken(refreshToken, (String) null); + } + + public OAuth2AccessToken refreshAccessToken(String refreshToken, String scope) + throws IOException, InterruptedException, ExecutionException { + final OAuthRequest request = createRefreshTokenRequest(refreshToken, scope); return sendAccessTokenRequestSync(request); } - public Future getAccessTokenPasswordGrantAsync(String uname, String password) { - return getAccessTokenPasswordGrantAsync(uname, password, null); + public Future refreshAccessToken(String refreshToken, + OAuthAsyncRequestCallback callback) { + final OAuthRequest request = createRefreshTokenRequest(refreshToken, null); + + return sendAccessTokenRequestAsync(request, callback); } - /** - * Request Access Token Password Grant async version - * - * @param uname User name - * @param password User password - * @param callback Optional callback - * @return Future - */ - public Future getAccessTokenPasswordGrantAsync(String uname, String password, + public Future refreshAccessToken(String refreshToken, String scope, OAuthAsyncRequestCallback callback) { - final OAuthRequest request = createAccessTokenPasswordGrantRequest(uname, password); + final OAuthRequest request = createRefreshTokenRequest(refreshToken, scope); return sendAccessTokenRequestAsync(request, callback); } - protected OAuthRequest createAccessTokenPasswordGrantRequest(String username, String password) { + // ===== 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); - final String scope = getScope(); if (scope != null) { request.addParameter(OAuthConstants.SCOPE, scope); + } else if (defaultScope != null) { + request.addParameter(OAuthConstants.SCOPE, defaultScope); } request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.PASSWORD); api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + logRequestWithParams("access token password grant", request); + return request; } - public Future getAccessTokenClientCredentialsGrantAsync() { - return getAccessTokenClientCredentialsGrant(null); + public OAuth2AccessToken getAccessTokenPasswordGrant(String username, String password) + throws IOException, InterruptedException, ExecutionException { + final OAuthRequest request = createAccessTokenPasswordGrantRequest(username, password, null); + + return sendAccessTokenRequestSync(request); } - public OAuth2AccessToken getAccessTokenClientCredentialsGrant() + public OAuth2AccessToken getAccessTokenPasswordGrant(String username, String password, String scope) throws IOException, InterruptedException, ExecutionException { - final OAuthRequest request = createAccessTokenClientCredentialsGrantRequest(); + final OAuthRequest request = createAccessTokenPasswordGrantRequest(username, password, scope); return sendAccessTokenRequestSync(request); } + public Future getAccessTokenPasswordGrantAsync(String username, String password) { + return getAccessTokenPasswordGrantAsync(username, password, + (OAuthAsyncRequestCallback) null); + } + + public Future getAccessTokenPasswordGrantAsync(String username, String password, String scope) { + return getAccessTokenPasswordGrantAsync(username, password, scope, null); + } + /** - * Start the request to retrieve the access token using client-credentials grant. The optionally provided callback - * will be called with the Token when it is available. + * Request Access Token Password Grant async version * - * @param callback optional callback + * @param username User name + * @param password User password + * @param callback Optional callback * @return Future */ - public Future getAccessTokenClientCredentialsGrant( + public Future getAccessTokenPasswordGrantAsync(String username, String password, + OAuthAsyncRequestCallback callback) { + final OAuthRequest request = createAccessTokenPasswordGrantRequest(username, password, null); + + return sendAccessTokenRequestAsync(request, callback); + } + + public Future getAccessTokenPasswordGrantAsync(String username, String password, String scope, OAuthAsyncRequestCallback callback) { - final OAuthRequest request = createAccessTokenClientCredentialsGrantRequest(); + final OAuthRequest request = createAccessTokenPasswordGrantRequest(username, password, scope); return sendAccessTokenRequestAsync(request, callback); } - protected OAuthRequest createAccessTokenClientCredentialsGrantRequest() { + // ===== get AccessToken client credentials flow methods ===== + protected OAuthRequest createAccessTokenClientCredentialsGrantRequest(String scope) { final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); - final String scope = getScope(); 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 Future getAccessTokenClientCredentialsGrantAsync() { + return getAccessTokenClientCredentialsGrant((OAuthAsyncRequestCallback) null); } - public void signRequest(String accessToken, OAuthRequest request) { - api.getSignatureType().signRequest(accessToken, request); + public Future getAccessTokenClientCredentialsGrantAsync(String scope) { + return getAccessTokenClientCredentialsGrant(scope, null); } - public void signRequest(OAuth2AccessToken accessToken, OAuthRequest request) { - signRequest(accessToken == null ? null : accessToken.getAccessToken(), request); - } + public OAuth2AccessToken getAccessTokenClientCredentialsGrant() + throws IOException, InterruptedException, ExecutionException { + final OAuthRequest request = createAccessTokenClientCredentialsGrantRequest(null); - public AuthorizationUrlWithPKCE getAuthorizationUrlWithPKCE() { - return getAuthorizationUrlWithPKCE(null); + return sendAccessTokenRequestSync(request); } - public AuthorizationUrlWithPKCE getAuthorizationUrlWithPKCE(Map additionalParams) { - final PKCE pkce = PKCE_SERVICE.generatePKCE(); - return new AuthorizationUrlWithPKCE(pkce, getAuthorizationUrl(additionalParams, pkce)); - } + public OAuth2AccessToken getAccessTokenClientCredentialsGrant(String scope) + throws IOException, InterruptedException, ExecutionException { + final OAuthRequest request = createAccessTokenClientCredentialsGrantRequest(scope); - /** - * 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 getAuthorizationUrl(null, null); + return sendAccessTokenRequestSync(request); } /** - * Returns the URL where you should redirect your users to authenticate your application. + * Start the request to retrieve the access token using client-credentials grant. The optionally provided callback + * will be called with the Token when it is available. * - * @param additionalParams any additional GET params to add to the URL - * @return the URL where you should redirect your users + * @param callback optional callback + * @return Future */ - public String getAuthorizationUrl(Map additionalParams) { - return getAuthorizationUrl(additionalParams, null); - } + public Future getAccessTokenClientCredentialsGrant( + OAuthAsyncRequestCallback callback) { + final OAuthRequest request = createAccessTokenClientCredentialsGrantRequest(null); - public String getAuthorizationUrl(PKCE pkce) { - return getAuthorizationUrl(null, pkce); + return sendAccessTokenRequestAsync(request, callback); } - public String getAuthorizationUrl(Map additionalParams, PKCE pkce) { - final Map params; - if (pkce == null) { - params = additionalParams; - } else { - params = additionalParams == null ? new HashMap() : new HashMap<>(additionalParams); - params.putAll(pkce.getAuthorizationUrlParams()); - } - return api.getAuthorizationUrl(getResponseType(), getApiKey(), getCallback(), getScope(), getState(), params); - } + public Future getAccessTokenClientCredentialsGrant(String scope, + OAuthAsyncRequestCallback callback) { + final OAuthRequest request = createAccessTokenClientCredentialsGrantRequest(scope); - public DefaultApi20 getApi() { - return api; + return sendAccessTokenRequestAsync(request, callback); } + // ===== revoke AccessToken methods ===== protected OAuthRequest createRevokeTokenRequest(String tokenToRevoke, TokenTypeHint tokenTypeHint) { final OAuthRequest request = new OAuthRequest(Verb.POST, api.getRevokeTokenEndpoint()); @@ -312,8 +447,11 @@ protected OAuthRequest createRevokeTokenRequest(String tokenToRevoke, TokenTypeH request.addParameter("token", tokenToRevoke); if (tokenTypeHint != null) { - request.addParameter("token_type_hint", tokenTypeHint.toString()); + request.addParameter("token_type_hint", tokenTypeHint.getValue()); } + + logRequestWithParams("revoke token", request); + return request; } @@ -333,7 +471,9 @@ public void revokeToken(String tokenToRevoke, TokenTypeHint tokenTypeHint) throws IOException, InterruptedException, ExecutionException { final OAuthRequest request = createRevokeTokenRequest(tokenToRevoke, tokenTypeHint); - checkForErrorRevokeToken(execute(request)); + try (Response response = execute(request)) { + checkForErrorRevokeToken(response); + } } public Future revokeToken(String tokenToRevoke, OAuthAsyncRequestCallback callback) { @@ -348,6 +488,7 @@ public Future revokeToken(String tokenToRevoke, OAuthAsyncRequestCallback< @Override public Void convert(Response response) throws IOException { checkForErrorRevokeToken(response); + response.close(); return null; } }); @@ -355,38 +496,181 @@ public Void convert(Response response) throws IOException { private void checkForErrorRevokeToken(Response response) throws IOException { if (response.getCode() != 200) { - OAuth2AccessTokenJsonExtractor.instance().generateError(response.getBody()); + OAuth2AccessTokenJsonExtractor.instance().generateError(response); } } - public OAuth2Authorization extractAuthorization(String redirectLocation) { - final OAuth2Authorization authorization = new OAuth2Authorization(); - int end = redirectLocation.indexOf('#'); - if (end == -1) { - end = redirectLocation.length(); + // ===== device Authorisation codes methods ===== + protected OAuthRequest createDeviceAuthorizationCodesRequest(String scope) { + final OAuthRequest request = new OAuthRequest(Verb.POST, api.getDeviceAuthorizationEndpoint()); + request.addParameter(OAuthConstants.CLIENT_ID, getApiKey()); + if (scope != null) { + request.addParameter(OAuthConstants.SCOPE, scope); + } else if (defaultScope != null) { + request.addParameter(OAuthConstants.SCOPE, defaultScope); } - for (String param : redirectLocation.substring(redirectLocation.indexOf('?') + 1, end).split("&")) { - final String[] keyValue = param.split("="); - if (keyValue.length == 2) { - switch (keyValue[0]) { - case "code": - authorization.setCode(keyValue[1]); - break; - case "state": - authorization.setState(keyValue[1]); - break; - default: //just ignore any other param; - } + + logRequestWithParams("Device Authorization Codes", request); + + return request; + } + + /** + * Requests a set of verification codes from the authorization server with the default scope + * + * @see RFC 8628 + * + * @return DeviceAuthorization + * @throws InterruptedException InterruptedException + * @throws ExecutionException ExecutionException + * @throws IOException IOException + */ + public DeviceAuthorization getDeviceAuthorizationCodes() + throws InterruptedException, ExecutionException, IOException { + return getDeviceAuthorizationCodes((String) null); + } + + /** + * Requests a set of verification codes from the authorization server + * + * @see RFC 8628 + * + * @param scope scope + * @return DeviceAuthorization + * @throws InterruptedException InterruptedException + * @throws ExecutionException ExecutionException + * @throws IOException IOException + */ + public DeviceAuthorization getDeviceAuthorizationCodes(String scope) + throws InterruptedException, ExecutionException, IOException { + final OAuthRequest request = createDeviceAuthorizationCodesRequest(scope); + + try (Response response = execute(request)) { + if (isDebug()) { + log("got DeviceAuthorizationCodes response"); + log("response status code: %s", response.getCode()); + log("response body: %s", response.getBody()); } + return api.getDeviceAuthorizationExtractor().extract(response); } - return authorization; } - public String getResponseType() { - return responseType; + public Future getDeviceAuthorizationCodes( + OAuthAsyncRequestCallback callback) { + return getDeviceAuthorizationCodes(null, callback); } - public String getState() { - return state; + public Future getDeviceAuthorizationCodes(String scope, + OAuthAsyncRequestCallback callback) { + final OAuthRequest request = createDeviceAuthorizationCodesRequest(scope); + + return execute(request, callback, new OAuthRequest.ResponseConverter() { + @Override + public DeviceAuthorization convert(Response response) throws IOException { + final DeviceAuthorization deviceAuthorization = api.getDeviceAuthorizationExtractor().extract(response); + response.close(); + return deviceAuthorization; + } + }); + } + + public Future getDeviceAuthorizationCodesAsync() { + return getDeviceAuthorizationCodesAsync(null); + } + + 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"); + request.addParameter("device_code", deviceAuthorization.getDeviceCode()); + api.getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret()); + return request; + } + + /** + * Attempts to get a token from a server. + * + * Function {@link #pollAccessTokenDeviceAuthorizationGrant(com.github.scribejava.core.model.DeviceAuthorization)} + * is usually used instead of this. + * + * @param deviceAuthorization deviceAuthorization + * @return token + * + * @throws java.lang.InterruptedException InterruptedException + * @throws java.util.concurrent.ExecutionException ExecutionException + * @throws java.io.IOException IOException + * @throws OAuth2AccessTokenErrorResponse If {@link OAuth2AccessTokenErrorResponse#getError()} is + * {@link com.github.scribejava.core.oauth2.OAuth2Error#AUTHORIZATION_PENDING} or + * {@link com.github.scribejava.core.oauth2.OAuth2Error#SLOW_DOWN}, another attempt should be made after a while. + * + * @see #getDeviceAuthorizationCodes() + */ + public OAuth2AccessToken getAccessTokenDeviceAuthorizationGrant(DeviceAuthorization deviceAuthorization) + throws InterruptedException, ExecutionException, IOException { + final OAuthRequest request = createAccessTokenDeviceAuthorizationGrantRequest(deviceAuthorization); + + try (Response response = execute(request)) { + if (isDebug()) { + log("got AccessTokenDeviceAuthorizationGrant response"); + log("response status code: %s", response.getCode()); + log("response body: %s", response.getBody()); + } + return api.getAccessTokenExtractor().extract(response); + } + } + + public Future getAccessTokenDeviceAuthorizationGrant(DeviceAuthorization deviceAuthorization, + OAuthAsyncRequestCallback callback) { + final OAuthRequest request = createAccessTokenDeviceAuthorizationGrantRequest(deviceAuthorization); + + return execute(request, callback, new OAuthRequest.ResponseConverter() { + @Override + public OAuth2AccessToken convert(Response response) throws IOException { + final OAuth2AccessToken accessToken = api.getAccessTokenExtractor().extract(response); + response.close(); + return accessToken; + } + }); + } + + public Future getAccessTokenDeviceAuthorizationGrantAsync( + DeviceAuthorization deviceAuthorization) { + return getAccessTokenDeviceAuthorizationGrant(deviceAuthorization, null); + } + + /** + * Periodically tries to get a token from a server (waiting for the user to give consent). Sync only version. No + * Async variants yet, one should implement async scenarios themselves. + * + * @param deviceAuthorization deviceAuthorization + * @return token + * @throws java.lang.InterruptedException InterruptedException + * @throws java.util.concurrent.ExecutionException ExecutionException + * @throws java.io.IOException IOException + * @throws OAuth2AccessTokenErrorResponse Indicates OAuth error. + * + * @see #getDeviceAuthorizationCodes() + */ + public OAuth2AccessToken pollAccessTokenDeviceAuthorizationGrant(DeviceAuthorization deviceAuthorization) + throws InterruptedException, ExecutionException, IOException { + long intervalMillis = deviceAuthorization.getIntervalSeconds() * 1000; + while (true) { + try { + return getAccessTokenDeviceAuthorizationGrant(deviceAuthorization); + } catch (OAuth2AccessTokenErrorResponse e) { + if (e.getError() != OAuth2Error.AUTHORIZATION_PENDING) { + if (e.getError() == OAuth2Error.SLOW_DOWN) { + intervalMillis += 5000; + } else { + throw e; + } + } + } + Thread.sleep(intervalMillis); + } } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuthService.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuthService.java index 9f331a4ba..996abee6f 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuthService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuthService.java @@ -12,6 +12,7 @@ import java.io.File; import java.io.IOException; +import java.io.OutputStream; import java.util.ServiceLoader; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -21,16 +22,16 @@ public abstract class OAuthService implements Closeable { private final String apiKey; private final String apiSecret; private final String callback; - private final String scope; private final String userAgent; private final HttpClient httpClient; + private final OutputStream debugStream; - public OAuthService(String apiKey, String apiSecret, String callback, String scope, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { + public OAuthService(String apiKey, String apiSecret, String callback, OutputStream debugStream, + String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { this.apiKey = apiKey; this.apiSecret = apiSecret; this.callback = callback; - this.scope = scope; + this.debugStream = debugStream; this.userAgent = userAgent; if (httpClientConfig == null && httpClient == null) { @@ -67,10 +68,6 @@ public String getCallback() { return callback; } - public String getScope() { - return scope; - } - /** * Returns the OAuth version of the service. * @@ -110,12 +107,42 @@ public Response execute(OAuthRequest request) throws InterruptedException, Execu } else if (request.getStringPayload() != null) { return httpClient.execute(userAgent, request.getHeaders(), request.getVerb(), request.getCompleteUrl(), request.getStringPayload()); - } else if (request.getMultipartPayloads() != null) { + } else if (request.getMultipartPayload() != null) { return httpClient.execute(userAgent, request.getHeaders(), request.getVerb(), request.getCompleteUrl(), - request.getMultipartPayloads()); + request.getMultipartPayload()); } else { return httpClient.execute(userAgent, request.getHeaders(), request.getVerb(), request.getCompleteUrl(), request.getByteArrayPayload()); } } + + /** + * No need to wrap usages in {@link #isDebug()}. + * + * @param message message to log + */ + public void log(String message) { + if (debugStream != null) { + log(message, (Object[]) null); + } + } + + /** + * Wrap usages in {@link #isDebug()}. It was made for optimization - to not calculate "params" in production mode. + * + * @param messagePattern messagePattern + * @param params params + */ + public void log(String messagePattern, Object... params) { + final String message = String.format(messagePattern, params) + '\n'; + try { + debugStream.write(message.getBytes("UTF8")); + } catch (IOException | RuntimeException e) { + throw new RuntimeException("there were problems while writting to the debug stream", e); + } + } + + protected boolean isDebug() { + return debugStream != null; + } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/OAuth2Error.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/OAuth2Error.java new file mode 100644 index 000000000..b1422bcae --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/OAuth2Error.java @@ -0,0 +1,108 @@ +package com.github.scribejava.core.oauth2; + +import java.util.EnumSet; +import java.util.Set; + +public enum OAuth2Error { + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + * @see RFC 6749, 5.2 Error Response + * @see RFC 6750, 6.2. OAuth Extensions Error + * Registration + */ + INVALID_REQUEST("invalid_request"), + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + * @see RFC 6749, 5.2 Error Response + */ + UNAUTHORIZED_CLIENT("unauthorized_client"), + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + * @see RFC 8628, 3.5. Device Access Token Response + */ + ACCESS_DENIED("access_denied"), + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + */ + UNSUPPORTED_RESPONSE_TYPE("unsupported_response_type"), + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + * @see RFC 6749, 5.2 Error Response + */ + INVALID_SCOPE("invalid_scope"), + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + */ + SERVER_ERROR("server_error"), + /** + * @see RFC 6749, 4.1.2.1 Error Response + * @see RFC 6749, 4.2.2.1 Error Response + */ + TEMPORARILY_UNAVAILABLE("temporarily_unavailable"), + /** + * @see RFC 6749, 5.2 Error Response + */ + INVALID_CLIENT("invalid_client"), + /** + * @see RFC 6749, 5.2 Error Response + */ + INVALID_GRANT("invalid_grant"), + /** + * @see RFC 6749, 5.2 Error Response + */ + UNSUPPORTED_GRANT_TYPE("unsupported_grant_type"), + /** + * @see RFC 6750, 6.2. OAuth Extensions Error + * Registration + */ + INVALID_TOKEN("invalid_token"), + /** + * @see RFC 6750, 6.2. OAuth Extensions Error + * Registration + */ + INSUFFICIENT_SCOPE("insufficient_scope"), + /** + * @see RFC 7009, 4.1. OAuth Extensions Error + * Registration + */ + UNSUPPORTED_TOKEN_TYPE("unsupported_token_type"), + /** + * @see RFC 8628, 3.5. Device Access Token Response + */ + AUTHORIZATION_PENDING("authorization_pending"), + /** + * @see RFC 8628, 3.5. Device Access Token Response + */ + SLOW_DOWN("slow_down"), + /** + * @see RFC 8628, 3.5. Device Access Token Response + */ + EXPIRED_TOKEN("expired_token"); + + private static final Set VALUES = EnumSet.allOf(OAuth2Error.class); + + private final String errorString; + + OAuth2Error(String errorString) { + this.errorString = errorString; + } + + public static OAuth2Error parseFrom(String errorString) { + for (OAuth2Error error : VALUES) { + if (error.errorString.equals(errorString)) { + return error; + } + } + throw new IllegalArgumentException("there is no knowlege about '" + errorString + "' Error"); + } + + public String getErrorString() { + return errorString; + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignature.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignature.java new file mode 100644 index 000000000..61739e93e --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignature.java @@ -0,0 +1,12 @@ +package com.github.scribejava.core.oauth2.bearersignature; + +import com.github.scribejava.core.model.OAuthRequest; + +/** + * Represents
+ * 2. Authenticated Requests
+ * https://tools.ietf.org/html/rfc6750#section-2 + */ +public interface BearerSignature { + void signRequest(String accessToken, OAuthRequest request); +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignatureAuthorizationRequestHeaderField.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignatureAuthorizationRequestHeaderField.java new file mode 100644 index 000000000..98196a708 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignatureAuthorizationRequestHeaderField.java @@ -0,0 +1,29 @@ +package com.github.scribejava.core.oauth2.bearersignature; + +import com.github.scribejava.core.model.OAuthConstants; +import com.github.scribejava.core.model.OAuthRequest; + +/** + * 2.1. Authorization Request Header Field
+ * https://tools.ietf.org/html/rfc6750#section-2.1 + */ +public class BearerSignatureAuthorizationRequestHeaderField implements BearerSignature { + + protected BearerSignatureAuthorizationRequestHeaderField() { + } + + private static class InstanceHolder { + + private static final BearerSignatureAuthorizationRequestHeaderField INSTANCE + = new BearerSignatureAuthorizationRequestHeaderField(); + } + + public static BearerSignatureAuthorizationRequestHeaderField instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public void signRequest(String accessToken, OAuthRequest request) { + request.addHeader(OAuthConstants.HEADER, "Bearer " + accessToken); + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignatureURIQueryParameter.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignatureURIQueryParameter.java new file mode 100644 index 000000000..72cc64b43 --- /dev/null +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/bearersignature/BearerSignatureURIQueryParameter.java @@ -0,0 +1,27 @@ +package com.github.scribejava.core.oauth2.bearersignature; + +import com.github.scribejava.core.model.OAuthConstants; +import com.github.scribejava.core.model.OAuthRequest; + +/** + * 2.3. URI Query Parameter
+ * https://tools.ietf.org/html/rfc6750#section-2.3 + */ +public class BearerSignatureURIQueryParameter implements BearerSignature { + protected BearerSignatureURIQueryParameter() { + } + + private static class InstanceHolder { + + private static final BearerSignatureURIQueryParameter INSTANCE = new BearerSignatureURIQueryParameter(); + } + + public static BearerSignatureURIQueryParameter instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public void signRequest(String accessToken, OAuthRequest request) { + request.addQuerystringParameter(OAuthConstants.ACCESS_TOKEN, accessToken); + } +} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/clientauthentication/HttpBasicAuthenticationScheme.java b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/clientauthentication/HttpBasicAuthenticationScheme.java index 509869d51..3931f6f7b 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/clientauthentication/HttpBasicAuthenticationScheme.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/oauth2/clientauthentication/HttpBasicAuthenticationScheme.java @@ -1,6 +1,6 @@ package com.github.scribejava.core.oauth2.clientauthentication; -import com.github.scribejava.core.java8.Base64; +import com.github.scribejava.core.base64.Base64; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; import java.nio.charset.Charset; @@ -14,8 +14,6 @@ */ public class HttpBasicAuthenticationScheme implements ClientAuthentication { - private final Base64.Encoder base64Encoder = Base64.getEncoder(); - protected HttpBasicAuthenticationScheme() { } @@ -32,8 +30,7 @@ public static HttpBasicAuthenticationScheme instance() { public void addClientAuthentication(OAuthRequest request, String apiKey, String apiSecret) { if (apiKey != null && apiSecret != null) { request.addHeader(OAuthConstants.HEADER, OAuthConstants.BASIC + ' ' - + base64Encoder.encodeToString( - String.format("%s:%s", apiKey, apiSecret).getBytes(Charset.forName("UTF-8")))); + + Base64.encode(String.format("%s:%s", apiKey, apiSecret).getBytes(Charset.forName("UTF-8")))); } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/pkce/AuthorizationUrlWithPKCE.java b/scribejava-core/src/main/java/com/github/scribejava/core/pkce/AuthorizationUrlWithPKCE.java deleted file mode 100644 index 101f82f10..000000000 --- a/scribejava-core/src/main/java/com/github/scribejava/core/pkce/AuthorizationUrlWithPKCE.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.scribejava.core.pkce; - -public class AuthorizationUrlWithPKCE { - - private final PKCE pkce; - private final String authorizationUrl; - - public AuthorizationUrlWithPKCE(PKCE pkce, String authorizationUrl) { - this.pkce = pkce; - this.authorizationUrl = authorizationUrl; - } - - public PKCE getPkce() { - return pkce; - } - - public String getAuthorizationUrl() { - return authorizationUrl; - } - -} diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethod.java b/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethod.java index 29648859c..374f80336 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethod.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethod.java @@ -1,21 +1,19 @@ package com.github.scribejava.core.pkce; -import com.github.scribejava.core.java8.Base64; +import com.github.scribejava.core.base64.Base64; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public enum PKCECodeChallengeMethod { S256 { - private final Base64.Encoder base64Encoder = Base64.getUrlEncoder().withoutPadding(); - @Override public String transform2CodeChallenge(String codeVerifier) throws NoSuchAlgorithmException { - return base64Encoder.encodeToString( + return Base64.encodeUrlWithoutPadding( MessageDigest.getInstance("SHA-256").digest(codeVerifier.getBytes(StandardCharsets.US_ASCII))); } }, - plain { + PLAIN { @Override public String transform2CodeChallenge(String codeVerifier) { return codeVerifier; diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCEService.java b/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCEService.java index 2af370a75..23a5347ec 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCEService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/pkce/PKCEService.java @@ -1,6 +1,6 @@ package com.github.scribejava.core.pkce; -import com.github.scribejava.core.java8.Base64; +import com.github.scribejava.core.base64.Base64; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -11,7 +11,6 @@ public class PKCEService { private static final SecureRandom RANDOM = new SecureRandom(); - private static final Base64.Encoder BASE_64_ENCODER = Base64.getUrlEncoder().withoutPadding(); /** * number of octets to randomly generate. */ @@ -28,6 +27,15 @@ public PKCEService() { this(32); } + private static class DefaultInstanceHolder { + + private static final PKCEService INSTANCE = new PKCEService(); + } + + public static PKCEService defaultInstance() { + return DefaultInstanceHolder.INSTANCE; + } + public PKCE generatePKCE() { final byte[] bytes = new byte[numberOFOctets]; RANDOM.nextBytes(bytes); @@ -35,16 +43,16 @@ public PKCE generatePKCE() { } public PKCE generatePKCE(byte[] randomBytes) { - final String codeVerifier = BASE_64_ENCODER.encodeToString(randomBytes); + final String codeVerifier = Base64.encodeUrlWithoutPadding(randomBytes); final PKCE pkce = new PKCE(); pkce.setCodeVerifier(codeVerifier); try { pkce.setCodeChallenge(pkce.getCodeChallengeMethod().transform2CodeChallenge(codeVerifier)); } catch (NoSuchAlgorithmException nsaE) { - pkce.setCodeChallengeMethod(PKCECodeChallengeMethod.plain); + pkce.setCodeChallengeMethod(PKCECodeChallengeMethod.PLAIN); try { - pkce.setCodeChallenge(PKCECodeChallengeMethod.plain.transform2CodeChallenge(codeVerifier)); + pkce.setCodeChallenge(PKCECodeChallengeMethod.PLAIN.transform2CodeChallenge(codeVerifier)); } catch (NoSuchAlgorithmException unrealE) { throw new IllegalStateException("It's just cannot be", unrealE); } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/revoke/OAuth2RevokeTokenResponseConverter.java b/scribejava-core/src/main/java/com/github/scribejava/core/revoke/OAuth2RevokeTokenResponseConverter.java index b287d7868..dc595a410 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/revoke/OAuth2RevokeTokenResponseConverter.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/revoke/OAuth2RevokeTokenResponseConverter.java @@ -8,7 +8,7 @@ public class OAuth2RevokeTokenResponseConverter { public Void convert(Response response) throws IOException { if (response.getCode() != 200) { - OAuth2AccessTokenJsonExtractor.instance().generateError(response.getBody()); + OAuth2AccessTokenJsonExtractor.instance().generateError(response); } return null; } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/revoke/TokenTypeHint.java b/scribejava-core/src/main/java/com/github/scribejava/core/revoke/TokenTypeHint.java index 55a95057e..79de78d26 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/revoke/TokenTypeHint.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/revoke/TokenTypeHint.java @@ -8,5 +8,16 @@ * @see RFC 7009, 2.1. Revocation Request */ public enum TokenTypeHint { - access_token, refresh_token + ACCESS_TOKEN("access_token"), + REFRESH_TOKEN("refresh_token"); + + private final String value; + + TokenTypeHint(String value) { + this.value = value; + } + + public String getValue() { + return value; + } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/services/HMACSha1SignatureService.java b/scribejava-core/src/main/java/com/github/scribejava/core/services/HMACSha1SignatureService.java index 82d1135be..363011a13 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/services/HMACSha1SignatureService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/services/HMACSha1SignatureService.java @@ -1,5 +1,6 @@ package com.github.scribejava.core.services; +import com.github.scribejava.core.base64.Base64; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -10,8 +11,7 @@ import com.github.scribejava.core.utils.Preconditions; /** - * HMAC-SHA1 implementation of {@link SignatureService} - * https://tools.ietf.org/html/rfc5849#section-3.4.2 + * HMAC-SHA1 implementation of {@link SignatureService} https://tools.ietf.org/html/rfc5849#section-3.4.2 */ public class HMACSha1SignatureService implements SignatureService { @@ -27,8 +27,8 @@ public class HMACSha1SignatureService implements SignatureService { @Override public String getSignature(String baseString, String apiSecret, String tokenSecret) { try { - Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string"); - Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string"); + Preconditions.checkEmptyString(baseString, "Base string can't be null or empty string"); + Preconditions.checkNotNull(apiSecret, "Api secret can't be null"); return doSign(baseString, OAuthEncoder.encode(apiSecret) + '&' + OAuthEncoder.encode(tokenSecret)); } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException | RuntimeException e) { throw new OAuthSignatureException(baseString, e); @@ -41,7 +41,7 @@ private String doSign(String toSign, String keyString) throws UnsupportedEncodin final Mac mac = Mac.getInstance(HMAC_SHA1); mac.init(key); final byte[] bytes = mac.doFinal(toSign.getBytes(UTF8)); - return BASE_64_ENCODER.encodeToString(bytes).replace(CARRIAGE_RETURN, EMPTY_STRING); + return Base64.encode(bytes).replace(CARRIAGE_RETURN, EMPTY_STRING); } /** diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/services/PlaintextSignatureService.java b/scribejava-core/src/main/java/com/github/scribejava/core/services/PlaintextSignatureService.java index 33661f10a..143348484 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/services/PlaintextSignatureService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/services/PlaintextSignatureService.java @@ -17,7 +17,7 @@ public class PlaintextSignatureService implements SignatureService { @Override public String getSignature(String baseString, String apiSecret, String tokenSecret) { try { - Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string"); + Preconditions.checkNotNull(apiSecret, "Api secret can't be null"); return OAuthEncoder.encode(apiSecret) + '&' + OAuthEncoder.encode(tokenSecret); } catch (Exception e) { throw new OAuthSignatureException(baseString, e); diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/services/RSASha1SignatureService.java b/scribejava-core/src/main/java/com/github/scribejava/core/services/RSASha1SignatureService.java index 9cb460e7b..dc16eace4 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/services/RSASha1SignatureService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/services/RSASha1SignatureService.java @@ -1,5 +1,6 @@ package com.github.scribejava.core.services; +import com.github.scribejava.core.base64.Base64; import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; @@ -32,9 +33,9 @@ public String getSignature(String baseString, String apiSecret, String tokenSecr final Signature signature = Signature.getInstance(RSA_SHA1); signature.initSign(privateKey); signature.update(baseString.getBytes(UTF8)); - return BASE_64_ENCODER.encodeToString(signature.sign()); - } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | UnsupportedEncodingException | - RuntimeException e) { + return Base64.encode(signature.sign()); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | UnsupportedEncodingException + | RuntimeException e) { throw new OAuthSignatureException(baseString, e); } } diff --git a/scribejava-core/src/main/java/com/github/scribejava/core/services/SignatureService.java b/scribejava-core/src/main/java/com/github/scribejava/core/services/SignatureService.java index 8cd4f2372..10c50f3ae 100644 --- a/scribejava-core/src/main/java/com/github/scribejava/core/services/SignatureService.java +++ b/scribejava-core/src/main/java/com/github/scribejava/core/services/SignatureService.java @@ -1,13 +1,9 @@ package com.github.scribejava.core.services; -import com.github.scribejava.core.java8.Base64; - /** - * Signs a base string, returning the OAuth signature - * https://tools.ietf.org/html/rfc5849#section-3.4 + * Signs a base string, returning the OAuth signature https://tools.ietf.org/html/rfc5849#section-3.4 */ public interface SignatureService { - Base64.Encoder BASE_64_ENCODER = Base64.getEncoder(); /** * Returns the signature diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/AbstractClientTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/AbstractClientTest.java index 58c4664de..c1bc1967e 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/AbstractClientTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/AbstractClientTest.java @@ -19,6 +19,8 @@ import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; public abstract class AbstractClientTest { @@ -44,7 +46,7 @@ public Response getResponse() { @Before public void setUp() { - oAuthService = new OAuth20Service(null, "test", "test", null, null, null, null, null, null, + oAuthService = new OAuth20Service(null, "test", "test", null, null, null, System.out, null, null, createNewClient()); } @@ -66,9 +68,10 @@ public void shouldSendGetRequest() throws Exception { final HttpUrl baseUrl = server.url("/testUrl"); final OAuthRequest request = new OAuthRequest(Verb.GET, baseUrl.toString()); - final Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS); - assertEquals(expectedResponseBody, response.getBody()); + try (Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS)) { + assertEquals(expectedResponseBody, response.getBody()); + } final RecordedRequest recordedRequest = server.takeRequest(); assertEquals("GET", recordedRequest.getMethod()); @@ -77,37 +80,122 @@ public void shouldSendGetRequest() throws Exception { } @Test - public void shouldSendPostRequest() throws Exception { + public void shouldSendPostWithApplicationXWwwFormUrlencodedRequestContentTypeHeader() throws Exception { + final MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse()); + server.start(); + + final HttpUrl baseUrl = server.url("/testUrl"); + + final OAuthRequest request = new OAuthRequest(Verb.POST, baseUrl.toString()); + oAuthService.execute(request, null).get(30, TimeUnit.SECONDS).close(); + + final RecordedRequest recordedRequest = server.takeRequest(); + assertEquals("POST", recordedRequest.getMethod()); + assertEquals(HttpClient.DEFAULT_CONTENT_TYPE, recordedRequest.getHeader(HttpClient.CONTENT_TYPE)); + + server.shutdown(); + } + + @Test + public void shouldSendPostRequestWithEmptyBody() throws Exception { final String expectedResponseBody = "response body for test shouldSendPostRequest"; - final String expectedRequestBody = "request body"; + final String expectedRequestBody = ""; final MockWebServer server = new MockWebServer(); server.enqueue(new MockResponse().setBody(expectedResponseBody)); + server.start(); + + final HttpUrl baseUrl = server.url("/testUrl"); + + final OAuthRequest request = new OAuthRequest(Verb.POST, baseUrl.toString()); + try (Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS)) { + assertEquals(expectedResponseBody, response.getBody()); + } + + final RecordedRequest recordedRequest = server.takeRequest(); + assertEquals("POST", recordedRequest.getMethod()); + assertEquals(expectedRequestBody, recordedRequest.getBody().readUtf8()); + assertEquals(HttpClient.DEFAULT_CONTENT_TYPE, recordedRequest.getHeader(HttpClient.CONTENT_TYPE)); + + server.shutdown(); + } + + @Test + public void shouldSendPostRequestWithStringBody() throws Exception { + final String expectedResponseBody = "response body for test shouldSendPostRequest"; + final String expectedRequestBody = "request body"; + + final MockWebServer server = new MockWebServer(); server.enqueue(new MockResponse().setBody(expectedResponseBody)); server.start(); final HttpUrl baseUrl = server.url("/testUrl"); - // request with body - OAuthRequest request = new OAuthRequest(Verb.POST, baseUrl.toString()); + final OAuthRequest request = new OAuthRequest(Verb.POST, baseUrl.toString()); request.setPayload(expectedRequestBody); - Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS); + try (Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS)) { + assertEquals(expectedResponseBody, response.getBody()); + } + + final RecordedRequest recordedRequest = server.takeRequest(); + assertEquals("POST", recordedRequest.getMethod()); + assertEquals(expectedRequestBody, recordedRequest.getBody().readUtf8()); + final String contentTypeHeader = recordedRequest.getHeader(HttpClient.CONTENT_TYPE); + assertNotNull(contentTypeHeader); + assertTrue(contentTypeHeader.startsWith(HttpClient.DEFAULT_CONTENT_TYPE)); + + server.shutdown(); + } + + @Test + public void shouldSendPostRequestWithByteBodyBody() throws Exception { + final String expectedResponseBody = "response body for test shouldSendPostRequest"; + final String expectedRequestBody = "request body"; - assertEquals(expectedResponseBody, response.getBody()); + final MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setBody(expectedResponseBody)); + server.start(); - RecordedRequest recordedRequest = server.takeRequest(); + final HttpUrl baseUrl = server.url("/testUrl"); + + final OAuthRequest request = new OAuthRequest(Verb.POST, baseUrl.toString()); + request.setPayload(expectedRequestBody.getBytes()); + try (Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS)) { + assertEquals(expectedResponseBody, response.getBody()); + } + + final RecordedRequest recordedRequest = server.takeRequest(); assertEquals("POST", recordedRequest.getMethod()); assertEquals(expectedRequestBody, recordedRequest.getBody().readUtf8()); + assertEquals(HttpClient.DEFAULT_CONTENT_TYPE, recordedRequest.getHeader(HttpClient.CONTENT_TYPE)); - // request with empty body - request = new OAuthRequest(Verb.POST, baseUrl.toString()); - response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS); + server.shutdown(); + } - assertEquals(expectedResponseBody, response.getBody()); + @Test + public void shouldSendPostRequestWithBodyParamsBody() throws Exception { + final String expectedResponseBody = "response body for test shouldSendPostRequest"; + final String expectedRequestBodyParamName = "request_body_param_name"; + final String expectedRequestBodyParamValue = "request_body_param_value"; + final String expectedRequestBody = expectedRequestBodyParamName + '=' + expectedRequestBodyParamValue; - recordedRequest = server.takeRequest(); + final MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setBody(expectedResponseBody)); + server.start(); + + final HttpUrl baseUrl = server.url("/testUrl"); + + final OAuthRequest request = new OAuthRequest(Verb.POST, baseUrl.toString()); + request.addBodyParameter(expectedRequestBodyParamName, expectedRequestBodyParamValue); + try (Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS)) { + assertEquals(expectedResponseBody, response.getBody()); + } + + final RecordedRequest recordedRequest = server.takeRequest(); assertEquals("POST", recordedRequest.getMethod()); - assertEquals("", recordedRequest.getBody().readUtf8()); + assertEquals(expectedRequestBody, recordedRequest.getBody().readUtf8()); + assertEquals(HttpClient.DEFAULT_CONTENT_TYPE, recordedRequest.getHeader(HttpClient.CONTENT_TYPE)); server.shutdown(); } @@ -123,9 +211,9 @@ public void shouldReadResponseStream() throws Exception { final HttpUrl baseUrl = server.url("/testUrl"); final OAuthRequest request = new OAuthRequest(Verb.GET, baseUrl.toString()); - final Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS); - - assertEquals(expectedResponseBody, StreamUtils.getStreamContents(response.getStream())); + try (Response response = oAuthService.execute(request, null).get(30, TimeUnit.SECONDS)) { + assertEquals(expectedResponseBody, StreamUtils.getStreamContents(response.getStream())); + } final RecordedRequest recordedRequest = server.takeRequest(); assertEquals("GET", recordedRequest.getMethod()); @@ -165,10 +253,11 @@ public void shouldPassErrors() throws Exception { final OAuthRequest request = new OAuthRequest(Verb.GET, baseUrl.toString()); final TestCallback callback = new TestCallback(); - final Response response = oAuthService.execute(request, callback).get(); + try (Response response = oAuthService.execute(request, callback).get()) { - assertEquals(500, response.getCode()); - assertEquals(500, callback.getResponse().getCode()); + assertEquals(500, response.getCode()); + assertEquals(500, callback.getResponse().getCode()); + } server.shutdown(); } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/base64/Base64Test.java b/scribejava-core/src/test/java/com/github/scribejava/core/base64/Base64Test.java new file mode 100644 index 000000000..4d345b77d --- /dev/null +++ b/scribejava-core/src/test/java/com/github/scribejava/core/base64/Base64Test.java @@ -0,0 +1,213 @@ +package com.github.scribejava.core.base64; + +import java.io.UnsupportedEncodingException; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; + +public class Base64Test { + + private Base64 java8Base64; + private Base64 commonsCodecBase64; + private Base64 jaxbBase64; + private Base64 jaxb230Base64; + private byte[] helloWorldBytes; + private byte[] helloWorldTwoLinesBytes; + private byte[] helloWorldTwoLinesAndNewLineBytes; + private byte[] helloWorldDifferentCharsBytes; + private byte[] bytes; + private byte[] allBytes; + + @Before + public void setUp() throws UnsupportedEncodingException { + helloWorldBytes = "Hello World".getBytes("UTF-8"); + helloWorldTwoLinesBytes = "Hello World\r\nNew Line2".getBytes("UTF-8"); + helloWorldTwoLinesAndNewLineBytes = "Hello World\r\nSecond Line\r\n".getBytes("UTF-8"); + helloWorldDifferentCharsBytes = ("`1234567890-=~!@#$%^&*()_+ёЁ\"№;:?qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP" + + "{}|ASDFGHJKL:ZXCVBNM<>?йфяцычувскамепинртгоьшлбщдюзж.хэъ\\ЙФЯЦЫЧУВСКАМЕПИНРТГОЬШЛБЩДЮЗЖ,ХЭЪ/\r\t\f\'" + + "\b\n").getBytes("UTF-8"); + bytes = new byte[]{48, -126, 2, 118, 2, 1, 0, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 4, -126, + 2, 96, 48, -126, 2, 92, 2, 1, 0, 2, -127, -127, 0, -61, -48, -28, 16, -116, -58, 85, 42, -39, 54, 50, -119, + 18, 40, 17, 75, 51, -24, 113, -109, 38, 17, -18, 106, -60, -74, -97, 29, 82, 123, -128, -88, -34, 92, 112, + -57, 43, -101, 85, -47, 99, -16, 11, -95, 28, -46, 82, -104, -101, -29, -106, -106, -45, -80, 99, -93, 45, + -102, 107, 31, 32, -60, 13, -46, 102, 127, 81, 94, -98, -56, 117, 50, 21, 39, 5, -98, 26, -18, -30, -21, + 102, -78, -77, 20, 113, -55, 117, -87, -105, -10, -100, 90, -92, 31, 61, -68, -73, -121, -108, 42, 45, -10, + 21, 87, 118, -74, 71, -100, -37, 96, -24, 87, 102, 68, -95, -1, -14, 6, -20, -14, 32, -14, 33, -84, -123, + -65, 54, 3, 2, 3, 1, 0, 1, 2, -127, -128, 62, 115, -45, 41, 76, 28, -67, 113, 11, 17, -12, 16, 47, -112, 67, + -29, -66, 76, 118, 92, -66, 25, -99, -10, -61, -126, -109, 64, -32, -37, -82, -17, 44, -20, 66, -77, -29, + 62, -119, -94, 92, -61, 100, -110, 32, 5, 28, 126, -69, -55, 92, 112, 2, 88, 17, -113, 43, -82, 66, 88, 13, + 53, 58, 74, -65, 36, 45, 93, -63, -15, 125, -7, -44, -45, -51, -76, 86, 97, 54, -36, -49, -117, -18, 56, 54, + 78, 80, 119, -6, -75, 39, 16, 57, -125, -68, 42, 50, -114, 92, 6, 13, 30, -91, 53, -66, -19, -20, 88, 32, + -38, 36, 126, -119, -86, 47, -46, 37, 115, -49, -23, 125, -61, 75, 37, 70, 92, -122, -79, 2, 65, 0, -11, + -105, 91, 105, -73, 54, 97, 96, -87, -16, -15, -73, 15, 31, -80, -96, -74, -53, -54, 53, -17, -9, 39, 62, + 58, 51, 68, 107, 86, 111, -62, -48, -125, 117, 66, 111, -55, 27, 56, 81, -50, 96, -47, -102, -50, -83, -52, + -17, -20, 3, -42, -94, 11, 23, 104, 127, 29, -25, 32, 43, -41, -112, -83, -99, 2, 65, 0, -52, 29, 122, 9, + 49, -14, -118, 110, -79, 107, 76, -88, 4, -49, 40, 32, 59, 88, 45, -71, 62, 78, 93, -121, -123, 123, 3, 4, + 111, -112, 27, 12, -115, -123, 125, 39, 54, 96, -2, -46, 30, 40, -4, -119, 13, -121, 118, -23, 1, -83, -76, + -26, -117, -86, -79, -121, 113, -26, 33, 30, 124, 35, -16, 31, 2, 65, 0, -47, -113, 111, -81, 75, 104, -103, + -69, 20, 7, -57, 25, -65, 75, -7, 57, -118, 1, 102, -16, -109, 108, -64, 13, -73, 55, -37, -32, 3, -121, + -90, 34, -86, -87, -70, 33, 12, -25, -81, 45, 14, -1, 74, -101, -32, 84, 41, -107, 104, 60, -10, 62, -101, + 92, 68, 12, -124, 5, -98, 76, 10, -53, 39, 121, 2, 64, 7, 106, 102, -67, -96, -57, -20, 9, -101, 126, -121, + 121, 111, 59, 75, 124, -24, 75, 10, -42, 57, 18, 69, -55, -97, -86, -39, 112, 54, -47, 104, 122, 43, 70, 23, + 70, -18, 109, -43, -76, 50, -114, 80, -90, 118, 12, 94, -32, -106, 68, 6, 87, 125, -23, -124, -85, -92, 18, + -75, 79, 83, 57, 71, 7, 2, 64, 73, -64, -3, 78, -90, -122, -64, -99, -29, -71, 75, 21, -74, -24, -43, -37, + 116, -89, 31, -115, -30, 50, 8, 23, 79, -71, -68, -39, 36, -23, 60, 102, -90, -42, 19, -33, -102, -85, -74, + 103, 73, -30, 120, -15, 104, -9, 110, -24, -127, 14, -57, -44, 67, 9, 80, 120, 42, 94, 107, -81, -109, 101, + -1, 91}; + + allBytes = new byte[]{-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, + -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, + -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, + -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, + -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, + -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, + -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127}; + + java8Base64 = new Java8Base64(); + commonsCodecBase64 = new CommonsCodecBase64(); + jaxbBase64 = new JaxbBase64(); + jaxb230Base64 = new Jaxb230Base64(); + } + + @Test + public void allImplementationsAreAvailable() { + assertTrue(Java8Base64.isAvailable()); + assertTrue(CommonsCodecBase64.isAvailable()); + assertTrue(JaxbBase64.isAvailable()); + assertTrue(Jaxb230Base64.isAvailable()); + } + + @Test + public void testEncode() { + final String helloWorldEncoded = "SGVsbG8gV29ybGQ="; + final String helloWorldTwoLinesEncoded = "SGVsbG8gV29ybGQNCk5ldyBMaW5lMg=="; + final String helloWorldTwoLinesAndNewLineEncoded = "SGVsbG8gV29ybGQNClNlY29uZCBMaW5lDQo="; + final String helloWorldDifferentCharsEncoded = "YDEyMzQ1Njc4OTAtPX4hQCMkJV4mKigpXyvRkdCBIuKEljs6P3F3ZXJ0eXVpb3B" + + "bXWFzZGZnaGprbDsnenhjdmJubSwuL1FXRVJUWVVJT1B7fXxBU0RGR0hKS0w6WlhDVkJOTTw+P9C50YTRj9GG0YvRh9GD0LLRgdC" + + "60LDQvNC10L/QuNC90YDRgtCz0L7RjNGI0LvQsdGJ0LTRjtC30LYu0YXRjdGKXNCZ0KTQr9Cm0KvQp9Cj0JLQodCa0JDQnNCV0J/" + + "QmNCd0KDQotCT0J7QrNCo0JvQkdCp0JTQrtCX0JYs0KXQrdCqLw0JDCcICg=="; + final String str = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMPQ5BCMxlUq2TYy" + + "iRIoEUsz6HGTJhHuasS2nx1Se4Co3lxwxyubVdFj8AuhHNJSmJvjlpbTsGOjLZpr" + + "HyDEDdJmf1Fensh1MhUnBZ4a7uLrZrKzFHHJdamX9pxapB89vLeHlCot9hVXdrZH" + + "nNtg6FdmRKH/8gbs8iDyIayFvzYDAgMBAAECgYA+c9MpTBy9cQsR9BAvkEPjvkx2" + + "XL4ZnfbDgpNA4Nuu7yzsQrPjPomiXMNkkiAFHH67yVxwAlgRjyuuQlgNNTpKvyQt" + + "XcHxffnU0820VmE23M+L7jg2TlB3+rUnEDmDvCoyjlwGDR6lNb7t7Fgg2iR+iaov" + + "0iVzz+l9w0slRlyGsQJBAPWXW2m3NmFgqfDxtw8fsKC2y8o17/cnPjozRGtWb8LQ" + + "g3VCb8kbOFHOYNGazq3M7+wD1qILF2h/HecgK9eQrZ0CQQDMHXoJMfKKbrFrTKgE" + + "zyggO1gtuT5OXYeFewMEb5AbDI2FfSc2YP7SHij8iQ2HdukBrbTmi6qxh3HmIR58" + + "I/AfAkEA0Y9vr0tombsUB8cZv0v5OYoBZvCTbMANtzfb4AOHpiKqqbohDOevLQ7/" + + "SpvgVCmVaDz2PptcRAyEBZ5MCssneQJAB2pmvaDH7Ambfod5bztLfOhLCtY5EkXJ" + + "n6rZcDbRaHorRhdG7m3VtDKOUKZ2DF7glkQGV33phKukErVPUzlHBwJAScD9TqaG" + + "wJ3juUsVtujV23SnH43iMggXT7m82STpPGam1hPfmqu2Z0niePFo927ogQ7H1EMJ" + + "UHgqXmuvk2X/Ww=="; + + final String allBytesStr = "gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2" + + "+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwg" + + "JCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlN" + + "UVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+fw=="; + + assertEquals(helloWorldEncoded, java8Base64.internalEncode(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, java8Base64.internalEncode(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + java8Base64.internalEncode(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, java8Base64.internalEncode(helloWorldDifferentCharsBytes)); + assertEquals(str, java8Base64.internalEncode(bytes)); + assertEquals(allBytesStr, java8Base64.internalEncode(allBytes)); + + assertEquals(helloWorldEncoded, commonsCodecBase64.internalEncode(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, commonsCodecBase64.internalEncode(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + commonsCodecBase64.internalEncode(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, commonsCodecBase64.internalEncode(helloWorldDifferentCharsBytes)); + assertEquals(str, commonsCodecBase64.internalEncode(bytes)); + assertEquals(allBytesStr, commonsCodecBase64.internalEncode(allBytes)); + + assertEquals(helloWorldEncoded, jaxbBase64.internalEncode(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, jaxbBase64.internalEncode(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, jaxbBase64.internalEncode(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, jaxbBase64.internalEncode(helloWorldDifferentCharsBytes)); + assertEquals(str, jaxbBase64.internalEncode(bytes)); + assertEquals(allBytesStr, jaxbBase64.internalEncode(allBytes)); + + assertEquals(helloWorldEncoded, jaxb230Base64.internalEncode(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, jaxb230Base64.internalEncode(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + jaxb230Base64.internalEncode(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, jaxb230Base64.internalEncode(helloWorldDifferentCharsBytes)); + assertEquals(str, jaxb230Base64.internalEncode(bytes)); + assertEquals(allBytesStr, jaxb230Base64.internalEncode(allBytes)); + } + + @Test + public void testEncodeUrlWithoutPadding() { + final String helloWorldEncoded = "SGVsbG8gV29ybGQ"; + final String helloWorldTwoLinesEncoded = "SGVsbG8gV29ybGQNCk5ldyBMaW5lMg"; + final String helloWorldTwoLinesAndNewLineEncoded = "SGVsbG8gV29ybGQNClNlY29uZCBMaW5lDQo"; + final String helloWorldDifferentCharsEncoded = "YDEyMzQ1Njc4OTAtPX4hQCMkJV4mKigpXyvRkdCBIuKEljs6P3F3ZXJ0eXVpb3B" + + "bXWFzZGZnaGprbDsnenhjdmJubSwuL1FXRVJUWVVJT1B7fXxBU0RGR0hKS0w6WlhDVkJOTTw-P9C50YTRj9GG0YvRh9GD0LLRgdC" + + "60LDQvNC10L_QuNC90YDRgtCz0L7RjNGI0LvQsdGJ0LTRjtC30LYu0YXRjdGKXNCZ0KTQr9Cm0KvQp9Cj0JLQodCa0JDQnNCV0J_" + + "QmNCd0KDQotCT0J7QrNCo0JvQkdCp0JTQrtCX0JYs0KXQrdCqLw0JDCcICg"; + final String str = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMPQ5BCMxlUq2TYy" + + "iRIoEUsz6HGTJhHuasS2nx1Se4Co3lxwxyubVdFj8AuhHNJSmJvjlpbTsGOjLZpr" + + "HyDEDdJmf1Fensh1MhUnBZ4a7uLrZrKzFHHJdamX9pxapB89vLeHlCot9hVXdrZH" + + "nNtg6FdmRKH_8gbs8iDyIayFvzYDAgMBAAECgYA-c9MpTBy9cQsR9BAvkEPjvkx2" + + "XL4ZnfbDgpNA4Nuu7yzsQrPjPomiXMNkkiAFHH67yVxwAlgRjyuuQlgNNTpKvyQt" + + "XcHxffnU0820VmE23M-L7jg2TlB3-rUnEDmDvCoyjlwGDR6lNb7t7Fgg2iR-iaov" + + "0iVzz-l9w0slRlyGsQJBAPWXW2m3NmFgqfDxtw8fsKC2y8o17_cnPjozRGtWb8LQ" + + "g3VCb8kbOFHOYNGazq3M7-wD1qILF2h_HecgK9eQrZ0CQQDMHXoJMfKKbrFrTKgE" + + "zyggO1gtuT5OXYeFewMEb5AbDI2FfSc2YP7SHij8iQ2HdukBrbTmi6qxh3HmIR58" + + "I_AfAkEA0Y9vr0tombsUB8cZv0v5OYoBZvCTbMANtzfb4AOHpiKqqbohDOevLQ7_" + + "SpvgVCmVaDz2PptcRAyEBZ5MCssneQJAB2pmvaDH7Ambfod5bztLfOhLCtY5EkXJ" + + "n6rZcDbRaHorRhdG7m3VtDKOUKZ2DF7glkQGV33phKukErVPUzlHBwJAScD9TqaG" + + "wJ3juUsVtujV23SnH43iMggXT7m82STpPGam1hPfmqu2Z0niePFo927ogQ7H1EMJ" + + "UHgqXmuvk2X_Ww"; + + final String allBytesStr = "gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp-goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2" + + "-v8DBwsPExcbHyMnKy8zNzs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5ufo6err7O3u7_Dx8vP09fb3-Pn6-_z9_v8AAQIDBAUGBwg" + + "JCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkdISUpLTE1OT1BRUlN" + + "UVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-fw"; + + assertEquals(helloWorldEncoded, java8Base64.internalEncodeUrlWithoutPadding(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, java8Base64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + java8Base64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, + java8Base64.internalEncodeUrlWithoutPadding(helloWorldDifferentCharsBytes)); + assertEquals(str, java8Base64.internalEncodeUrlWithoutPadding(bytes)); + assertEquals(allBytesStr, java8Base64.internalEncodeUrlWithoutPadding(allBytes)); + + assertEquals(helloWorldEncoded, commonsCodecBase64.internalEncodeUrlWithoutPadding(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, + commonsCodecBase64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + commonsCodecBase64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, + commonsCodecBase64.internalEncodeUrlWithoutPadding(helloWorldDifferentCharsBytes)); + assertEquals(str, commonsCodecBase64.internalEncodeUrlWithoutPadding(bytes)); + assertEquals(allBytesStr, commonsCodecBase64.internalEncodeUrlWithoutPadding(allBytes)); + + assertEquals(helloWorldEncoded, jaxbBase64.internalEncodeUrlWithoutPadding(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, jaxbBase64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + jaxbBase64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, + jaxbBase64.internalEncodeUrlWithoutPadding(helloWorldDifferentCharsBytes)); + assertEquals(str, jaxbBase64.internalEncodeUrlWithoutPadding(bytes)); + assertEquals(allBytesStr, jaxbBase64.internalEncodeUrlWithoutPadding(allBytes)); + + assertEquals(helloWorldEncoded, jaxb230Base64.internalEncodeUrlWithoutPadding(helloWorldBytes)); + assertEquals(helloWorldTwoLinesEncoded, jaxb230Base64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesBytes)); + assertEquals(helloWorldTwoLinesAndNewLineEncoded, + jaxb230Base64.internalEncodeUrlWithoutPadding(helloWorldTwoLinesAndNewLineBytes)); + assertEquals(helloWorldDifferentCharsEncoded, + jaxb230Base64.internalEncodeUrlWithoutPadding(helloWorldDifferentCharsBytes)); + assertEquals(str, jaxb230Base64.internalEncodeUrlWithoutPadding(bytes)); + assertEquals(allBytesStr, jaxb230Base64.internalEncodeUrlWithoutPadding(allBytes)); + } +} diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/BaseStringExtractorTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/BaseStringExtractorTest.java index bc833db08..89865a637 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/BaseStringExtractorTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/BaseStringExtractorTest.java @@ -7,6 +7,8 @@ import com.github.scribejava.core.exceptions.OAuthParametersMissingException; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Verb; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class BaseStringExtractorTest { @@ -83,15 +85,23 @@ public void shouldExcludePort443v2() { assertEquals(expected, baseString); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfRquestIsNull() { - extractor.extract(null); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(null); + } + }); } - @Test(expected = OAuthParametersMissingException.class) public void shouldThrowExceptionIfRquestHasNoOAuthParameters() { final OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com"); - extractor.extract(request); + assertThrows(OAuthParametersMissingException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(request); + } + }); } @Test diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/HeaderExtractorTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/HeaderExtractorTest.java index c1658fc7e..b515908c8 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/HeaderExtractorTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/HeaderExtractorTest.java @@ -2,12 +2,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; import org.junit.Before; import org.junit.Test; import com.github.scribejava.core.exceptions.OAuthParametersMissingException; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.ObjectMother; +import org.junit.function.ThrowingRunnable; public class HeaderExtractorTest { @@ -36,21 +38,29 @@ public void shouldExtractStandardHeader() { assertTrue(header.contains(timestamp)); // Assert that header only contains the checked elements above and nothing else assertEquals(", , , ", - header.replaceFirst(oauth, "") - .replaceFirst(callback, "") - .replaceFirst(signature, "") - .replaceFirst(key, "") - .replaceFirst(timestamp, "")); + header.replaceFirst(oauth, "") + .replaceFirst(callback, "") + .replaceFirst(signature, "") + .replaceFirst(key, "") + .replaceFirst(timestamp, "")); } - @Test(expected = IllegalArgumentException.class) public void shouldExceptionIfRequestIsNull() { - extractor.extract(null); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(null); + } + }); } - @Test(expected = OAuthParametersMissingException.class) public void shouldExceptionIfRequestHasNoOAuthParams() { final OAuthRequest emptyRequest = new OAuthRequest(Verb.GET, "http://example.com"); - extractor.extract(emptyRequest); + assertThrows(OAuthParametersMissingException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(emptyRequest); + } + }); } } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth1AccessTokenExtractorTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth1AccessTokenExtractorTest.java index 36ac4cd2e..b62d9bf1e 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth1AccessTokenExtractorTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth1AccessTokenExtractorTest.java @@ -10,6 +10,8 @@ import java.util.Collections; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class OAuth1AccessTokenExtractorTest { @@ -22,58 +24,94 @@ public void setUp() { @Test public void shouldExtractTokenFromOAuthStandardResponse() throws IOException { - final String response = "oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03"; - final OAuth1Token extracted = extractor.extract(ok(response)); + final String responseBody = "oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03"; + final OAuth1Token extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("hh5s93j4hdidpola", extracted.getToken()); assertEquals("hdhd0244k9j7ao03", extracted.getTokenSecret()); } @Test public void shouldExtractTokenFromInvertedOAuthStandardResponse() throws IOException { - final String response = "oauth_token_secret=hh5s93j4hdidpola&oauth_token=hdhd0244k9j7ao03"; - final OAuth1Token extracted = extractor.extract(ok(response)); + final String responseBody = "oauth_token_secret=hh5s93j4hdidpola&oauth_token=hdhd0244k9j7ao03"; + final OAuth1Token extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("hh5s93j4hdidpola", extracted.getTokenSecret()); assertEquals("hdhd0244k9j7ao03", extracted.getToken()); } @Test public void shouldExtractTokenFromResponseWithCallbackConfirmed() throws IOException { - final String response = "oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03" + final String responseBody = "oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03" + "&callback_confirmed=true"; - final OAuth1Token extracted = extractor.extract(ok(response)); + final OAuth1Token extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("hh5s93j4hdidpola", extracted.getToken()); assertEquals("hdhd0244k9j7ao03", extracted.getTokenSecret()); } @Test public void shouldExtractTokenWithEmptySecret() throws IOException { - final String response = "oauth_token=hh5s93j4hdidpola&oauth_token_secret="; - final OAuth1Token extracted = extractor.extract(ok(response)); + final String responseBody = "oauth_token=hh5s93j4hdidpola&oauth_token_secret="; + final OAuth1Token extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("hh5s93j4hdidpola", extracted.getToken()); assertEquals("", extracted.getTokenSecret()); } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfTokenIsAbsent() throws IOException { - final String response = "oauth_secret=hh5s93j4hdidpola&callback_confirmed=true"; - extractor.extract(ok(response)); + final String responseBody = "oauth_secret=hh5s93j4hdidpola&callback_confirmed=true"; + try (Response response = ok(responseBody)) { + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfSecretIsAbsent() throws IOException { - final String response = "oauth_token=hh5s93j4hdidpola&callback_confirmed=true"; - extractor.extract(ok(response)); + final String responseBody = "oauth_token=hh5s93j4hdidpola&callback_confirmed=true"; + try (Response response = ok(responseBody)) { + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfResponseIsNull() throws IOException { - extractor.extract(ok(null)); + try (Response response = ok(null)) { + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfResponseIsEmptyString() throws IOException { - final String response = ""; - extractor.extract(ok(response)); + final String responseBody = ""; + try (Response response = ok(responseBody)) { + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } private static Response ok(String body) { diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenExtractorTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenExtractorTest.java index a79a87615..4f71c011d 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenExtractorTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenExtractorTest.java @@ -10,6 +10,8 @@ import java.util.Collections; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class OAuth2AccessTokenExtractorTest { @@ -22,18 +24,24 @@ public void setUp() { @Test public void shouldExtractTokenFromOAuthStandardResponse() throws IOException { - final String response = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159" + final String responseBody = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159" + "|RsXNdKrpxg8L6QNLWcs2TVTmcaE"; - final OAuth2AccessToken extracted = extractor.extract(ok(response)); + final OAuth2AccessToken extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE", extracted.getAccessToken()); } @Test public void shouldExtractTokenFromResponseWithExpiresParam() throws IOException { - final String response = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159" + final String responseBody = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159" + "|RsXNdKrpxg8L6QNLWcs2TVTmcaE&expires_in=5108"; - final OAuth2AccessToken extracted = extractor.extract(ok(response)); + final OAuth2AccessToken extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE", extracted.getAccessToken()); assertEquals(Integer.valueOf(5108), extracted.getExpiresIn()); @@ -41,9 +49,12 @@ public void shouldExtractTokenFromResponseWithExpiresParam() throws IOException @Test public void shouldExtractTokenFromResponseWithExpiresAndRefreshParam() throws IOException { - final String response = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159" + final String responseBody = "access_token=166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159" + "|RsXNdKrpxg8L6QNLWcs2TVTmcaE&expires_in=5108&token_type=bearer&refresh_token=166942940015970"; - final OAuth2AccessToken extracted = extractor.extract(ok(response)); + final OAuth2AccessToken extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("166942940015970|2.2ltzWXYNDjCtg5ZDVVJJeg__.3600.1295816400-548517159|RsXNdKrpxg8L6QNLWcs2TVTmcaE", extracted.getAccessToken()); assertEquals(Integer.valueOf(5108), extracted.getExpiresIn()); @@ -53,32 +64,59 @@ public void shouldExtractTokenFromResponseWithExpiresAndRefreshParam() throws IO @Test public void shouldExtractTokenFromResponseWithManyParameters() throws IOException { - final String response = "access_token=foo1234&other_stuff=yeah_we_have_this_too&number=42"; - final OAuth2AccessToken extracted = extractor.extract(ok(response)); + final String responseBody = "access_token=foo1234&other_stuff=yeah_we_have_this_too&number=42"; + final OAuth2AccessToken extracted; + try (Response response = ok(responseBody)) { + extracted = extractor.extract(response); + } assertEquals("foo1234", extracted.getAccessToken()); } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfErrorResponse() throws IOException { - final String response = ""; - extractor.extract(error(response)); + final String responseBody = ""; + try (Response response = error(responseBody)) { + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfTokenIsAbsent() throws IOException { - final String response = "&expires=5108"; - extractor.extract(ok(response)); + final String responseBody = "&expires=5108"; + try (Response response = ok(responseBody)) { + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfResponseIsNull() throws IOException { - extractor.extract(ok(null)); + try (Response response = ok(null)) { + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfResponseIsEmptyString() throws IOException { - final String response = ""; - extractor.extract(ok(response)); + final String responseBody = ""; + try (Response response = ok(responseBody)) { + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } private static Response ok(String body) { diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractorTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractorTest.java index 3aa80cd30..6628d1d9b 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractorTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/extractors/OAuth2AccessTokenJsonExtractorTest.java @@ -3,13 +3,15 @@ import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.oauth2.OAuth2Error; import org.junit.Test; import java.io.IOException; import java.util.Collections; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class OAuth2AccessTokenJsonExtractorTest { @@ -17,59 +19,103 @@ public class OAuth2AccessTokenJsonExtractorTest { @Test public void shouldParseResponse() throws IOException { - final OAuth2AccessToken token = extractor.extract( - ok("{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T3X\"}")); + final String responseBody = "{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T3X\", " + + "\"token_type\":\"example\"}"; + final OAuth2AccessToken token; + try (Response response = ok(responseBody)) { + token = extractor.extract(response); + } assertEquals("I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T3X", token.getAccessToken()); } @Test public void shouldParseScopeFromResponse() throws IOException { - OAuth2AccessToken token = extractor.extract( - ok("{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T4X\", " - + "\"scope\":\"s1\"}")); + final String responseBody = "{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T4X\", " + + "\"token_type\":\"example\"," + + "\"scope\":\"s1\"}"; + final OAuth2AccessToken token; + try (Response response = ok(responseBody)) { + token = extractor.extract(response); + } assertEquals("I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T4X", token.getAccessToken()); assertEquals("s1", token.getScope()); - token = extractor.extract( - ok("{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T5X\", " - + "\"scope\":\"s1 s2\"}")); - assertEquals("I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T5X", token.getAccessToken()); - assertEquals("s1 s2", token.getScope()); + final String responseBody2 = "{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T5X\", " + + "\"token_type\":\"example\"," + + "\"scope\":\"s1 s2\"}"; + final OAuth2AccessToken token2; + try (Response response = ok(responseBody2)) { + token2 = extractor.extract(response); + } + assertEquals("I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T5X", token2.getAccessToken()); + assertEquals("s1 s2", token2.getScope()); - token = extractor.extract( - ok("{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T6X\", " - + "\"scope\":\"s3 s4\", " - + "\"refresh_token\":\"refresh_token1\"}")); - assertEquals("I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T6X", token.getAccessToken()); - assertEquals("s3 s4", token.getScope()); - assertEquals("refresh_token1", token.getRefreshToken()); + final String responseBody3 = "{ \"access_token\":\"I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T6X\", " + + "\"token_type\":\"example\"," + + "\"scope\":\"s3 s4\", " + + "\"refresh_token\":\"refresh_token1\"}"; + final OAuth2AccessToken token3; + try (Response response = ok(responseBody3)) { + token3 = extractor.extract(response); + } + assertEquals("I0122HHJKLEM21F3WLPYHDKGKZULAUO4SGMV3ABKFTDT3T6X", token3.getAccessToken()); + assertEquals("s3 s4", token3.getScope()); + assertEquals("refresh_token1", token3.getRefreshToken()); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfForNullParameters() throws IOException { - extractor.extract(ok(null)); + try (Response response = ok(null)) { + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfForEmptyStrings() throws IOException { - extractor.extract(ok("")); + final String responseBody = ""; + try (Response response = ok(responseBody)) { + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + } } @Test public void shouldThrowExceptionIfResponseIsError() throws IOException { - final String body = "{" + - "\"error_description\":\"unknown, invalid, or expired refresh token\"," + - "\"error\":\"invalid_grant\"" + - "}"; - try { - extractor.extract(error(body)); - fail(); - } catch (OAuth2AccessTokenErrorResponse oaer) { - assertEquals(OAuth2AccessTokenErrorResponse.ErrorCode.invalid_grant, oaer.getErrorCode()); + final String responseBody = "{" + + "\"error_description\":\"unknown, invalid, or expired refresh token\"," + + "\"error\":\"invalid_grant\"" + + "}"; + try (Response response = error(responseBody)) { + final OAuth2AccessTokenErrorResponse oaer = assertThrows(OAuth2AccessTokenErrorResponse.class, + new ThrowingRunnable() { + @Override + public void run() throws Throwable { + extractor.extract(response); + } + }); + assertEquals(OAuth2Error.INVALID_GRANT, oaer.getError()); assertEquals("unknown, invalid, or expired refresh token", oaer.getErrorDescription()); } } + @Test + public void testEscapedJsonInResponse() throws IOException { + final String responseBody = "{ \"access_token\":\"I0122HKLEM2\\/MV3ABKFTDT3T5X\"," + + "\"token_type\":\"example\"}"; + final OAuth2AccessToken token; + try (Response response = ok(responseBody)) { + token = extractor.extract(response); + } + assertEquals("I0122HKLEM2/MV3ABKFTDT3T5X", token.getAccessToken()); + } + private static Response ok(String body) { return new Response(200, /* message */ null, /* headers */ Collections.emptyMap(), body); } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/httpclient/multipart/MultipartUtilsTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/httpclient/multipart/MultipartUtilsTest.java new file mode 100644 index 000000000..c726dd9a7 --- /dev/null +++ b/scribejava-core/src/test/java/com/github/scribejava/core/httpclient/multipart/MultipartUtilsTest.java @@ -0,0 +1,353 @@ +package com.github.scribejava.core.httpclient.multipart; + +import com.github.scribejava.core.httpclient.HttpClient; +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; + +public class MultipartUtilsTest { + + @Test + public void testEmptyMultipartPayload() throws IOException { + final MultipartPayload mP = new MultipartPayload(); + + final StringBuilder headersString = new StringBuilder(); + for (Map.Entry header : mP.getHeaders().entrySet()) { + headersString.append(header.getKey()) + .append(": ") + .append(header.getValue()) + .append("\r\n"); + } + + assertEquals("Content-Type: multipart/form-data; boundary=\"" + mP.getBoundary() + "\"\r\n", + headersString.toString()); + + assertEquals("", MultipartUtils.getPayload(mP).toString()); + } + + @Test + public void testSimpleMultipartPayload() throws IOException { + final Map headers = new LinkedHashMap<>(); + headers.put("X-Header", "X-Value"); + headers.put("Content-Disposition", "Content-Disposition-Value"); + final MultipartPayload mP = new MultipartPayload("mixed", "simple boundary", headers); + mP.setPreamble("This is the preamble. It is to be ignored, though it\n" + + "is a handy place for composition agents to include an\n" + + "explanatory note to non-MIME conformant readers."); + + mP.addBodyPart(new ByteArrayBodyPartPayload(("This is implicitly typed plain US-ASCII text.\n" + + "It does NOT end with a linebreak.").getBytes())); + + final ByteArrayBodyPartPayload bP = new ByteArrayBodyPartPayload( + ("This is explicitly typed plain US-ASCII text.\n" + + "It DOES end with a linebreak.\n").getBytes(), + Collections.singletonMap(HttpClient.CONTENT_TYPE, "text/plain; charset=us-ascii")); + mP.addBodyPart(bP); + + mP.setEpilogue("This is the epilogue. It is also to be ignored."); + + final StringBuilder headersString = new StringBuilder(); + for (Map.Entry header : mP.getHeaders().entrySet()) { + headersString.append(header.getKey()) + .append(": ") + .append(header.getValue()) + .append("\r\n"); + } + + assertEquals("X-Header: X-Value\r\n" + + "Content-Disposition: Content-Disposition-Value\r\n" + + "Content-Type: multipart/mixed; boundary=\"simple boundary\"\r\n", + headersString.toString()); + + assertEquals("This is the preamble. It is to be ignored, though it\n" + + "is a handy place for composition agents to include an\n" + + "explanatory note to non-MIME conformant readers." + + "\r\n--simple boundary\r\n" + + "\r\n" + + "This is implicitly typed plain US-ASCII text.\n" + + "It does NOT end with a linebreak." + + "\r\n--simple boundary\r\n" + + "Content-Type: text/plain; charset=us-ascii\r\n" + + "\r\n" + + "This is explicitly typed plain US-ASCII text.\n" + + "It DOES end with a linebreak.\n" + + "\r\n--simple boundary--" + + "\r\nThis is the epilogue. It is also to be ignored.", + MultipartUtils.getPayload(mP).toString()); + } + + @Test + public void testCRLFMultipartPayload() throws IOException { + final MultipartPayload mP = new MultipartPayload("simple-boundary"); + mP.addBodyPart(new ByteArrayBodyPartPayload("It does NOT end with a linebreak.".getBytes())); + mP.addBodyPart(new ByteArrayBodyPartPayload("It does end with a \\r linebreak.\r".getBytes())); + mP.addBodyPart(new ByteArrayBodyPartPayload("It does end with a \\n linebreak.\n".getBytes())); + mP.addBodyPart(new ByteArrayBodyPartPayload("It does end with a \\r\\n linebreak.\r\n".getBytes())); + mP.addBodyPart(new ByteArrayBodyPartPayload("the last one".getBytes())); + + final StringBuilder headersString = new StringBuilder(); + for (Map.Entry header : mP.getHeaders().entrySet()) { + headersString.append(header.getKey()) + .append(": ") + .append(header.getValue()) + .append("\r\n"); + } + + assertEquals("Content-Type: multipart/form-data; boundary=\"simple-boundary\"\r\n", headersString.toString()); + + assertEquals("--simple-boundary\r\n" + + "\r\n" + + "It does NOT end with a linebreak." + + "\r\n--simple-boundary\r\n" + + "\r\n" + + "It does end with a \\r linebreak.\r" + + "\r\n--simple-boundary\r\n" + + "\r\n" + + "It does end with a \\n linebreak.\n" + + "\r\n--simple-boundary\r\n" + + "\r\n" + + "It does end with a \\r\\n linebreak.\r\n" + + "\r\n--simple-boundary\r\n" + + "\r\n" + + "the last one" + + "\r\n--simple-boundary--", + MultipartUtils.getPayload(mP).toString()); + } + + @Test + public void testFileByteArrayBodyPartPayloadMultipartPayload() throws IOException { + final MultipartPayload mP = new MultipartPayload("testFileByteArrayBodyPartPayloadMultipartPayload boundary"); + mP.addBodyPart(new FileByteArrayBodyPartPayload("fileContent".getBytes(), "name", "filename.ext")); + + final StringBuilder headersString = new StringBuilder(); + for (Map.Entry header : mP.getHeaders().entrySet()) { + headersString.append(header.getKey()) + .append(": ") + .append(header.getValue()) + .append("\r\n"); + } + + assertEquals("Content-Type: multipart/form-data; " + + "boundary=\"testFileByteArrayBodyPartPayloadMultipartPayload boundary\"\r\n", + headersString.toString()); + + assertEquals("--testFileByteArrayBodyPartPayloadMultipartPayload boundary\r\n" + + "Content-Disposition: form-data; name=\"name\"; filename=\"filename.ext\"\r\n" + + "\r\n" + + "fileContent" + + "\r\n--testFileByteArrayBodyPartPayloadMultipartPayload boundary--", + MultipartUtils.getPayload(mP).toString()); + } + + @Test + public void testComplexMultipartPayload() throws IOException { + final MultipartPayload mP = new MultipartPayload("mixed", "unique-boundary-1"); + + mP.setPreamble("This is the preamble area of a multipart message.\n" + + "Mail readers that understand multipart format\n" + + "should ignore this preamble.\n" + + "\n" + + "If you are reading this text, you might want to\n" + + "consider changing to a mail reader that understands\n" + + "how to properly display multipart messages.\n"); + + mP.addBodyPart(new ByteArrayBodyPartPayload("... Some text appears here ...".getBytes())); + + mP.addBodyPart(new ByteArrayBodyPartPayload(("This could have been part of the previous part, but\n" + + "illustrates explicit versus implicit typing of body\n" + + "parts.\n").getBytes(), "text/plain; charset=US-ASCII")); + + final MultipartPayload innerMP = new MultipartPayload("parallel", "unique-boundary-2"); + mP.addBodyPart(innerMP); + + final Map audioHeaders = new LinkedHashMap<>(); + audioHeaders.put("Content-Type", "audio/basic"); + audioHeaders.put("Content-Transfer-Encoding", "base64"); + innerMP.addBodyPart(new ByteArrayBodyPartPayload(("... base64-encoded 8000 Hz single-channel\n" + + " mu-law-format audio data goes here ...").getBytes(), audioHeaders)); + + final Map imageHeaders = new LinkedHashMap<>(); + imageHeaders.put("Content-Type", "image/jpeg"); + imageHeaders.put("Content-Transfer-Encoding", "base64"); + innerMP.addBodyPart(new ByteArrayBodyPartPayload("... base64-encoded image data goes here ...".getBytes(), + imageHeaders)); + + mP.addBodyPart(new ByteArrayBodyPartPayload(("This is enriched.\n" + + "as defined in RFC 1896\n" + + "\n" + + "Isn't it\n" + + "cool?\n").getBytes(), "text/enriched")); + + mP.addBodyPart(new ByteArrayBodyPartPayload(("From: (mailbox in US-ASCII)\n" + + "To: (address in US-ASCII)\n" + + "Subject: (subject in US-ASCII)\n" + + "Content-Type: Text/plain; charset=ISO-8859-1\n" + + "Content-Transfer-Encoding: Quoted-printable\n" + + "\n" + + "... Additional text in ISO-8859-1 goes here ...\n").getBytes(), "message/rfc822")); + + final StringBuilder headersString = new StringBuilder(); + for (Map.Entry header : mP.getHeaders().entrySet()) { + headersString.append(header.getKey()) + .append(": ") + .append(header.getValue()) + .append("\r\n"); + } + assertEquals("Content-Type: multipart/mixed; boundary=\"unique-boundary-1\"\r\n", headersString.toString()); + + assertEquals("This is the preamble area of a multipart message.\n" + + "Mail readers that understand multipart format\n" + + "should ignore this preamble.\n" + + "\n" + + "If you are reading this text, you might want to\n" + + "consider changing to a mail reader that understands\n" + + "how to properly display multipart messages.\n" + + "\r\n--unique-boundary-1\r\n" + + "\r\n" + + "... Some text appears here ..." + + "\r\n--unique-boundary-1\r\n" + + "Content-Type: text/plain; charset=US-ASCII\r\n" + + "\r\n" + + "This could have been part of the previous part, but\n" + + "illustrates explicit versus implicit typing of body\n" + + "parts.\n" + + "\r\n--unique-boundary-1\r\n" + + "Content-Type: multipart/parallel; boundary=\"unique-boundary-2\"\r\n" + + "\r\n--unique-boundary-2\r\n" + + "Content-Type: audio/basic\r\n" + + "Content-Transfer-Encoding: base64\r\n" + + "\r\n" + + "... base64-encoded 8000 Hz single-channel\n" + + " mu-law-format audio data goes here ..." + + "\r\n--unique-boundary-2\r\n" + + "Content-Type: image/jpeg\r\n" + + "Content-Transfer-Encoding: base64\r\n" + + "\r\n" + + "... base64-encoded image data goes here ..." + + "\r\n--unique-boundary-2--" + + "\r\n--unique-boundary-1\r\n" + + "Content-Type: text/enriched\r\n" + + "\r\n" + + "This is enriched.\n" + + "as defined in RFC 1896\n" + + "\n" + + "Isn't it\n" + + "cool?\n" + + "\r\n--unique-boundary-1\r\n" + + "Content-Type: message/rfc822\r\n" + + "\r\n" + + "From: (mailbox in US-ASCII)\n" + + "To: (address in US-ASCII)\n" + + "Subject: (subject in US-ASCII)\n" + + "Content-Type: Text/plain; charset=ISO-8859-1\n" + + "Content-Transfer-Encoding: Quoted-printable\n" + + "\n" + + "... Additional text in ISO-8859-1 goes here ...\n" + + "\r\n--unique-boundary-1--", + MultipartUtils.getPayload(mP).toString()); + } + + @Test + public void testParseBoundaryFromHeader() { + assertNull(MultipartUtils.parseBoundaryFromHeader(null)); + + assertEquals("0aA'()+_,-./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=\"0aA'()+_,-./:=?\"")); + + assertEquals("0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=\"0aA'()+_, -./:=?\"")); + + assertEquals("0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=\"0aA'()+_, -./:=? \"")); + + assertEquals("0aA'()+_,-./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=0aA'()+_,-./:=?")); + + assertEquals("0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=0aA'()+_, -./:=?")); + + assertEquals("0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=0aA'()+_, -./:=? ")); + + assertEquals(" 0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary= 0aA'()+_, -./:=?")); + + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundar=0aA'()+_, -./:=? ")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; ")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype;")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=")); + + assertEquals("0aA'()+_,", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=0aA'()+_,; -./:=? ")); + + assertEquals("0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=\"0aA'()+_, -./:=?")); + + assertEquals("0aA'()+_, -./:=?", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=0aA'()+_, -./:=?\"")); + + assertEquals("1234567890123456789012345678901234567890123456789012345678901234567890", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; " + + "boundary=1234567890123456789012345678901234567890123456789012345678901234567890")); + + assertEquals("1234567890123456789012345678901234567890123456789012345678901234567890", + MultipartUtils.parseBoundaryFromHeader("multipart/subtype; " + + "boundary=12345678901234567890123456789012345678901234567890123456789012345678901")); + + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=\"\"")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=;123")); + assertNull(MultipartUtils.parseBoundaryFromHeader("multipart/subtype; boundary=\"\"123")); + } + + @Test + public void testValidCheckBoundarySyntax() { + MultipartUtils.checkBoundarySyntax("0aA'()+_,-./:=?"); + MultipartUtils.checkBoundarySyntax("0aA'()+_,- ./:=?"); + MultipartUtils.checkBoundarySyntax(" 0aA'()+_,-./:=?"); + MultipartUtils.checkBoundarySyntax("1234567890123456789012345678901234567890123456789012345678901234567890"); + } + + @Test + public void testNonValidLastWhiteSpaceCheckBoundarySyntax() { + testNotValidBoundary("0aA'()+_,-./:=? "); + } + + @Test + public void testNonValidEmptyCheckBoundarySyntax() { + testNotValidBoundary(""); + } + + @Test + public void testNonValidIllegalSymbolCheckBoundarySyntax() { + testNotValidBoundary("0aA'()+_;,-./:=? "); + } + + @Test + public void testNonValidTooLongCheckBoundarySyntax() { + testNotValidBoundary("12345678901234567890123456789012345678901234567890123456789012345678901"); + } + + @Test + public void testNonValidNullCheckBoundarySyntax() { + testNotValidBoundary(null); + } + + private static void testNotValidBoundary(final String boundary) { + final IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + MultipartUtils.checkBoundarySyntax(boundary); + } + }); + assertTrue(thrown.getMessage().startsWith("{'boundary'='" + boundary + "'} has invalid syntax. Should be '")); + } +} diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/model/OAuthRequestTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/model/OAuthRequestTest.java index 0ea88985d..32d5d6731 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/model/OAuthRequestTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/model/OAuthRequestTest.java @@ -1,8 +1,11 @@ package com.github.scribejava.core.model; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import org.junit.function.ThrowingRunnable; public class OAuthRequestTest { @@ -24,8 +27,30 @@ public void shouldAddOAuthParamters() { assertEquals(5, request.getOauthParameters().size()); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfParameterIsNotOAuth() { - request.addOAuthParameter("otherParam", "value"); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + request.addOAuthParameter("otherParam", "value"); + } + }); + } + + @Test + public void shouldNotSentHeaderTwice() { + assertTrue(request.getHeaders().isEmpty()); + request.addHeader("HEADER-NAME", "first"); + request.addHeader("header-name", "middle"); + request.addHeader("Header-Name", "last"); + + assertEquals(1, request.getHeaders().size()); + + assertTrue(request.getHeaders().containsKey("HEADER-NAME")); + assertTrue(request.getHeaders().containsKey("header-name")); + assertTrue(request.getHeaders().containsKey("Header-Name")); + + assertEquals("last", request.getHeaders().get("HEADER-NAME")); + assertEquals("last", request.getHeaders().get("header-name")); + assertEquals("last", request.getHeaders().get("Header-Name")); } } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/model/ParameterListTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/model/ParameterListTest.java index 78a22c9f9..702c66395 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/model/ParameterListTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/model/ParameterListTest.java @@ -5,6 +5,8 @@ import org.junit.Test; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class ParameterListTest { @@ -15,9 +17,13 @@ public void setUp() { this.params = new ParameterList(); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionWhenAppendingNullMapToQuerystring() { - params.appendTo(null); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + params.appendTo(null); + } + }); } @Test diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/model/RequestTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/model/RequestTest.java index 274ccca23..87189632b 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/model/RequestTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/model/RequestTest.java @@ -1,27 +1,21 @@ package com.github.scribejava.core.model; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import org.junit.Before; import org.junit.Test; -import java.net.MalformedURLException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; public class RequestTest { - private OAuthRequest getRequest; - private OAuthRequest postRequest; - - @Before - public void setUp() throws MalformedURLException { - postRequest = new OAuthRequest(Verb.POST, "http://example.com"); + @Test + public void shouldGetQueryStringParameters() { + final OAuthRequest postRequest = new OAuthRequest(Verb.POST, "http://example.com"); postRequest.addBodyParameter("param", "value"); postRequest.addBodyParameter("param with spaces", "value with spaces"); - getRequest = new OAuthRequest(Verb.GET, "http://example.com?qsparam=value&other+param=value+with+spaces"); - } + final OAuthRequest getRequest + = new OAuthRequest(Verb.GET, "http://example.com?qsparam=value&other+param=value+with+spaces"); - @Test - public void shouldGetQueryStringParameters() { assertEquals(2, getRequest.getQueryStringParams().size()); assertEquals(0, postRequest.getQueryStringParams().size()); assertTrue(getRequest.getQueryStringParams().contains(new Parameter("qsparam", "value"))); @@ -29,13 +23,21 @@ public void shouldGetQueryStringParameters() { @Test public void shouldSetBodyParamsAndAddContentLength() { + final OAuthRequest postRequest = new OAuthRequest(Verb.POST, "http://example.com"); + postRequest.addBodyParameter("param", "value"); + postRequest.addBodyParameter("param with spaces", "value with spaces"); + assertEquals("param=value¶m%20with%20spaces=value%20with%20spaces", new String(postRequest.getByteArrayPayload())); } @Test public void shouldSetPayloadAndHeaders() { + final OAuthRequest postRequest = new OAuthRequest(Verb.POST, "http://example.com"); + postRequest.addBodyParameter("param", "value"); + postRequest.addBodyParameter("param with spaces", "value with spaces"); postRequest.setPayload("PAYLOAD"); + assertEquals("PAYLOAD", postRequest.getStringPayload()); } @@ -57,6 +59,41 @@ public void shouldReturnTheCompleteUrl() { @Test public void shouldHandleQueryStringSpaceEncodingProperly() { + final OAuthRequest getRequest + = new OAuthRequest(Verb.GET, "http://example.com?qsparam=value&other+param=value+with+spaces"); + assertTrue(getRequest.getQueryStringParams().contains(new Parameter("other param", "value with spaces"))); } + + @Test + public void shouldNotEncodeInStringPayload() throws Exception { + final String requestBody = "~/!@#$%^&*( )_+//\r\n%2F&"; + + final OAuthRequest postRequest = new OAuthRequest(Verb.POST, "http://example.com"); + postRequest.setPayload(requestBody); + + assertEquals(requestBody, postRequest.getStringPayload()); + } + + @Test + public void shouldNotEncodeInByteBodyPayload() throws Exception { + final byte[] requestBody = "~/!@#$%^&*( )_+//\r\n%2F&".getBytes(); + + final OAuthRequest postRequest = new OAuthRequest(Verb.POST, "http://example.com"); + postRequest.setPayload(requestBody); + + assertArrayEquals(requestBody, postRequest.getByteArrayPayload()); + } + + @Test + public void shouldEncodeInBodyParamsPayload() throws Exception { + final String expectedRequestBodyParamName = "~/!@#$%^&*( )_+//\r\n%2F&name"; + final String expectedRequestBodyParamValue = "~/!@#$%^&*( )_+//\r\n%2F&value"; + final String expectedRequestBody = "~%2F%21%40%23%24%25%5E%26%2A%28%20%29_%2B%2F%2F%0D%0A%252F%26amp%3Bname=" + + "~%2F%21%40%23%24%25%5E%26%2A%28%20%29_%2B%2F%2F%0D%0A%252F%26amp%3Bvalue"; + + final OAuthRequest postRequest = new OAuthRequest(Verb.POST, "http://example.com"); + postRequest.addBodyParameter(expectedRequestBodyParamName, expectedRequestBodyParamValue); + assertArrayEquals(expectedRequestBody.getBytes(), postRequest.getByteArrayPayload()); + } } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ApiUnit.java b/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ApiUnit.java index a3187957e..cd9e58550 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ApiUnit.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ApiUnit.java @@ -1,10 +1,12 @@ package com.github.scribejava.core.oauth; +import java.io.OutputStream; + import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.builder.api.OAuth2SignatureType; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; -import java.io.OutputStream; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignature; +import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter; class OAuth20ApiUnit extends DefaultApi20 { @@ -19,15 +21,15 @@ protected String getAuthorizationBaseUrl() { } @Override - public OAuth20ServiceUnit createService(String apiKey, String apiSecret, String callback, String scope, - OutputStream debugStream, String state, String responseType, String userAgent, - HttpClientConfig httpClientConfig, HttpClient httpClient) { - return new OAuth20ServiceUnit(this, apiKey, apiSecret, callback, scope, state, responseType, userAgent, - httpClientConfig, httpClient); + public OAuth20ServiceUnit createService(String apiKey, String apiSecret, String callback, String defaultScope, + String responseType, OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, + HttpClient httpClient) { + return new OAuth20ServiceUnit(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, + userAgent, httpClientConfig, httpClient); } @Override - public OAuth2SignatureType getSignatureType() { - return OAuth2SignatureType.BEARER_URI_QUERY_PARAMETER; + public BearerSignature getBearerSignature() { + return BearerSignatureURIQueryParameter.instance(); } } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceTest.java index c74e0ea57..3e0024c6c 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceTest.java @@ -1,24 +1,23 @@ package com.github.scribejava.core.oauth; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.scribejava.core.base64.Base64; import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.java8.Base64; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuth2Authorization; import com.github.scribejava.core.model.OAuthConstants; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import java.io.IOException; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertEquals; import org.junit.Test; import java.nio.charset.Charset; -import java.util.Map; import java.util.concurrent.ExecutionException; public class OAuth20ServiceTest { - private final Base64.Encoder base64Encoder = Base64.getEncoder(); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Test public void shouldProduceCorrectRequestSync() throws IOException, InterruptedException, ExecutionException { @@ -27,51 +26,46 @@ public void shouldProduceCorrectRequestSync() throws IOException, InterruptedExc .build(new OAuth20ApiUnit()); final OAuth2AccessToken token = service.getAccessTokenPasswordGrant("user1", "password1"); - final Gson json = new Gson(); - assertNotNull(token); - final Map map = json.fromJson(token.getRawResponse(), new TypeTokenImpl().getType()); + final JsonNode response = OBJECT_MAPPER.readTree(token.getRawResponse()); - assertEquals(OAuth20ServiceUnit.TOKEN, map.get(OAuthConstants.ACCESS_TOKEN)); - assertEquals(OAuth20ServiceUnit.STATE, map.get(OAuthConstants.STATE)); - assertEquals(OAuth20ServiceUnit.EXPIRES, map.get("expires_in")); + assertEquals(OAuth20ServiceUnit.TOKEN, response.get(OAuthConstants.ACCESS_TOKEN).asText()); + assertEquals(OAuth20ServiceUnit.EXPIRES, response.get("expires_in").asInt()); - final String authorize = base64Encoder.encodeToString( + final String authorize = Base64.encode( String.format("%s:%s", service.getApiKey(), service.getApiSecret()).getBytes(Charset.forName("UTF-8"))); - assertEquals(OAuthConstants.BASIC + " " + authorize, map.get(OAuthConstants.HEADER)); + assertEquals(OAuthConstants.BASIC + ' ' + authorize, response.get(OAuthConstants.HEADER).asText()); - assertEquals("user1", map.get("query-username")); - assertEquals("password1", map.get("query-password")); - assertEquals("password", map.get("query-grant_type")); + assertEquals("user1", response.get("query-username").asText()); + assertEquals("password1", response.get("query-password").asText()); + assertEquals("password", response.get("query-grant_type").asText()); } @Test - public void shouldProduceCorrectRequestAsync() throws ExecutionException, InterruptedException { + public void shouldProduceCorrectRequestAsync() throws ExecutionException, InterruptedException, IOException { final OAuth20Service service = new ServiceBuilder("your_api_key") .apiSecret("your_api_secret") .build(new OAuth20ApiUnit()); - final OAuth2AccessToken token = service.getAccessTokenPasswordGrantAsync("user1", "password1", null).get(); - final Gson json = new Gson(); + final OAuth2AccessToken token = service.getAccessTokenPasswordGrantAsync("user1", "password1").get(); assertNotNull(token); - final Map map = json.fromJson(token.getRawResponse(), new TypeTokenImpl().getType()); + final JsonNode response = OBJECT_MAPPER.readTree(token.getRawResponse()); - assertEquals(OAuth20ServiceUnit.TOKEN, map.get(OAuthConstants.ACCESS_TOKEN)); - assertEquals(OAuth20ServiceUnit.STATE, map.get(OAuthConstants.STATE)); - assertEquals(OAuth20ServiceUnit.EXPIRES, map.get("expires_in")); + assertEquals(OAuth20ServiceUnit.TOKEN, response.get(OAuthConstants.ACCESS_TOKEN).asText()); + assertEquals(OAuth20ServiceUnit.EXPIRES, response.get("expires_in").asInt()); - final String authorize = base64Encoder.encodeToString( + final String authorize = Base64.encode( String.format("%s:%s", service.getApiKey(), service.getApiSecret()).getBytes(Charset.forName("UTF-8"))); - assertEquals(OAuthConstants.BASIC + " " + authorize, map.get(OAuthConstants.HEADER)); + assertEquals(OAuthConstants.BASIC + ' ' + authorize, response.get(OAuthConstants.HEADER).asText()); - assertEquals("user1", map.get("query-username")); - assertEquals("password1", map.get("query-password")); - assertEquals("password", map.get("query-grant_type")); + assertEquals("user1", response.get("query-username").asText()); + assertEquals("password1", response.get("query-password").asText()); + assertEquals("password", response.get("query-grant_type").asText()); } @Test @@ -119,13 +113,5 @@ public void testOAuthExtractAuthorization() { authorization = service.extractAuthorization("https://cl.ex.com/cb"); assertEquals(null, authorization.getCode()); assertEquals(null, authorization.getState()); - - } - - private static class TypeTokenImpl extends TypeToken> { - - private TypeTokenImpl() { - } } - } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceUnit.java b/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceUnit.java index a5cbf9763..2766b7f2b 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceUnit.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/oauth/OAuth20ServiceUnit.java @@ -1,5 +1,7 @@ package com.github.scribejava.core.oauth; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.httpclient.HttpClient; import com.github.scribejava.core.httpclient.HttpClientConfig; @@ -8,8 +10,8 @@ import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Parameter; -import com.google.gson.Gson; +import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Future; @@ -18,11 +20,14 @@ class OAuth20ServiceUnit extends OAuth20Service { static final String TOKEN = "ae82980abab675c646a070686d5558ad"; static final String STATE = "123"; - static final String EXPIRES = "3600"; + static final int EXPIRES = 3600; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - OAuth20ServiceUnit(DefaultApi20 api, String apiKey, String apiSecret, String callback, String scope, String state, - String responseType, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) { - super(api, apiKey, apiSecret, callback, scope, state, responseType, userAgent, httpClientConfig, httpClient); + OAuth20ServiceUnit(DefaultApi20 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); } @Override @@ -31,8 +36,7 @@ protected OAuth2AccessToken sendAccessTokenRequestSync(OAuthRequest request) { } private String prepareRawResponse(OAuthRequest request) { - final Gson json = new Gson(); - final Map response = new HashMap<>(); + final Map response = new HashMap<>(); response.put(OAuthConstants.ACCESS_TOKEN, TOKEN); response.put(OAuthConstants.STATE, STATE); response.put("expires_in", EXPIRES); @@ -44,7 +48,11 @@ private String prepareRawResponse(OAuthRequest request) { response.put("query-" + param.getKey(), param.getValue()); } - return json.toJson(response); + try { + return OBJECT_MAPPER.writeValueAsString(response); + } catch (JsonProcessingException ex) { + throw new IllegalStateException("smth wrong with Jackson?"); + } } @Override diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethodTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethodTest.java index 1f580480a..a83a5470d 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethodTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/pkce/PKCECodeChallengeMethodTest.java @@ -16,7 +16,7 @@ public class PKCECodeChallengeMethodTest { @Test public void testGeneratingPKCE() { - final PKCE pkce = new PKCEService().generatePKCE(RANDOM_BYTES); + final PKCE pkce = PKCEService.defaultInstance().generatePKCE(RANDOM_BYTES); assertEquals(PKCECodeChallengeMethod.S256, pkce.getCodeChallengeMethod()); assertEquals("dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", pkce.getCodeVerifier()); diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/services/HMACSha1SignatureServiceTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/services/HMACSha1SignatureServiceTest.java index d3fba9ae2..d824d2112 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/services/HMACSha1SignatureServiceTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/services/HMACSha1SignatureServiceTest.java @@ -4,6 +4,8 @@ import org.junit.Before; import org.junit.Test; import com.github.scribejava.core.exceptions.OAuthException; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class HMACSha1SignatureServiceTest { @@ -29,23 +31,34 @@ public void shouldReturnSignature() { assertEquals(signature, service.getSignature(baseString, apiSecret, tokenSecret)); } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfBaseStringIsNull() { - service.getSignature(null, "apiSecret", "tokenSecret"); + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + service.getSignature(null, "apiSecret", "tokenSecret"); + } + }); } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfBaseStringIsEmpty() { - service.getSignature(" ", "apiSecret", "tokenSecret"); + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + service.getSignature(" ", "apiSecret", "tokenSecret"); + } + }); } - @Test(expected = OAuthException.class) public void shouldThrowExceptionIfApiSecretIsNull() { - service.getSignature("base string", null, "tokenSecret"); + assertThrows(OAuthException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + service.getSignature("base string", null, "tokenSecret"); + } + }); } - @Test(expected = OAuthException.class) - public void shouldThrowExceptionIfApiSecretIsEmpty() { + public void shouldNotThrowExceptionIfApiSecretIsEmpty() { service.getSignature("base string", " ", "tokenSecret"); } } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/services/RSASha1SignatureServiceTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/services/RSASha1SignatureServiceTest.java index 261bc2bb4..652f328e3 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/services/RSASha1SignatureServiceTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/services/RSASha1SignatureServiceTest.java @@ -5,7 +5,7 @@ import java.security.PrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; -import javax.xml.bind.DatatypeConverter; +import org.apache.commons.codec.binary.Base64; import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -48,11 +48,12 @@ private static PrivateKey getPrivateKey() { + "I/AfAkEA0Y9vr0tombsUB8cZv0v5OYoBZvCTbMANtzfb4AOHpiKqqbohDOevLQ7/\n" + "SpvgVCmVaDz2PptcRAyEBZ5MCssneQJAB2pmvaDH7Ambfod5bztLfOhLCtY5EkXJ\n" + "n6rZcDbRaHorRhdG7m3VtDKOUKZ2DF7glkQGV33phKukErVPUzlHBwJAScD9TqaG\n" - + "wJ3juUsVtujV23SnH43iMggXT7m82STpPGam1hPfmqu2Z0niePFo927ogQ7H1EMJ\n" + "UHgqXmuvk2X/Ww=="; + + "wJ3juUsVtujV23SnH43iMggXT7m82STpPGam1hPfmqu2Z0niePFo927ogQ7H1EMJ\n" + + "UHgqXmuvk2X/Ww=="; try { final KeyFactory fac = KeyFactory.getInstance("RSA"); - final PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(DatatypeConverter.parseBase64Binary(str)); + final PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(str)); return fac.generatePrivate(privKeySpec); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new RuntimeException(e); diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/utils/OAuthEncoderTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/utils/OAuthEncoderTest.java index 1a1489b41..9a27d238d 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/utils/OAuthEncoderTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/utils/OAuthEncoderTest.java @@ -1,7 +1,9 @@ package com.github.scribejava.core.utils; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; import org.junit.Test; +import org.junit.function.ThrowingRunnable; public class OAuthEncoderTest { @@ -34,14 +36,22 @@ public void shouldNotPercentEncodeReservedCharacters() { assertEquals(encoded, OAuthEncoder.encode(plain)); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfStringToEncodeIsNull() { - OAuthEncoder.encode(null); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + OAuthEncoder.encode(null); + } + }); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfStringToDecodeIsNull() { - OAuthEncoder.decode(null); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + OAuthEncoder.decode(null); + } + }); } @Test diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/utils/PreconditionsTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/utils/PreconditionsTest.java index ec6722c5a..1e3bd71e2 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/utils/PreconditionsTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/utils/PreconditionsTest.java @@ -1,28 +1,45 @@ package com.github.scribejava.core.utils; -import org.junit.Test; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class PreconditionsTest { private static final String ERROR_MSG = ""; - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionForNullObjects() { - Preconditions.checkNotNull(null, ERROR_MSG); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + Preconditions.checkNotNull(null, ERROR_MSG); + } + }); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionForNullStrings() { - Preconditions.checkEmptyString(null, ERROR_MSG); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + Preconditions.checkEmptyString(null, ERROR_MSG); + } + }); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionForEmptyStrings() { - Preconditions.checkEmptyString("", ERROR_MSG); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + Preconditions.checkEmptyString("", ERROR_MSG); + } + }); } - @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionForSpacesOnlyStrings() { - Preconditions.checkEmptyString(" ", ERROR_MSG); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + Preconditions.checkEmptyString(" ", ERROR_MSG); + } + }); } } diff --git a/scribejava-core/src/test/java/com/github/scribejava/core/utils/StreamUtilsTest.java b/scribejava-core/src/test/java/com/github/scribejava/core/utils/StreamUtilsTest.java index cb5c6c7c9..61937bac6 100644 --- a/scribejava-core/src/test/java/com/github/scribejava/core/utils/StreamUtilsTest.java +++ b/scribejava-core/src/test/java/com/github/scribejava/core/utils/StreamUtilsTest.java @@ -4,8 +4,9 @@ import java.io.IOException; import java.io.InputStream; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import org.junit.Test; +import org.junit.function.ThrowingRunnable; public class StreamUtilsTest { @@ -27,16 +28,22 @@ public void shouldCorrectlyDecodeAStream() throws IOException { assertEquals("expected", decoded); } - @Test(expected = IllegalArgumentException.class) public void shouldFailForNullParameter() throws IOException { - StreamUtils.getStreamContents(null); - fail("Must throw exception before getting here"); + assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + StreamUtils.getStreamContents(null); + } + }); } - @Test(expected = IOException.class) public void shouldFailWithBrokenStream() throws IOException { - // This object simulates problems with input stream. - StreamUtils.getStreamContents(ALLWAYS_ERROR_INPUT_STREAM); - fail("Must throw exception before getting here"); + assertThrows(IOException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + // This object simulates problems with input stream. + StreamUtils.getStreamContents(ALLWAYS_ERROR_INPUT_STREAM); + } + }); } } diff --git a/scribejava-httpclient-ahc/pom.xml b/scribejava-httpclient-ahc/pom.xml index eacdd6208..fabd225c3 100644 --- a/scribejava-httpclient-ahc/pom.xml +++ b/scribejava-httpclient-ahc/pom.xml @@ -5,10 +5,10 @@ com.github.scribejava scribejava - 5.5.1-SNAPSHOT + 8.3.4-SNAPSHOT ../pom.xml - + com.github.scribejava scribejava-httpclient-ahc ScribeJava Async Http Http Client support @@ -20,10 +20,16 @@ scribejava-core ${project.version} + + org.slf4j + slf4j-simple + 2.0.3 + test + org.asynchttpclient async-http-client - 2.5.2 + 2.12.3 com.github.scribejava diff --git a/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/AhcHttpClient.java b/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/AhcHttpClient.java index ebe551571..5c9b87249 100644 --- a/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/AhcHttpClient.java +++ b/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/AhcHttpClient.java @@ -1,8 +1,7 @@ package com.github.scribejava.httpclient.ahc; import com.github.scribejava.core.httpclient.AbstractAsyncOnlyHttpClient; -import com.github.scribejava.core.httpclient.MultipartPayload; -import com.github.scribejava.core.java8.Consumer; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; @@ -42,9 +41,8 @@ public void close() throws IOException { @Override public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, - final byte[] bodyContents, OAuthAsyncRequestCallback callback, - OAuthRequest.ResponseConverter converter) { - return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new ByteArrayConsumer(bodyContents), callback, + byte[] bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodySetter.BYTE_ARRAY, bodyContents, callback, converter); } @@ -58,22 +56,20 @@ public Future executeAsync(String userAgent, Map headers, @Override public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, - final String bodyContents, OAuthAsyncRequestCallback callback, - OAuthRequest.ResponseConverter converter) { - return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new StringConsumer(bodyContents), callback, + String bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodySetter.STRING, bodyContents, callback, converter); } @Override public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, - final File bodyContents, OAuthAsyncRequestCallback callback, - OAuthRequest.ResponseConverter converter) { - return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new FileConsumer(bodyContents), callback, + File bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodySetter.FILE, bodyContents, callback, converter); } private Future doExecuteAsync(String userAgent, Map headers, Verb httpVerb, - String completeUrl, Consumer bodySetter, OAuthAsyncRequestCallback callback, + String completeUrl, BodySetter bodySetter, Object bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { final BoundRequestBuilder boundRequestBuilder; switch (httpVerb) { @@ -97,7 +93,7 @@ private Future doExecuteAsync(String userAgent, Map heade if (!headers.containsKey(CONTENT_TYPE)) { boundRequestBuilder.addHeader(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); } - bodySetter.accept(boundRequestBuilder); + bodySetter.setBody(boundRequestBuilder, bodyContents); } for (Map.Entry header : headers.entrySet()) { @@ -111,45 +107,26 @@ private Future doExecuteAsync(String userAgent, Map heade return boundRequestBuilder.execute(new OAuthAsyncCompletionHandler<>(callback, converter)); } - private static class ByteArrayConsumer implements Consumer { - - private final byte[] bodyContents; - - private ByteArrayConsumer(byte[] bodyContents) { - this.bodyContents = bodyContents; - } - - @Override - public void accept(BoundRequestBuilder requestBuilder) { - requestBuilder.setBody(bodyContents); - } - } - - private static class StringConsumer implements Consumer { - - private final String bodyContents; - - private StringConsumer(String bodyContents) { - this.bodyContents = bodyContents; - } - - @Override - public void accept(BoundRequestBuilder requestBuilder) { - requestBuilder.setBody(bodyContents); - } - } - - private static class FileConsumer implements Consumer { - - private final File bodyContents; - - private FileConsumer(File bodyContents) { - this.bodyContents = bodyContents; - } + private enum BodySetter { + BYTE_ARRAY { + @Override + BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder, Object bodyContents) { + return requestBuilder.setBody((byte[]) bodyContents); + } + }, + STRING { + @Override + BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder, Object bodyContents) { + return requestBuilder.setBody((String) bodyContents); + } + }, + FILE { + @Override + BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder, Object bodyContents) { + return requestBuilder.setBody((File) bodyContents); + } + }; - @Override - public void accept(BoundRequestBuilder requestBuilder) { - requestBuilder.setBody(bodyContents); - } + abstract BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder, Object bodyContents); } } diff --git a/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/OAuthAsyncCompletionHandler.java b/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/OAuthAsyncCompletionHandler.java index 08706c195..0cb77af25 100644 --- a/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/OAuthAsyncCompletionHandler.java +++ b/scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/OAuthAsyncCompletionHandler.java @@ -48,4 +48,4 @@ public void onThrowable(Throwable t) { callback.onThrowable(t); } } -}; +} diff --git a/scribejava-httpclient-ahc/src/test/java/com/github/scribejava/httpclient/ahc/AhcHttpClientTest.java b/scribejava-httpclient-ahc/src/test/java/com/github/scribejava/httpclient/ahc/AhcHttpClientTest.java index 1ee1ebaa1..5de2d153e 100644 --- a/scribejava-httpclient-ahc/src/test/java/com/github/scribejava/httpclient/ahc/AhcHttpClientTest.java +++ b/scribejava-httpclient-ahc/src/test/java/com/github/scribejava/httpclient/ahc/AhcHttpClientTest.java @@ -2,9 +2,7 @@ import com.github.scribejava.core.AbstractClientTest; import com.github.scribejava.core.httpclient.HttpClient; -import org.junit.Ignore; -@Ignore(value = "we are java7 and AHC is java8") public class AhcHttpClientTest extends AbstractClientTest { @Override diff --git a/scribejava-httpclient-apache/pom.xml b/scribejava-httpclient-apache/pom.xml index 0043155d0..1dc9dd53c 100644 --- a/scribejava-httpclient-apache/pom.xml +++ b/scribejava-httpclient-apache/pom.xml @@ -5,10 +5,10 @@ com.github.scribejava scribejava - 5.5.1-SNAPSHOT + 8.3.4-SNAPSHOT ../pom.xml - + com.github.scribejava scribejava-httpclient-apache ScribeJava Apache HttpComponents HttpClient support @@ -23,12 +23,12 @@ org.apache.httpcomponents httpclient - 4.5.6 + 4.5.13 org.apache.httpcomponents httpasyncclient - 4.1.4 + 4.1.5 com.github.scribejava diff --git a/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/ApacheHttpClient.java b/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/ApacheHttpClient.java index dc5a3607b..8c204e67b 100644 --- a/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/ApacheHttpClient.java +++ b/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/ApacheHttpClient.java @@ -1,7 +1,7 @@ package com.github.scribejava.httpclient.apache; import com.github.scribejava.core.httpclient.AbstractAsyncOnlyHttpClient; -import com.github.scribejava.core.httpclient.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; diff --git a/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandler.java b/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandler.java index 65b92a178..7779b83e7 100644 --- a/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandler.java +++ b/scribejava-httpclient-apache/src/main/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandler.java @@ -17,6 +17,8 @@ import com.github.scribejava.core.model.OAuthRequest.ResponseConverter; import com.github.scribejava.core.model.Response; import java.io.IOException; +import java.io.InputStream; +import org.apache.http.HttpEntity; public class OAuthAsyncCompletionHandler implements FutureCallback { @@ -42,8 +44,10 @@ public void completed(HttpResponse httpResponse) { final StatusLine statusLine = httpResponse.getStatusLine(); + final HttpEntity httpEntity = httpResponse.getEntity(); + final InputStream contentStream = httpEntity == null ? null : httpEntity.getContent(); final Response response = new Response(statusLine.getStatusCode(), statusLine.getReasonPhrase(), headersMap, - httpResponse.getEntity().getContent()); + contentStream, contentStream); @SuppressWarnings("unchecked") final T t = converter == null ? (T) response : converter.convert(response); diff --git a/scribejava-httpclient-apache/src/test/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandlerTest.java b/scribejava-httpclient-apache/src/test/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandlerTest.java index c43fbed9e..684ac5c62 100644 --- a/scribejava-httpclient-apache/src/test/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandlerTest.java +++ b/scribejava-httpclient-apache/src/test/java/com/github/scribejava/httpclient/apache/OAuthAsyncCompletionHandlerTest.java @@ -4,7 +4,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -23,6 +22,8 @@ import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Response; +import static org.junit.Assert.assertThrows; +import org.junit.function.ThrowingRunnable; public class OAuthAsyncCompletionHandlerTest { @@ -80,7 +81,7 @@ public void shouldReleaseLatchOnSuccess() throws Exception { } @Test - public void shouldReleaseLatchOnIOException() throws Exception { + public void shouldReleaseLatchOnIOException() { handler = new OAuthAsyncCompletionHandler<>(callback, EXCEPTION_RESPONSE_CONVERTER); final HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("4", 1, 1), 200, "ok")); @@ -92,16 +93,16 @@ public void shouldReleaseLatchOnIOException() throws Exception { assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof IOException); // verify latch is released - try { - handler.getResult(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + handler.getResult(); + } + }); } @Test - public void shouldReportOAuthException() throws Exception { + public void shouldReportOAuthException() { handler = new OAuthAsyncCompletionHandler<>(callback, OAUTH_EXCEPTION_RESPONSE_CONVERTER); final HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("4", 1, 1), 200, "ok")); @@ -113,16 +114,16 @@ public void shouldReportOAuthException() throws Exception { assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof OAuthException); // verify latch is released - try { - handler.getResult(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + handler.getResult(); + } + }); } @Test - public void shouldReleaseLatchOnCancel() throws Exception { + public void shouldReleaseLatchOnCancel() { handler = new OAuthAsyncCompletionHandler<>(callback, ALL_GOOD_RESPONSE_CONVERTER); final HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("4", 1, 1), 200, "ok")); @@ -134,16 +135,16 @@ public void shouldReleaseLatchOnCancel() throws Exception { assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof CancellationException); // verify latch is released - try { - handler.getResult(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + handler.getResult(); + } + }); } @Test - public void shouldReleaseLatchOnFailure() throws Exception { + public void shouldReleaseLatchOnFailure() { handler = new OAuthAsyncCompletionHandler<>(callback, ALL_GOOD_RESPONSE_CONVERTER); final HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("4", 1, 1), 200, "ok")); @@ -155,18 +156,19 @@ public void shouldReleaseLatchOnFailure() throws Exception { assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof RuntimeException); // verify latch is released - try { - handler.getResult(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + handler.getResult(); + } + }); } private static class AllGoodResponseConverter implements OAuthRequest.ResponseConverter { @Override public String convert(Response response) throws IOException { + response.close(); return "All good"; } } @@ -175,6 +177,7 @@ private static class ExceptionResponseConverter implements OAuthRequest.Response @Override public String convert(Response response) throws IOException { + response.close(); throw new IOException("Failed to convert"); } } @@ -183,6 +186,7 @@ private static class OAuthExceptionResponseConverter implements OAuthRequest.Res @Override public String convert(Response response) throws IOException { + response.close(); throw new OAuthException("bad oauth"); } } diff --git a/scribejava-httpclient-armeria/pom.xml b/scribejava-httpclient-armeria/pom.xml new file mode 100644 index 000000000..54e58c619 --- /dev/null +++ b/scribejava-httpclient-armeria/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + com.github.scribejava + scribejava + 8.3.4-SNAPSHOT + ../pom.xml + + + com.github.scribejava + scribejava-httpclient-armeria + ScribeJava Async Armeria Client support + jar + + + + com.github.scribejava + scribejava-core + ${project.version} + + + org.slf4j + slf4j-simple + 2.0.3 + test + + + com.linecorp.armeria + armeria + 1.20.2 + + + com.github.scribejava + scribejava-core + ${project.version} + test-jar + test + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + + + 8 + + diff --git a/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClient.java b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClient.java new file mode 100644 index 000000000..982ddc63a --- /dev/null +++ b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClient.java @@ -0,0 +1,375 @@ +package com.github.scribejava.httpclient.armeria; + +import static java.util.Objects.requireNonNull; + +import com.github.scribejava.core.httpclient.AbstractAsyncOnlyHttpClient; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartUtils; +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.Response; +import com.github.scribejava.core.model.Verb; +import com.linecorp.armeria.client.WebClient; +import com.linecorp.armeria.common.AggregatedHttpResponse; +import com.linecorp.armeria.common.HttpData; +import com.linecorp.armeria.common.HttpMethod; +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.common.HttpStatus; +import com.linecorp.armeria.common.MediaType; +import com.linecorp.armeria.common.RequestHeaders; +import com.linecorp.armeria.common.RequestHeadersBuilder; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Supplier; + +/** + * An implementation of {@link AbstractAsyncOnlyHttpClient} based on + * Armeria HTTP client. + */ +public class ArmeriaHttpClient extends AbstractAsyncOnlyHttpClient { + + /** + * A builder of new instances of Armeria's {@link WebClient} + */ + private final ArmeriaWebClientBuilder clientBuilder; + /** + * A list of cached Endpoints. It helps avoiding building a new Endpoint per each request. + */ + private final Map httpClients = new HashMap<>(); + /** + * A read/write lock to access the list of cached Endpoints concurrently. + */ + private final ReentrantReadWriteLock httpClientsLock = new ReentrantReadWriteLock(); + + public ArmeriaHttpClient() { + this(ArmeriaHttpClientConfig.defaultConfig()); + } + + public ArmeriaHttpClient(ArmeriaHttpClientConfig config) { + clientBuilder = config.createClientBuilder(); + } + + /** + * Cleans up the list of cached Endpoints. + */ + @Override + public void close() { + final Lock writeLock = httpClientsLock.writeLock(); + writeLock.lock(); + try { + httpClients.clear(); + } finally { + writeLock.unlock(); + } + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + byte[] bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new BytesBody(bodyContents), callback, + converter); + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + MultipartPayload bodyContents, OAuthAsyncRequestCallback callback, + OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new MultipartBody(bodyContents), callback, + converter); + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + String bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new StringBody(bodyContents), callback, + converter); + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + File bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new FileBody(bodyContents), callback, + converter); + } + + private CompletableFuture doExecuteAsync(String userAgent, Map headers, Verb httpVerb, + String completeUrl, Supplier contentSupplier, OAuthAsyncRequestCallback callback, + OAuthRequest.ResponseConverter converter) { + // Get the URI and Path + final URI uri = URI.create(completeUrl); + final String path = getServicePath(uri); + + // Fetch/Create WebClient instance for a given Endpoint + final WebClient client = getClient(uri); + + // Build HTTP request + final RequestHeadersBuilder headersBuilder = RequestHeaders.of(getHttpMethod(httpVerb), path).toBuilder(); + + headersBuilder.add(headers.entrySet()); + if (userAgent != null) { + headersBuilder.add(OAuthConstants.USER_AGENT_HEADER_NAME, userAgent); + } + + // Build the request body and execute HTTP request + final HttpResponse response; + if (httpVerb.isPermitBody()) { // POST, PUT, PATCH and DELETE methods + final HttpData contents = contentSupplier.get(); + if (httpVerb.isRequiresBody() && contents == null) { // POST or PUT methods + throw new IllegalArgumentException("Contents missing for request method " + httpVerb.name()); + } + + if (headersBuilder.contentType() == null) { + headersBuilder.contentType(MediaType.FORM_DATA); + } + + if (contents != null) { + response = client.execute(headersBuilder.build(), contents); + } else { + response = client.execute(headersBuilder.build()); + } + } else { + response = client.execute(headersBuilder.build()); + } + + // Aggregate HTTP response (asynchronously) and return the result Future + return response.aggregate() + .thenApply(aggregatedResponse -> whenResponseComplete(callback, converter, aggregatedResponse)) + .exceptionally(throwable -> completeExceptionally(callback, throwable)); + } + + /** + * Provides an instance of {@link WebClient} for a given endpoint {@link URI} based on an endpoint as + * {@code scheme://authority}. + * + * @param uri an endpoint {@link URI} + * @return {@link WebClient} instance + */ + private WebClient getClient(URI uri) { + final String endpoint = getEndPoint(uri); + + WebClient client; + final Lock readLock = httpClientsLock.readLock(); + readLock.lock(); + try { + client = httpClients.get(endpoint); + } finally { + readLock.unlock(); + } + + if (client != null) { + return client; + } + + client = clientBuilder.newWebClient( + requireNonNull(uri.getScheme(), "scheme"), + requireNonNull(uri.getAuthority(), "authority")); + + final Lock writeLock = httpClientsLock.writeLock(); + writeLock.lock(); + try { + if (!httpClients.containsKey(endpoint)) { + httpClients.put(endpoint, client); + return client; + } else { + return httpClients.get(endpoint); + } + } finally { + writeLock.unlock(); + } + } + + /** + * Extracts {@code scheme} and {@code authority} portion of the {@link URI}. + * + * Assuming the {@link URI} as the following: {@code URI = scheme:[//authority]path[?query][#fragment]} + */ + private static String getEndPoint(URI uri) { + return requireNonNull(uri.getScheme(), "scheme") + "://" + requireNonNull(uri.getAuthority(), "authority"); + } + + /** + * Extracts {@code path}, {@code query} and {@code fragment} portion of the {@link URI}. + * + * Assuming the {@link URI} as the following: {@code URI = scheme:[//authority]path[?query][#fragment]} + */ + private static String getServicePath(URI uri) { + final StringBuilder builder = new StringBuilder() + .append(requireNonNull(uri.getPath(), "path")); + final String query = uri.getQuery(); + if (query != null) { + builder.append('?').append(query); + } + final String fragment = uri.getFragment(); + if (fragment != null) { + builder.append('#').append(fragment); + } + return builder.toString(); + } + + /** + * Maps {@link Verb} to {@link HttpMethod} + * + * @param httpVerb a {@link Verb} to match with {@link HttpMethod} + * @return {@link HttpMethod} corresponding to the parameter + */ + private static HttpMethod getHttpMethod(Verb httpVerb) { + switch (httpVerb) { + case GET: + return HttpMethod.GET; + case POST: + return HttpMethod.POST; + case PUT: + return HttpMethod.PUT; + case DELETE: + return HttpMethod.DELETE; + case HEAD: + return HttpMethod.HEAD; + case OPTIONS: + return HttpMethod.OPTIONS; + case TRACE: + return HttpMethod.TRACE; + case PATCH: + return HttpMethod.PATCH; + default: + throw new IllegalArgumentException( + "message build error: unsupported HTTP method: " + httpVerb.name()); + } + } + + // Response asynchronous handlers + /** + * Converts {@link AggregatedHttpResponse} to {@link Response} + * + * @param aggregatedResponse an instance of {@link AggregatedHttpResponse} to convert to {@link Response} + * @return a {@link Response} converted from {@link AggregatedHttpResponse} + */ + private Response convertResponse(AggregatedHttpResponse aggregatedResponse) { + final Map headersMap = new HashMap<>(); + aggregatedResponse.headers().forEach((header, value) -> headersMap.put(header.toString(), value)); + + final HttpStatus status = aggregatedResponse.status(); + final InputStream inputStream = aggregatedResponse.content().toInputStream(); + + return new Response(status.code(), status.reasonPhrase(), headersMap, inputStream, inputStream); + } + + /** + * Converts {@link AggregatedHttpResponse} to {@link Response} upon its aggregation completion and invokes + * {@link OAuthAsyncRequestCallback} for it. + * + * @param callback a {@link OAuthAsyncRequestCallback} callback to invoke upon response completion + * @param converter an optional {@link OAuthRequest.ResponseConverter} result converter for {@link Response} + * @param aggregatedResponse a source {@link AggregatedHttpResponse} to handle + * @param converter {@link OAuthRequest.ResponseConverter} specific type or {@link Response} + * @return either instance of {@link Response} or converted result based on {@link OAuthRequest.ResponseConverter} + */ + private T whenResponseComplete(OAuthAsyncRequestCallback callback, + OAuthRequest.ResponseConverter converter, AggregatedHttpResponse aggregatedResponse) { + final Response response = convertResponse(aggregatedResponse); + try { + @SuppressWarnings("unchecked") + final T t = converter == null ? (T) response : converter.convert(response); + if (callback != null) { + callback.onCompleted(t); + } + return t; + } catch (IOException | RuntimeException e) { + return completeExceptionally(callback, e); + } + } + + /** + * Invokes {@link OAuthAsyncRequestCallback} upon {@link Throwable} error result + * + * @param callback a {@link OAuthAsyncRequestCallback} callback to invoke upon response completion + * @param throwable a {@link Throwable} error result + * @param converter {@link OAuthRequest.ResponseConverter} specific type or {@link Response} + * @return null + */ + private T completeExceptionally(OAuthAsyncRequestCallback callback, Throwable throwable) { + if (callback != null) { + callback.onThrowable(throwable); + } + return null; + } + + // Body type suppliers + private static class BytesBody implements Supplier { + + private final byte[] bodyContents; + + BytesBody(byte[] bodyContents) { + this.bodyContents = bodyContents; + } + + @Override + public HttpData get() { + return (bodyContents != null) ? HttpData.wrap(bodyContents) : null; + } + } + + private static class StringBody implements Supplier { + + private final String bodyContents; + + StringBody(String bodyContents) { + this.bodyContents = bodyContents; + } + + @Override + public HttpData get() { + return (bodyContents != null) ? HttpData.ofUtf8(bodyContents) : null; + } + } + + private static class FileBody implements Supplier { + + private final File bodyContents; + + FileBody(File bodyContents) { + this.bodyContents = bodyContents; + } + + @Override + public HttpData get() { + try { + return (bodyContents != null) + ? HttpData.wrap(Files.readAllBytes(bodyContents.toPath())) + : null; + } catch (IOException ioE) { + throw new RuntimeException(ioE); + } + } + } + + private static class MultipartBody implements Supplier { + + private final MultipartPayload bodyContents; + + MultipartBody(MultipartPayload bodyContents) { + this.bodyContents = bodyContents; + } + + @Override + public HttpData get() { + try { + return (bodyContents != null) + ? HttpData.wrap(MultipartUtils.getPayload(bodyContents).toByteArray()) + : null; + } catch (IOException ioE) { + throw new RuntimeException(ioE); + } + } + } +} diff --git a/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClientConfig.java b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClientConfig.java new file mode 100644 index 000000000..f9d494f52 --- /dev/null +++ b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClientConfig.java @@ -0,0 +1,93 @@ +package com.github.scribejava.httpclient.armeria; + +import com.github.scribejava.core.httpclient.HttpClientConfig; +import com.linecorp.armeria.client.ClientFactory; +import com.linecorp.armeria.client.ClientOptions; +import com.linecorp.armeria.client.HttpClient; +import com.linecorp.armeria.client.logging.LoggingClient; +import com.linecorp.armeria.client.retry.RetryingClient; +import com.linecorp.armeria.common.SessionProtocol; +import java.util.function.Function; + +public class ArmeriaHttpClientConfig implements HttpClientConfig { + + private static final SessionProtocol DEFAULT_PROTOCOL_PREFERENCE = SessionProtocol.H1; // H1 or H2 + + private final ClientOptions clientOptions; + private final ClientFactory clientFactory; + private SessionProtocol protocolPreference; + private Function retry; + private Function logging; + + /** + * Creates new {@link ArmeriaHttpClientConfig} using provided {@link ClientOptions} and {@link ClientFactory}. + * + * @param clientOptions clientOptions + * @param clientFactory clientFactory + */ + public ArmeriaHttpClientConfig(ClientOptions clientOptions, ClientFactory clientFactory) { + this.clientOptions = clientOptions; + this.clientFactory = clientFactory; + protocolPreference = DEFAULT_PROTOCOL_PREFERENCE; + } + + /** + * Creates new {@link HttpClientConfig} using default settings. + * + * @return new {@link HttpClientConfig} using default settings. + */ + @Override + public HttpClientConfig createDefaultConfig() { + return defaultConfig(); + } + + /** + * Creates new {@link ArmeriaHttpClientConfig} using default settings. + * + * @return ArmeriaHttpClientConfig + */ + public static ArmeriaHttpClientConfig defaultConfig() { + return new ArmeriaHttpClientConfig(null, null); + } + + /** + * Selects which protocol shall take preference when generic protocol scheme used by the URL, like {@code http} or + * {@code https}. + * + * @param protocolPreference specifies which protocol shall take preference. Acceptable values: + * {@link SessionProtocol#H1} and {@link SessionProtocol#H2} + */ + public void setProtocolPreference(SessionProtocol protocolPreference) { + if (protocolPreference != SessionProtocol.H1 && protocolPreference != SessionProtocol.H2) { + throw new IllegalArgumentException("Invalid protocolPreference: " + protocolPreference); + } + this.protocolPreference = protocolPreference; + } + + public ArmeriaHttpClientConfig withProtocolPreference(SessionProtocol protocolPreference) { + setProtocolPreference(protocolPreference); + return this; + } + + public void setRetry(Function retry) { + this.retry = retry; + } + + public ArmeriaHttpClientConfig withRetry(Function retry) { + this.retry = retry; + return this; + } + + public void setLogging(Function logging) { + this.logging = logging; + } + + public ArmeriaHttpClientConfig withLogging(Function logging) { + this.logging = logging; + return this; + } + + ArmeriaWebClientBuilder createClientBuilder() { + return new ArmeriaWebClientBuilder(clientOptions, clientFactory, protocolPreference, retry, logging); + } +} diff --git a/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaProvider.java b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaProvider.java new file mode 100644 index 000000000..323eb7599 --- /dev/null +++ b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaProvider.java @@ -0,0 +1,16 @@ +package com.github.scribejava.httpclient.armeria; + +import com.github.scribejava.core.httpclient.HttpClientProvider; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.HttpClientConfig; + +public class ArmeriaProvider implements HttpClientProvider { + + @Override + public HttpClient createClient(HttpClientConfig config) { + if (config instanceof ArmeriaHttpClientConfig) { + return new ArmeriaHttpClient((ArmeriaHttpClientConfig) config); + } + return null; + } +} diff --git a/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaWebClientBuilder.java b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaWebClientBuilder.java new file mode 100644 index 000000000..6972fadd0 --- /dev/null +++ b/scribejava-httpclient-armeria/src/main/java/com/github/scribejava/httpclient/armeria/ArmeriaWebClientBuilder.java @@ -0,0 +1,74 @@ +package com.github.scribejava.httpclient.armeria; + +import com.linecorp.armeria.client.ClientFactory; +import com.linecorp.armeria.client.ClientOptions; +import com.linecorp.armeria.client.Endpoint; +import com.linecorp.armeria.client.HttpClient; +import com.linecorp.armeria.client.WebClient; +import com.linecorp.armeria.client.WebClientBuilder; +import com.linecorp.armeria.client.logging.LoggingClient; +import com.linecorp.armeria.client.retry.RetryingClient; +import com.linecorp.armeria.common.SessionProtocol; +import java.util.function.Function; + +/** + * A builder of {@link WebClient} using supplied configuration parameters. + */ +public class ArmeriaWebClientBuilder { + + private final ClientFactory clientFactory; + private final ClientOptions clientOptions; + private final SessionProtocol protocolPreference; + private final Function retry; + private final Function logging; + + ArmeriaWebClientBuilder(ClientOptions clientOptions, ClientFactory clientFactory, + SessionProtocol protocolPreference, Function retry, + Function logging) { + this.clientOptions = clientOptions; + this.clientFactory = clientFactory; + this.protocolPreference = protocolPreference; + this.retry = retry; + this.logging = logging; + } + + WebClient newWebClient(String scheme, String authority) { + final SessionProtocol protocol = protocol(scheme); + final Endpoint endpoint = Endpoint.parse(authority); + final WebClientBuilder clientBuilder = WebClient.builder(protocol, endpoint); + if (clientOptions != null) { + clientBuilder.options(clientOptions); + } + if (clientFactory != null) { + clientBuilder.factory(clientFactory); + } + if (retry != null) { + clientBuilder.decorator(retry); + } + if (logging != null) { + clientBuilder.decorator(logging); + } + return clientBuilder.build(); + } + + private SessionProtocol protocol(String scheme) { + final SessionProtocol protocol = SessionProtocol.of(scheme); + switch (protocol) { + case HTTP: + if (protocolPreference == SessionProtocol.H1) { + // enforce HTTP/1 protocol + return SessionProtocol.H1C; + } + break; + case HTTPS: + if (protocolPreference == SessionProtocol.H1) { + // enforce HTTP/1 protocol + return SessionProtocol.H1; + } + break; + default: + break; + } + return protocol; + } +} diff --git a/scribejava-httpclient-armeria/src/main/resources/META-INF/services/com.github.scribejava.core.httpclient.HttpClientProvider b/scribejava-httpclient-armeria/src/main/resources/META-INF/services/com.github.scribejava.core.httpclient.HttpClientProvider new file mode 100644 index 000000000..bba338db5 --- /dev/null +++ b/scribejava-httpclient-armeria/src/main/resources/META-INF/services/com.github.scribejava.core.httpclient.HttpClientProvider @@ -0,0 +1 @@ +com.github.scribejava.httpclient.armeria.ArmeriaProvider diff --git a/scribejava-httpclient-armeria/src/test/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClientTest.java b/scribejava-httpclient-armeria/src/test/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClientTest.java new file mode 100644 index 000000000..c94d6b369 --- /dev/null +++ b/scribejava-httpclient-armeria/src/test/java/com/github/scribejava/httpclient/armeria/ArmeriaHttpClientTest.java @@ -0,0 +1,88 @@ +package com.github.scribejava.httpclient.armeria; + +import com.github.scribejava.core.AbstractClientTest; +import com.github.scribejava.core.httpclient.HttpClient; +import com.linecorp.armeria.client.ClientFactory; +import com.linecorp.armeria.client.logging.LoggingClient; +import com.linecorp.armeria.client.retry.Backoff; +import com.linecorp.armeria.client.retry.RetryRule; +import com.linecorp.armeria.client.retry.RetryingClient; +import com.linecorp.armeria.common.HttpStatus; +import com.linecorp.armeria.common.logging.LogLevel; +import io.netty.channel.EventLoopGroup; +import io.netty.resolver.AbstractAddressResolver; +import io.netty.resolver.AddressResolver; +import io.netty.resolver.AddressResolverGroup; +import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.Promise; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import org.slf4j.LoggerFactory; + +public class ArmeriaHttpClientTest extends AbstractClientTest { + + @Override + protected HttpClient createNewClient() { + // simulate DNS resolution for a mock address ("kubernetes.docker.internal") + final Function> addressRGF + = eventLoopGroup -> new MockAddressResolverGroup(); + // No-Op DNS resolver to avoid resolution issues in the unit test + final ClientFactory clientFactory = ClientFactory.builder().addressResolverGroupFactory(addressRGF).build(); + final ArmeriaHttpClientConfig config = new ArmeriaHttpClientConfig(null, clientFactory); + + // enable client-side HTTP tracing + config.setLogging(LoggingClient.builder() + .logger(LoggerFactory.getLogger("HTTP_TRACE")) + .requestLogLevel(LogLevel.valueOf("INFO")) + .successfulResponseLogLevel(LogLevel.valueOf("INFO")) + .failureResponseLogLevel(LogLevel.valueOf("WARN")) + .newDecorator()); + + // enable request retry + final Backoff retryBackoff = Backoff.of("exponential=200:10000,jitter=0.2,maxAttempts=5"); + final RetryRule retryRule = RetryRule.builder() + .onStatus(HttpStatus.SERVICE_UNAVAILABLE) + .onUnprocessed() + .thenBackoff(retryBackoff); + + return new ArmeriaHttpClient(config.withRetry(RetryingClient.newDecorator(retryRule))); + } + + // No-Op DNS resolver to avoid resolution issues in the unit test + private static class MockAddressResolverGroup extends AddressResolverGroup { + + @Override + protected AddressResolver newResolver(EventExecutor executor) { + return new MockAddressResolver(executor); + } + } + + private static class MockAddressResolver extends AbstractAddressResolver { + + private MockAddressResolver(EventExecutor executor) { + super(executor); + } + + @Override + protected boolean doIsResolved(InetSocketAddress address) { + return !address.isUnresolved(); + } + + private InetSocketAddress resolveToLoopback(InetSocketAddress unresolvedAddress) { + return new InetSocketAddress(InetAddress.getLoopbackAddress(), unresolvedAddress.getPort()); + } + + @Override + protected void doResolve(InetSocketAddress unresolvedAddress, Promise promise) { + promise.setSuccess(resolveToLoopback(unresolvedAddress)); + } + + @Override + protected void doResolveAll(InetSocketAddress unresolvedAddress, Promise> promise) { + promise.setSuccess(Collections.singletonList(resolveToLoopback(unresolvedAddress))); + } + } +} diff --git a/scribejava-httpclient-ning/pom.xml b/scribejava-httpclient-ning/pom.xml index fcd3e33aa..39696d698 100644 --- a/scribejava-httpclient-ning/pom.xml +++ b/scribejava-httpclient-ning/pom.xml @@ -5,10 +5,10 @@ com.github.scribejava scribejava - 5.5.1-SNAPSHOT + 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-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClient.java b/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClient.java index 4463ea9e1..52250f698 100644 --- a/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClient.java +++ b/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClient.java @@ -1,8 +1,7 @@ package com.github.scribejava.httpclient.ning; import com.github.scribejava.core.httpclient.AbstractAsyncOnlyHttpClient; -import com.github.scribejava.core.httpclient.MultipartPayload; -import com.github.scribejava.core.java8.Consumer; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; @@ -50,7 +49,7 @@ public Future executeAsync(String userAgent, Map headers, final byte[] bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { - return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new ByteArrayConsumer(bodyContents), callback, + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodySetter.BYTE_ARRAY, bodyContents, callback, converter); } @@ -67,7 +66,7 @@ public Future executeAsync(String userAgent, Map headers, final String bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { - return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new StringConsumer(bodyContents), callback, + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodySetter.STRING, bodyContents, callback, converter); } @@ -76,13 +75,13 @@ public Future executeAsync(String userAgent, Map headers, final File bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { - return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new FileConsumer(bodyContents), callback, + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodySetter.FILE, bodyContents, callback, converter); } private Future doExecuteAsync(String userAgent, Map headers, Verb httpVerb, - String completeUrl, Consumer bodySetter, - OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + String completeUrl, BodySetter bodySetter, Object bodyContents, OAuthAsyncRequestCallback callback, + OAuthRequest.ResponseConverter converter) { final AsyncHttpClient.BoundRequestBuilder boundRequestBuilder; switch (httpVerb) { case GET: @@ -105,7 +104,7 @@ private Future doExecuteAsync(String userAgent, Map heade if (!headers.containsKey(CONTENT_TYPE)) { boundRequestBuilder.addHeader(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); } - bodySetter.accept(boundRequestBuilder); + bodySetter.setBody(boundRequestBuilder, bodyContents); } for (Map.Entry header : headers.entrySet()) { @@ -119,45 +118,30 @@ private Future doExecuteAsync(String userAgent, Map heade return boundRequestBuilder.execute(new OAuthAsyncCompletionHandler<>(callback, converter)); } - private static class ByteArrayConsumer implements Consumer { - - private final byte[] bodyContents; - - private ByteArrayConsumer(byte[] bodyContents) { - this.bodyContents = bodyContents; - } - - @Override - public void accept(AsyncHttpClient.BoundRequestBuilder requestBuilder) { - requestBuilder.setBody(bodyContents); - } - } - - private static class StringConsumer implements Consumer { - - private final String bodyContents; - - private StringConsumer(String bodyContents) { - this.bodyContents = bodyContents; - } - - @Override - public void accept(AsyncHttpClient.BoundRequestBuilder requestBuilder) { - requestBuilder.setBody(bodyContents); - } - } - - private static class FileConsumer implements Consumer { - - private final File bodyContents; - - private FileConsumer(File bodyContents) { - this.bodyContents = bodyContents; - } + private enum BodySetter { + BYTE_ARRAY { + @Override + AsyncHttpClient.BoundRequestBuilder setBody(AsyncHttpClient.BoundRequestBuilder requestBuilder, + Object bodyContents) { + return requestBuilder.setBody((byte[]) bodyContents); + } + }, + STRING { + @Override + AsyncHttpClient.BoundRequestBuilder setBody(AsyncHttpClient.BoundRequestBuilder requestBuilder, + Object bodyContents) { + return requestBuilder.setBody((String) bodyContents); + } + }, + FILE { + @Override + AsyncHttpClient.BoundRequestBuilder setBody(AsyncHttpClient.BoundRequestBuilder requestBuilder, + Object bodyContents) { + return requestBuilder.setBody((File) bodyContents); + } + }; - @Override - public void accept(AsyncHttpClient.BoundRequestBuilder requestBuilder) { - requestBuilder.setBody(bodyContents); - } + abstract AsyncHttpClient.BoundRequestBuilder setBody(AsyncHttpClient.BoundRequestBuilder requestBuilder, + Object bodyContents); } } diff --git a/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClientConfig.java b/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClientConfig.java index 9eb5d83c2..6e8842cc7 100644 --- a/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClientConfig.java +++ b/scribejava-httpclient-ning/src/main/java/com/github/scribejava/httpclient/ning/NingHttpClientConfig.java @@ -20,6 +20,11 @@ public void setNingAsyncHttpProviderClassName(String ningAsyncHttpProviderClassN this.ningAsyncHttpProviderClassName = ningAsyncHttpProviderClassName; } + public NingHttpClientConfig withNingAsyncHttpProviderClassName(String ningAsyncHttpProviderClassName) { + this.ningAsyncHttpProviderClassName = ningAsyncHttpProviderClassName; + return this; + } + public AsyncHttpClientConfig getConfig() { return config; } diff --git a/scribejava-httpclient-ning/src/test/java/com/github/scribejava/httpclient/ning/OAuthAsyncCompletionHandlerTest.java b/scribejava-httpclient-ning/src/test/java/com/github/scribejava/httpclient/ning/OAuthAsyncCompletionHandlerTest.java index c235061e9..7bc56e1e1 100644 --- a/scribejava-httpclient-ning/src/test/java/com/github/scribejava/httpclient/ning/OAuthAsyncCompletionHandlerTest.java +++ b/scribejava-httpclient-ning/src/test/java/com/github/scribejava/httpclient/ning/OAuthAsyncCompletionHandlerTest.java @@ -84,6 +84,7 @@ private static class AllGoodResponseConverter implements OAuthRequest.ResponseCo @Override public String convert(Response response) throws IOException { + response.close(); return "All good"; } } @@ -92,6 +93,7 @@ private static class OAuthExceptionResponseConverter implements OAuthRequest.Res @Override public String convert(Response response) throws IOException { + response.close(); throw new OAuthException("bad oauth"); } } diff --git a/scribejava-httpclient-okhttp/pom.xml b/scribejava-httpclient-okhttp/pom.xml index 554be1054..59bc2bffc 100644 --- a/scribejava-httpclient-okhttp/pom.xml +++ b/scribejava-httpclient-okhttp/pom.xml @@ -5,10 +5,10 @@ com.github.scribejava scribejava - 5.5.1-SNAPSHOT + 8.3.4-SNAPSHOT ../pom.xml - + com.github.scribejava scribejava-httpclient-okhttp ScribeJava Async OkHttp Client support @@ -23,7 +23,7 @@ com.squareup.okhttp3 okhttp - 3.11.0 + 4.10.0 com.github.scribejava diff --git a/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandler.java b/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandler.java index 8345fa9d1..787b70395 100644 --- a/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandler.java +++ b/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandler.java @@ -38,15 +38,15 @@ public void onResponse(Call call, okhttp3.Response okHttpResponse) { try { final Response response = OkHttpHttpClient.convertResponse(okHttpResponse); - try { + try { @SuppressWarnings("unchecked") final T t = converter == null ? (T) response : converter.convert(response); okHttpFuture.setResult(t); if (callback != null) { callback.onCompleted(t); } - } catch (IOException | RuntimeException e) { - okHttpFuture.setException(e); + } catch (IOException | RuntimeException e) { + okHttpFuture.setException(e); if (callback != null) { callback.onThrowable(e); } diff --git a/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OkHttpHttpClient.java b/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OkHttpHttpClient.java index 8436f11ed..f82697db0 100644 --- a/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OkHttpHttpClient.java +++ b/scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OkHttpHttpClient.java @@ -1,7 +1,7 @@ package com.github.scribejava.httpclient.okhttp; import com.github.scribejava.core.httpclient.HttpClient; -import com.github.scribejava.core.httpclient.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; import com.github.scribejava.core.model.OAuthAsyncRequestCallback; import com.github.scribejava.core.model.OAuthConstants; import com.github.scribejava.core.model.OAuthRequest; @@ -17,6 +17,7 @@ import java.util.concurrent.Future; import com.github.scribejava.core.model.Response; import java.io.File; +import java.io.InputStream; import java.util.HashMap; import java.util.concurrent.ExecutionException; import okhttp3.Cache; @@ -165,19 +166,19 @@ private enum BodyType { BYTE_ARRAY { @Override RequestBody createBody(MediaType mediaType, Object bodyContents) { - return RequestBody.create(mediaType, (byte[]) bodyContents); + return RequestBody.create((byte[]) bodyContents, mediaType); } }, STRING { @Override RequestBody createBody(MediaType mediaType, Object bodyContents) { - return RequestBody.create(mediaType, (String) bodyContents); + return RequestBody.create((String) bodyContents, mediaType); } }, FILE { @Override RequestBody createBody(MediaType mediaType, Object bodyContents) { - return RequestBody.create(mediaType, (File) bodyContents); + return RequestBody.create((File) bodyContents, mediaType); } }; @@ -192,8 +193,9 @@ static Response convertResponse(okhttp3.Response okHttpResponse) { } final ResponseBody body = okHttpResponse.body(); - return new Response(okHttpResponse.code(), okHttpResponse.message(), headersMap, - body == null ? null : body.byteStream()); + final InputStream bodyStream = body == null ? null : body.byteStream(); + return new Response(okHttpResponse.code(), okHttpResponse.message(), headersMap, bodyStream, bodyStream, body, + okHttpResponse); } } diff --git a/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/MockCall.java b/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/MockCall.java index 967d96c4a..7fa14a630 100644 --- a/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/MockCall.java +++ b/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/MockCall.java @@ -8,6 +8,7 @@ import okhttp3.Callback; import okhttp3.Request; import okhttp3.Response; +import okio.Timeout; public class MockCall implements Call { @@ -48,7 +49,12 @@ public boolean isExecuted() { } @Override - public Call clone() { + public MockCall clone() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Timeout timeout() { throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandlerTest.java b/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandlerTest.java index 863d2eee3..b58e8df93 100644 --- a/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandlerTest.java +++ b/scribejava-httpclient-okhttp/src/test/java/com/github/scribejava/httpclient/okhttp/OAuthAsyncCompletionHandlerTest.java @@ -4,7 +4,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -22,6 +22,7 @@ import okhttp3.Protocol; import okhttp3.Request; import okhttp3.ResponseBody; +import org.junit.function.ThrowingRunnable; public class OAuthAsyncCompletionHandlerTest { @@ -72,13 +73,13 @@ public void shouldReleaseLatchOnSuccess() throws Exception { handler = new OAuthAsyncCompletionHandler<>(callback, ALL_GOOD_RESPONSE_CONVERTER, future); call.enqueue(handler); - final okhttp3.Request request = new Request.Builder().url("http://localhost/").build(); + final Request request = new Request.Builder().url("http://localhost/").build(); final okhttp3.Response response = new okhttp3.Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(200) .message("ok") - .body(ResponseBody.create(MediaType.get("text/plain"), new byte[0])) + .body(ResponseBody.create(new byte[0], MediaType.get("text/plain"))) .build(); handler.onResponse(call, response); assertNotNull(callback.getResponse()); @@ -88,59 +89,59 @@ public void shouldReleaseLatchOnSuccess() throws Exception { } @Test - public void shouldReleaseLatchOnIOException() throws Exception { + public void shouldReleaseLatchOnIOException() { handler = new OAuthAsyncCompletionHandler<>(callback, EXCEPTION_RESPONSE_CONVERTER, future); call.enqueue(handler); - final okhttp3.Request request = new Request.Builder().url("http://localhost/").build(); + final Request request = new Request.Builder().url("http://localhost/").build(); final okhttp3.Response response = new okhttp3.Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(200) .message("ok") - .body(ResponseBody.create(MediaType.get("text/plain"), new byte[0])) + .body(ResponseBody.create(new byte[0], MediaType.get("text/plain"))) .build(); handler.onResponse(call, response); assertNull(callback.getResponse()); assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof IOException); // verify latch is released - try { - future.get(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + future.get(); + } + }); } @Test - public void shouldReportOAuthException() throws Exception { + public void shouldReportOAuthException() { handler = new OAuthAsyncCompletionHandler<>(callback, OAUTH_EXCEPTION_RESPONSE_CONVERTER, future); call.enqueue(handler); - final okhttp3.Request request = new Request.Builder().url("http://localhost/").build(); + final Request request = new Request.Builder().url("http://localhost/").build(); final okhttp3.Response response = new okhttp3.Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(200) .message("ok") - .body(ResponseBody.create(MediaType.get("text/plain"), new byte[0])) + .body(ResponseBody.create(new byte[0], MediaType.get("text/plain"))) .build(); handler.onResponse(call, response); assertNull(callback.getResponse()); assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof OAuthException); // verify latch is released - try { - future.get(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + future.get(); + } + }); } @Test - public void shouldReleaseLatchOnCancel() throws Exception { + public void shouldReleaseLatchOnCancel() { handler = new OAuthAsyncCompletionHandler<>(callback, ALL_GOOD_RESPONSE_CONVERTER, future); call.enqueue(handler); @@ -149,16 +150,16 @@ public void shouldReleaseLatchOnCancel() throws Exception { assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof IOException); // verify latch is released - try { - future.get(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + future.get(); + } + }); } @Test - public void shouldReleaseLatchOnFailure() throws Exception { + public void shouldReleaseLatchOnFailure() { handler = new OAuthAsyncCompletionHandler<>(callback, ALL_GOOD_RESPONSE_CONVERTER, future); call.enqueue(handler); @@ -167,18 +168,19 @@ public void shouldReleaseLatchOnFailure() throws Exception { assertNotNull(callback.getThrowable()); assertTrue(callback.getThrowable() instanceof IOException); // verify latch is released - try { - future.get(); - fail(); - } catch (ExecutionException expected) { - // expected - } + assertThrows(ExecutionException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + future.get(); + } + }); } private static class AllGoodResponseConverter implements OAuthRequest.ResponseConverter { @Override public String convert(Response response) throws IOException { + response.close(); return "All good"; } } @@ -187,6 +189,7 @@ private static class ExceptionResponseConverter implements OAuthRequest.Response @Override public String convert(Response response) throws IOException { + response.close(); throw new IOException("Failed to convert"); } } @@ -195,6 +198,7 @@ private static class OAuthExceptionResponseConverter implements OAuthRequest.Res @Override public String convert(Response response) throws IOException { + response.close(); throw new OAuthException("bad oauth"); } } diff --git a/scribejava-java8/pom.xml b/scribejava-java8/pom.xml new file mode 100644 index 000000000..b75f6d2de --- /dev/null +++ b/scribejava-java8/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + + com.github.scribejava + scribejava + 8.3.4-SNAPSHOT + ../pom.xml + + + com.github.scribejava + scribejava-java8 + ScribeJava Java 8+ compatibility stuff + jar + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + + + 8 + + diff --git a/scribejava-java8/src/main/java/com/github/scribejava/java8/base64/Java8Base64.java b/scribejava-java8/src/main/java/com/github/scribejava/java8/base64/Java8Base64.java new file mode 100644 index 000000000..eb391dcad --- /dev/null +++ b/scribejava-java8/src/main/java/com/github/scribejava/java8/base64/Java8Base64.java @@ -0,0 +1,17 @@ +package com.github.scribejava.java8.base64; + +public class Java8Base64 { + + private static final java.util.Base64.Encoder BASE64_ENCODER = java.util.Base64.getEncoder(); + private static final java.util.Base64.Encoder BASE64_URL_ENCODER_WITHOUT_PADDING + = java.util.Base64.getUrlEncoder().withoutPadding(); + + public String internalEncode(byte[] bytes) { + return BASE64_ENCODER.encodeToString(bytes); + } + + public String internalEncodeUrlWithoutPadding(byte[] bytes) { + return BASE64_URL_ENCODER_WITHOUT_PADDING.encodeToString(bytes); + } + +}