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
17package com.android.server.wifi.util;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertTrue;
22import static org.junit.Assert.fail;
23import static org.mockito.Matchers.anyInt;
24import static org.mockito.Matchers.anyString;
25import static org.mockito.Mockito.doAnswer;
26import static org.mockito.Mockito.doThrow;
27import static org.mockito.Mockito.when;
28
29import android.Manifest;
30import android.app.AppOpsManager;
31import android.content.ComponentName;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.pm.ApplicationInfo;
35import android.content.pm.PackageManager;
36import android.content.pm.UserInfo;
37import android.net.NetworkScoreManager;
38import android.net.NetworkScorerAppData;
39import android.net.wifi.WifiConfiguration;
40import android.os.Build;
41import android.os.RemoteException;
42import android.os.UserHandle;
43import android.os.UserManager;
44import android.provider.Settings;
45
46import com.android.server.wifi.BinderUtil;
47import com.android.server.wifi.FakeWifiLog;
48import com.android.server.wifi.FrameworkFacade;
49import com.android.server.wifi.WifiInjector;
50import com.android.server.wifi.WifiSettingsStore;
51
52import org.junit.Before;
53import org.junit.Test;
54import org.junit.runner.RunWith;
55import org.junit.runners.JUnit4;
56import org.mockito.Mock;
57import org.mockito.MockitoAnnotations;
58import org.mockito.Spy;
59import org.mockito.invocation.InvocationOnMock;
60import org.mockito.stubbing.Answer;
61
62import java.util.Arrays;
63import java.util.HashMap;
64
65/** Unit tests for {@link WifiPermissionsUtil}. */
66@RunWith(JUnit4.class)
67public class WifiPermissionsUtilTest {
68    public static final String TAG = "WifiPermissionsUtilTest";
69
70    // Mock objects for testing
71    @Mock private WifiPermissionsWrapper mMockPermissionsWrapper;
72    @Mock private Context mMockContext;
73    @Mock private PackageManager mMockPkgMgr;
74    @Mock private ApplicationInfo mMockApplInfo;
75    @Mock private AppOpsManager mMockAppOps;
76    @Mock private UserInfo mMockUserInfo;
77    @Mock private UserManager mMockUserManager;
78    @Mock private WifiSettingsStore mMockWifiSettingsStore;
79    @Mock private ContentResolver mMockContentResolver;
80    @Mock private NetworkScoreManager mMockNetworkScoreManager;
81    @Mock private WifiInjector mMockWifiInjector;
82    @Mock private FrameworkFacade mMockFrameworkFacade;
83    @Mock private WifiConfiguration mMockWifiConfig;
84    @Spy private FakeWifiLog mWifiLog;
85
86    private static final String TEST_PACKAGE_NAME = "com.google.somePackage";
87    private static final String INVALID_PACKAGE  = "BAD_PACKAGE";
88    private static final int MANAGED_PROFILE_UID = 1100000;
89    private static final int OTHER_USER_UID = 1200000;
90
91    private final int mCallingUser = UserHandle.USER_CURRENT_OR_SELF;
92    private final String mMacAddressPermission = "android.permission.PEERS_MAC_ADDRESS";
93    private final String mInteractAcrossUsersFullPermission =
94            "android.permission.INTERACT_ACROSS_USERS_FULL";
95    private final String mManifestStringCoarse =
96            Manifest.permission.ACCESS_COARSE_LOCATION;
97
98    // Test variables
99    private int mWifiScanAllowApps;
100    private int mUid;
101    private int mCoarseLocationPermission;
102    private int mAllowCoarseLocationApps;
103    private String mPkgNameOfTopActivity;
104    private int mCurrentUser;
105    private int mLocationModeSetting;
106    private boolean mThrowSecurityException;
107    private int mTargetVersion;
108    private boolean mActiveNwScorer;
109    private Answer<Integer> mReturnPermission;
110    private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
111    private String mUseOpenWifiPackage;
112    private NetworkScorerAppData mNetworkScorerAppData;
113    private boolean mGetActiveScorerThrowsSecurityException;
114    private boolean mConfigIsOpen;
115
116    /**
117    * Set up Mockito tests
118    */
119    @Before
120    public void setUp() {
121        MockitoAnnotations.initMocks(this);
122        initTestVars();
123    }
124
125    private void setupTestCase() throws Exception {
126        setupMocks();
127        setupMockInterface();
128    }
129
130    /**
131     * Verify we return true when the UID does have the override config permission
132     */
133    @Test
134    public void testCheckConfigOverridePermissionApproved() throws Exception {
135        mUid = MANAGED_PROFILE_UID;  // do not really care about this value
136        setupTestCase();
137        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
138                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
139                mMockWifiInjector);
140        when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
141                .thenReturn(PackageManager.PERMISSION_GRANTED);
142        assertTrue(codeUnderTest.checkConfigOverridePermission(mUid));
143    }
144
145    /**
146     * Verify we return false when the UID does not have the override config permission.
147     */
148    @Test
149    public void testCheckConfigOverridePermissionDenied() throws Exception {
150        mUid = OTHER_USER_UID;  // do not really care about this value
151        setupTestCase();
152        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
153                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
154                mMockWifiInjector);
155        when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
156                .thenReturn(PackageManager.PERMISSION_DENIED);
157        assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
158    }
159
160    /**
161     * Verify we return false when the override config permission check throws a RemoteException.
162     */
163    @Test
164    public void testCheckConfigOverridePermissionWithException() throws Exception {
165        mUid = OTHER_USER_UID;  // do not really care about this value
166        setupTestCase();
167        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
168                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
169                mMockWifiInjector);
170        doThrow(new RemoteException("Failed to check permissions for " + mUid))
171                .when(mMockPermissionsWrapper).getOverrideWifiConfigPermission(mUid);
172        assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
173    }
174
175    /**
176     * Test case setting: Package is valid
177     *                    Caller can read peers mac address
178     *                    This App has permission to request WIFI_SCAN
179     *                    User is current
180     * Validate result is true
181     * - User has all the permissions
182     */
183    @Test
184    public void testCanReadPeersMacAddressCurrentUserAndAllPermissions() throws Exception {
185        boolean output = false;
186        mThrowSecurityException = false;
187        mUid = MANAGED_PROFILE_UID;
188        mPermissionsList.put(mMacAddressPermission, mUid);
189        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
190        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
191        setupTestCase();
192        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
193                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
194                mMockWifiInjector);
195        try {
196            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
197        } catch (SecurityException e) {
198            throw e;
199        }
200        assertEquals(output, true);
201    }
202
203    /**
204     * Test case setting: Package is valid
205     *                    Caller can read peers mac address
206     *                    This App has permission to request WIFI_SCAN
207     *                    User profile is current
208     * Validate result is true
209     * - User has all the permissions
210     */
211    @Test
212    public void testCanReadPeersMacAddressCurrentProfileAndAllPermissions() throws Exception {
213        boolean output = false;
214        mThrowSecurityException = false;
215        mUid = MANAGED_PROFILE_UID;
216        mPermissionsList.put(mMacAddressPermission, mUid);
217        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
218        mMockUserInfo.id = mCallingUser;
219        setupTestCase();
220        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
221                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
222                mMockWifiInjector);
223        try {
224            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
225        } catch (SecurityException e) {
226            throw e;
227        }
228        assertEquals(output, true);
229    }
230
231    /**
232     * Test case setting: Package is valid
233     *                    Caller can read peers mac address
234     * Validate result is false
235     * - This App doesn't have permission to request Wifi Scan
236     */
237    @Test
238    public void testCannotAccessScanResult_AppNotAllowed() throws Exception {
239        boolean output = true;
240        mThrowSecurityException = false;
241        mPermissionsList.put(mMacAddressPermission, mUid);
242        setupTestCase();
243        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
244                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
245                mMockWifiInjector);
246        try {
247            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
248        } catch (SecurityException e) {
249            throw e;
250        }
251        assertEquals(output, false);
252    }
253
254    /**
255     * Test case setting: Package is valid
256     *                    Caller can read peers mac address
257     *                    This App has permission to request WIFI_SCAN
258     *                    User or profile is not current but the uid has
259     *                    permission to INTERACT_ACROSS_USERS_FULL
260     * Validate result is true
261     * - User has all the permissions
262     */
263    @Test
264    public void testCanAccessScanResults_UserOrProfileNotCurrent() throws Exception {
265        boolean output = false;
266        mThrowSecurityException = false;
267        mUid = MANAGED_PROFILE_UID;
268        mPermissionsList.put(mMacAddressPermission, mUid);
269        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
270        mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
271        setupTestCase();
272        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
273                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
274                mMockWifiInjector);
275        try {
276            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
277        } catch (SecurityException e) {
278            throw e;
279        }
280        assertEquals(output, true);
281    }
282
283    /**
284     * Test case setting: Package is valid
285     *                    Caller can read peers mac address
286     *                    This App has permission to request WIFI_SCAN
287     *                    User or profile is not Current
288     * Validate result is false
289     * - Calling uid doesn't have INTERACT_ACROSS_USERS_FULL permission
290     */
291    @Test
292    public void testCannotAccessScanResults_NoInteractAcrossUsersFullPermission() throws Exception {
293        boolean output = true;
294        mThrowSecurityException = false;
295        mUid = MANAGED_PROFILE_UID;
296        mPermissionsList.put(mMacAddressPermission, mUid);
297        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
298        setupTestCase();
299        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
300                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
301                mMockWifiInjector);
302        try {
303            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
304        } catch (SecurityException e) {
305            throw e;
306        }
307        assertEquals(output, false);
308    }
309
310    /**
311     * Test case setting: Package is valid
312     *                    Caller is active network scorer
313     *                    This App has permission to request WIFI_SCAN
314     *                    User is current
315     * Validate result is true
316     */
317    @Test
318    public void testCanAccessScanResults_CallerIsActiveNwScorer() throws Exception {
319        boolean output = false;
320        mThrowSecurityException = false;
321        mActiveNwScorer = true;
322        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
323        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
324        setupTestCase();
325        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
326                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
327                mMockWifiInjector);
328        try {
329            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
330        } catch (SecurityException e) {
331            throw e;
332        }
333        assertEquals(output, true);
334    }
335
336    /**
337     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
338     *                    User is current
339     *                    The current config is for an open network.
340     * Validate result is true
341     */
342    @Test
343    public void testCanAccessFullConnectionInfo_PackageIsUseOpenWifiPackage() throws Exception {
344        final boolean output;
345        mThrowSecurityException = false;
346        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
347        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
348        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
349        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
350                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
351                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
352        setupTestCase();
353        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
354                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
355                mMockWifiInjector);
356
357        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
358                mUid, mTargetVersion);
359
360        assertEquals(true, output);
361    }
362
363    /**
364     * Test case setting: Package is valid because the caller has access to scan results.
365     *                    Location mode is ON
366     *                    User is current
367     *                    The current config is not for an open network.
368     * Validate result is true
369     */
370    @Test
371    public void testCanAccessFullConnectionInfo_HasAccessToScanResults() throws Exception {
372        final boolean output;
373        mThrowSecurityException = false;
374        mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
375        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
376        mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
377        mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
378        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
379        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
380        mConfigIsOpen = false;
381
382        setupTestCase();
383        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
384                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
385                mMockWifiInjector);
386
387        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
388                mUid, mTargetVersion);
389
390        assertEquals(true, output);
391    }
392
393    /**
394     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
395     *                    User or profile is not current but the uid has
396     *                    permission to INTERACT_ACROSS_USERS_FULL
397     *                    The current config is for an open network.
398     * Validate result is true
399     */
400    @Test
401    public void testCanAccessFullConnectionInfo_UserNotCurrentButHasInteractAcrossUsers()
402            throws Exception {
403        final boolean output;
404        mThrowSecurityException = false;
405        mUid = MANAGED_PROFILE_UID;
406        mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
407        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
408        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
409        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
410                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
411                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
412        setupTestCase();
413        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
414                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
415                mMockWifiInjector);
416
417        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
418                mUid, mTargetVersion);
419
420        assertEquals(true, output);
421    }
422
423    /**
424     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
425     *                    User or profile is NOT current
426     *                    INTERACT_ACROSS_USERS_FULL NOT granted
427     *                    The current config is for an open network.
428     * Validate result is false
429     */
430    @Test
431    public void testCanAccessFullConnectionInfo_UserNotCurrentNoInteractAcrossUsers()
432            throws Exception {
433        final boolean output;
434        mThrowSecurityException = false;
435        mUid = MANAGED_PROFILE_UID;
436        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
437        setupTestCase();
438        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
439                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
440                mMockWifiInjector);
441
442        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
443                mUid, mTargetVersion);
444
445        assertEquals(false, output);
446    }
447
448    /**
449     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
450     *                    User is current
451     *                    The current config is NULL.
452     * Validate result is false
453     */
454    @Test
455    public void testCanAccessFullConnectionInfo_WiFiConfigIsNull() throws Exception {
456        final boolean output;
457        mThrowSecurityException = false;
458        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
459        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
460        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
461        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
462                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
463                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
464        setupTestCase();
465        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
466                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
467                mMockWifiInjector);
468
469        output = codeUnderTest.canAccessFullConnectionInfo(null /*config*/, TEST_PACKAGE_NAME,
470                mUid, mTargetVersion);
471
472        assertEquals(false, output);
473    }
474
475    /**
476     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
477     *                    User is current
478     *                    The current config is not for an open network.
479     * Validate result is false
480     */
481    @Test
482    public void testCanAccessFullConnectionInfo_WiFiConfigIsNotOpen() throws Exception {
483        final boolean output;
484        mThrowSecurityException = false;
485        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
486        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
487        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
488        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
489                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
490                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
491        mConfigIsOpen = false;
492        setupTestCase();
493        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
494                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
495                mMockWifiInjector);
496
497        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
498                mUid, mTargetVersion);
499
500        assertEquals(false, output);
501    }
502
503    /**
504     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
505     *                    User is current
506     *                    The current config is for an open network.
507     *                    There is no active scorer
508     * Validate result is false
509     */
510    @Test
511    public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsSetButNoActiveScorer()
512            throws Exception {
513        final boolean output;
514        mThrowSecurityException = false;
515        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
516        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
517        mNetworkScorerAppData = null; // getActiveScorer() will return null
518        setupTestCase();
519        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
520                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
521                mMockWifiInjector);
522
523        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
524                mUid, mTargetVersion);
525
526        assertEquals(false, output);
527    }
528
529    /**
530     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
531     *                    User is current
532     *                    The current config is for an open network.
533     *                    The scorer is active but the useOpenWiFi component name doesn't match
534     *                    the provided package.
535     * Validate result is false
536     */
537    @Test
538    public void testCanAccessFullConnectionInfo_MismatchBetweenUseOpenWifiPackages()
539            throws Exception {
540        final boolean output;
541        mThrowSecurityException = false;
542        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
543        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
544        ComponentName useOpenWifiComponent =
545                new ComponentName(mUseOpenWifiPackage + ".nomatch", "TestClass");
546        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
547                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
548                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
549        setupTestCase();
550        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
551                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
552                mMockWifiInjector);
553
554        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
555                mUid, mTargetVersion);
556
557        assertEquals(false, output);
558    }
559
560    /**
561     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
562     *                    User is current
563     *                    The current config is for an open network.
564     *                    The scorer is active but the useOpenWiFi component name is null.
565     * Validate result is false
566     */
567    @Test
568    public void testCanAccessFullConnectionInfo_UseOpenWifiPackageFromScorerIsNull()
569            throws Exception {
570        final boolean output;
571        mThrowSecurityException = false;
572        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
573        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
574        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
575                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
576                null /*useOpenWifiComponent*/, null /*networkAvailableNotificationChannelId*/);
577        setupTestCase();
578        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
579                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
580                mMockWifiInjector);
581
582        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
583                mUid, mTargetVersion);
584
585        assertEquals(false, output);
586    }
587
588    /**
589     * Test case setting: Package is invalid because USE_OPEN_WIFI_PACKAGE is an empty string.
590     *                    Location mode is ON
591     *                    User is current
592     *                    The current config is for an open network.
593     * Validate result is false
594     */
595    @Test
596    public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsEmpty() throws Exception {
597        final boolean output;
598        mThrowSecurityException = false;
599        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
600        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
601        mUseOpenWifiPackage = "";
602        setupTestCase();
603        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
604                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
605                mMockWifiInjector);
606
607        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
608                mUid, mTargetVersion);
609
610        assertEquals(false, output);
611    }
612
613    /**
614     * Test case setting: Package is invalid because it does not match the USE_OPEN_WIFI_PACKAGE.
615     *                    User is current
616     *                    The current config is for an open network.
617     * Validate result is false
618     */
619    @Test
620    public void testCanAccessFullConnectionInfo_DoesNotMatchUseOpenWifiPackage() throws Exception {
621        final boolean output;
622        mThrowSecurityException = false;
623        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
624        mUseOpenWifiPackage = TEST_PACKAGE_NAME + ".nomatch";
625        setupTestCase();
626        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
627                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
628                mMockWifiInjector);
629
630        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
631                mUid, mTargetVersion);
632
633        assertEquals(false, output);
634    }
635
636    /**
637     * Test case setting: The caller is invalid because its UID does not match the provided package.
638     *
639     * Validate a SecurityException is thrown.
640     */
641    @Test
642    public void testCanAccessFullConnectionInfo_UidPackageCheckFails() throws Exception {
643        mThrowSecurityException = true;
644        setupTestCase();
645        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
646                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
647                mMockWifiInjector);
648
649        try {
650            codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
651                    mTargetVersion);
652            fail("SecurityException not thrown.");
653        } catch (SecurityException e) {
654            // expected
655        }
656    }
657
658    /**
659     * Test case setting: The getActiveScorer() call fails with a SecurityException.
660     *
661     * Validate a SecurityException is thrown.
662     */
663    @Test
664    public void testCanAccessFullConnectionInfo_GetActiveScorerFails() throws Exception {
665        mThrowSecurityException = false;
666        mGetActiveScorerThrowsSecurityException = true;
667        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
668        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
669        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
670        setupTestCase();
671        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
672                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
673                mMockWifiInjector);
674
675        try {
676            codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
677                    mTargetVersion);
678            fail("SecurityException not thrown.");
679        } catch (SecurityException e) {
680            // expected
681        }
682    }
683
684    /**
685     * Test case Setting: Package is valid
686     *                    Legacy App
687     *                    Foreground
688     *                    This App has permission to request WIFI_SCAN
689     *                    User is current
690     *  Validate result is true - has all permissions
691     */
692    @Test
693    public void testLegacyForegroundAppAndAllPermissions() throws Exception {
694        boolean output = false;
695        mThrowSecurityException = false;
696        mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
697        mPkgNameOfTopActivity = TEST_PACKAGE_NAME;
698        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
699        mUid = MANAGED_PROFILE_UID;
700        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
701        setupTestCase();
702        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
703                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
704                mMockWifiInjector);
705        try {
706            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
707        } catch (SecurityException e) {
708            throw e;
709        }
710        assertEquals(output, true);
711    }
712
713    /**
714     * Test case Setting: Package is valid
715     *                    Legacy App
716     *                    Location Mode Enabled
717     *                    Coarse Location Access
718     *                    This App has permission to request WIFI_SCAN
719     *                    User profile is current
720     *  Validate result is true - has all permissions
721     */
722    @Test
723    public void testLegacyAppHasLocationAndAllPermissions() throws Exception {
724        boolean output = false;
725        mThrowSecurityException = false;
726        mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
727        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
728        mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
729        mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
730        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
731        mUid = MANAGED_PROFILE_UID;
732        mMockUserInfo.id = mCallingUser;
733        setupTestCase();
734        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
735                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
736                mMockWifiInjector);
737        try {
738            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
739        } catch (SecurityException e) {
740            throw e;
741        }
742        assertEquals(output, true);
743    }
744
745    /**
746     * Test case setting: Package is valid
747     *                    Location Mode Enabled
748     * Validate result is false
749     * - Doesn't have Peer Mac Address read permission
750     * - Uid is not an active network scorer
751     * - Location Mode is enabled but the uid
752     * - doesn't have Coarse Location Access
753     * - which implies No Location Permission
754     */
755    @Test
756    public void testCannotAccessScanResults_NoCoarseLocationPermission() throws Exception {
757        boolean output = true;
758        mThrowSecurityException = false;
759        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
760        setupTestCase();
761        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
762                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
763                mMockWifiInjector);
764        try {
765            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
766        } catch (SecurityException e) {
767            throw e;
768        }
769        assertEquals(output, false);
770    }
771
772    /**
773     * Test case setting: Invalid Package
774     * Expect a securityException
775     */
776    @Test (expected = SecurityException.class)
777    public void testInvalidPackage() throws Exception {
778        boolean output = false;
779        setupTestCase();
780        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
781                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
782                mMockWifiInjector);
783        try {
784            output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
785        } catch (SecurityException e) {
786            throw e;
787        }
788    }
789
790    /**
791     * Test case setting: caller does have Location permission.
792     * A SecurityException should not be thrown.
793     */
794    @Test
795    public void testEnforceLocationPermission() throws Exception {
796        mThrowSecurityException = false;
797        mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
798        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
799        mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
800        mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
801        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
802        mUid = MANAGED_PROFILE_UID;
803        mMockUserInfo.id = mCallingUser;
804        setupTestCase();
805        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
806                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
807                mMockWifiInjector);
808        codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
809    }
810
811    /**
812     * Test case setting: caller does not have Location permission.
813     * Expect a SecurityException
814     */
815    @Test(expected = SecurityException.class)
816    public void testEnforceLocationPermissionExpectSecurityException() throws Exception {
817        setupTestCase();
818        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
819                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
820                mMockWifiInjector);
821        codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
822    }
823
824    private Answer<Integer> createPermissionAnswer() {
825        return new Answer<Integer>() {
826            @Override
827            public Integer answer(InvocationOnMock invocation) {
828                int myUid = (int) invocation.getArguments()[1];
829                String myPermission = (String) invocation.getArguments()[0];
830                mPermissionsList.get(myPermission);
831                if (mPermissionsList.containsKey(myPermission)) {
832                    int uid = mPermissionsList.get(myPermission);
833                    if (myUid == uid) {
834                        return PackageManager.PERMISSION_GRANTED;
835                    }
836                }
837                return PackageManager.PERMISSION_DENIED;
838            }
839        };
840    }
841
842    private void setupMocks() throws Exception {
843        when(mMockPkgMgr.getApplicationInfo(TEST_PACKAGE_NAME, 0))
844            .thenReturn(mMockApplInfo);
845        when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr);
846        when(mMockAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, mUid, TEST_PACKAGE_NAME))
847            .thenReturn(mWifiScanAllowApps);
848        when(mMockAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, mUid, TEST_PACKAGE_NAME))
849            .thenReturn(mAllowCoarseLocationApps);
850        if (mThrowSecurityException) {
851            doThrow(new SecurityException("Package " + TEST_PACKAGE_NAME + " doesn't belong"
852                    + " to application bound to user " + mUid))
853                    .when(mMockAppOps).checkPackage(mUid, TEST_PACKAGE_NAME);
854        }
855        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE))
856            .thenReturn(mMockAppOps);
857        when(mMockUserManager.getProfiles(mCurrentUser))
858            .thenReturn(Arrays.asList(mMockUserInfo));
859        when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
860        when(mMockContext.getSystemService(Context.USER_SERVICE))
861            .thenReturn(mMockUserManager);
862        when(mMockWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
863        when(mMockWifiInjector.getFrameworkFacade()).thenReturn(mMockFrameworkFacade);
864        if (mGetActiveScorerThrowsSecurityException) {
865            when(mMockNetworkScoreManager.getActiveScorer()).thenThrow(
866                    new SecurityException("Caller is neither the system process nor a "
867                            + "score requester."));
868        } else {
869            when(mMockNetworkScoreManager.getActiveScorer()).thenReturn(mNetworkScorerAppData);
870        }
871    }
872
873    private void initTestVars() {
874        mPermissionsList.clear();
875        mReturnPermission = createPermissionAnswer();
876        mWifiScanAllowApps = AppOpsManager.MODE_ERRORED;
877        mUid = OTHER_USER_UID;
878        mThrowSecurityException = true;
879        mMockUserInfo.id = UserHandle.USER_NULL;
880        mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M;
881        mTargetVersion = Build.VERSION_CODES.M;
882        mPkgNameOfTopActivity = INVALID_PACKAGE;
883        mLocationModeSetting = Settings.Secure.LOCATION_MODE_OFF;
884        mCurrentUser = UserHandle.USER_SYSTEM;
885        mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
886        mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
887        mActiveNwScorer = false;
888        mUseOpenWifiPackage = null;
889        mNetworkScorerAppData = null;
890        mGetActiveScorerThrowsSecurityException = false;
891        mConfigIsOpen = true;
892    }
893
894    private void setupMockInterface() {
895        BinderUtil.setUid(mUid);
896        doAnswer(mReturnPermission).when(mMockPermissionsWrapper).getUidPermission(
897                        anyString(), anyInt());
898        doAnswer(mReturnPermission).when(mMockPermissionsWrapper).getUidPermission(
899                        anyString(), anyInt());
900        when(mMockPermissionsWrapper.getCallingUserId(mUid)).thenReturn(mCallingUser);
901        when(mMockPermissionsWrapper.getCurrentUser()).thenReturn(mCurrentUser);
902        when(mMockNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
903        when(mMockPermissionsWrapper.getUidPermission(mManifestStringCoarse, mUid))
904            .thenReturn(mCoarseLocationPermission);
905        when(mMockWifiSettingsStore.getLocationModeSetting(mMockContext))
906            .thenReturn(mLocationModeSetting);
907        when(mMockPermissionsWrapper.getTopPkgName()).thenReturn(mPkgNameOfTopActivity);
908        when(mMockFrameworkFacade.getStringSetting(mMockContext,
909                Settings.Global.USE_OPEN_WIFI_PACKAGE)).thenReturn(mUseOpenWifiPackage);
910        when(mMockWifiConfig.isOpenNetwork()).thenReturn(mConfigIsOpen);
911    }
912}
913