1 /* 2 * Copyright (C) 2021 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 android.devicepolicy.cts; 18 19 import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE; 20 import static android.content.pm.PackageManager.FEATURE_SECURE_LOCK_SCREEN; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.junit.Assert.fail; 25 26 import android.app.admin.RemoteDevicePolicyManager; 27 import android.content.ComponentName; 28 29 import com.android.bedstead.harrier.BedsteadJUnit4; 30 import com.android.bedstead.harrier.DeviceState; 31 import com.android.bedstead.harrier.annotations.Postsubmit; 32 import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature; 33 import com.android.bedstead.harrier.annotations.RequireFeature; 34 import com.android.bedstead.enterprise.annotations.CanSetPolicyTest; 35 import com.android.bedstead.harrier.policies.LockscreenPolicyWithUnifiedChallenge; 36 import com.android.bedstead.harrier.policies.ScreenCaptureDisabled; 37 import com.android.bedstead.testapp.TestApp; 38 import com.android.bedstead.testapp.TestAppInstance; 39 40 import org.junit.Assume; 41 import org.junit.ClassRule; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.util.function.BiConsumer; 47 48 /** 49 * Test that DevicePolicyManager getters that accept "ComponentName who" argument don't allow a 50 * different app to probe for admins when policy is set: those getters should only allow either 51 * calls where "who" is null or "who" is not null and belongs to caller. SecurityExceptions that are 52 * thrown otherwise shouldn't leak that data either. 53 */ 54 // Password policies aren't supported on automotive 55 @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE) 56 @RequireFeature(FEATURE_SECURE_LOCK_SCREEN) 57 @RunWith(BedsteadJUnit4.class) 58 public class NoAdminLeakingTest { 59 @ClassRule 60 @Rule 61 public static final DeviceState sDeviceState = new DeviceState(); 62 63 private static final TestApp sTestApp = sDeviceState.testApps().any(); 64 65 @Postsubmit(reason = "new test") 66 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 67 @Test testPasswordQuality_adminPolicyNotAvailableToNonAdmin()68 public void testPasswordQuality_adminPolicyNotAvailableToNonAdmin() { 69 assertOnlyAggregatePolicyAvailableToNonAdmin( 70 (dpm, who) -> dpm.getPasswordQuality(who)); 71 } 72 73 @Postsubmit(reason = "new test") 74 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 75 @Test testPasswordMinimumLength_adminPolicyNotAvailableToNonAdmin()76 public void testPasswordMinimumLength_adminPolicyNotAvailableToNonAdmin() { 77 assertOnlyAggregatePolicyAvailableToNonAdmin( 78 (dpm, who) -> dpm.getPasswordMinimumLength(who)); 79 } 80 81 @Postsubmit(reason = "new test") 82 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 83 @Test testPasswordMinimumLetters_adminPolicyNotAvailableToNonAdmin()84 public void testPasswordMinimumLetters_adminPolicyNotAvailableToNonAdmin() { 85 assertOnlyAggregatePolicyAvailableToNonAdmin( 86 (dpm, who) -> dpm.getPasswordMinimumLetters(who)); 87 } 88 89 @Postsubmit(reason = "new test") 90 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 91 @Test testPasswordMinimumNonLetter_adminPolicyNotAvailableToNonAdmin()92 public void testPasswordMinimumNonLetter_adminPolicyNotAvailableToNonAdmin() { 93 assertOnlyAggregatePolicyAvailableToNonAdmin( 94 (dpm, who) -> dpm.getPasswordMinimumNonLetter(who)); 95 } 96 97 @Postsubmit(reason = "new test") 98 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 99 @Test testPasswordMinimumLowerCase_adminPolicyNotAvailableToNonAdmin()100 public void testPasswordMinimumLowerCase_adminPolicyNotAvailableToNonAdmin() { 101 assertOnlyAggregatePolicyAvailableToNonAdmin( 102 (dpm, who) -> dpm.getPasswordMinimumLowerCase(who)); 103 } 104 105 @Postsubmit(reason = "new test") 106 @Test 107 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) testPasswordMinimumUpperCase_adminPolicyNotAvailableToNonAdmin()108 public void testPasswordMinimumUpperCase_adminPolicyNotAvailableToNonAdmin() { 109 assertOnlyAggregatePolicyAvailableToNonAdmin( 110 (dpm, who) -> dpm.getPasswordMinimumUpperCase(who)); 111 } 112 113 @Postsubmit(reason = "new test") 114 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 115 @Test testPasswordMinimumNumeric_adminPolicyNotAvailableToNonAdmin()116 public void testPasswordMinimumNumeric_adminPolicyNotAvailableToNonAdmin() { 117 assertOnlyAggregatePolicyAvailableToNonAdmin( 118 (dpm, who) -> dpm.getPasswordMinimumNumeric(who)); 119 } 120 121 @Postsubmit(reason = "new test") 122 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 123 @Test testPasswordMinimumSymbols_adminPolicyNotAvailableToNonAdmin()124 public void testPasswordMinimumSymbols_adminPolicyNotAvailableToNonAdmin() { 125 assertOnlyAggregatePolicyAvailableToNonAdmin( 126 (dpm, who) -> dpm.getPasswordMinimumSymbols(who)); 127 } 128 129 @Postsubmit(reason = "new test") 130 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 131 @Test testPasswordHistoryLength_adminPolicyNotAvailableToNonAdmin()132 public void testPasswordHistoryLength_adminPolicyNotAvailableToNonAdmin() { 133 assertOnlyAggregatePolicyAvailableToNonAdmin( 134 (dpm, who) -> dpm.getPasswordHistoryLength(who)); 135 } 136 137 @Postsubmit(reason = "new test") 138 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 139 @Test testPasswordExpiration_adminPolicyNotAvailableToNonAdmin()140 public void testPasswordExpiration_adminPolicyNotAvailableToNonAdmin() { 141 assertOnlyAggregatePolicyAvailableToNonAdmin( 142 (dpm, who) -> dpm.getPasswordExpiration(who)); 143 } 144 145 @Postsubmit(reason = "new test") 146 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 147 @Test testPasswordExpirationTimeout_adminPolicyNotAvailableToNonAdmin()148 public void testPasswordExpirationTimeout_adminPolicyNotAvailableToNonAdmin() { 149 assertOnlyAggregatePolicyAvailableToNonAdmin( 150 (dpm, who) -> dpm.getPasswordExpirationTimeout(who)); 151 } 152 153 @Postsubmit(reason = "new test") 154 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 155 @Test testMaximumFailedPasswordsForWipe_adminPolicyNotAvailableToNonAdmin()156 public void testMaximumFailedPasswordsForWipe_adminPolicyNotAvailableToNonAdmin() { 157 assertOnlyAggregatePolicyAvailableToNonAdmin( 158 (dpm, who) -> dpm.getMaximumFailedPasswordsForWipe(who)); 159 } 160 161 @Postsubmit(reason = "new test") 162 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 163 @Test testMaximumTimeToLock_adminPolicyNotAvailableToNonAdmin()164 public void testMaximumTimeToLock_adminPolicyNotAvailableToNonAdmin() { 165 assertOnlyAggregatePolicyAvailableToNonAdmin( 166 (dpm, who) -> dpm.getMaximumTimeToLock(who)); 167 } 168 169 @Postsubmit(reason = "new test") 170 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 171 @Test testRequiredStrongAuthTimeout_adminPolicyNotAvailableToNonAdmin()172 public void testRequiredStrongAuthTimeout_adminPolicyNotAvailableToNonAdmin() { 173 assertOnlyAggregatePolicyAvailableToNonAdmin( 174 (dpm, who) -> dpm.getRequiredStrongAuthTimeout(who)); 175 } 176 177 @Postsubmit(reason = "new test") 178 @CanSetPolicyTest(policy = ScreenCaptureDisabled.class) 179 @Test testScreenCaptureDisabled_adminPolicyNotAvailableToNonAdmin()180 public void testScreenCaptureDisabled_adminPolicyNotAvailableToNonAdmin() { 181 Assume.assumeFalse("Test not suitable for non-deviceadmins", 182 sDeviceState.dpc().componentName() == null); 183 assertOnlyAggregatePolicyAvailableToNonAdmin( 184 (dpm, who) -> dpm.getScreenCaptureDisabled(who)); 185 } 186 187 @Postsubmit(reason = "new test") 188 @CanSetPolicyTest(policy = LockscreenPolicyWithUnifiedChallenge.class) 189 @Test testTrustAgentConfiguration_adminPolicyNotAvailableToNonAdmin()190 public void testTrustAgentConfiguration_adminPolicyNotAvailableToNonAdmin() { 191 assertOnlyAggregatePolicyAvailableToNonAdmin( 192 (dpm, who) -> dpm.getTrustAgentConfiguration(who, 193 sDeviceState.dpc().componentName() 194 /* agent component, need to be non-null */)); 195 } 196 197 // TODO(b/210996030): replace this with test method parametrization and separate "null" case. assertOnlyAggregatePolicyAvailableToNonAdmin( BiConsumer<RemoteDevicePolicyManager, ComponentName> accessor)198 private void assertOnlyAggregatePolicyAvailableToNonAdmin( 199 BiConsumer<RemoteDevicePolicyManager, ComponentName> accessor) { 200 try (TestAppInstance testApp = sTestApp.install()) { 201 // Invoking with null admin should not throw. 202 accessor.accept(testApp.devicePolicyManager(), /* who= */ null); 203 204 SecurityException adminPackageEx = null; 205 try { 206 // Requesting policy for an admin from a different app should throw. 207 accessor.accept(testApp.devicePolicyManager(), 208 sDeviceState.dpc().componentName()); 209 fail("Checking particular admin policy shouldn't be allowed for non admin"); 210 } catch (SecurityException e) { 211 adminPackageEx = e; 212 } 213 214 ComponentName nonexistentComponent = new ComponentName("bad_pkg_123", "bad_clz_456"); 215 SecurityException nonexistentPackageEx = null; 216 try { 217 // Requesting policy for a nonexistent admin should throw. 218 accessor.accept(testApp.devicePolicyManager(), nonexistentComponent); 219 fail("Querying policy for non-existent admin should have thrown an exception"); 220 } catch (SecurityException e) { 221 nonexistentPackageEx = e; 222 } 223 224 // Both exceptions should have the same message (except package name) to avoid revealing 225 // admin existence. 226 String adminMessage = adminPackageEx.getMessage() 227 .replace(sDeviceState.dpc().componentName().toString(), ""); 228 String nonexistentMessage = nonexistentPackageEx.getMessage() 229 .replace(nonexistentComponent.toString(), ""); 230 assertThat(adminMessage).isEqualTo(nonexistentMessage); 231 } 232 } 233 } 234