diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/FrappeApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/FrappeApi.java new file mode 100644 index 000000000..b0151cb7f --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/FrappeApi.java @@ -0,0 +1,45 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.apis.frappe.FrappeJsonTokenExtractor; +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.extractors.TokenExtractor; +import com.github.scribejava.core.model.OAuth2AccessToken; + +public class FrappeApi extends DefaultApi20 { + + private String serverURL = "https://scribejava.mntechnique.com"; + + protected FrappeApi() { + } + + private static class InstanceHolder { + private static final FrappeApi INSTANCE = new FrappeApi(); + } + + public static FrappeApi instance() { + return InstanceHolder.INSTANCE; + } + + public String getServerURL() { + return this.serverURL; + } + + public void setServerURL(String serverURL) { + this.serverURL = serverURL; + } + + @Override + public String getAccessTokenEndpoint() { + return this.serverURL + "/api/method/frappe.integrations.oauth2.get_token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return this.serverURL + "/api/method/frappe.integrations.oauth2.authorize"; + } + + @Override + public TokenExtractor getAccessTokenExtractor() { + return FrappeJsonTokenExtractor.instance(); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/frappe/FrappeJsonTokenExtractor.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/frappe/FrappeJsonTokenExtractor.java new file mode 100644 index 000000000..ddf7fe9c8 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/frappe/FrappeJsonTokenExtractor.java @@ -0,0 +1,31 @@ +package com.github.scribejava.apis.frappe; + +import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; +import java.util.regex.Pattern; + +/** + * additionally parses OpenID id_token + */ +public class FrappeJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { + + private static final Pattern ID_TOKEN_REGEX_PATTERN = Pattern.compile("\"id_token\"\\s*:\\s*\"(\\S*?)\""); + + protected FrappeJsonTokenExtractor() { + } + + private static class InstanceHolder { + + private static final FrappeJsonTokenExtractor INSTANCE = new FrappeJsonTokenExtractor(); + } + + public static FrappeJsonTokenExtractor instance() { + return InstanceHolder.INSTANCE; + } + + @Override + protected FrappeToken createToken(String accessToken, String tokenType, Integer expiresIn, + String refreshToken, String scope, String response) { + return new FrappeToken(accessToken, tokenType, expiresIn, refreshToken, scope, + extractParameter(response, ID_TOKEN_REGEX_PATTERN, false), response); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/frappe/FrappeToken.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/frappe/FrappeToken.java new file mode 100644 index 000000000..cc2776d87 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/frappe/FrappeToken.java @@ -0,0 +1,70 @@ +package com.github.scribejava.apis.frappe; + +import com.github.scribejava.core.model.OAuth2AccessToken; +import java.util.Objects; + +public class FrappeToken extends OAuth2AccessToken { + + private static final long serialVersionUID = 7845679917727899612L; + + /** + * Id_token is part of OpenID Connect specification. It can hold user information that you can directly extract + * without additional request to provider. + * + * See http://openid.net/specs/openid-connect-core-1_0.html#id_token-tokenExample and + * https://bitbucket.org/nimbusds/nimbus-jose-jwt/wiki/Home + * + * Here will be encoded and signed id token in JWT format or null, if not defined. + */ + private final String openIdToken; + + public FrappeToken(String accessToken, String openIdToken, String rawResponse) { + this(accessToken, null, null, null, null, openIdToken, rawResponse); + } + + public FrappeToken(String accessToken, String tokenType, Integer expiresIn, String refreshToken, String scope, + String openIdToken, String rawResponse) { + super(accessToken, tokenType, expiresIn, refreshToken, scope, rawResponse); + this.openIdToken = openIdToken; + } + + public String getOpenIdToken() { + return openIdToken; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 37 * hash + Objects.hashCode(openIdToken); + 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(openIdToken, ((FrappeToken) obj).getOpenIdToken()); + } + + @Override + public String toString() { + return "FrappeToken{" + + "access_token=" + getAccessToken() + + ", token_type=" + getTokenType() + + ", expires_in=" + getExpiresIn() + + ", refresh_token=" + getRefreshToken() + + ", scope=" + getScope() + + ", open_id_token=" + openIdToken + '}'; + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Frappe20Example.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Frappe20Example.java new file mode 100644 index 000000000..25e0f4e79 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Frappe20Example.java @@ -0,0 +1,69 @@ +package com.github.scribejava.apis.examples; + +import java.util.Scanner; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.apis.FrappeApi; +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 final class Frappe20Example { + + private static final String NETWORK_NAME = "Frappe"; + private static final String PROTECTED_RESOURCE_URL = "https://scribejava.mntechnique.com/" + + "api/method/frappe.integrations.oauth2.openid_profile"; + + private Frappe20Example() { + } + + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + //Replace these with your client id and secret + final String clientId = "37763ecdb0"; + final String clientSecret = "3e1d716ea7"; + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .scope("openid all") + .callback("https://example.com/callback") + .build(FrappeApi.instance()); + final Scanner in = new Scanner(System.in, "UTF-8"); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth 2.0 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(); + + // Trade the Authorization Code 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("(If you're 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); + 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()); + + System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); + } +}