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.server.wifi;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.mockito.Mockito.anyInt;
25 import static org.mockito.Mockito.lenient;
26 import static org.mockito.Mockito.when;
27 
28 import android.content.pm.UserInfo;
29 import android.net.wifi.ScanResult;
30 import android.net.wifi.WifiConfiguration;
31 import android.net.wifi.WifiManager;
32 import android.os.UserHandle;
33 import android.util.SparseArray;
34 
35 import androidx.test.filters.SmallTest;
36 
37 import com.android.server.wifi.util.WifiPermissionsUtil;
38 
39 import org.junit.After;
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.mockito.Mock;
43 import org.mockito.MockitoAnnotations;
44 import org.mockito.MockitoSession;
45 import org.mockito.stubbing.Answer;
46 
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collection;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Set;
53 
54 /**
55  * Unit tests for {@link com.android.server.wifi.ConfigurationMapTest}.
56  */
57 @SmallTest
58 public class ConfigurationMapTest extends WifiBaseTest {
59     private static final int SYSTEM_MANAGE_PROFILE_USER_ID = 12;
60     private static final String TEST_BSSID = "0a:08:5c:67:89:01";
61     private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
62             WifiConfigurationTestUtil.generateWifiConfig(
63                     0, 1000000, "\"red\"", true, true, null, null,
64                     WifiConfigurationTestUtil.SECURITY_NONE),
65             WifiConfigurationTestUtil.generateWifiConfig(
66                     1, 1000001, "\"green\"", true, false, "example.com", "Green",
67                     WifiConfigurationTestUtil.SECURITY_NONE),
68             WifiConfigurationTestUtil.generateWifiConfig(
69                     2, 1200000, "\"blue\"", false, true, null, null,
70                     WifiConfigurationTestUtil.SECURITY_NONE),
71             WifiConfigurationTestUtil.generateWifiConfig(
72                     3, 1100000, "\"cyan\"", true, true, null, null,
73                     WifiConfigurationTestUtil.SECURITY_NONE),
74             WifiConfigurationTestUtil.generateWifiConfig(
75                     4, 1100001, "\"yellow\"", true, true, "example.org", "Yellow",
76                     WifiConfigurationTestUtil.SECURITY_NONE),
77             WifiConfigurationTestUtil.generateWifiConfig(
78                     5, 1100002, "\"magenta\"", false, false, null, null,
79                     WifiConfigurationTestUtil.SECURITY_NONE));
80 
81     private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>();
82     static {
USER_PROFILES.put(UserHandle.USER_SYSTEM, Arrays.asList( new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0), new UserInfo(SYSTEM_MANAGE_PROFILE_USER_ID, "Managed Profile", 0)))83         USER_PROFILES.put(UserHandle.USER_SYSTEM, Arrays.asList(
84                 new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0),
85                 new UserInfo(SYSTEM_MANAGE_PROFILE_USER_ID, "Managed Profile", 0)));
86         USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0)));
87         USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0)));
88     }
89 
90     @Mock WifiPermissionsUtil mWifiPermissionsUtil;
91     @Mock WifiInjector mWifiInjector;
92     @Mock ActiveModeWarden mActiveModeWarden;
93     @Mock ClientModeManager mPrimaryClientModeManager;
94     @Mock WifiGlobals mWifiGlobals;
95     private MockitoSession mStaticMockSession = null;
96 
97     private int mCurrentUserId = UserHandle.USER_SYSTEM;
98     private ConfigurationMap mConfigs;
99 
100     /**
101      * Sets up the test harness before running a test.
102      */
103     @Before
setUp()104     public void setUp() {
105         MockitoAnnotations.initMocks(this);
106         mStaticMockSession = mockitoSession()
107                 .mockStatic(WifiInjector.class)
108                 .startMocking();
109         lenient().when(WifiInjector.getInstance()).thenReturn(mWifiInjector);
110         when(mWifiInjector.getActiveModeWarden()).thenReturn(mActiveModeWarden);
111         when(mWifiInjector.getWifiGlobals()).thenReturn(mWifiGlobals);
112         when(mActiveModeWarden.getPrimaryClientModeManager()).thenReturn(mPrimaryClientModeManager);
113         when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
114                 WifiManager.WIFI_FEATURE_WPA3_SAE | WifiManager.WIFI_FEATURE_OWE);
115         when(mWifiGlobals.isWpa3SaeUpgradeEnabled()).thenReturn(true);
116         when(mWifiGlobals.isOweUpgradeEnabled()).thenReturn(true);
117 
118         when(mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(anyInt()))
119                 .thenAnswer((Answer<Boolean>) invocation -> {
120                     Object[] args = invocation.getArguments();
121                     int userId = UserHandle.getUserId((int) args[0]);
122                     // Current userId matches input userId
123                     if (userId == mCurrentUserId) {
124                         return true;
125                     }
126                     // Current userId and input userId belong to the same profile group
127                     if (userId == UserHandle.USER_SYSTEM
128                             && mCurrentUserId == SYSTEM_MANAGE_PROFILE_USER_ID) {
129                         return true;
130                     }
131                     if (userId == SYSTEM_MANAGE_PROFILE_USER_ID
132                             && mCurrentUserId == UserHandle.USER_SYSTEM) {
133                         return true;
134                     }
135                     return false;
136                 });
137         mConfigs = new ConfigurationMap(mWifiPermissionsUtil);
138     }
139 
140     @After
cleanUp()141     public void cleanUp() throws Exception {
142         if (null != mStaticMockSession) {
143             mStaticMockSession.finishMocking();
144         }
145     }
146 
switchUser(int newUserId)147     private void switchUser(int newUserId) {
148         mCurrentUserId = newUserId;
149         mConfigs.setNewUser(newUserId);
150         mConfigs.clear();
151     }
152 
getEnabledNetworksForCurrentUser()153     private Collection<WifiConfiguration> getEnabledNetworksForCurrentUser() {
154         List<WifiConfiguration> list = new ArrayList<>();
155         for (WifiConfiguration config : mConfigs.valuesForCurrentUser()) {
156             if (config.status != WifiConfiguration.Status.DISABLED) {
157                 list.add(config);
158             }
159         }
160         return list;
161     }
162 
getEphemeralForCurrentUser(String ssid)163     private WifiConfiguration getEphemeralForCurrentUser(String ssid) {
164         for (WifiConfiguration config : mConfigs.valuesForCurrentUser()) {
165             if (ssid.equals(config.SSID) && config.ephemeral) {
166                 return config;
167             }
168         }
169         return null;
170     }
171 
addNetworks(List<WifiConfiguration> configs)172     private void addNetworks(List<WifiConfiguration> configs) {
173         for (WifiConfiguration config : configs) {
174             assertNull(mConfigs.put(config));
175         }
176     }
177 
verifyGetters(List<WifiConfiguration> configs)178     private void verifyGetters(List<WifiConfiguration> configs) {
179         final Set<WifiConfiguration> configsForCurrentUser = new HashSet<>();
180         final Set<WifiConfiguration> enabledConfigsForCurrentUser = new HashSet<>();
181         final List<WifiConfiguration> configsNotForCurrentUser = new ArrayList<>();
182 
183         // Find out which network configurations should be / should not be visible to the current
184         // user. Also, check that *ForAllUsers() methods can be used to access all network
185         // configurations, irrespective of their visibility to the current user.
186         for (WifiConfiguration config : configs) {
187             if (config.shared || mWifiPermissionsUtil
188                     .doesUidBelongToCurrentUserOrDeviceOwner(config.creatorUid)) {
189                 configsForCurrentUser.add(config);
190                 if (config.status != WifiConfiguration.Status.DISABLED) {
191                     enabledConfigsForCurrentUser.add(config);
192                 }
193             } else {
194                 configsNotForCurrentUser.add(config);
195             }
196 
197             assertEquals(config, mConfigs.getForAllUsers(config.networkId));
198         }
199 
200         // Verify that *ForCurrentUser() methods can be used to access network configurations
201         // visible to the current user.
202         for (WifiConfiguration config : configsForCurrentUser) {
203             assertEquals(config, mConfigs.getForCurrentUser(config.networkId));
204             assertEquals(config, mConfigs.getByConfigKeyForCurrentUser(
205                     config.getProfileKey()));
206             final boolean wasEphemeral = config.ephemeral;
207             config.ephemeral = false;
208             assertNull(getEphemeralForCurrentUser(config.SSID));
209             config.ephemeral = true;
210             assertEquals(config, getEphemeralForCurrentUser(config.SSID));
211             config.ephemeral = wasEphemeral;
212         }
213 
214         // Verify that *ForCurrentUser() methods cannot be used to access network configurations not
215         // visible to the current user.
216         for (WifiConfiguration config : configsNotForCurrentUser) {
217             assertNull(mConfigs.getForCurrentUser(config.networkId));
218             assertNull(mConfigs.getByConfigKeyForCurrentUser(config.getProfileKey()));
219             final boolean wasEphemeral = config.ephemeral;
220             config.ephemeral = false;
221             assertNull(getEphemeralForCurrentUser(config.SSID));
222             config.ephemeral = true;
223             assertNull(getEphemeralForCurrentUser(config.SSID));
224             config.ephemeral = wasEphemeral;
225         }
226 
227         // Verify that the methods which refer to more than one network configuration return the
228         // correct sets of networks.
229         assertEquals(configs.size(), mConfigs.sizeForAllUsers());
230         assertEquals(configsForCurrentUser.size(), mConfigs.sizeForCurrentUser());
231         assertEquals(enabledConfigsForCurrentUser,
232                 new HashSet<WifiConfiguration>(getEnabledNetworksForCurrentUser()));
233         assertEquals(new HashSet<>(configs),
234                 new HashSet<WifiConfiguration>(mConfigs.valuesForAllUsers()));
235     }
236 
createScanResultForNetwork(WifiConfiguration config)237     private ScanResult createScanResultForNetwork(WifiConfiguration config) {
238         return WifiConfigurationTestUtil.createScanDetailForNetwork(config, TEST_BSSID, 0, 0, 0, 0)
239                 .getScanResult();
240     }
241 
242     /**
243      * Helper function to create a scan result matching the network and ensuring that
244      * {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} can match that network.
245      */
verifyScanResultMatchWithNetwork(WifiConfiguration config)246     private void verifyScanResultMatchWithNetwork(WifiConfiguration config) {
247         mConfigs.put(config);
248         ScanResult scanResult = createScanResultForNetwork(config);
249         WifiConfiguration retrievedConfig =
250                 mConfigs.getByScanResultForCurrentUser(scanResult);
251         assertNotNull(retrievedConfig);
252         assertEquals(config.getProfileKey(), retrievedConfig.getProfileKey());
253     }
254 
255     /**
256      * Verifies that all getters return the correct network configurations, taking into account the
257      * current user. Also verifies that handleUserSwitch() returns the list of network
258      * configurations that are no longer visible.
259      */
260     @Test
testGettersAndHandleUserSwitch()261     public void testGettersAndHandleUserSwitch() {
262         addNetworks(CONFIGS);
263         verifyGetters(CONFIGS);
264 
265         switchUser(10);
266         addNetworks(CONFIGS);
267         verifyGetters(CONFIGS);
268 
269         switchUser(11);
270         addNetworks(CONFIGS);
271         verifyGetters(CONFIGS);
272     }
273 
274     /**
275      * Verifies put(), remove() and clear().
276      */
277     @Test
testPutRemoveClear()278     public void testPutRemoveClear() {
279         final List<WifiConfiguration> configs = new ArrayList<>();
280         final WifiConfiguration config1 = CONFIGS.get(0);
281 
282         // Verify that there are no network configurations to start with.
283         switchUser(UserHandle.getUserHandleForUid(config1.creatorUid).getIdentifier());
284         verifyGetters(configs);
285 
286         // Add |config1|.
287         assertNull(mConfigs.put(config1));
288         // Verify that the getters return |config1|.
289         configs.add(config1);
290         verifyGetters(configs);
291 
292         // Overwrite |config1| with |config2|.
293         final WifiConfiguration config2 = CONFIGS.get(1);
294         config2.networkId = config1.networkId;
295         assertEquals(config1, mConfigs.put(config2));
296         // Verify that the getters return |config2| only.
297         configs.clear();
298         configs.add(config2);
299         verifyGetters(configs);
300 
301         // Add |config3|, which belongs to a managed profile of the current user.
302         final WifiConfiguration config3 = CONFIGS.get(2);
303         assertNull(mConfigs.put(config3));
304         // Verify that the getters return |config2| and |config3|.
305         configs.add(config3);
306         verifyGetters(configs);
307 
308         // Remove |config2|.
309         assertEquals(config2, mConfigs.remove(config2.networkId));
310         // Verify that the getters return |config3| only.
311         configs.remove(config2);
312         verifyGetters(configs);
313 
314         // Clear all network configurations.
315         mConfigs.clear();
316         // Verify that the getters do not return any network configurations.
317         configs.clear();
318         verifyGetters(configs);
319     }
320 
321     /**
322      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} can
323      * positively match the corresponding networks.
324      */
325     @Test
testScanResultDoesMatchCorrespondingNetworks()326     public void testScanResultDoesMatchCorrespondingNetworks() {
327         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createOpenNetwork());
328         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createPskNetwork());
329         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createWepNetwork());
330         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createEapNetwork());
331     }
332 
333     /**
334      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} does not
335      * match other networks.
336      */
337     @Test
testScanResultDoesNotMatchWithOtherNetworks()338     public void testScanResultDoesNotMatchWithOtherNetworks() {
339         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
340         ScanResult scanResult = createScanResultForNetwork(config);
341         // Change the network security type and the old scan result should not match now.
342         config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
343         mConfigs.put(config);
344         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
345     }
346 
347     /**
348      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} does not
349      * match networks which have been removed.
350      */
351     @Test
testScanResultDoesNotMatchAfterNetworkRemove()352     public void testScanResultDoesNotMatchAfterNetworkRemove() {
353         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
354         ScanResult scanResult = createScanResultForNetwork(config);
355         config.networkId = 5;
356         mConfigs.put(config);
357         // Create another network in the map.
358         mConfigs.put(WifiConfigurationTestUtil.createPskNetwork());
359         assertNotNull(mConfigs.getByScanResultForCurrentUser(scanResult));
360 
361         mConfigs.remove(config.networkId);
362         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
363     }
364 
365     /**
366      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} does not
367      * match networks after clear.
368      */
369     @Test
testScanResultDoesNotMatchAfterClear()370     public void testScanResultDoesNotMatchAfterClear() {
371         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
372         ScanResult scanResult = createScanResultForNetwork(config);
373         config.networkId = 5;
374         mConfigs.put(config);
375         // Create another network in the map.
376         mConfigs.put(WifiConfigurationTestUtil.createPskNetwork());
377         assertNotNull(mConfigs.getByScanResultForCurrentUser(scanResult));
378 
379         mConfigs.clear();
380         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
381     }
382 
383     @Test
testScanResultDoesNotMatchForWifiNetworkSpecifier()384     public void testScanResultDoesNotMatchForWifiNetworkSpecifier() {
385         // Add regular saved network, this should create a scan result match info cache entry.
386         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
387         ScanResult scanResult = createScanResultForNetwork(config);
388         config.networkId = 5;
389         mConfigs.put(config);
390         assertNotNull(mConfigs.getByScanResultForCurrentUser(scanResult));
391 
392         mConfigs.clear();
393 
394         // Create WifiNetworkSpecifier network, this should not create a scan result match info
395         // cache entry.
396         config.ephemeral = true;
397         config.fromWifiNetworkSpecifier = true;
398         mConfigs.put(config);
399         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
400     }
401 
402     @Test
testScanResultDoesNotMatchForWifiNetworkSuggestion()403     public void testScanResultDoesNotMatchForWifiNetworkSuggestion() {
404         // Add regular saved network, this should create a scan result match info cache entry.
405         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
406         ScanResult scanResult = createScanResultForNetwork(config);
407         config.networkId = 5;
408         mConfigs.put(config);
409         assertNotNull(mConfigs.getByScanResultForCurrentUser(scanResult));
410 
411         mConfigs.clear();
412 
413         // Create WifiNetworkSuggestion network, this should not create a scan result match info
414         // cache entry.
415         config.ephemeral = true;
416         config.fromWifiNetworkSuggestion = true;
417         mConfigs.put(config);
418         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
419     }
420 
421     @Test
testScanResultDoesNotMatchForPasspoint()422     public void testScanResultDoesNotMatchForPasspoint() {
423         // Add passpoint network, this should not create a scan result match info cache entry.
424         WifiConfiguration config = WifiConfigurationTestUtil.createPasspointNetwork();
425         ScanResult scanResult = createScanResultForNetwork(config);
426         config.networkId = 5;
427         mConfigs.put(config);
428         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
429     }
430 }
431