| // 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.test; |
| |
| import android.accounts.AbstractAccountAuthenticator; |
| import android.accounts.Account; |
| import android.accounts.AccountAuthenticatorResponse; |
| import android.accounts.AccountManager; |
| import android.accounts.AuthenticatorException; |
| import android.accounts.NetworkErrorException; |
| import android.accounts.OperationCanceledException; |
| import android.app.Activity; |
| import android.content.Context; |
| import android.os.Bundle; |
| |
| import org.chromium.base.ApplicationStatus; |
| import org.chromium.base.annotations.CalledByNative; |
| import org.chromium.base.annotations.JNINamespace; |
| import org.chromium.base.annotations.NativeClassQualifiedName; |
| import org.chromium.net.HttpNegotiateConstants; |
| |
| import java.io.IOException; |
| |
| /** |
| * Dummy Android authenticator, to test SPNEGO/Keberos support on Android. This is deliberately |
| * minimal, and is not intended as an example of how to write a real SPNEGO Authenticator. |
| */ |
| @JNINamespace("net::android") |
| public class DummySpnegoAuthenticator extends AbstractAccountAuthenticator { |
| private static final String ACCOUNT_TYPE = "org.chromium.test.DummySpnegoAuthenticator"; |
| private static final String ACCOUNT_NAME = "DummySpnegoAccount"; |
| private static int sResult; |
| private static String sToken; |
| private static boolean sCheckArguments; |
| private static long sNativeDummySpnegoAuthenticator; |
| private static final int GSS_S_COMPLETE = 0; |
| private static final int GSS_S_CONTINUE_NEEDED = 1; |
| private static final int GSS_S_FAILURE = 2; |
| |
| /** |
| * @param context |
| */ |
| public DummySpnegoAuthenticator(Context context) { |
| super(context); |
| } |
| |
| @Override |
| public Bundle addAccount(AccountAuthenticatorResponse arg0, String accountType, String arg2, |
| String[] arg3, Bundle arg4) throws NetworkErrorException { |
| Bundle result = new Bundle(); |
| result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_REQUEST); |
| result.putString(AccountManager.KEY_ERROR_MESSAGE, "Can't add new SPNEGO accounts"); |
| return result; |
| } |
| |
| @Override |
| public Bundle confirmCredentials(AccountAuthenticatorResponse arg0, Account arg1, Bundle arg2) |
| throws NetworkErrorException { |
| Bundle result = new Bundle(); |
| result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); |
| return result; |
| } |
| |
| @Override |
| public Bundle editProperties(AccountAuthenticatorResponse arg0, String arg1) { |
| return new Bundle(); |
| } |
| |
| @Override |
| public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, |
| String authTokenType, Bundle options) throws NetworkErrorException { |
| long nativeQuery = nativeGetNextQuery(sNativeDummySpnegoAuthenticator); |
| String incomingToken = options.getString(HttpNegotiateConstants.KEY_INCOMING_AUTH_TOKEN); |
| nativeCheckGetTokenArguments(nativeQuery, incomingToken); |
| Bundle result = new Bundle(); |
| result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); |
| result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); |
| result.putString(AccountManager.KEY_AUTHTOKEN, nativeGetTokenToReturn(nativeQuery)); |
| result.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, |
| decodeResult(nativeGetResult(nativeQuery))); |
| return result; |
| } |
| |
| /** |
| * @param nativeGetResult |
| * @return |
| */ |
| private int decodeResult(int gssApiResult) { |
| // This only handles the result values currently used in the tests. |
| switch (gssApiResult) { |
| case GSS_S_COMPLETE: |
| case GSS_S_CONTINUE_NEEDED: |
| return 0; |
| case GSS_S_FAILURE: |
| return HttpNegotiateConstants.ERR_MISSING_AUTH_CREDENTIALS; |
| default: |
| return HttpNegotiateConstants.ERR_UNEXPECTED; |
| } |
| } |
| |
| @Override |
| public String getAuthTokenLabel(String arg0) { |
| return "Spnego " + arg0; |
| } |
| |
| @Override |
| public Bundle hasFeatures(AccountAuthenticatorResponse arg0, Account arg1, String[] features) |
| throws NetworkErrorException { |
| Bundle result = new Bundle(); |
| for (String feature : features) { |
| if (!feature.equals(HttpNegotiateConstants.SPNEGO_FEATURE)) { |
| result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); |
| return result; |
| } |
| } |
| result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); |
| return result; |
| } |
| |
| @Override |
| public Bundle updateCredentials(AccountAuthenticatorResponse arg0, Account arg1, String arg2, |
| Bundle arg3) throws NetworkErrorException { |
| Bundle result = new Bundle(); |
| result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_REQUEST); |
| result.putString(AccountManager.KEY_ERROR_MESSAGE, "Can't add new SPNEGO accounts"); |
| return result; |
| } |
| |
| /** |
| * Called from tests, sets up the test account, if it doesn't already exist |
| */ |
| @CalledByNative |
| private static void ensureTestAccountExists() { |
| Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); |
| AccountManager am = AccountManager.get(activity); |
| Account account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE); |
| am.addAccountExplicitly(account, null, null); |
| } |
| |
| /** |
| * Called from tests to tidy up test accounts. |
| */ |
| @SuppressWarnings("deprecation") |
| @CalledByNative |
| private static void removeTestAccounts() { |
| Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); |
| AccountManager am = AccountManager.get(activity); |
| String features[] = {HttpNegotiateConstants.SPNEGO_FEATURE}; |
| try { |
| Account accounts[] = |
| am.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, features, null, null).getResult(); |
| for (Account account : accounts) { |
| // Deprecated, but the replacement not available on Android JB. |
| am.removeAccount(account, null, null).getResult(); |
| } |
| } catch (OperationCanceledException | AuthenticatorException | IOException e) { |
| // Should never happen. This is tidy-up after the tests. Ignore. |
| } |
| } |
| |
| @CalledByNative |
| private static void setNativeAuthenticator(long nativeDummySpnegoAuthenticator) { |
| sNativeDummySpnegoAuthenticator = nativeDummySpnegoAuthenticator; |
| } |
| |
| /** |
| * Send the relevant decoded arguments of getAuthToken to C++ for checking by googletest checks |
| * If the checks fail then the C++ unit test using this authenticator will fail. |
| * |
| * @param authTokenType |
| * @param spn |
| * @param incomingToken |
| */ |
| @NativeClassQualifiedName("DummySpnegoAuthenticator::SecurityContextQuery") |
| private native void nativeCheckGetTokenArguments(long nativeQuery, String incomingToken); |
| |
| @NativeClassQualifiedName("DummySpnegoAuthenticator::SecurityContextQuery") |
| private native String nativeGetTokenToReturn(long nativeQuery); |
| |
| @NativeClassQualifiedName("DummySpnegoAuthenticator::SecurityContextQuery") |
| private native int nativeGetResult(long nativeQuery); |
| |
| private native long nativeGetNextQuery(long nativeDummySpnegoAuthenticator); |
| } |