blob: c0f27ff131017f05dbcac41358aa035ac2f771c3 [file] [log] [blame]
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001/*
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
Andrew Scull507d11c2017-05-03 17:19:01 +010017package com.android.server.locksettings;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000018
Adrian Roos7374d3a2017-03-31 14:14:53 -070019import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
20import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
21import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
22import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
23
Rubin Xu0cbc19e2016-12-09 14:00:21 +000024import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
25import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
26import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
27
Kenny Rootd01bb412019-11-22 09:34:03 -080028import static org.junit.Assert.assertEquals;
29import static org.junit.Assert.assertFalse;
30import static org.junit.Assert.assertNotNull;
31import static org.junit.Assert.assertNull;
32import static org.junit.Assert.assertTrue;
33import static org.junit.Assert.fail;
Annie Meng086ddc82019-03-29 17:43:35 +000034import static org.mockito.ArgumentMatchers.any;
35import static org.mockito.ArgumentMatchers.anyInt;
36import static org.mockito.ArgumentMatchers.eq;
37import static org.mockito.Mockito.never;
38import static org.mockito.Mockito.reset;
39import static org.mockito.Mockito.verify;
40
Rubin Xu0cbc19e2016-12-09 14:00:21 +000041import android.os.RemoteException;
Pavel Grafov57f1b662019-03-27 14:55:38 +000042import android.platform.test.annotations.Presubmit;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000043import android.service.gatekeeper.GateKeeperResponse;
44
Pavel Grafov57f1b662019-03-27 14:55:38 +000045import androidx.test.filters.SmallTest;
Kenny Rootd01bb412019-11-22 09:34:03 -080046import androidx.test.runner.AndroidJUnit4;
Pavel Grafov57f1b662019-03-27 14:55:38 +000047
Rubin Xu0cbc19e2016-12-09 14:00:21 +000048import com.android.internal.widget.LockPatternUtils;
49import com.android.internal.widget.VerifyCredentialResponse;
Rubin Xu16c823e2017-06-27 14:44:58 +010050import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
Lenka Trochtova66c492a2018-12-06 11:29:21 +010051import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000052
Kenny Rootd01bb412019-11-22 09:34:03 -080053import org.junit.Test;
54import org.junit.runner.RunWith;
55
Rubin Xu0cbc19e2016-12-09 14:00:21 +000056/**
Kenny Rootd01bb412019-11-22 09:34:03 -080057 * atest FrameworksServicesTests:LockSettingsServiceTests
Rubin Xu0cbc19e2016-12-09 14:00:21 +000058 */
Pavel Grafov57f1b662019-03-27 14:55:38 +000059@SmallTest
60@Presubmit
Kenny Rootd01bb412019-11-22 09:34:03 -080061@RunWith(AndroidJUnit4.class)
Rubin Xu0cbc19e2016-12-09 14:00:21 +000062public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
Kenny Rootd01bb412019-11-22 09:34:03 -080063 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +000064 public void testCreatePasswordPrimaryUser() throws RemoteException {
Adrian Roos7374d3a2017-03-31 14:14:53 -070065 testCreateCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD,
66 PASSWORD_QUALITY_ALPHABETIC);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000067 }
68
Kenny Rootd01bb412019-11-22 09:34:03 -080069 @Test
Lenka Trochtova66c492a2018-12-06 11:29:21 +010070 public void testCreatePasswordFailsWithoutLockScreen() throws RemoteException {
71 testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "password",
72 CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
73 }
74
Kenny Rootd01bb412019-11-22 09:34:03 -080075 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +000076 public void testCreatePatternPrimaryUser() throws RemoteException {
Adrian Roos7374d3a2017-03-31 14:14:53 -070077 testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN,
78 PASSWORD_QUALITY_SOMETHING);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000079 }
80
Kenny Rootd01bb412019-11-22 09:34:03 -080081 @Test
Lenka Trochtova66c492a2018-12-06 11:29:21 +010082 public void testCreatePatternFailsWithoutLockScreen() throws RemoteException {
83 testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "123456789",
84 CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
85 }
86
Kenny Rootd01bb412019-11-22 09:34:03 -080087 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +000088 public void testChangePasswordPrimaryUser() throws RemoteException {
89 testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
Adrian Roos7374d3a2017-03-31 14:14:53 -070090 "asdfghjk", CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000091 }
92
Kenny Rootd01bb412019-11-22 09:34:03 -080093 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +000094 public void testChangePatternPrimaryUser() throws RemoteException {
95 testChangeCredentials(PRIMARY_USER_ID, "!£$%^&*(())", CREDENTIAL_TYPE_PASSWORD,
Adrian Roos7374d3a2017-03-31 14:14:53 -070096 "1596321", CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000097 }
98
Kenny Rootd01bb412019-11-22 09:34:03 -080099 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000100 public void testChangePasswordFailPrimaryUser() throws RemoteException {
101 final long sid = 1234;
102 final String FAILED_MESSAGE = "Failed to enroll password";
103 initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
104
105 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800106 mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000107 "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000108 fail("Did not fail when enrolling using incorrect credential");
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000109 } catch (IllegalStateException expected) {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000110 assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
111 }
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000112 assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
113 }
114
Kenny Rootd01bb412019-11-22 09:34:03 -0800115 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000116 public void testClearPasswordPrimaryUser() throws RemoteException {
117 final String PASSWORD = "password";
118 initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
Rich Canningsf64ec632019-02-21 12:40:36 -0800119 mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000120 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000121 assertFalse(mService.havePassword(PRIMARY_USER_ID));
122 assertFalse(mService.havePattern(PRIMARY_USER_ID));
123 assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
124 }
125
Kenny Rootd01bb412019-11-22 09:34:03 -0800126 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000127 public void testManagedProfileUnifiedChallenge() throws RemoteException {
Rubin Xu16c823e2017-06-27 14:44:58 +0100128 final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1";
129 final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
Rich Canningsf64ec632019-02-21 12:40:36 -0800130 mService.setLockCredential(firstUnifiedPassword.getBytes(),
131 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000132 null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000133 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
134 final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
135 final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
Charles Hedec05402017-04-21 13:45:34 +0100136 final long turnedOffProfileSid =
Andrew Scull8e87af52017-03-03 15:38:48 +0000137 mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000138 assertTrue(primarySid != 0);
139 assertTrue(profileSid != 0);
140 assertTrue(profileSid != primarySid);
Charles Hedec05402017-04-21 13:45:34 +0100141 assertTrue(turnedOffProfileSid != 0);
142 assertTrue(turnedOffProfileSid != primarySid);
143 assertTrue(turnedOffProfileSid != profileSid);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000144
145 // clear auth token and wait for verify challenge from primary user to re-generate it.
146 mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
Andrew Scull8e87af52017-03-03 15:38:48 +0000147 mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000148 // verify credential
149 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800150 firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
151 PRIMARY_USER_ID).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000152
153 // Verify that we have a new auth token for the profile
154 assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
155 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
156
Charles Hedec05402017-04-21 13:45:34 +0100157 // Verify that profile which aren't running (e.g. turn off work) don't get unlocked
Andrew Scull8e87af52017-03-03 15:38:48 +0000158 assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
159
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000160 /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
161 * credential as part of verifyCredential() before the new credential is committed in
162 * StorageManager. So we relax the check in our mock StorageManager to allow that.
163 */
164 mStorageManager.setIgnoreBadUnlock(true);
165 // Change primary password and verify that profile SID remains
Rich Canningsf64ec632019-02-21 12:40:36 -0800166 mService.setLockCredential(secondUnifiedPassword.getBytes(),
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000167 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, firstUnifiedPassword.getBytes(),
168 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000169 mStorageManager.setIgnoreBadUnlock(false);
170 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
Andrew Scull8e87af52017-03-03 15:38:48 +0000171 assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
Rubin Xu3bf722a2016-12-15 16:07:38 +0000172
Andrew Scull8e87af52017-03-03 15:38:48 +0000173 // Clear unified challenge
Rubin Xu16c823e2017-06-27 14:44:58 +0100174 mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000175 secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID,
176 false);
Rubin Xu3bf722a2016-12-15 16:07:38 +0000177 assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
178 assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
Andrew Scull8e87af52017-03-03 15:38:48 +0000179 assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000180 }
181
Kenny Rootd01bb412019-11-22 09:34:03 -0800182 @Test
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000183 public void testManagedProfileSeparateChallenge() throws RemoteException {
184 final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
185 final String profilePassword = "testManagedProfileSeparateChallenge-profile";
Rich Canningsf64ec632019-02-21 12:40:36 -0800186 mService.setLockCredential(primaryPassword.getBytes(),
187 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000188 PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000189 /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
190 * credential as part of verifyCredential() before the new credential is committed in
191 * StorageManager. So we relax the check in our mock StorageManager to allow that.
192 */
193 mStorageManager.setIgnoreBadUnlock(true);
Rich Canningsf64ec632019-02-21 12:40:36 -0800194 mService.setLockCredential(profilePassword.getBytes(),
195 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000196 PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000197 mStorageManager.setIgnoreBadUnlock(false);
198
199 final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
200 final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
201 assertTrue(primarySid != 0);
202 assertTrue(profileSid != 0);
203 assertTrue(profileSid != primarySid);
204
205 // clear auth token and make sure verify challenge from primary user does not regenerate it.
206 mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
207 // verify primary credential
208 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800209 primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
210 PRIMARY_USER_ID).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000211 assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
212
213 // verify profile credential
214 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800215 profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000216 MANAGED_PROFILE_USER_ID).getResponseCode());
217 assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
218 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
219
220 // Change primary credential and make sure we don't affect profile
221 mStorageManager.setIgnoreBadUnlock(true);
Rich Canningsf64ec632019-02-21 12:40:36 -0800222 mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000223 primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000224 mStorageManager.setIgnoreBadUnlock(false);
225 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800226 profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000227 MANAGED_PROFILE_USER_ID).getResponseCode());
228 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
229 }
230
Kenny Rootd01bb412019-11-22 09:34:03 -0800231 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000232 public void testSetLockCredential_forPrimaryUser_sendsCredentials() throws Exception {
233 final byte[] password = "password".getBytes();
234
235 mService.setLockCredential(
236 password,
237 CREDENTIAL_TYPE_PASSWORD,
238 null,
239 PASSWORD_QUALITY_ALPHABETIC,
240 PRIMARY_USER_ID,
241 false);
242
243 verify(mRecoverableKeyStoreManager)
244 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, password, PRIMARY_USER_ID);
245 }
246
Kenny Rootd01bb412019-11-22 09:34:03 -0800247 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000248 public void testSetLockCredential_forProfileWithSeparateChallenge_sendsCredentials()
249 throws Exception {
250 final byte[] pattern = "12345".getBytes();
251
252 mService.setLockCredential(
253 pattern,
254 CREDENTIAL_TYPE_PATTERN,
255 null,
256 PASSWORD_QUALITY_SOMETHING,
257 MANAGED_PROFILE_USER_ID,
258 false);
259
260 verify(mRecoverableKeyStoreManager)
261 .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, pattern, MANAGED_PROFILE_USER_ID);
262 }
263
Kenny Rootd01bb412019-11-22 09:34:03 -0800264 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000265 public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
266 throws Exception {
267 final String oldCredential = "12345";
268 final byte[] newCredential = "newPassword".getBytes();
269 initializeStorageWithCredential(
270 MANAGED_PROFILE_USER_ID,
271 oldCredential,
272 CREDENTIAL_TYPE_PATTERN,
273 PASSWORD_QUALITY_SOMETHING);
274
275 mService.setLockCredential(
276 newCredential,
277 CREDENTIAL_TYPE_PASSWORD,
278 oldCredential.getBytes(),
279 PASSWORD_QUALITY_ALPHABETIC,
280 MANAGED_PROFILE_USER_ID,
281 false);
282
283 verify(mRecoverableKeyStoreManager)
284 .lockScreenSecretChanged(
285 CREDENTIAL_TYPE_PASSWORD, newCredential, MANAGED_PROFILE_USER_ID);
286 }
287
Kenny Rootd01bb412019-11-22 09:34:03 -0800288 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000289 public void testSetLockCredential_forProfileWithUnifiedChallenge_doesNotSendRandomCredential()
290 throws Exception {
291 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
292
293 mService.setLockCredential(
294 "12345".getBytes(),
295 CREDENTIAL_TYPE_PATTERN,
296 null,
297 PASSWORD_QUALITY_SOMETHING,
298 PRIMARY_USER_ID,
299 false);
300
301 verify(mRecoverableKeyStoreManager, never())
302 .lockScreenSecretChanged(
303 eq(CREDENTIAL_TYPE_PASSWORD), any(), eq(MANAGED_PROFILE_USER_ID));
304 }
305
Kenny Rootd01bb412019-11-22 09:34:03 -0800306 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000307 public void
308 testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_updatesBothCredentials()
309 throws Exception {
310 final String oldCredential = "oldPassword";
311 final byte[] newCredential = "newPassword".getBytes();
312 initializeStorageWithCredential(
313 PRIMARY_USER_ID, oldCredential, CREDENTIAL_TYPE_PASSWORD, 1234);
314 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
315
316 mService.setLockCredential(
317 newCredential,
318 CREDENTIAL_TYPE_PASSWORD,
319 oldCredential.getBytes(),
320 PASSWORD_QUALITY_ALPHABETIC,
321 PRIMARY_USER_ID,
322 false);
323
324 verify(mRecoverableKeyStoreManager)
325 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential, PRIMARY_USER_ID);
326 verify(mRecoverableKeyStoreManager)
327 .lockScreenSecretChanged(
328 CREDENTIAL_TYPE_PASSWORD, newCredential, MANAGED_PROFILE_USER_ID);
329 }
330
Kenny Rootd01bb412019-11-22 09:34:03 -0800331 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000332 public void
333 testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
334 throws Exception {
335 final String oldCredential = "oldPassword";
336 initializeStorageWithCredential(
337 PRIMARY_USER_ID, oldCredential, CREDENTIAL_TYPE_PASSWORD, 1234);
338 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
339
340 mService.setLockCredential(
341 null,
342 CREDENTIAL_TYPE_NONE,
343 oldCredential.getBytes(),
344 PASSWORD_QUALITY_UNSPECIFIED,
345 PRIMARY_USER_ID,
346 false);
347
348 verify(mRecoverableKeyStoreManager)
349 .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, PRIMARY_USER_ID);
350 verify(mRecoverableKeyStoreManager)
351 .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, MANAGED_PROFILE_USER_ID);
352 }
353
Kenny Rootd01bb412019-11-22 09:34:03 -0800354 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000355 public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials()
356 throws Exception {
357 final String parentPassword = "parentPassword";
358 final byte[] profilePassword = "profilePassword".getBytes();
359 initializeStorageWithCredential(
360 PRIMARY_USER_ID, parentPassword, CREDENTIAL_TYPE_PASSWORD, 1234);
361 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
362
363 mService.setLockCredential(
364 profilePassword,
365 CREDENTIAL_TYPE_PASSWORD,
366 null,
367 PASSWORD_QUALITY_ALPHABETIC,
368 MANAGED_PROFILE_USER_ID,
369 false);
370
371 verify(mRecoverableKeyStoreManager)
372 .lockScreenSecretChanged(
373 CREDENTIAL_TYPE_PASSWORD, profilePassword, MANAGED_PROFILE_USER_ID);
374 }
375
Kenny Rootd01bb412019-11-22 09:34:03 -0800376 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000377 public void
378 testSetLockCredential_forSeparateToUnifiedChallengeProfile_doesNotSendRandomCredential()
379 throws Exception {
380 final String parentPassword = "parentPassword";
381 final String profilePassword = "12345";
382 initializeStorageWithCredential(
383 PRIMARY_USER_ID, parentPassword, CREDENTIAL_TYPE_PASSWORD, 1234);
384 // Create and verify separate profile credentials.
385 testCreateCredential(
386 MANAGED_PROFILE_USER_ID,
387 profilePassword,
388 CREDENTIAL_TYPE_PATTERN,
389 PASSWORD_QUALITY_SOMETHING);
390
391 mService.setSeparateProfileChallengeEnabled(
392 MANAGED_PROFILE_USER_ID, false, profilePassword.getBytes());
393
394 // Called once for setting the initial separate profile credentials and not again during
395 // unification.
396 verify(mRecoverableKeyStoreManager)
397 .lockScreenSecretChanged(anyInt(), any(), eq(MANAGED_PROFILE_USER_ID));
398 }
399
Kenny Rootd01bb412019-11-22 09:34:03 -0800400 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000401 public void testVerifyCredential_forPrimaryUser_sendsCredentials() throws Exception {
402 final String password = "password";
403 initializeStorageWithCredential(PRIMARY_USER_ID, password, CREDENTIAL_TYPE_PASSWORD, 1234);
404 reset(mRecoverableKeyStoreManager);
405
406 mService.verifyCredential(
407 password.getBytes(), CREDENTIAL_TYPE_PASSWORD, 1, PRIMARY_USER_ID);
408
409 verify(mRecoverableKeyStoreManager)
410 .lockScreenSecretAvailable(
411 CREDENTIAL_TYPE_PASSWORD, password.getBytes(), PRIMARY_USER_ID);
412 }
413
Kenny Rootd01bb412019-11-22 09:34:03 -0800414 @Test
Annie Meng086ddc82019-03-29 17:43:35 +0000415 public void testVerifyCredential_forProfileWithSeparateChallenge_sendsCredentials()
416 throws Exception {
417 final byte[] pattern = "12345".getBytes();
418 mService.setLockCredential(
419 pattern,
420 CREDENTIAL_TYPE_PATTERN,
421 null,
422 PASSWORD_QUALITY_SOMETHING,
423 MANAGED_PROFILE_USER_ID,
424 false);
425 reset(mRecoverableKeyStoreManager);
426
427 mService.verifyCredential(pattern, CREDENTIAL_TYPE_PATTERN, 1, MANAGED_PROFILE_USER_ID);
428
429 verify(mRecoverableKeyStoreManager)
430 .lockScreenSecretAvailable(
431 CREDENTIAL_TYPE_PATTERN, pattern, MANAGED_PROFILE_USER_ID);
432 }
433
Kenny Rootd01bb412019-11-22 09:34:03 -0800434 @Test
435 public void verifyCredential_forPrimaryUserWithUnifiedChallengeProfile_sendsCredentialsForBoth()
Annie Meng086ddc82019-03-29 17:43:35 +0000436 throws Exception {
437 final String pattern = "12345";
438 initializeStorageWithCredential(PRIMARY_USER_ID, pattern, CREDENTIAL_TYPE_PATTERN, 1234);
439 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
440 reset(mRecoverableKeyStoreManager);
441
442 mService.verifyCredential(pattern.getBytes(), CREDENTIAL_TYPE_PATTERN, 1, PRIMARY_USER_ID);
443
444 // Parent sends its credentials for both the parent and profile.
445 verify(mRecoverableKeyStoreManager)
446 .lockScreenSecretAvailable(
447 CREDENTIAL_TYPE_PATTERN, pattern.getBytes(), PRIMARY_USER_ID);
448 verify(mRecoverableKeyStoreManager)
449 .lockScreenSecretAvailable(
450 CREDENTIAL_TYPE_PATTERN, pattern.getBytes(), MANAGED_PROFILE_USER_ID);
451 // Profile doesn't send its own random credentials.
452 verify(mRecoverableKeyStoreManager, never())
453 .lockScreenSecretAvailable(
454 eq(CREDENTIAL_TYPE_PASSWORD), any(), eq(MANAGED_PROFILE_USER_ID));
455 }
456
Adrian Roos7374d3a2017-03-31 14:14:53 -0700457 private void testCreateCredential(int userId, String credential, int type, int quality)
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000458 throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800459 mService.setLockCredential(credential.getBytes(), type, null, quality,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000460 userId, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000461 assertVerifyCredentials(userId, credential, type, -1);
462 }
463
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100464 private void testCreateCredentialFailsWithoutLockScreen(
465 int userId, String credential, int type, int quality) throws RemoteException {
466 mHasSecureLockScreen = false;
467
468 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800469 mService.setLockCredential(credential.getBytes(), type, null, quality,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000470 userId, false);
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100471 fail("An exception should have been thrown.");
472 } catch (UnsupportedOperationException e) {
473 // Success - the exception was expected.
474 }
475
476 assertFalse(mService.havePassword(userId));
477 assertFalse(mService.havePattern(userId));
478 }
479
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000480 private void testChangeCredentials(int userId, String newCredential, int newType,
Adrian Roos7374d3a2017-03-31 14:14:53 -0700481 String oldCredential, int oldType, int quality) throws RemoteException {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000482 final long sid = 1234;
483 initializeStorageWithCredential(userId, oldCredential, oldType, sid);
Rich Canningsf64ec632019-02-21 12:40:36 -0800484 mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000485 quality, userId, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000486 assertVerifyCredentials(userId, newCredential, newType, sid);
487 }
488
489 private void assertVerifyCredentials(int userId, String credential, int type, long sid)
490 throws RemoteException{
491 final long challenge = 54321;
Rich Canningsf64ec632019-02-21 12:40:36 -0800492 VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(),
493 type, challenge, userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000494
495 assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
496 if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
497 final int incorrectType;
498 if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
499 assertTrue(mService.havePassword(userId));
500 assertFalse(mService.havePattern(userId));
501 incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
502 } else if (type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
503 assertFalse(mService.havePassword(userId));
504 assertTrue(mService.havePattern(userId));
505 incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
506 } else {
507 assertFalse(mService.havePassword(userId));
508 assertFalse(mService.havePassword(userId));
509 incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
510 }
511 // check for bad type
Rich Canningsf64ec632019-02-21 12:40:36 -0800512 assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
513 credential.getBytes(), incorrectType, challenge, userId).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000514 // check for bad credential
Rich Canningsf64ec632019-02-21 12:40:36 -0800515 assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
516 ("0" + credential).getBytes(), type, challenge, userId).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000517 }
518
Rubin Xu16c823e2017-06-27 14:44:58 +0100519 private void initializeStorageWithCredential(int userId, String credential, int type, long sid)
520 throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800521 byte[] credentialBytes = credential == null ? null : credential.getBytes();
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000522 byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
Rubin Xu16c823e2017-06-27 14:44:58 +0100523 if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
Rich Canningsf64ec632019-02-21 12:40:36 -0800524 mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type,
Rubin Xu16c823e2017-06-27 14:44:58 +0100525 type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC
526 : PASSWORD_QUALITY_SOMETHING, userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000527 } else {
Rubin Xu16c823e2017-06-27 14:44:58 +0100528 if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
529 mStorage.writeCredentialHash(CredentialHash.create(oldHash,
530 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
531 } else {
532 mStorage.writeCredentialHash(CredentialHash.create(oldHash,
533 LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
534 }
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000535 }
536 }
537}