Home | History | Annotate | Download | only in cts
      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
     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 
     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      */
     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      */
    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
    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
    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 
    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 
    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      */
    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