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