diff options
4 files changed, 534 insertions, 42 deletions
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 9e124463d..e04d33e5b 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -1770,7 +1770,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss uid) == PackageManager.PERMISSION_GRANTED) { result.setMacAddress(mWifiInfo.getMacAddress()); } - if (mWifiPermissionsUtil.canAccessScanResults( + final WifiConfiguration currentWifiConfiguration = getCurrentWifiConfiguration(); + if (mWifiPermissionsUtil.canAccessFullConnectionInfo( + currentWifiConfiguration, callingPackage, uid, Build.VERSION_CODES.O)) { diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java index 069e5a823..52c96183e 100644 --- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java +++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java @@ -17,17 +17,23 @@ package com.android.server.wifi.util; import android.Manifest; +import android.annotation.Nullable; import android.app.AppOpsManager; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.net.ConnectivityManager; import android.net.NetworkScoreManager; +import android.net.NetworkScorerAppData; +import android.net.wifi.WifiConfiguration; import android.os.Binder; import android.os.RemoteException; import android.os.UserManager; import android.provider.Settings; +import android.text.TextUtils; +import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiLog; import com.android.server.wifi.WifiSettingsStore; @@ -46,6 +52,7 @@ public class WifiPermissionsUtil { private final UserManager mUserManager; private final WifiSettingsStore mSettingsStore; private final NetworkScoreManager mNetworkScoreManager; + private final FrameworkFacade mFrameworkFacade; private WifiLog mLog; public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, @@ -58,6 +65,7 @@ public class WifiPermissionsUtil { mSettingsStore = settingsStore; mLog = wifiInjector.makeLog(TAG); mNetworkScoreManager = networkScoreManager; + mFrameworkFacade = wifiInjector.getFrameworkFacade(); } /** @@ -168,10 +176,81 @@ public class WifiPermissionsUtil { } // If the User or profile is current, permission is granted // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. - if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) { + if (!canAccessUserProfile(uid)) { + mLog.tC("Denied: Profile not permitted"); + return false; + } + return true; + } + + /** + * API to determine if the caller has permissions to get a {@link android.net.wifi.WifiInfo} + * instance containing the SSID and BSSID. + * + * + * @param currentConfig the currently connected WiFi config + * @param pkgName package name of the application requesting access + * @param uid The uid of the package + * @param minVersion Minimum app API Version number to enforce location permission + * @return boolean true if the SSID/BSSID can be sent to the user, false if they + * should be hidden/removed. + */ + public boolean canAccessFullConnectionInfo(@Nullable WifiConfiguration currentConfig, + String pkgName, int uid, int minVersion) throws SecurityException { + mAppOps.checkPackage(uid, pkgName); + + // The User or profile must be current or the uid must + // have INTERACT_ACROSS_USERS_FULL permission. + if (!canAccessUserProfile(uid)) { mLog.tC("Denied: Profile not permitted"); return false; } + + // If the caller has scan result access then they can also see the full connection info. + // Otherwise the caller must be the active use open wifi package and the current config + // must be for an open network. + return canAccessScanResults(pkgName, uid, minVersion) + || isUseOpenWifiPackageWithConnectionInfoAccess(currentConfig, pkgName); + + } + + /** + * Returns true if the given WiFi config is for an open network and the package is the active + * use open wifi app. + */ + private boolean isUseOpenWifiPackageWithConnectionInfoAccess( + @Nullable WifiConfiguration currentConfig, String pkgName) { + + // Access is only granted for open networks. + if (currentConfig == null) { + mLog.tC("Denied: WifiConfiguration is NULL."); + return false; + } + + // Access is only granted for open networks. + if (!currentConfig.isOpenNetwork()) { + mLog.tC("Denied: The current config is not for an open network."); + return false; + } + + // The USE_OPEN_WIFI_PACKAGE can access the full connection info details without + // scan result access. + if (!isUseOpenWifiPackage(pkgName)) { + mLog.tC("Denied: caller is not the current USE_OPEN_WIFI_PACKAGE"); + return false; + } + + return true; + } + + /** + * Returns true if the User or profile is current or the + * uid has the INTERACT_ACROSS_USERS_FULL permission. + */ + private boolean canAccessUserProfile(int uid) { + if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) { + return false; + } return true; } @@ -192,6 +271,43 @@ public class WifiPermissionsUtil { } /** + * Returns true if the given package is equal to the setting keyed by + * {@link Settings.Global#USE_OPEN_WIFI_PACKAGE} and the NetworkScoreManager + * has the package name set as the use open wifi package. + */ + private boolean isUseOpenWifiPackage(String packageName) { + if (TextUtils.isEmpty(packageName)) { + return false; + } + + // When the setting is enabled it's set to the package name of the use open wifi app. + final String useOpenWifiPkg = + mFrameworkFacade.getStringSetting(mContext, Settings.Global.USE_OPEN_WIFI_PACKAGE); + if (packageName.equals(useOpenWifiPkg)) { + // If the package name matches the setting then also confirm that the scorer is + // active and the package matches the expected use open wifi package from the scorer's + // perspective. The scorer can be active when the use open wifi feature is off so we + // can't rely on this check alone. + // TODO(b/67278755): Refactor this into an API similar to isCallerActiveScorer() + final NetworkScorerAppData appData; + final long token = Binder.clearCallingIdentity(); + try { + appData = mNetworkScoreManager.getActiveScorer(); + } finally { + Binder.restoreCallingIdentity(token); + } + if (appData != null) { + final ComponentName enableUseOpenWifiActivity = + appData.getEnableUseOpenWifiActivity(); + return enableUseOpenWifiActivity != null + && packageName.equals(enableUseOpenWifiActivity.getPackageName()); + } + } + + return false; + } + + /** * Returns true if Wifi scan operation is allowed for this caller * and package. */ diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java index ecb4c959c..8f67df491 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java @@ -2275,8 +2275,8 @@ public class WifiStateMachineTest { assertEquals(sBSSID, wifiInfo.getBSSID()); assertEquals(sWifiSsid, wifiInfo.getWifiSsid()); - when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt())) - .thenReturn(false); + when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid), + anyInt())).thenReturn(false); WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName()); @@ -2308,8 +2308,8 @@ public class WifiStateMachineTest { assertEquals(sBSSID, wifiInfo.getBSSID()); assertEquals(sWifiSsid, wifiInfo.getWifiSsid()); - when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt())) - .thenThrow(new SecurityException()); + when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid), + anyInt())).thenThrow(new SecurityException()); WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName()); @@ -2338,8 +2338,8 @@ public class WifiStateMachineTest { assertEquals(sBSSID, wifiInfo.getBSSID()); assertEquals(sWifiSsid, wifiInfo.getWifiSsid()); - when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt())) - .thenReturn(true); + when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid), + anyInt())).thenReturn(true); WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName()); diff --git a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java index 308e26776..7f5a66d0e 100644 --- a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java +++ b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java @@ -19,6 +19,7 @@ package com.android.server.wifi.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doAnswer; @@ -27,12 +28,15 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.app.AppOpsManager; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.net.NetworkScoreManager; +import android.net.NetworkScorerAppData; +import android.net.wifi.WifiConfiguration; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; @@ -41,6 +45,7 @@ import android.provider.Settings; import com.android.server.wifi.BinderUtil; import com.android.server.wifi.FakeWifiLog; +import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiSettingsStore; @@ -72,8 +77,10 @@ public class WifiPermissionsUtilTest { @Mock private UserManager mMockUserManager; @Mock private WifiSettingsStore mMockWifiSettingsStore; @Mock private ContentResolver mMockContentResolver; - @Mock private NetworkScoreManager mNetworkScoreManager; - @Mock private WifiInjector mWifiInjector; + @Mock private NetworkScoreManager mMockNetworkScoreManager; + @Mock private WifiInjector mMockWifiInjector; + @Mock private FrameworkFacade mMockFrameworkFacade; + @Mock private WifiConfiguration mMockWifiConfig; @Spy private FakeWifiLog mWifiLog; private static final String TEST_PACKAGE_NAME = "com.google.somePackage"; @@ -101,6 +108,10 @@ public class WifiPermissionsUtilTest { private boolean mActiveNwScorer; private Answer<Integer> mReturnPermission; private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>(); + private String mUseOpenWifiPackage; + private NetworkScorerAppData mNetworkScorerAppData; + private boolean mGetActiveScorerThrowsSecurityException; + private boolean mConfigIsOpen; /** * Set up Mockito tests @@ -124,8 +135,8 @@ public class WifiPermissionsUtilTest { mUid = MANAGED_PROFILE_UID; // do not really care about this value setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt())) .thenReturn(PackageManager.PERMISSION_GRANTED); assertTrue(codeUnderTest.checkConfigOverridePermission(mUid)); @@ -139,8 +150,8 @@ public class WifiPermissionsUtilTest { mUid = OTHER_USER_UID; // do not really care about this value setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt())) .thenReturn(PackageManager.PERMISSION_DENIED); assertFalse(codeUnderTest.checkConfigOverridePermission(mUid)); @@ -154,8 +165,8 @@ public class WifiPermissionsUtilTest { mUid = OTHER_USER_UID; // do not really care about this value setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); doThrow(new RemoteException("Failed to check permissions for " + mUid)) .when(mMockPermissionsWrapper).getOverrideWifiConfigPermission(mUid); assertFalse(codeUnderTest.checkConfigOverridePermission(mUid)); @@ -179,8 +190,8 @@ public class WifiPermissionsUtilTest { mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -207,8 +218,8 @@ public class WifiPermissionsUtilTest { mMockUserInfo.id = mCallingUser; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -230,8 +241,8 @@ public class WifiPermissionsUtilTest { mPermissionsList.put(mMacAddressPermission, mUid); setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -259,8 +270,8 @@ public class WifiPermissionsUtilTest { mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid); setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -286,8 +297,8 @@ public class WifiPermissionsUtilTest { mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -312,8 +323,8 @@ public class WifiPermissionsUtilTest { mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -323,6 +334,354 @@ public class WifiPermissionsUtilTest { } /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is for an open network. + * Validate result is true + */ + @Test + public void testCanAccessFullConnectionInfo_PackageIsUseOpenWifiPackage() throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass"); + mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/, + null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/, + useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/); + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(true, output); + } + + /** + * Test case setting: Package is valid because the caller has access to scan results. + * Location mode is ON + * User is current + * The current config is not for an open network. + * Validate result is true + */ + @Test + public void testCanAccessFullConnectionInfo_HasAccessToScanResults() throws Exception { + final boolean output; + mThrowSecurityException = false; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD; + mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mConfigIsOpen = false; + + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(true, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User or profile is not current but the uid has + * permission to INTERACT_ACROSS_USERS_FULL + * The current config is for an open network. + * Validate result is true + */ + @Test + public void testCanAccessFullConnectionInfo_UserNotCurrentButHasInteractAcrossUsers() + throws Exception { + final boolean output; + mThrowSecurityException = false; + mUid = MANAGED_PROFILE_UID; + mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid); + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass"); + mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/, + null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/, + useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/); + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(true, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User or profile is NOT current + * INTERACT_ACROSS_USERS_FULL NOT granted + * The current config is for an open network. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_UserNotCurrentNoInteractAcrossUsers() + throws Exception { + final boolean output; + mThrowSecurityException = false; + mUid = MANAGED_PROFILE_UID; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is NULL. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_WiFiConfigIsNull() throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass"); + mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/, + null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/, + useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/); + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(null /*config*/, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is not for an open network. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_WiFiConfigIsNotOpen() throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass"); + mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/, + null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/, + useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/); + mConfigIsOpen = false; + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is for an open network. + * There is no active scorer + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsSetButNoActiveScorer() + throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + mNetworkScorerAppData = null; // getActiveScorer() will return null + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is for an open network. + * The scorer is active but the useOpenWiFi component name doesn't match + * the provided package. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_MismatchBetweenUseOpenWifiPackages() + throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + ComponentName useOpenWifiComponent = + new ComponentName(mUseOpenWifiPackage + ".nomatch", "TestClass"); + mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/, + null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/, + useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/); + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is for an open network. + * The scorer is active but the useOpenWiFi component name is null. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_UseOpenWifiPackageFromScorerIsNull() + throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/, + null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/, + null /*useOpenWifiComponent*/, null /*networkAvailableNotificationChannelId*/); + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is invalid because USE_OPEN_WIFI_PACKAGE is an empty string. + * Location mode is ON + * User is current + * The current config is for an open network. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsEmpty() throws Exception { + final boolean output; + mThrowSecurityException = false; + mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = ""; + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: Package is invalid because it does not match the USE_OPEN_WIFI_PACKAGE. + * User is current + * The current config is for an open network. + * Validate result is false + */ + @Test + public void testCanAccessFullConnectionInfo_DoesNotMatchUseOpenWifiPackage() throws Exception { + final boolean output; + mThrowSecurityException = false; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME + ".nomatch"; + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, + mUid, mTargetVersion); + + assertEquals(false, output); + } + + /** + * Test case setting: The caller is invalid because its UID does not match the provided package. + * + * Validate a SecurityException is thrown. + */ + @Test + public void testCanAccessFullConnectionInfo_UidPackageCheckFails() throws Exception { + mThrowSecurityException = true; + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + try { + codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid, + mTargetVersion); + fail("SecurityException not thrown."); + } catch (SecurityException e) { + // expected + } + } + + /** + * Test case setting: The getActiveScorer() call fails with a SecurityException. + * + * Validate a SecurityException is thrown. + */ + @Test + public void testCanAccessFullConnectionInfo_GetActiveScorerFails() throws Exception { + mThrowSecurityException = false; + mGetActiveScorerThrowsSecurityException = true; + mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY; + mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; + mUseOpenWifiPackage = TEST_PACKAGE_NAME; + setupTestCase(); + WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); + + try { + codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid, + mTargetVersion); + fail("SecurityException not thrown."); + } catch (SecurityException e) { + // expected + } + } + + /** * Test case Setting: Package is valid * Legacy App * Foreground @@ -341,8 +700,8 @@ public class WifiPermissionsUtilTest { mCurrentUser = UserHandle.USER_CURRENT_OR_SELF; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -373,8 +732,8 @@ public class WifiPermissionsUtilTest { mMockUserInfo.id = mCallingUser; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -400,8 +759,8 @@ public class WifiPermissionsUtilTest { mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -419,8 +778,8 @@ public class WifiPermissionsUtilTest { boolean output = false; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); try { output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion); } catch (SecurityException e) { @@ -444,8 +803,8 @@ public class WifiPermissionsUtilTest { mMockUserInfo.id = mCallingUser; setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid); } @@ -457,8 +816,8 @@ public class WifiPermissionsUtilTest { public void testEnforceLocationPermissionExpectSecurityException() throws Exception { setupTestCase(); WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager, - mWifiInjector); + mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager, + mMockWifiInjector); codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid); } @@ -500,7 +859,15 @@ public class WifiPermissionsUtilTest { when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); when(mMockContext.getSystemService(Context.USER_SERVICE)) .thenReturn(mMockUserManager); - when(mWifiInjector.makeLog(anyString())).thenReturn(mWifiLog); + when(mMockWifiInjector.makeLog(anyString())).thenReturn(mWifiLog); + when(mMockWifiInjector.getFrameworkFacade()).thenReturn(mMockFrameworkFacade); + if (mGetActiveScorerThrowsSecurityException) { + when(mMockNetworkScoreManager.getActiveScorer()).thenThrow( + new SecurityException("Caller is neither the system process nor a " + + "score requester.")); + } else { + when(mMockNetworkScoreManager.getActiveScorer()).thenReturn(mNetworkScorerAppData); + } } private void initTestVars() { @@ -518,6 +885,10 @@ public class WifiPermissionsUtilTest { mCoarseLocationPermission = PackageManager.PERMISSION_DENIED; mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; mActiveNwScorer = false; + mUseOpenWifiPackage = null; + mNetworkScorerAppData = null; + mGetActiveScorerThrowsSecurityException = false; + mConfigIsOpen = true; } private void setupMockInterface() { @@ -528,11 +899,14 @@ public class WifiPermissionsUtilTest { anyString(), anyInt()); when(mMockPermissionsWrapper.getCallingUserId(mUid)).thenReturn(mCallingUser); when(mMockPermissionsWrapper.getCurrentUser()).thenReturn(mCurrentUser); - when(mNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer); + when(mMockNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer); when(mMockPermissionsWrapper.getUidPermission(mManifestStringCoarse, mUid)) .thenReturn(mCoarseLocationPermission); when(mMockWifiSettingsStore.getLocationModeSetting(mMockContext)) .thenReturn(mLocationModeSetting); when(mMockPermissionsWrapper.getTopPkgName()).thenReturn(mPkgNameOfTopActivity); + when(mMockFrameworkFacade.getStringSetting(mMockContext, + Settings.Global.USE_OPEN_WIFI_PACKAGE)).thenReturn(mUseOpenWifiPackage); + when(mMockWifiConfig.isOpenNetwork()).thenReturn(mConfigIsOpen); } } |