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