Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java

Issue 1128043007: Support Kerberos on Android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix cbentzel@'s nits Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
diff --git a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..86474073623dc6edf7afd148041e0a08f55ae130
--- /dev/null
+++ b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
@@ -0,0 +1,222 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.net;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowAccountManager;
+
+import java.io.IOException;
+
+/**
+ * Robolectric tests for HttpNegotiateAuthenticator
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE,
+ shadows = HttpNegotiateAuthenticatorTest.ExtendedShadowAccountManager.class,
+ application = BaseChromiumApplication.class)
+public class HttpNegotiateAuthenticatorTest {
+ static int sCallCount = 0;
+ static String sAccountTypeReceived;
+ static String sAuthTokenTypeReceived;
+ static String sFeaturesReceived[];
+ static Bundle sAddAccountOptionsReceived;
+ static Bundle sAuthTokenOptionsReceived;
+ static AccountManagerCallback<Bundle> sCallbackReceived;
+ static Handler sHandlerReceived;
+
+ /**
+ * Robolectic's ShadowAccountManager doesn't implement getAccountsByTypeAndFeature so extend it.
+ * We simply check the call is correct, and don't try to emulate it Note: Shadow classes need to
+ * be public and static.
+ */
+ @Implements(AccountManager.class)
+ public static class ExtendedShadowAccountManager extends ShadowAccountManager {
+ @Implementation
+ public AccountManagerFuture<Bundle> getAuthTokenByFeatures(String accountType,
+ String authTokenType, String[] features, Activity activity,
+ Bundle addAccountOptions, Bundle getAuthTokenOptions,
+ AccountManagerCallback<Bundle> callback, Handler handler) {
+ sCallCount++;
+ sAccountTypeReceived = accountType;
+ sAuthTokenTypeReceived = authTokenType;
+ sFeaturesReceived = features;
+ sAddAccountOptionsReceived = addAccountOptions;
+ sAuthTokenOptionsReceived = getAuthTokenOptions;
+ sCallbackReceived = callback;
+ sHandlerReceived = handler;
+
+ return null;
+ }
+ }
+
+ /**
+ * Test of {@link HttpNegotiateAuthenticator#getNextAuthToken}
+ */
+ @Test
+ public void testGetNextAuthToken() {
+ HttpNegotiateAuthenticator authenticator =
+ HttpNegotiateAuthenticator.create("Dummy_Account");
+ Robolectric.buildActivity(Activity.class).create().start().resume().visible();
+ authenticator.getNextAuthToken(0, "test_principal", "", true);
+ assertThat("getAuthTokenByFeatures called precisely once", sCallCount, equalTo(1));
+ assertThat("Received account type matches input", sAccountTypeReceived,
+ equalTo("Dummy_Account"));
+ assertThat("AuthTokenType is \"SPNEGO:HOSTBASED:test_principal\"", sAuthTokenTypeReceived,
+ equalTo("SPNEGO:HOSTBASED:test_principal"));
+ assertThat("Features are precisely {\"SPNEGO\"}", sFeaturesReceived,
+ equalTo(new String[] {"SPNEGO"}));
+ assertThat("No account options requested", sAddAccountOptionsReceived, nullValue());
+ assertThat("There is no existing context",
+ sAuthTokenOptionsReceived.get(HttpNegotiateConstants.KEY_SPNEGO_CONTEXT),
+ nullValue());
+ assertThat("The existing token is empty",
+ sAuthTokenOptionsReceived.getString(HttpNegotiateConstants.KEY_INCOMING_AUTH_TOKEN),
+ equalTo(""));
+ assertThat("Delegation is allowed",
+ sAuthTokenOptionsReceived.getBoolean(HttpNegotiateConstants.KEY_CAN_DELEGATE),
+ equalTo(true));
+ assertThat("getAuthTokenByFeatures was called with a callback", sCallbackReceived,
+ notNullValue());
+ assertThat("getAuthTokenByFeatures was called with a handler", sHandlerReceived,
+ notNullValue());
+ }
+
+ /**
+ * Test of callback called when getting the auth token completes.
+ */
+ @Test
+ public void testAccountManagerCallbackRun() {
+ // Spy on the authenticator so that we can override and intercept the native method call.
+ HttpNegotiateAuthenticator authenticator =
+ spy(HttpNegotiateAuthenticator.create("Dummy_Account"));
+ doNothing().when(authenticator).nativeSetResult(anyLong(), anyInt(), anyString());
+
+ Robolectric.buildActivity(Activity.class).create().start().resume().visible();
+
+ // Call getNextAuthToken to get the callback
+ authenticator.getNextAuthToken(1234, "test_principal", "", true);
+
+ // Avoid warning when creating mock accountManagerFuture, can't take .class of an
+ // instantiated generic type, yet compiler complains if I leave it uninstantiated.
+ @SuppressWarnings("unchecked")
+ AccountManagerFuture<Bundle> accountManagerFuture = mock(AccountManagerFuture.class);
+ Bundle resultBundle = new Bundle();
+ Bundle context = new Bundle();
+ context.putString("String", "test_context");
+ resultBundle.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, HttpNegotiateConstants.OK);
+ resultBundle.putBundle(HttpNegotiateConstants.KEY_SPNEGO_CONTEXT, context);
+ resultBundle.putString(AccountManager.KEY_AUTHTOKEN, "output_token");
+ try {
+ when(accountManagerFuture.getResult()).thenReturn(resultBundle);
+ } catch (OperationCanceledException | AuthenticatorException | IOException e) {
+ // Can never happen - artifact of Mockito.
+ fail();
+ }
+ sCallbackReceived.run(accountManagerFuture);
+ verify(authenticator).nativeSetResult(1234, 0, "output_token");
+
+ // Check that the next call to getNextAuthToken uses the correct context
+ authenticator.getNextAuthToken(5678, "test_principal", "", true);
+ assertThat("The spnego context is preserved between calls",
+ sAuthTokenOptionsReceived.getBundle(HttpNegotiateConstants.KEY_SPNEGO_CONTEXT),
+ equalTo(context));
+
+ // Test exception path
+ try {
+ when(accountManagerFuture.getResult()).thenThrow(new OperationCanceledException());
+ } catch (OperationCanceledException | AuthenticatorException | IOException e) {
+ // Can never happen - artifact of Mockito.
+ fail();
+ }
+ sCallbackReceived.run(accountManagerFuture);
+ verify(authenticator).nativeSetResult(5678, NetError.ERR_ABORTED, null);
+ }
+
+ private void checkErrorReturn(Integer spnegoError, int expectedError) {
+ // Spy on the authenticator so that we can override and intercept the native method call.
+ HttpNegotiateAuthenticator authenticator =
+ spy(HttpNegotiateAuthenticator.create("Dummy_Account"));
+ doNothing().when(authenticator).nativeSetResult(anyLong(), anyInt(), anyString());
+
+ Robolectric.buildActivity(Activity.class).create().start().resume().visible();
+
+ // Call getNextAuthToken to get the callback
+ authenticator.getNextAuthToken(1234, "test_principal", "", true);
+
+ // Avoid warning when creating mock accountManagerFuture, can't take .class of an
+ // instantiated generic type, yet compiler complains if I leave it uninstantiated.
+ @SuppressWarnings("unchecked")
+ AccountManagerFuture<Bundle> accountManagerFuture = mock(AccountManagerFuture.class);
+ Bundle resultBundle = new Bundle();
+ if (spnegoError != null) {
+ resultBundle.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, spnegoError);
+ }
+ try {
+ when(accountManagerFuture.getResult()).thenReturn(resultBundle);
+ } catch (OperationCanceledException | AuthenticatorException | IOException e) {
+ // Can never happen - artifact of Mockito.
+ fail();
+ }
+ sCallbackReceived.run(accountManagerFuture);
+ verify(authenticator).nativeSetResult(anyLong(), eq(expectedError), anyString());
+ }
+
+ /**
+ * Test of callback error returns when getting the auth token completes.
+ */
+ @Test
+ public void testAccountManagerCallbackErrorReturns() {
+ checkErrorReturn(null, NetError.ERR_UNEXPECTED);
+ checkErrorReturn(HttpNegotiateConstants.ERR_UNEXPECTED, NetError.ERR_UNEXPECTED);
+ checkErrorReturn(HttpNegotiateConstants.ERR_ABORTED, NetError.ERR_ABORTED);
+ checkErrorReturn(HttpNegotiateConstants.ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS,
+ NetError.ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS);
+ checkErrorReturn(
+ HttpNegotiateConstants.ERR_INVALID_RESPONSE, NetError.ERR_INVALID_RESPONSE);
+ checkErrorReturn(HttpNegotiateConstants.ERR_INVALID_AUTH_CREDENTIALS,
+ NetError.ERR_INVALID_AUTH_CREDENTIALS);
+ checkErrorReturn(HttpNegotiateConstants.ERR_UNSUPPORTED_AUTH_SCHEME,
+ NetError.ERR_UNSUPPORTED_AUTH_SCHEME);
+ checkErrorReturn(HttpNegotiateConstants.ERR_MISSING_AUTH_CREDENTIALS,
+ NetError.ERR_MISSING_AUTH_CREDENTIALS);
+ checkErrorReturn(HttpNegotiateConstants.ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS,
+ NetError.ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS);
+ checkErrorReturn(
+ HttpNegotiateConstants.ERR_MALFORMED_IDENTITY, NetError.ERR_MALFORMED_IDENTITY);
+ // 9999 is not a valid return value
+ checkErrorReturn(9999, NetError.ERR_UNEXPECTED);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698