• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.net.test;
6 
7 import android.accounts.AbstractAccountAuthenticator;
8 import android.accounts.Account;
9 import android.accounts.AccountAuthenticatorResponse;
10 import android.accounts.AccountManager;
11 import android.accounts.AuthenticatorException;
12 import android.accounts.OperationCanceledException;
13 import android.app.Activity;
14 import android.content.Context;
15 import android.os.Bundle;
16 
17 import org.jni_zero.CalledByNative;
18 import org.jni_zero.JNINamespace;
19 import org.jni_zero.NativeClassQualifiedName;
20 import org.jni_zero.NativeMethods;
21 
22 import org.chromium.base.ApplicationStatus;
23 import org.chromium.net.HttpNegotiateConstants;
24 
25 import java.io.IOException;
26 
27 /**
28  * Dummy Android authenticator, to test SPNEGO/Keberos support on Android. This is deliberately
29  * minimal, and is not intended as an example of how to write a real SPNEGO Authenticator.
30  */
31 @JNINamespace("net::android")
32 public class DummySpnegoAuthenticator extends AbstractAccountAuthenticator {
33     private static final String ACCOUNT_TYPE = "org.chromium.test.DummySpnegoAuthenticator";
34     private static final String ACCOUNT_NAME = "DummySpnegoAccount";
35     private static int sResult;
36     private static String sToken;
37     private static boolean sCheckArguments;
38     private static long sNativeDummySpnegoAuthenticator;
39     private static final int GSS_S_COMPLETE = 0;
40     private static final int GSS_S_CONTINUE_NEEDED = 1;
41     private static final int GSS_S_FAILURE = 2;
42 
43     /**
44      * @param context
45      */
DummySpnegoAuthenticator(Context context)46     public DummySpnegoAuthenticator(Context context) {
47         super(context);
48     }
49 
50     @Override
addAccount( AccountAuthenticatorResponse arg0, String accountType, String arg2, String[] arg3, Bundle arg4)51     public Bundle addAccount(
52             AccountAuthenticatorResponse arg0,
53             String accountType,
54             String arg2,
55             String[] arg3,
56             Bundle arg4) {
57         Bundle result = new Bundle();
58         result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_REQUEST);
59         result.putString(AccountManager.KEY_ERROR_MESSAGE, "Can't add new SPNEGO accounts");
60         return result;
61     }
62 
63     @Override
confirmCredentials(AccountAuthenticatorResponse arg0, Account arg1, Bundle arg2)64     public Bundle confirmCredentials(AccountAuthenticatorResponse arg0, Account arg1, Bundle arg2) {
65         Bundle result = new Bundle();
66         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
67         return result;
68     }
69 
70     @Override
editProperties(AccountAuthenticatorResponse arg0, String arg1)71     public Bundle editProperties(AccountAuthenticatorResponse arg0, String arg1) {
72         return new Bundle();
73     }
74 
75     @Override
getAuthToken( AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)76     public Bundle getAuthToken(
77             AccountAuthenticatorResponse response,
78             Account account,
79             String authTokenType,
80             Bundle options) {
81         long nativeQuery =
82                 DummySpnegoAuthenticatorJni.get().getNextQuery(sNativeDummySpnegoAuthenticator);
83         String incomingToken = options.getString(HttpNegotiateConstants.KEY_INCOMING_AUTH_TOKEN);
84         DummySpnegoAuthenticatorJni.get().checkGetTokenArguments(nativeQuery, incomingToken);
85         Bundle result = new Bundle();
86         result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
87         result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
88         result.putString(
89                 AccountManager.KEY_AUTHTOKEN,
90                 DummySpnegoAuthenticatorJni.get().getTokenToReturn(nativeQuery));
91         result.putInt(
92                 HttpNegotiateConstants.KEY_SPNEGO_RESULT,
93                 decodeResult(DummySpnegoAuthenticatorJni.get().getResult(nativeQuery)));
94         return result;
95     }
96 
97     /**
98      * @param DummySpnegoAuthenticatorJni.get().getResult
99      * @return
100      */
decodeResult(int gssApiResult)101     private int decodeResult(int gssApiResult) {
102         // This only handles the result values currently used in the tests.
103         switch (gssApiResult) {
104             case GSS_S_COMPLETE:
105             case GSS_S_CONTINUE_NEEDED:
106                 return 0;
107             case GSS_S_FAILURE:
108                 return HttpNegotiateConstants.ERR_MISSING_AUTH_CREDENTIALS;
109             default:
110                 return HttpNegotiateConstants.ERR_UNEXPECTED;
111         }
112     }
113 
114     @Override
getAuthTokenLabel(String arg0)115     public String getAuthTokenLabel(String arg0) {
116         return "Spnego " + arg0;
117     }
118 
119     @Override
hasFeatures(AccountAuthenticatorResponse arg0, Account arg1, String[] features)120     public Bundle hasFeatures(AccountAuthenticatorResponse arg0, Account arg1, String[] features) {
121         Bundle result = new Bundle();
122         for (String feature : features) {
123             if (!feature.equals(HttpNegotiateConstants.SPNEGO_FEATURE)) {
124                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
125                 return result;
126             }
127         }
128         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
129         return result;
130     }
131 
132     @Override
updateCredentials( AccountAuthenticatorResponse arg0, Account arg1, String arg2, Bundle arg3)133     public Bundle updateCredentials(
134             AccountAuthenticatorResponse arg0, Account arg1, String arg2, Bundle arg3) {
135         Bundle result = new Bundle();
136         result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_REQUEST);
137         result.putString(AccountManager.KEY_ERROR_MESSAGE, "Can't add new SPNEGO accounts");
138         return result;
139     }
140 
141     /** Called from tests, sets up the test account, if it doesn't already exist */
142     @CalledByNative
ensureTestAccountExists()143     private static void ensureTestAccountExists() {
144         Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
145         AccountManager am = AccountManager.get(activity);
146         Account account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
147         am.addAccountExplicitly(account, null, null);
148     }
149 
150     /** Called from tests to tidy up test accounts. */
151     @SuppressWarnings("deprecation")
152     @CalledByNative
removeTestAccounts()153     private static void removeTestAccounts() {
154         Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
155         AccountManager am = AccountManager.get(activity);
156         String features[] = {HttpNegotiateConstants.SPNEGO_FEATURE};
157         try {
158             Account accounts[] =
159                     am.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, features, null, null).getResult();
160             for (Account account : accounts) {
161                 // Deprecated, but the replacement not available on Android JB.
162                 am.removeAccount(account, null, null).getResult();
163             }
164         } catch (OperationCanceledException | AuthenticatorException | IOException e) {
165             // Should never happen. This is tidy-up after the tests. Ignore.
166         }
167     }
168 
169     @CalledByNative
setNativeAuthenticator(long nativeDummySpnegoAuthenticator)170     private static void setNativeAuthenticator(long nativeDummySpnegoAuthenticator) {
171         sNativeDummySpnegoAuthenticator = nativeDummySpnegoAuthenticator;
172     }
173 
174     @NativeMethods
175     interface Natives {
176         /**
177          * Send the relevant decoded arguments of getAuthToken to C++ for checking by googletest
178          * checks If the checks fail then the C++ unit test using this authenticator will fail.
179          *
180          * @param authTokenType
181          * @param spn
182          * @param incomingToken
183          */
184         @NativeClassQualifiedName("DummySpnegoAuthenticator::SecurityContextQuery")
checkGetTokenArguments(long nativeQuery, String incomingToken)185         void checkGetTokenArguments(long nativeQuery, String incomingToken);
186 
187         @NativeClassQualifiedName("DummySpnegoAuthenticator::SecurityContextQuery")
getTokenToReturn(long nativeQuery)188         String getTokenToReturn(long nativeQuery);
189 
190         @NativeClassQualifiedName("DummySpnegoAuthenticator::SecurityContextQuery")
getResult(long nativeQuery)191         int getResult(long nativeQuery);
192 
getNextQuery(long nativeDummySpnegoAuthenticator)193         long getNextQuery(long nativeDummySpnegoAuthenticator);
194     }
195 }
196