Skip to content

Commit

Permalink
Merge pull request #40 from auth0/http-logging
Browse files Browse the repository at this point in the history
Add Logging for Requests/Responses and Uri's.
  • Loading branch information
hzalaz committed Nov 30, 2016
2 parents 8323003 + 1b4dd70 commit dbba9d2
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 28 deletions.
7 changes: 4 additions & 3 deletions auth0/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,15 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile "com.google.code.gson:gson:2.6.2"
compile 'com.squareup.okhttp:okhttp:2.7.5'
compile 'com.squareup.okhttp:logging-interceptor:2.7.5'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.auth0.android:jwtdecode:1.0.0'

testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:java-hamcrest:2.0.0.0'
testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'com.squareup.okhttp:mockwebserver:2.5.0'
testCompile 'com.squareup.okhttp:mockwebserver:2.7.5'
testCompile 'com.jayway.awaitility:awaitility:1.6.4'
testCompile 'org.robolectric:robolectric:3.1.2'
testCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
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 @@ -91,6 +92,7 @@ public class AuthenticationAPIClient {

private final Auth0 auth0;
private final OkHttpClient client;
private final HttpLoggingInterceptor logInterceptor;
private final Gson gson;
private final com.auth0.android.request.internal.RequestFactory factory;
private final ErrorBuilder<AuthenticationException> authErrorBuilder;
Expand All @@ -116,13 +118,15 @@ public AuthenticationAPIClient(Context context) {
}

@VisibleForTesting
AuthenticationAPIClient(Auth0 auth0, RequestFactory factory) {
this(auth0, factory, new OkHttpClient(), GsonProvider.buildGson());
AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client) {
this(auth0, factory, client, GsonProvider.buildGson());
}

private AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client, Gson gson) {
this.auth0 = auth0;
this.client = client;
this.logInterceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.NONE);
this.client.interceptors().add(logInterceptor);
this.gson = gson;
this.factory = factory;
this.authErrorBuilder = new AuthenticationErrorBuilder();
Expand All @@ -132,6 +136,21 @@ private AuthenticationAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClien
}
}

/**
* Log every Request and Response made by this client.
* You shouldn't enable logging in release builds as it may leak sensitive information.
*/
public void setLoggingEnabled(boolean enabled) {
logInterceptor.setLevel(enabled ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
}

/**
* Getter for the current client logger enabled state.
*/
public boolean isLoggingEnabled() {
return logInterceptor.getLevel() == HttpLoggingInterceptor.Level.BODY;
}

public String getClientId() {
return auth0.getClientId();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;

import java.util.List;
import java.util.Map;
Expand All @@ -67,6 +68,7 @@ public class UsersAPIClient {

private final Auth0 auth0;
private final OkHttpClient client;
private final HttpLoggingInterceptor logInterceptor;
private final Gson gson;
private final RequestFactory factory;
private final ErrorBuilder<ManagementException> mgmtErrorBuilder;
Expand All @@ -93,13 +95,15 @@ public UsersAPIClient(Context context, String token) {
}

@VisibleForTesting
UsersAPIClient(Auth0 auth0, RequestFactory factory) {
this(auth0, factory, new OkHttpClient(), GsonProvider.buildGson());
UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client) {
this(auth0, factory, client, GsonProvider.buildGson());
}

private UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client, Gson gson) {
this.auth0 = auth0;
this.client = client;
this.logInterceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.NONE);
this.client.interceptors().add(logInterceptor);
this.gson = gson;
this.factory = factory;
this.mgmtErrorBuilder = new ManagementErrorBuilder();
Expand All @@ -109,6 +113,14 @@ private UsersAPIClient(Auth0 auth0, RequestFactory factory, OkHttpClient client,
}
}

/**
* Log every Request and Response made by this client.
* You shouldn't enable logging in release builds as it may leak sensitive information.
*/
public void enableLogging() {
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
}

public String getClientId() {
return auth0.getClientId();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,16 @@ byte[] getSHA256(byte[] input) {
return signature;
}

public String generateCodeVerifier() {
String generateCodeVerifier() {
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
Log.d(TAG, "Generated code verifier is " + verifier);
return verifier;
return Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
}

public String generateCodeChallenge(@NonNull String codeVerifier) {
String generateCodeChallenge(@NonNull String codeVerifier) {
byte[] input = getASCIIBytes(codeVerifier);
byte[] signature = getSHA256(input);
String challenge = getBase64String(signature);
Log.d(TAG, "Generated code challenge is " + challenge);
return challenge;
return getBase64String(signature);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public class WebAuthProvider {
private Map<String, String> parameters;

private static WebAuthProvider providerInstance;
private boolean loggingEnabled;

@VisibleForTesting
WebAuthProvider(@NonNull Auth0 account) {
Expand All @@ -105,6 +106,7 @@ public static class Builder {
private boolean useBrowser;
private boolean useFullscreen;
private PKCE pkce;
private boolean loggingEnabled;

Builder(Auth0 account) {
this.account = account;
Expand Down Expand Up @@ -253,6 +255,15 @@ public Builder withConnection(@NonNull String connectionName) {
return this;
}

/**
* Log every Request and Response made by this provider.
* You shouldn't enable logging in release builds as it may leak sensitive information.
*/
public Builder enableLogging() {
this.loggingEnabled = true;
return this;
}

@VisibleForTesting
Builder withPKCE(PKCE pkce) {
this.pkce = pkce;
Expand All @@ -276,6 +287,7 @@ public void start(@NonNull Activity activity, @NonNull AuthCallback callback, in
webAuth.useFullscreen = useFullscreen;
webAuth.parameters = values;
webAuth.pkce = pkce;
webAuth.loggingEnabled = loggingEnabled;

providerInstance = webAuth;

Expand Down Expand Up @@ -368,6 +380,7 @@ private boolean authorize(@NonNull AuthorizeResult data) {
Log.w(TAG, "The response didn't contain any of these values: code, state, id_token, access_token, token_type, refresh_token");
return false;
}
logDebug("The parsed CallbackURI contains the following values: " + values);

if (values.containsKey(KEY_ERROR)) {
Log.e(TAG, "Error, access denied. Check that the required Permissions are granted and that the Application has this Connection configured in Auth0 Dashboard.");
Expand Down Expand Up @@ -507,12 +520,18 @@ Uri buildAuthorizeUri() {
builder.appendQueryParameter(entry.getKey(), entry.getValue());
}
Uri uri = builder.build();
Log.d(TAG, "The final Authorize Uri is " + uri.toString());
logDebug("The parsed CallbackURI contains the following values: " + "Using the following AuthorizeURI: " + uri.toString());
return uri;
}

private PKCE createPKCE(String redirectUri) {
return pkce == null ? new PKCE(new AuthenticationAPIClient(account), redirectUri) : pkce;
if (pkce == null) {
final AuthenticationAPIClient client = new AuthenticationAPIClient(account);
client.setLoggingEnabled(loggingEnabled);
return new PKCE(client, redirectUri);
} else {
return pkce;
}
}

@VisibleForTesting
Expand All @@ -525,6 +544,14 @@ private String getState() {
return parameters.containsKey(KEY_STATE) ? parameters.get(KEY_STATE) : secureRandomString();
}

String getScope() {
return this.parameters.get(KEY_SCOPE) != null ? this.parameters.get(KEY_SCOPE) : SCOPE_TYPE_OPENID;
}

boolean isLoggingEnabled() {
return loggingEnabled;
}

private String getNonce() {
return parameters.containsKey(KEY_NONCE) ? parameters.get(KEY_NONCE) : secureRandomString();
}
Expand All @@ -543,4 +570,10 @@ private String secureRandomString() {
sr.nextBytes(randomBytes);
return Base64.encodeToString(randomBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
}

private void logDebug(String message) {
if (loggingEnabled) {
Log.d(TAG, message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,20 @@
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;
import com.squareup.okhttp.mockwebserver.RecordedRequest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

Expand All @@ -64,6 +69,7 @@
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
Expand Down Expand Up @@ -110,8 +116,10 @@ public void tearDown() throws Exception {

@Test
public void shouldSetUserAgent() throws Exception {
Auth0 account = mock(Auth0.class);
RequestFactory factory = mock(RequestFactory.class);
AuthenticationAPIClient client = new AuthenticationAPIClient(new Auth0(CLIENT_ID, DOMAIN), factory);
OkHttpClient okClient = mock(OkHttpClient.class);
AuthenticationAPIClient client = new AuthenticationAPIClient(account, factory, okClient);
client.setUserAgent("nexus-5x");
verify(factory).setUserAgent("nexus-5x");
}
Expand All @@ -121,21 +129,88 @@ public void shouldSetTelemetryIfPresent() throws Exception {
final Telemetry telemetry = mock(Telemetry.class);
when(telemetry.getValue()).thenReturn("the-telemetry-data");
RequestFactory factory = mock(RequestFactory.class);
OkHttpClient okClient = mock(OkHttpClient.class);
Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
auth0.setTelemetry(telemetry);
new AuthenticationAPIClient(auth0, factory);
new AuthenticationAPIClient(auth0, factory, okClient);
verify(factory).setClientInfo("the-telemetry-data");
}

@Test
public void shouldNotSetTelemetryIfMissing() throws Exception {
RequestFactory factory = mock(RequestFactory.class);
OkHttpClient okClient = mock(OkHttpClient.class);
Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
auth0.doNotSendTelemetry();
new AuthenticationAPIClient(auth0, factory);
new AuthenticationAPIClient(auth0, factory, okClient);
verify(factory, never()).setClientInfo(any(String.class));
}

@SuppressWarnings("unchecked")
@Test
public void shouldEnableHttpLogging() throws Exception {
Auth0 account = mock(Auth0.class);
RequestFactory factory = mock(RequestFactory.class);
OkHttpClient okClient = mock(OkHttpClient.class);
List list = mock(List.class);
when(okClient.interceptors()).thenReturn(list);

ArgumentCaptor<Interceptor> interceptorCaptor = ArgumentCaptor.forClass(Interceptor.class);
AuthenticationAPIClient client = new AuthenticationAPIClient(account, factory, okClient);
client.setLoggingEnabled(true);

verify(okClient).interceptors();
verify(list).add(interceptorCaptor.capture());

assertThat(interceptorCaptor.getValue(), is(notNullValue()));
assertThat(interceptorCaptor.getValue(), is(instanceOf(HttpLoggingInterceptor.class)));
assertThat(((HttpLoggingInterceptor) interceptorCaptor.getValue()).getLevel(), is(HttpLoggingInterceptor.Level.BODY));
assertThat(client.isLoggingEnabled(), is(true));
}

@SuppressWarnings("unchecked")
@Test
public void shouldDisableHttpLogging() throws Exception {
Auth0 account = mock(Auth0.class);
RequestFactory factory = mock(RequestFactory.class);
OkHttpClient okClient = mock(OkHttpClient.class);
List list = mock(List.class);
when(okClient.interceptors()).thenReturn(list);

ArgumentCaptor<Interceptor> interceptorCaptor = ArgumentCaptor.forClass(Interceptor.class);
AuthenticationAPIClient client = new AuthenticationAPIClient(account, factory, okClient);
client.setLoggingEnabled(false);

verify(okClient).interceptors();
verify(list).add(interceptorCaptor.capture());

assertThat(interceptorCaptor.getValue(), is(notNullValue()));
assertThat(interceptorCaptor.getValue(), is(instanceOf(HttpLoggingInterceptor.class)));
assertThat(((HttpLoggingInterceptor) interceptorCaptor.getValue()).getLevel(), is(HttpLoggingInterceptor.Level.NONE));
assertThat(client.isLoggingEnabled(), is(false));
}

@SuppressWarnings("unchecked")
@Test
public void shouldHaveHttpLoggingDisabledByDefault() throws Exception {
Auth0 account = mock(Auth0.class);
RequestFactory factory = mock(RequestFactory.class);
OkHttpClient okClient = mock(OkHttpClient.class);
List list = mock(List.class);
when(okClient.interceptors()).thenReturn(list);

ArgumentCaptor<Interceptor> interceptorCaptor = ArgumentCaptor.forClass(Interceptor.class);
new AuthenticationAPIClient(account, factory, okClient);

verify(okClient).interceptors();
verify(list).add(interceptorCaptor.capture());

assertThat(interceptorCaptor.getValue(), is(notNullValue()));
assertThat(interceptorCaptor.getValue(), is(instanceOf(HttpLoggingInterceptor.class)));
assertThat(((HttpLoggingInterceptor) interceptorCaptor.getValue()).getLevel(), is(HttpLoggingInterceptor.Level.NONE));
assertThat(client.isLoggingEnabled(), is(false));
}

@Test
public void shouldCreateClientWithAccountInfo() throws Exception {
AuthenticationAPIClient client = new AuthenticationAPIClient(new Auth0(CLIENT_ID, DOMAIN));
Expand Down
Loading

0 comments on commit dbba9d2

Please sign in to comment.