Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for TLS1.2 on pre-lollipop devices. #128

Merged
merged 7 commits into from
Nov 16, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions auth0/src/main/java/com/auth0/android/Auth0.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public class Auth0 {
private Telemetry telemetry;
private boolean oidcConformant;
private boolean loggingEnabled;
private boolean tls12Enforced;

/**
* Creates a new Auth0 instance with the 'com_auth0_client_id' and 'com_auth0_domain' values
Expand Down Expand Up @@ -204,6 +205,23 @@ public void setLoggingEnabled(boolean enabled) {
loggingEnabled = enabled;
}

/**
* Getter for whether TLS 1.2 is enforced on devices with API 16-21.
*
* @return whether TLS 1.2 is enforced on devices with API 16-21.
*/
public boolean isTLS12Enforced() {
return tls12Enforced;
}

/**
* Set whether to enforce TLS 1.2 on devices with API 16-21.
* @param enforced whether TLS 1.2 is enforced on devices with API 16-21.
*/
public void setTLS12Enforced(boolean enforced) {
tls12Enforced = enforced;
}

private HttpUrl resolveConfiguration(@Nullable String configurationDomain, @NonNull HttpUrl domainUrl) {
HttpUrl url = ensureValidUrl(configurationDomain);
if (url == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,11 @@
import com.auth0.android.result.DatabaseUser;
import com.auth0.android.result.Delegation;
import com.auth0.android.result.UserProfile;
import com.auth0.android.util.OkHttpTLS12Compat;
import com.auth0.android.request.internal.OkHttpClientFactory;
import com.auth0.android.util.Telemetry;
import com.google.gson.Gson;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;

import java.util.Map;

Expand Down Expand Up @@ -99,7 +98,6 @@ public class AuthenticationAPIClient {

private final Auth0 auth0;
@VisibleForTesting final OkHttpClient client;
private final OkHttpTLS12Compat tlsCompat;
private final Gson gson;
private final RequestFactory factory;
private final ErrorBuilder<AuthenticationException> authErrorBuilder;
Expand All @@ -111,7 +109,7 @@ public class AuthenticationAPIClient {
* @param auth0 account information
*/
public AuthenticationAPIClient(@NonNull Auth0 auth0) {
this(auth0, new RequestFactory(), new OkHttpClient(), new OkHttpTLS12Compat(), GsonProvider.buildGson());
this(auth0, new RequestFactory(), new OkHttpClientFactory(), GsonProvider.buildGson());
}

/**
Expand All @@ -125,17 +123,13 @@ public AuthenticationAPIClient(Context context) {
}

@VisibleForTesting
AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client, OkHttpTLS12Compat tlsCompat) {
this(auth0, factory, client, tlsCompat, GsonProvider.buildGson());
AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClientFactory clientFactory) {
this(auth0, factory, clientFactory, GsonProvider.buildGson());
}

private AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client, OkHttpTLS12Compat tlsCompat, Gson gson) {
private AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClientFactory clientFactory, Gson gson) {
this.auth0 = auth0;
this.client = client;
this.tlsCompat = tlsCompat;
if (auth0.isLoggingEnabled()) {
this.client.interceptors().add(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
}
this.client = clientFactory.createClient(auth0.isLoggingEnabled(), auth0.isTLS12Enforced());
this.gson = gson;
this.factory = factory;
this.authErrorBuilder = new AuthenticationErrorBuilder();
Expand Down Expand Up @@ -163,11 +157,6 @@ public void setUserAgent(String userAgent) {
factory.setUserAgent(userAgent);
}

@SuppressWarnings("unused")
public void enableTLS12OnPreLollipop() {
tlsCompat.setClient(client).enableForClient();
}

/**
* Log in a user with email/username and password for a connection/realm.
* In OIDC conformant mode ({@link Auth0#isOIDCConformant()}) it will use the password-realm grant type for the {@code /oauth/token} endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import com.auth0.android.request.internal.RequestFactory;
import com.auth0.android.result.UserIdentity;
import com.auth0.android.result.UserProfile;
import com.auth0.android.util.OkHttpTLS12Compat;
import com.auth0.android.request.internal.OkHttpClientFactory;
import com.auth0.android.util.Telemetry;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
Expand Down Expand Up @@ -69,7 +69,6 @@ public class UsersAPIClient {
private static final String USER_METADATA_KEY = "user_metadata";

private final Auth0 auth0;
private final OkHttpTLS12Compat tlsCompat;
@VisibleForTesting final OkHttpClient client;
private final Gson gson;
private final RequestFactory factory;
Expand All @@ -82,7 +81,7 @@ public class UsersAPIClient {
* @param token of the primary identity
*/
public UsersAPIClient(Auth0 auth0, String token) {
this(auth0, new RequestFactory(token), new OkHttpClient(), new OkHttpTLS12Compat(), GsonProvider.buildGson());
this(auth0, new RequestFactory(token), new OkHttpClientFactory(), GsonProvider.buildGson());
}

/**
Expand All @@ -97,17 +96,13 @@ public UsersAPIClient(Context context, String token) {
}

@VisibleForTesting
UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client, OkHttpTLS12Compat tlsCompat) {
this(auth0, factory, client, tlsCompat, GsonProvider.buildGson());
UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClientFactory clientFactory) {
this(auth0, factory, clientFactory, GsonProvider.buildGson());
}

private UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client, OkHttpTLS12Compat tlsCompat, Gson gson) {
private UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClientFactory clientFactory, Gson gson) {
this.auth0 = auth0;
this.client = client;
this.tlsCompat = tlsCompat;
if (auth0.isLoggingEnabled()) {
this.client.interceptors().add(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
}
client = clientFactory.createClient(auth0.isLoggingEnabled(), auth0.isTLS12Enforced());
this.gson = gson;
this.factory = factory;
this.mgmtErrorBuilder = new ManagementErrorBuilder();
Expand Down Expand Up @@ -135,11 +130,6 @@ public void setUserAgent(String userAgent) {
factory.setUserAgent(userAgent);
}

@SuppressWarnings("Unused")
public void enableTLS12OnPreLollipop() {
tlsCompat.setClient(client).enableForClient();
}

/**
* Link a user identity calling <a href="https://auth0.com/docs/link-accounts#the-management-api">'/api/v2/users/:primaryUserId/identities'</a> endpoint
* Example usage:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.auth0.android.util;
package com.auth0.android.request.internal;

import android.os.Build;
import android.support.annotation.VisibleForTesting;
import android.util.Log;

import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.TlsVersion;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
Expand All @@ -14,32 +17,49 @@

import javax.net.ssl.SSLContext;

public class OkHttpTLS12Compat {
public class OkHttpClientFactory {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an additional javadoc at the class level:

Factory class used to configure and obtain a new OkHttpClient instance. This class is meant for internal use only, breaking changes may appear at any time without backwards compatibility guarantee.

or something like that 🙂


private static final String TAG = OkHttpTLS12Compat.class.getSimpleName();

private OkHttpClient client = null;
private static final String TAG = OkHttpClientFactory.class.getSimpleName();

/**
* Sets the OkHttp client instance
* @param client OkHttpClient instance to be modified
* This method creates an instance of OKHttpClient according to the provided parameters.
* It is used internally and is not intended to be used directly.
* @param loggingEnabled Enable logging in the created OkHttpClient.
* @param tls12Enforced Enforce TLS 1.2 in the created OkHttpClient on devices with API 16-21
* @return new OkHttpClient instance created according to the parameters.
*/
public OkHttpTLS12Compat setClient(OkHttpClient client) {
this.client = client;
return this;
public OkHttpClient createClient(boolean loggingEnabled, boolean tls12Enforced) {
return modifyClient(new OkHttpClient(), loggingEnabled, tls12Enforced);
}

@VisibleForTesting
OkHttpClient modifyClient(OkHttpClient client, boolean loggingEnabled, boolean tls12Enforced) {
if (loggingEnabled) {
enableLogging(client);
}
if (tls12Enforced) {
enforceTls12(client);
}
return client;
}

private void enableLogging(OkHttpClient client) {
Interceptor interceptor = new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY);
client.interceptors().add(interceptor);
}

/**
* Enable TLS 1.2 on the OkHttpClient on API 16-21, which is supported but not enabled by default.
* @link https://github.com/square/okhttp/issues/2372
* @see TLS12SocketFactory
*/
public OkHttpTLS12Compat enableForClient() {
private void enforceTls12(OkHttpClient client) {
// No need to modify client as TLS 1.2 is enabled by default on API21+
// Lollipop is included because some Samsung devices face the same problem on API 21.
if (client == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove client==null check as the client is always valid, since the only entry point is the createClient method. Add a @NonNull annotation to these methods parameters if you want instead, just to help devs as users won't see them.

|| Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
return this;
return;
}
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
Expand All @@ -59,6 +79,5 @@ public OkHttpTLS12Compat enableForClient() {
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Log.e(TAG, "Error while setting TLS 1.2", e);
}
return this;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.android.util;
package com.auth0.android.request.internal;

import android.support.annotation.VisibleForTesting;

Expand Down
22 changes: 22 additions & 0 deletions auth0/src/test/java/com/auth0/android/Auth0Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,28 @@ public void shouldNotHaveLoggingEnabled() throws Exception {
assertThat(auth0.isLoggingEnabled(), is(false));
}

@Test
public void shouldNotEnforceTLS12ByDefault() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
assertThat(auth0.isTLS12Enforced(), is(false));
}

@Test
public void shouldHaveTLS12Enforced() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
auth0.setTLS12Enforced(true);

assertThat(auth0.isTLS12Enforced(), is(true));
}

@Test
public void shouldNotHaveTLS12Enforced() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
auth0.setTLS12Enforced(false);

assertThat(auth0.isTLS12Enforced(), is(false));
}

@Test
public void shouldNotHaveLoggingEnabledByDefault() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
Expand Down
Loading