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