1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.accounts.cts; 18 19 import android.accounts.Account; 20 import android.accounts.AccountManager; 21 import android.accounts.AccountManagerFuture; 22 import android.accounts.AuthenticatorException; 23 import android.accounts.OperationCanceledException; 24 import android.accounts.cts.common.AuthenticatorContentProvider; 25 import android.accounts.cts.common.Fixtures; 26 import android.accounts.cts.common.tx.AddAccountTx; 27 import android.accounts.cts.common.tx.UpdateCredentialsTx; 28 import android.content.ContentProviderClient; 29 import android.content.ContentResolver; 30 import android.os.Bundle; 31 import android.os.RemoteException; 32 import android.platform.test.annotations.AppModeFull; 33 import android.test.AndroidTestCase; 34 35 import java.io.IOException; 36 37 /** 38 * Tests for AccountManager and AbstractAccountAuthenticator. This is to test 39 * default implementation of account session api in 40 * {@link android.accounts.AbstractAccountAuthenticator}. 41 * <p> 42 * You can run those unit tests with the following command line: 43 * <p> 44 * adb shell am instrument 45 * -e debug false -w 46 * -e class android.accounts.cts.AbstractAuthenticatorTests 47 * android.accounts.cts/androidx.test.runner.AndroidJUnitRunner 48 */ 49 public class AbstractAuthenticatorTests extends AndroidTestCase { 50 51 private AccountManager mAccountManager; 52 private ContentProviderClient mProviderClient; 53 54 @Override setUp()55 public void setUp() throws Exception { 56 // bind to the diagnostic service and set it up. 57 mAccountManager = AccountManager.get(getContext()); 58 ContentResolver resolver = getContext().getContentResolver(); 59 mProviderClient = resolver.acquireContentProviderClient( 60 AuthenticatorContentProvider.AUTHORITY); 61 } 62 tearDown()63 public void tearDown() throws RemoteException { 64 if (mProviderClient != null) { 65 // mProviderClient is null in case of instant test 66 mProviderClient.release(); 67 } 68 } 69 70 /** 71 * Tests startAddAccountSession default implementation. An encrypted session 72 * bundle should always be returned without password or status token. 73 */ testStartAddAccountSessionDefaultImpl()74 public void testStartAddAccountSessionDefaultImpl() 75 throws OperationCanceledException, AuthenticatorException, IOException { 76 Bundle options = new Bundle(); 77 String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE; 78 options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName); 79 80 AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession( 81 Fixtures.TYPE_DEFAULT, 82 null /* authTokenType */, 83 null /* requiredFeatures */, 84 options, 85 null /* activity */, 86 null /* callback */, 87 null /* handler */); 88 89 Bundle result = future.getResult(); 90 91 // Validate that auth token was stripped from result. 92 assertNull(result.get(AccountManager.KEY_AUTHTOKEN)); 93 94 // Validate that no password nor status token is returned in the result 95 // for default implementation. 96 validateNullPasswordAndStatusToken(result); 97 98 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 99 // Validate session bundle is returned but data in the bundle is 100 // encrypted and hence not visible. 101 assertNotNull(sessionBundle); 102 assertNull(sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE)); 103 } 104 105 106 /** 107 * Tests startUpdateCredentialsSession default implementation. An encrypted session 108 * bundle should always be returned without password or status token. 109 */ testStartUpdateCredentialsSessionDefaultImpl()110 public void testStartUpdateCredentialsSessionDefaultImpl() 111 throws OperationCanceledException, AuthenticatorException, IOException { 112 Bundle options = new Bundle(); 113 String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE; 114 options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName); 115 116 AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession( 117 Fixtures.ACCOUNT_DEFAULT, 118 null /* authTokenType */, 119 options, 120 null /* activity */, 121 null /* callback */, 122 null /* handler */); 123 124 Bundle result = future.getResult(); 125 assertTrue(future.isDone()); 126 assertNotNull(result); 127 128 // Validate no auth token in result. 129 assertNull(result.get(AccountManager.KEY_AUTHTOKEN)); 130 131 // Validate that no password nor status token is returned in the result 132 // for default implementation. 133 validateNullPasswordAndStatusToken(result); 134 135 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 136 // Validate session bundle is returned but data in the bundle is 137 // encrypted and hence not visible. 138 assertNotNull(sessionBundle); 139 assertNull(sessionBundle.getString(Fixtures.KEY_ACCOUNT_NAME)); 140 } 141 142 /** 143 * Tests finishSession default implementation with default startAddAccountSession. 144 * Only account name and account type should be returned as a bundle. 145 */ 146 @AppModeFull testFinishSessionAndStartAddAccountSessionDefaultImpl()147 public void testFinishSessionAndStartAddAccountSessionDefaultImpl() 148 throws OperationCanceledException, AuthenticatorException, IOException, 149 RemoteException { 150 Bundle options = new Bundle(); 151 String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE; 152 options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName); 153 154 // First obtain an encrypted session bundle from startAddAccountSession(...) default 155 // implementation. 156 AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession( 157 Fixtures.TYPE_DEFAULT, 158 null /* authTokenType */, 159 null /* requiredFeatures */, 160 options, 161 null /* activity */, 162 null /* callback */, 163 null /* handler */); 164 165 Bundle result = future.getResult(); 166 assertTrue(future.isDone()); 167 assertNotNull(result); 168 169 // Assert that result contains a non-null session bundle. 170 Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 171 assertNotNull(escrowBundle); 172 173 // Now call finishSession(...) with the session bundle we just obtained. 174 future = mAccountManager.finishSession( 175 escrowBundle, 176 null /* activity */, 177 null /* callback */, 178 null /* handler */); 179 180 result = future.getResult(); 181 assertTrue(future.isDone()); 182 assertNotNull(result); 183 184 // Validate that parameters are passed to addAccount(...) correctly in default finishSession 185 // implementation. 186 Bundle providerBundle = mProviderClient.call( 187 AuthenticatorContentProvider.METHOD_GET, 188 null /* arg */, 189 null /* extras */); 190 providerBundle.setClassLoader(AddAccountTx.class.getClassLoader()); 191 AddAccountTx addAccountTx = providerBundle 192 .getParcelable(AuthenticatorContentProvider.KEY_TX); 193 assertNotNull(addAccountTx); 194 195 // Assert parameters has been passed to addAccount(...) correctly 196 assertEquals(Fixtures.TYPE_DEFAULT, addAccountTx.accountType); 197 assertNull(addAccountTx.authTokenType); 198 199 validateSystemOptions(addAccountTx.options); 200 // Validate options 201 assertNotNull(addAccountTx.options); 202 assertEquals(accountName, addAccountTx.options.getString(Fixtures.KEY_ACCOUNT_NAME)); 203 // Validate features. 204 assertEquals(0, addAccountTx.requiredFeatures.size()); 205 206 // Assert returned result contains correct account name, account type and null auth token. 207 assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME)); 208 assertEquals(Fixtures.TYPE_DEFAULT, result.get(AccountManager.KEY_ACCOUNT_TYPE)); 209 assertNull(result.get(AccountManager.KEY_AUTHTOKEN)); 210 } 211 212 /** 213 * Tests finishSession default implementation with default startUpdateCredentialsSession. 214 * Only account name and account type should be returned as a bundle. 215 */ 216 @AppModeFull testFinishSessionAndStartUpdateCredentialsSessionDefaultImpl()217 public void testFinishSessionAndStartUpdateCredentialsSessionDefaultImpl() 218 throws OperationCanceledException, AuthenticatorException, IOException, 219 RemoteException { 220 Bundle options = new Bundle(); 221 String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE; 222 options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName); 223 224 // First obtain an encrypted session bundle from startUpdateCredentialsSession(...) default 225 // implementation. 226 AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession( 227 Fixtures.ACCOUNT_DEFAULT, 228 null /* authTokenTYpe */, 229 options, 230 null /* activity */, 231 null /* callback */, 232 null /* handler */); 233 234 Bundle result = future.getResult(); 235 assertTrue(future.isDone()); 236 assertNotNull(result); 237 238 // Assert that result contains a non-null session bundle. 239 Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 240 assertNotNull(escrowBundle); 241 242 // Now call finishSession(...) with the session bundle we just obtained. 243 future = mAccountManager.finishSession( 244 escrowBundle, 245 null /* activity */, 246 null /* callback */, 247 null /* handler */); 248 249 result = future.getResult(); 250 assertTrue(future.isDone()); 251 assertNotNull(result); 252 253 // Validate that parameters are passed to updateCredentials(...) correctly in default 254 // finishSession implementation. 255 Bundle providerBundle = mProviderClient.call( 256 AuthenticatorContentProvider.METHOD_GET, 257 null /* arg */, 258 null /* extras */); 259 providerBundle.setClassLoader(UpdateCredentialsTx.class.getClassLoader()); 260 UpdateCredentialsTx updateCredentialsTx = providerBundle 261 .getParcelable(AuthenticatorContentProvider.KEY_TX); 262 assertNotNull(updateCredentialsTx); 263 264 // Assert parameters has been passed to updateCredentials(...) correctly 265 assertEquals(Fixtures.ACCOUNT_DEFAULT, updateCredentialsTx.account); 266 assertNull(updateCredentialsTx.authTokenType); 267 268 validateSystemOptions(updateCredentialsTx.options); 269 // Validate options 270 assertNotNull(updateCredentialsTx.options); 271 assertEquals(accountName, updateCredentialsTx.options.getString(Fixtures.KEY_ACCOUNT_NAME)); 272 273 // Assert returned result contains correct account name, account type and null auth token. 274 assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME)); 275 assertEquals(Fixtures.TYPE_DEFAULT, result.get(AccountManager.KEY_ACCOUNT_TYPE)); 276 assertNull(result.get(AccountManager.KEY_AUTHTOKEN)); 277 } 278 validateSystemOptions(Bundle options)279 private void validateSystemOptions(Bundle options) { 280 assertNotNull(options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME)); 281 assertTrue(options.containsKey(AccountManager.KEY_CALLER_UID)); 282 assertTrue(options.containsKey(AccountManager.KEY_CALLER_PID)); 283 } 284 validateNullPasswordAndStatusToken(Bundle result)285 private void validateNullPasswordAndStatusToken(Bundle result) { 286 assertNull(result.getString(AccountManager.KEY_PASSWORD)); 287 assertNull(result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN)); 288 } 289 290 /** 291 * Tests isCredentialsUpdateSuggested default implementation. 292 * A bundle with boolean false should be returned. 293 */ testIsCredentialsUpdateSuggestedDefaultImpl()294 public void testIsCredentialsUpdateSuggestedDefaultImpl() 295 throws OperationCanceledException, AuthenticatorException, IOException, 296 RemoteException { 297 String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE; 298 Account account = new Account(accountName, Fixtures.TYPE_DEFAULT); 299 String statusToken = Fixtures.PREFIX_STATUS_TOKEN + accountName; 300 301 AccountManagerFuture<Boolean> future = mAccountManager.isCredentialsUpdateSuggested( 302 account, 303 statusToken, 304 null /* callback */, 305 null /* handler */); 306 307 assertFalse(future.getResult()); 308 assertTrue(future.isDone()); 309 } 310 } 311