diff --git a/build.gradle b/build.gradle index edb3243..8e6261d 100644 --- a/build.gradle +++ b/build.gradle @@ -10,11 +10,11 @@ buildscript { } plugins { - id "com.jfrog.bintray" version "1.7.3" + id "com.jfrog.bintray" version "1.8.4" } plugins { - id "com.github.dcendents.android-maven" version "2.0" + id "com.github.dcendents.android-maven" version "2.1" } bintray { diff --git a/library/build.gradle b/library/build.gradle index 471e149..d44f271 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -8,7 +8,7 @@ ext { GROUP = 'com.codepath.libraries' BASE_VERSION = "2.0" - VERSION_NAME = "2.0.0" + VERSION_NAME = "2.1.0" POM_PACKAGING = "aar" POM_DESCRIPTION = "CodePath OAuth Handler" @@ -54,49 +54,16 @@ android { } } -install { - repositories.mavenInstaller { - pom.project { - name POM_NAME - description POM_DESCRIPTION - url POM_URL - inceptionYear '2016' - - packaging 'aar' - group GROUP - artifactId POM_ARTIFACT_ID - version VERSION_NAME - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - scm { - connection POM_SCM_URL - url POM_SCM_CONNECTION - - } - developers { - developer { - name 'CodePath, Inc.' - } - } - } - } -} - bintray { - user = System.getenv('BINTRAY_USER') - key = System.getenv('BINTRAY_API_KEY') + user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') + key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') + configurations = ['archives'] // needs apply plugin 'com.jfrog.bintray' to work pkg { repo = 'maven' name = 'android-oauth-handler' -// userOrg = 'codepath' + userOrg = 'codepath' licenses = ['Apache-2.0'] vcsUrl = 'https://github.com/codepath/android-oauth-handler.git' version { @@ -109,14 +76,22 @@ bintray { } +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + archiveClassifier.set("sources") +} + +artifacts { + archives sourcesJar +} + ext { supportVersion = '28.0.0' } dependencies { api "androidx.appcompat:appcompat:1.0.2" - api 'com.codepath.libraries:asynchttpclient:0.0.5' - implementation files('libs/codepath-utils.jar') + api 'com.codepath.libraries:asynchttpclient:0.0.8' api 'com.github.scribejava:scribejava-apis:4.1.1' api 'com.github.scribejava:scribejava-httpclient-okhttp:4.1.1' implementation 'se.akerfeldt:okhttp-signpost:1.1.0' diff --git a/library/libs/codepath-utils.jar b/library/libs/codepath-utils.jar deleted file mode 100755 index 7294db1..0000000 Binary files a/library/libs/codepath-utils.jar and /dev/null differ diff --git a/library/src/main/java/com/codepath/oauth/OAuthAsyncHttpClient.java b/library/src/main/java/com/codepath/oauth/OAuthAsyncHttpClient.java index 8b345e7..2ddfc23 100644 --- a/library/src/main/java/com/codepath/oauth/OAuthAsyncHttpClient.java +++ b/library/src/main/java/com/codepath/oauth/OAuthAsyncHttpClient.java @@ -3,8 +3,16 @@ import com.codepath.asynchttpclient.AsyncHttpClient; import com.facebook.stetho.okhttp3.StethoInterceptor; import com.github.scribejava.core.model.OAuth1AccessToken; +import com.github.scribejava.core.model.OAuth2AccessToken; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +import okhttp3.Interceptor; import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import se.akerfeldt.okhttp.signpost.OkHttpOAuthConsumer; import se.akerfeldt.okhttp.signpost.SigningInterceptor; @@ -17,10 +25,30 @@ protected OAuthAsyncHttpClient(OkHttpClient httpClient) { public static OAuthAsyncHttpClient create(String consumerKey, String consumerSecret, OAuth1AccessToken token) { OkHttpOAuthConsumer consumer = new OkHttpOAuthConsumer(consumerKey, consumerSecret); consumer.setTokenWithSecret(token.getToken(), token.getTokenSecret()); - OkHttpClient httpClient = new OkHttpClient.Builder().addNetworkInterceptor(new StethoInterceptor()).addInterceptor(new SigningInterceptor(consumer)).build(); + OkHttpClient httpClient = new OkHttpClient.Builder() + .addNetworkInterceptor(new StethoInterceptor()) + .addInterceptor(new SigningInterceptor(consumer)).build(); OAuthAsyncHttpClient asyncHttpClient = new OAuthAsyncHttpClient(httpClient); return asyncHttpClient; } + public static OAuthAsyncHttpClient create(final OAuth2AccessToken token) { + final String bearer = String.format("Bearer %s", token.getAccessToken()); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .addNetworkInterceptor(new StethoInterceptor()) + .addInterceptor(new Interceptor() { + @NotNull + @Override + public Response intercept(@NotNull Chain chain) throws IOException { + Request originalRequest = chain.request(); + Request authedRequest = originalRequest.newBuilder().header("Authorization", bearer).build(); + return chain.proceed(authedRequest); + } + }).build(); + + OAuthAsyncHttpClient asyncHttpClient = new OAuthAsyncHttpClient(httpClient); + return asyncHttpClient; + } } \ No newline at end of file diff --git a/library/src/main/java/com/codepath/oauth/OAuthBaseClient.java b/library/src/main/java/com/codepath/oauth/OAuthBaseClient.java index 04ef5fc..1b0dcff 100755 --- a/library/src/main/java/com/codepath/oauth/OAuthBaseClient.java +++ b/library/src/main/java/com/codepath/oauth/OAuthBaseClient.java @@ -5,6 +5,8 @@ import android.content.SharedPreferences; import android.net.Uri; +import androidx.annotation.Nullable; + import com.github.scribejava.core.builder.api.BaseApi; import com.github.scribejava.core.model.OAuth1AccessToken; import com.github.scribejava.core.model.OAuth1RequestToken; @@ -46,11 +48,11 @@ public static OAuthBaseClient getInstance(Class klass return instance; } - public OAuthBaseClient(Context c, final BaseApi apiInstance, String consumerUrl, final String consumerKey, final String consumerSecret, String callbackUrl) { + public OAuthBaseClient(Context c, final BaseApi apiInstance, String consumerUrl, final String consumerKey, final String consumerSecret, @Nullable String scope, String callbackUrl) { this.baseUrl = consumerUrl; this.callbackUrl = callbackUrl; tokenClient = new OAuthTokenClient(apiInstance, consumerKey, - consumerSecret, callbackUrl, new OAuthTokenClient.OAuthTokenHandler() { + consumerSecret, callbackUrl, scope, new OAuthTokenClient.OAuthTokenHandler() { // Store request token and launch the authorization URL in the browser @Override @@ -86,8 +88,7 @@ public void onReceivedAccessToken(Token accessToken, String oAuthVersion) { editor.commit(); } else if (oAuthVersion == OAUTH2_VERSION) { OAuth2AccessToken oAuth2AccessToken = (OAuth2AccessToken) accessToken; - - //TODO(rhu) - create client for OAuth2 cases + instantiateClient(consumerKey, consumerSecret, oAuth2AccessToken); tokenClient.setAccessToken(accessToken); editor.putString(OAuthConstants.TOKEN, oAuth2AccessToken.getAccessToken()); editor.putString(OAuthConstants.SCOPE, oAuth2AccessToken.getScope()); @@ -122,8 +123,10 @@ public void instantiateClient(String consumerKey, String consumerSecret, Token t if (token instanceof OAuth1AccessToken) { client = OAuthAsyncHttpClient.create(consumerKey, consumerSecret, (OAuth1AccessToken)(token)); + } else if (token instanceof OAuth2AccessToken){ + client = OAuthAsyncHttpClient.create((OAuth2AccessToken) token); } else { - + throw new IllegalStateException("unrecognized token type" + token); } } @@ -138,7 +141,7 @@ public void authorize(Uri uri, OAuthAccessHandler handler) { this.accessHandler = handler; if (checkAccessToken() == null && uri != null) { // TODO: check UriServiceCallback with intent:// scheme - tokenClient.fetchAccessToken(getOAuth1RequestToken(), uri); + tokenClient.fetchAccessToken(checkAccessToken(), uri); } else if (checkAccessToken() != null) { // already have access token this.accessHandler.onLoginSuccess(); diff --git a/library/src/main/java/com/codepath/oauth/OAuthTokenClient.java b/library/src/main/java/com/codepath/oauth/OAuthTokenClient.java index b92c578..03629b4 100755 --- a/library/src/main/java/com/codepath/oauth/OAuthTokenClient.java +++ b/library/src/main/java/com/codepath/oauth/OAuthTokenClient.java @@ -30,7 +30,7 @@ public class OAuthTokenClient { // Requires the apiClass, consumerKey, consumerSecret and callbackUrl along with the TokenHandler public OAuthTokenClient(BaseApi apiInstance, String consumerKey, String consumerSecret, String callbackUrl, - OAuthTokenHandler handler) { + String scope, OAuthTokenHandler handler) { this.apiInstance = apiInstance; this.handler = handler; if (callbackUrl == null) { callbackUrl = OAuthConstants.OUT_OF_BAND; }; @@ -38,6 +38,7 @@ public OAuthTokenClient(BaseApi apiInstance, String consumerKey, String consumer .apiKey(consumerKey) .apiSecret(consumerSecret).callback(callbackUrl) .httpClientConfig(OkHttpHttpClientConfig.defaultConfig()) + .scope(scope) // OAuth2 requires scope .build(apiInstance); } diff --git a/library/src/main/java/com/codepath/utils/GenericsUtil.java b/library/src/main/java/com/codepath/utils/GenericsUtil.java new file mode 100644 index 0000000..66298f9 --- /dev/null +++ b/library/src/main/java/com/codepath/utils/GenericsUtil.java @@ -0,0 +1,80 @@ +package com.codepath.utils; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +@SuppressWarnings("rawtypes") +public class GenericsUtil { + public static List> getTypeArguments(Class baseClass, + Class childClass) { + Map resolvedTypes = new HashMap(); + Type type = childClass; + // start walking up the inheritance hierarchy until we hit baseClass + while (!getClass(type).equals(baseClass)) { + if (type instanceof Class) { + type = ((Class) type).getGenericSuperclass(); + } else { + ParameterizedType parameterizedType = (ParameterizedType) type; + assert parameterizedType != null; + Class rawType = (Class) parameterizedType.getRawType(); + + Type[] actualTypeArguments = parameterizedType + .getActualTypeArguments(); + TypeVariable[] typeParameters = rawType.getTypeParameters(); + for (int i = 0; i < actualTypeArguments.length; i++) { + resolvedTypes + .put(typeParameters[i], actualTypeArguments[i]); + } + + if (!rawType.equals(baseClass)) { + type = rawType.getGenericSuperclass(); + } + } + } + + // finally, for each actual type argument provided to baseClass, + // determine (if possible) + // the raw class for that type argument. + Type[] actualTypeArguments; + if (type instanceof Class) { + actualTypeArguments = ((Class) type).getTypeParameters(); + } else { + assert !(type == null); + actualTypeArguments = ((ParameterizedType) type) + .getActualTypeArguments(); + } + List> typeArgumentsAsClasses = new ArrayList>(); + // resolve types by chasing down type variables. + for (Type baseType : actualTypeArguments) { + while (resolvedTypes.containsKey(baseType)) { + baseType = resolvedTypes.get(baseType); + } + typeArgumentsAsClasses.add(getClass(baseType)); + } + return typeArgumentsAsClasses; + } + + private static Class getClass(Type type) { + if (type instanceof Class) { + return (Class) type; + } else if (type instanceof ParameterizedType) { + return getClass(((ParameterizedType) type).getRawType()); + } else if (type instanceof GenericArrayType) { + Type componentType = ((GenericArrayType) type) + .getGenericComponentType(); + Class componentClass = getClass(componentType); + if (componentClass != null) { + return Array.newInstance(componentClass, 0).getClass(); + } else { + return null; + } + } else { + return null; + } + } + +}