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 com.android.systemui.statusbar.policy;
18 
19 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
20 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.mockito.Matchers.any;
26 import static org.mockito.Matchers.anyInt;
27 import static org.mockito.Matchers.anyObject;
28 import static org.mockito.Matchers.argThat;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.times;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.admin.DevicePolicyManager;
35 import android.content.BroadcastReceiver;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.StringParceledListSlice;
40 import android.content.pm.UserInfo;
41 import android.net.ConnectivityManager;
42 import android.net.ConnectivityManager.NetworkCallback;
43 import android.net.NetworkRequest;
44 import android.os.Handler;
45 import android.os.UserManager;
46 import android.security.IKeyChainService;
47 
48 import androidx.test.filters.SmallTest;
49 import androidx.test.runner.AndroidJUnit4;
50 
51 import com.android.systemui.SysuiTestCase;
52 import com.android.systemui.broadcast.BroadcastDispatcher;
53 import com.android.systemui.dump.DumpManager;
54 import com.android.systemui.settings.UserTracker;
55 import com.android.systemui.util.concurrency.FakeExecutor;
56 import com.android.systemui.util.time.FakeSystemClock;
57 
58 import org.junit.Before;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 import org.mockito.ArgumentCaptor;
62 import org.mockito.Mockito;
63 
64 import java.util.ArrayList;
65 import java.util.Arrays;
66 import java.util.List;
67 import java.util.concurrent.atomic.AtomicBoolean;
68 
69 @SmallTest
70 @RunWith(AndroidJUnit4.class)
71 public class SecurityControllerTest extends SysuiTestCase {
72     private static final ComponentName DEVICE_OWNER_COMPONENT =
73             new ComponentName("com.android.foo", "bar");
74 
75     private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
76     private final IKeyChainService.Stub mKeyChainService = mock(IKeyChainService.Stub.class);
77     private final UserManager mUserManager = mock(UserManager.class);
78     private final UserTracker mUserTracker = mock(UserTracker.class);
79     private final BroadcastDispatcher mBroadcastDispatcher = mock(BroadcastDispatcher.class);
80     private final Handler mHandler = mock(Handler.class);
81     private SecurityControllerImpl mSecurityController;
82     private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class);
83     private FakeExecutor mMainExecutor;
84     private FakeExecutor mBgExecutor;
85     private BroadcastReceiver mBroadcastReceiver;
86 
87     @Before
setUp()88     public void setUp() throws Exception {
89         mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
90         mContext.addMockSystemService(Context.USER_SERVICE, mUserManager);
91         mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mConnectivityManager);
92 
93         Intent intent = new Intent(IKeyChainService.class.getName());
94         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
95         mContext.addMockService(comp, mKeyChainService);
96 
97         when(mUserManager.getUserInfo(anyInt())).thenReturn(new UserInfo());
98         when(mUserManager.isUserUnlocked(any())).thenReturn(true);
99 
100         when(mKeyChainService.getUserCaAliases())
101                 .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
102         // Without this line, mKeyChainService gets wrapped in a proxy when Stub.asInterface() is
103         // used on it, and the mocking above does not work.
104         when(mKeyChainService.queryLocalInterface("android.security.IKeyChainService"))
105                 .thenReturn(mKeyChainService);
106 
107         ArgumentCaptor<BroadcastReceiver> brCaptor =
108                 ArgumentCaptor.forClass(BroadcastReceiver.class);
109 
110         mMainExecutor = new FakeExecutor(new FakeSystemClock());
111         mBgExecutor = new FakeExecutor(new FakeSystemClock());
112         mSecurityController = new SecurityControllerImpl(
113                 mContext,
114                 mUserTracker,
115                 mHandler,
116                 mBroadcastDispatcher,
117                 mMainExecutor,
118                 mBgExecutor,
119                 Mockito.mock(DumpManager.class));
120 
121         verify(mBroadcastDispatcher).registerReceiverWithHandler(
122                 brCaptor.capture(),
123                 anyObject(),
124                 anyObject(),
125                 anyObject());
126 
127         mBroadcastReceiver = brCaptor.getValue();
128     }
129 
130     @Test
testIsDeviceManaged()131     public void testIsDeviceManaged() {
132         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
133         assertTrue(mSecurityController.isDeviceManaged());
134 
135         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
136         assertFalse(mSecurityController.isDeviceManaged());
137     }
138 
139     @Test
testGetDeviceOwnerOrganizationName()140     public void testGetDeviceOwnerOrganizationName() {
141         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn("organization");
142         assertEquals("organization", mSecurityController.getDeviceOwnerOrganizationName());
143     }
144 
145     @Test
testGetDeviceOwnerComponentOnAnyUser()146     public void testGetDeviceOwnerComponentOnAnyUser() {
147         when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
148                 .thenReturn(DEVICE_OWNER_COMPONENT);
149         assertEquals(mSecurityController.getDeviceOwnerComponentOnAnyUser(),
150                 DEVICE_OWNER_COMPONENT);
151     }
152 
153     @Test
testIsFinancedDevice()154     public void testIsFinancedDevice() {
155         when(mDevicePolicyManager.isFinancedDevice()).thenReturn(true);
156         // TODO(b/259908270): remove
157         when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
158                 .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
159         assertEquals(mSecurityController.isFinancedDevice(), true);
160     }
161 
162     @Test
testWorkAccount()163     public void testWorkAccount() throws Exception {
164         assertFalse(mSecurityController.hasCACertInCurrentUser());
165 
166         final int PRIMARY_USER_ID = 0;
167         final int MANAGED_USER_ID = 1;
168         List<UserInfo> profiles = Arrays.asList(new UserInfo(PRIMARY_USER_ID, "Primary",
169                                                              UserInfo.FLAG_PRIMARY),
170                                                 new UserInfo(MANAGED_USER_ID, "Working",
171                                                              UserInfo.FLAG_MANAGED_PROFILE));
172         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
173         assertTrue(mSecurityController.hasWorkProfile());
174         assertFalse(mSecurityController.hasCACertInWorkProfile());
175 
176         when(mKeyChainService.getUserCaAliases())
177                 .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias")));
178 
179         refreshCACerts(MANAGED_USER_ID);
180         mBgExecutor.runAllReady();
181 
182         assertTrue(mSecurityController.hasCACertInWorkProfile());
183     }
184 
185     @Test
testCaCertLoader()186     public void testCaCertLoader() throws Exception {
187         assertFalse(mSecurityController.hasCACertInCurrentUser());
188 
189         // With a CA cert
190         when(mKeyChainService.getUserCaAliases())
191                 .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias")));
192 
193         refreshCACerts(0);
194         mBgExecutor.runAllReady();
195 
196         assertTrue(mSecurityController.hasCACertInCurrentUser());
197 
198         // Exception
199         when(mKeyChainService.getUserCaAliases())
200                 .thenThrow(new AssertionError("Test AssertionError"))
201                 .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
202 
203         refreshCACerts(0);
204         mBgExecutor.runAllReady();
205 
206         assertTrue(mSecurityController.hasCACertInCurrentUser());
207 
208         refreshCACerts(0);
209         mBgExecutor.runAllReady();
210 
211         assertFalse(mSecurityController.hasCACertInCurrentUser());
212     }
213 
214     @Test
testNetworkRequest()215     public void testNetworkRequest() {
216         verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat(
217                 (NetworkRequest request) ->
218                         request.equals(new NetworkRequest.Builder()
219                                 .clearCapabilities().addTransportType(TRANSPORT_VPN).build())
220                 ), any(NetworkCallback.class));
221     }
222 
223     @Test
testRemoveCallbackWhileDispatch_doesntCrash()224     public void testRemoveCallbackWhileDispatch_doesntCrash() {
225         final AtomicBoolean remove = new AtomicBoolean(false);
226         SecurityController.SecurityControllerCallback callback =
227                 new SecurityController.SecurityControllerCallback() {
228                     @Override
229                     public void onStateChanged() {
230                         if (remove.get()) {
231                             mSecurityController.removeCallback(this);
232                         }
233                     }
234                 };
235         mSecurityController.addCallback(callback);
236         // Add another callback so the iteration continues
237         mSecurityController.addCallback(() -> {});
238         mBgExecutor.runAllReady();
239         remove.set(true);
240 
241         mSecurityController.onUserSwitched(10);
242         mBgExecutor.runAllReady();
243     }
244 
245     /**
246      * refresh CA certs by sending a user unlocked broadcast for the desired user
247      */
refreshCACerts(int userId)248     private void refreshCACerts(int userId) {
249         Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
250         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
251         mBroadcastReceiver.onReceive(mContext, intent);
252     }
253 }
254