blob: 67d6eda1b3eefe4e3a62a54fd4e926c52f3b4652 [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
Annie Meng086ddc82019-03-29 17:43:35 +000028import static org.mockito.ArgumentMatchers.any;
29import static org.mockito.ArgumentMatchers.anyInt;
30import static org.mockito.ArgumentMatchers.eq;
31import static org.mockito.Mockito.never;
32import static org.mockito.Mockito.reset;
33import static org.mockito.Mockito.verify;
34
Rubin Xu0cbc19e2016-12-09 14:00:21 +000035import android.os.RemoteException;
Pavel Grafov57f1b662019-03-27 14:55:38 +000036import android.platform.test.annotations.Presubmit;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000037import android.service.gatekeeper.GateKeeperResponse;
38
Pavel Grafov57f1b662019-03-27 14:55:38 +000039import androidx.test.filters.SmallTest;
40
Rubin Xu0cbc19e2016-12-09 14:00:21 +000041import com.android.internal.widget.LockPatternUtils;
42import com.android.internal.widget.VerifyCredentialResponse;
Rubin Xu16c823e2017-06-27 14:44:58 +010043import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
Lenka Trochtova66c492a2018-12-06 11:29:21 +010044import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000045
46/**
Andrew Scull507d11c2017-05-03 17:19:01 +010047 * runtest frameworks-services -c com.android.server.locksettings.LockSettingsServiceTests
Rubin Xu0cbc19e2016-12-09 14:00:21 +000048 */
Pavel Grafov57f1b662019-03-27 14:55:38 +000049@SmallTest
50@Presubmit
Rubin Xu0cbc19e2016-12-09 14:00:21 +000051public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
52
53 @Override
54 protected void setUp() throws Exception {
55 super.setUp();
56 }
57
58 @Override
59 protected void tearDown() throws Exception {
60 super.tearDown();
61 }
62
63 public void testCreatePasswordPrimaryUser() throws RemoteException {
Adrian Roos7374d3a2017-03-31 14:14:53 -070064 testCreateCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD,
65 PASSWORD_QUALITY_ALPHABETIC);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000066 }
67
Lenka Trochtova66c492a2018-12-06 11:29:21 +010068 public void testCreatePasswordFailsWithoutLockScreen() throws RemoteException {
69 testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "password",
70 CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
71 }
72
Rubin Xu0cbc19e2016-12-09 14:00:21 +000073 public void testCreatePatternPrimaryUser() throws RemoteException {
Adrian Roos7374d3a2017-03-31 14:14:53 -070074 testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN,
75 PASSWORD_QUALITY_SOMETHING);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000076 }
77
Lenka Trochtova66c492a2018-12-06 11:29:21 +010078 public void testCreatePatternFailsWithoutLockScreen() throws RemoteException {
79 testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "123456789",
80 CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
81 }
82
Rubin Xu0cbc19e2016-12-09 14:00:21 +000083 public void testChangePasswordPrimaryUser() throws RemoteException {
84 testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
Adrian Roos7374d3a2017-03-31 14:14:53 -070085 "asdfghjk", CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000086 }
87
88 public void testChangePatternPrimaryUser() throws RemoteException {
89 testChangeCredentials(PRIMARY_USER_ID, "!£$%^&*(())", CREDENTIAL_TYPE_PASSWORD,
Adrian Roos7374d3a2017-03-31 14:14:53 -070090 "1596321", CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
Rubin Xu0cbc19e2016-12-09 14:00:21 +000091 }
92
93 public void testChangePasswordFailPrimaryUser() throws RemoteException {
94 final long sid = 1234;
95 final String FAILED_MESSAGE = "Failed to enroll password";
96 initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
97
98 try {
Rich Canningsf64ec632019-02-21 12:40:36 -080099 mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000100 "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000101 fail("Did not fail when enrolling using incorrect credential");
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000102 } catch (IllegalStateException expected) {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000103 assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
104 }
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000105 assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
106 }
107
108 public void testClearPasswordPrimaryUser() throws RemoteException {
109 final String PASSWORD = "password";
110 initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
Rich Canningsf64ec632019-02-21 12:40:36 -0800111 mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000112 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000113 assertFalse(mService.havePassword(PRIMARY_USER_ID));
114 assertFalse(mService.havePattern(PRIMARY_USER_ID));
115 assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
116 }
117
118 public void testManagedProfileUnifiedChallenge() throws RemoteException {
Rubin Xu16c823e2017-06-27 14:44:58 +0100119 final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1";
120 final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
Rich Canningsf64ec632019-02-21 12:40:36 -0800121 mService.setLockCredential(firstUnifiedPassword.getBytes(),
122 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000123 null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000124 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
125 final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
126 final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
Charles Hedec05402017-04-21 13:45:34 +0100127 final long turnedOffProfileSid =
Andrew Scull8e87af52017-03-03 15:38:48 +0000128 mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000129 assertTrue(primarySid != 0);
130 assertTrue(profileSid != 0);
131 assertTrue(profileSid != primarySid);
Charles Hedec05402017-04-21 13:45:34 +0100132 assertTrue(turnedOffProfileSid != 0);
133 assertTrue(turnedOffProfileSid != primarySid);
134 assertTrue(turnedOffProfileSid != profileSid);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000135
136 // clear auth token and wait for verify challenge from primary user to re-generate it.
137 mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
Andrew Scull8e87af52017-03-03 15:38:48 +0000138 mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000139 // verify credential
140 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800141 firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
142 PRIMARY_USER_ID).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000143
144 // Verify that we have a new auth token for the profile
145 assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
146 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
147
Charles Hedec05402017-04-21 13:45:34 +0100148 // Verify that profile which aren't running (e.g. turn off work) don't get unlocked
Andrew Scull8e87af52017-03-03 15:38:48 +0000149 assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
150
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000151 /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
152 * credential as part of verifyCredential() before the new credential is committed in
153 * StorageManager. So we relax the check in our mock StorageManager to allow that.
154 */
155 mStorageManager.setIgnoreBadUnlock(true);
156 // Change primary password and verify that profile SID remains
Rich Canningsf64ec632019-02-21 12:40:36 -0800157 mService.setLockCredential(secondUnifiedPassword.getBytes(),
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000158 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, firstUnifiedPassword.getBytes(),
159 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000160 mStorageManager.setIgnoreBadUnlock(false);
161 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
Andrew Scull8e87af52017-03-03 15:38:48 +0000162 assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
Rubin Xu3bf722a2016-12-15 16:07:38 +0000163
Andrew Scull8e87af52017-03-03 15:38:48 +0000164 // Clear unified challenge
Rubin Xu16c823e2017-06-27 14:44:58 +0100165 mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000166 secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID,
167 false);
Rubin Xu3bf722a2016-12-15 16:07:38 +0000168 assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
169 assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
Andrew Scull8e87af52017-03-03 15:38:48 +0000170 assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000171 }
172
173 public void testManagedProfileSeparateChallenge() throws RemoteException {
174 final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
175 final String profilePassword = "testManagedProfileSeparateChallenge-profile";
Rich Canningsf64ec632019-02-21 12:40:36 -0800176 mService.setLockCredential(primaryPassword.getBytes(),
177 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000178 PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000179 /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
180 * credential as part of verifyCredential() before the new credential is committed in
181 * StorageManager. So we relax the check in our mock StorageManager to allow that.
182 */
183 mStorageManager.setIgnoreBadUnlock(true);
Rich Canningsf64ec632019-02-21 12:40:36 -0800184 mService.setLockCredential(profilePassword.getBytes(),
185 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000186 PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000187 mStorageManager.setIgnoreBadUnlock(false);
188
189 final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
190 final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
191 assertTrue(primarySid != 0);
192 assertTrue(profileSid != 0);
193 assertTrue(profileSid != primarySid);
194
195 // clear auth token and make sure verify challenge from primary user does not regenerate it.
196 mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
197 // verify primary credential
198 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800199 primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
200 PRIMARY_USER_ID).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000201 assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
202
203 // verify profile credential
204 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800205 profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000206 MANAGED_PROFILE_USER_ID).getResponseCode());
207 assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
208 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
209
210 // Change primary credential and make sure we don't affect profile
211 mStorageManager.setIgnoreBadUnlock(true);
Rich Canningsf64ec632019-02-21 12:40:36 -0800212 mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000213 primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000214 mStorageManager.setIgnoreBadUnlock(false);
215 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
Rich Canningsf64ec632019-02-21 12:40:36 -0800216 profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000217 MANAGED_PROFILE_USER_ID).getResponseCode());
218 assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
219 }
220
Annie Meng086ddc82019-03-29 17:43:35 +0000221 public void testSetLockCredential_forPrimaryUser_sendsCredentials() throws Exception {
222 final byte[] password = "password".getBytes();
223
224 mService.setLockCredential(
225 password,
226 CREDENTIAL_TYPE_PASSWORD,
227 null,
228 PASSWORD_QUALITY_ALPHABETIC,
229 PRIMARY_USER_ID,
230 false);
231
232 verify(mRecoverableKeyStoreManager)
233 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, password, PRIMARY_USER_ID);
234 }
235
236 public void testSetLockCredential_forProfileWithSeparateChallenge_sendsCredentials()
237 throws Exception {
238 final byte[] pattern = "12345".getBytes();
239
240 mService.setLockCredential(
241 pattern,
242 CREDENTIAL_TYPE_PATTERN,
243 null,
244 PASSWORD_QUALITY_SOMETHING,
245 MANAGED_PROFILE_USER_ID,
246 false);
247
248 verify(mRecoverableKeyStoreManager)
249 .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, pattern, MANAGED_PROFILE_USER_ID);
250 }
251
252 public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
253 throws Exception {
254 final String oldCredential = "12345";
255 final byte[] newCredential = "newPassword".getBytes();
256 initializeStorageWithCredential(
257 MANAGED_PROFILE_USER_ID,
258 oldCredential,
259 CREDENTIAL_TYPE_PATTERN,
260 PASSWORD_QUALITY_SOMETHING);
261
262 mService.setLockCredential(
263 newCredential,
264 CREDENTIAL_TYPE_PASSWORD,
265 oldCredential.getBytes(),
266 PASSWORD_QUALITY_ALPHABETIC,
267 MANAGED_PROFILE_USER_ID,
268 false);
269
270 verify(mRecoverableKeyStoreManager)
271 .lockScreenSecretChanged(
272 CREDENTIAL_TYPE_PASSWORD, newCredential, MANAGED_PROFILE_USER_ID);
273 }
274
275 public void testSetLockCredential_forProfileWithUnifiedChallenge_doesNotSendRandomCredential()
276 throws Exception {
277 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
278
279 mService.setLockCredential(
280 "12345".getBytes(),
281 CREDENTIAL_TYPE_PATTERN,
282 null,
283 PASSWORD_QUALITY_SOMETHING,
284 PRIMARY_USER_ID,
285 false);
286
287 verify(mRecoverableKeyStoreManager, never())
288 .lockScreenSecretChanged(
289 eq(CREDENTIAL_TYPE_PASSWORD), any(), eq(MANAGED_PROFILE_USER_ID));
290 }
291
292 public void
293 testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_updatesBothCredentials()
294 throws Exception {
295 final String oldCredential = "oldPassword";
296 final byte[] newCredential = "newPassword".getBytes();
297 initializeStorageWithCredential(
298 PRIMARY_USER_ID, oldCredential, CREDENTIAL_TYPE_PASSWORD, 1234);
299 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
300
301 mService.setLockCredential(
302 newCredential,
303 CREDENTIAL_TYPE_PASSWORD,
304 oldCredential.getBytes(),
305 PASSWORD_QUALITY_ALPHABETIC,
306 PRIMARY_USER_ID,
307 false);
308
309 verify(mRecoverableKeyStoreManager)
310 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential, PRIMARY_USER_ID);
311 verify(mRecoverableKeyStoreManager)
312 .lockScreenSecretChanged(
313 CREDENTIAL_TYPE_PASSWORD, newCredential, MANAGED_PROFILE_USER_ID);
314 }
315
316 public void
317 testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
318 throws Exception {
319 final String oldCredential = "oldPassword";
320 initializeStorageWithCredential(
321 PRIMARY_USER_ID, oldCredential, CREDENTIAL_TYPE_PASSWORD, 1234);
322 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
323
324 mService.setLockCredential(
325 null,
326 CREDENTIAL_TYPE_NONE,
327 oldCredential.getBytes(),
328 PASSWORD_QUALITY_UNSPECIFIED,
329 PRIMARY_USER_ID,
330 false);
331
332 verify(mRecoverableKeyStoreManager)
333 .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, PRIMARY_USER_ID);
334 verify(mRecoverableKeyStoreManager)
335 .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, MANAGED_PROFILE_USER_ID);
336 }
337
338 public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials()
339 throws Exception {
340 final String parentPassword = "parentPassword";
341 final byte[] profilePassword = "profilePassword".getBytes();
342 initializeStorageWithCredential(
343 PRIMARY_USER_ID, parentPassword, CREDENTIAL_TYPE_PASSWORD, 1234);
344 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
345
346 mService.setLockCredential(
347 profilePassword,
348 CREDENTIAL_TYPE_PASSWORD,
349 null,
350 PASSWORD_QUALITY_ALPHABETIC,
351 MANAGED_PROFILE_USER_ID,
352 false);
353
354 verify(mRecoverableKeyStoreManager)
355 .lockScreenSecretChanged(
356 CREDENTIAL_TYPE_PASSWORD, profilePassword, MANAGED_PROFILE_USER_ID);
357 }
358
359 public void
360 testSetLockCredential_forSeparateToUnifiedChallengeProfile_doesNotSendRandomCredential()
361 throws Exception {
362 final String parentPassword = "parentPassword";
363 final String profilePassword = "12345";
364 initializeStorageWithCredential(
365 PRIMARY_USER_ID, parentPassword, CREDENTIAL_TYPE_PASSWORD, 1234);
366 // Create and verify separate profile credentials.
367 testCreateCredential(
368 MANAGED_PROFILE_USER_ID,
369 profilePassword,
370 CREDENTIAL_TYPE_PATTERN,
371 PASSWORD_QUALITY_SOMETHING);
372
373 mService.setSeparateProfileChallengeEnabled(
374 MANAGED_PROFILE_USER_ID, false, profilePassword.getBytes());
375
376 // Called once for setting the initial separate profile credentials and not again during
377 // unification.
378 verify(mRecoverableKeyStoreManager)
379 .lockScreenSecretChanged(anyInt(), any(), eq(MANAGED_PROFILE_USER_ID));
380 }
381
382 public void testVerifyCredential_forPrimaryUser_sendsCredentials() throws Exception {
383 final String password = "password";
384 initializeStorageWithCredential(PRIMARY_USER_ID, password, CREDENTIAL_TYPE_PASSWORD, 1234);
385 reset(mRecoverableKeyStoreManager);
386
387 mService.verifyCredential(
388 password.getBytes(), CREDENTIAL_TYPE_PASSWORD, 1, PRIMARY_USER_ID);
389
390 verify(mRecoverableKeyStoreManager)
391 .lockScreenSecretAvailable(
392 CREDENTIAL_TYPE_PASSWORD, password.getBytes(), PRIMARY_USER_ID);
393 }
394
395 public void testVerifyCredential_forProfileWithSeparateChallenge_sendsCredentials()
396 throws Exception {
397 final byte[] pattern = "12345".getBytes();
398 mService.setLockCredential(
399 pattern,
400 CREDENTIAL_TYPE_PATTERN,
401 null,
402 PASSWORD_QUALITY_SOMETHING,
403 MANAGED_PROFILE_USER_ID,
404 false);
405 reset(mRecoverableKeyStoreManager);
406
407 mService.verifyCredential(pattern, CREDENTIAL_TYPE_PATTERN, 1, MANAGED_PROFILE_USER_ID);
408
409 verify(mRecoverableKeyStoreManager)
410 .lockScreenSecretAvailable(
411 CREDENTIAL_TYPE_PATTERN, pattern, MANAGED_PROFILE_USER_ID);
412 }
413
414 public void
415 testVerifyCredential_forPrimaryUserWithUnifiedChallengeProfile_sendsCredentialsForBoth()
416 throws Exception {
417 final String pattern = "12345";
418 initializeStorageWithCredential(PRIMARY_USER_ID, pattern, CREDENTIAL_TYPE_PATTERN, 1234);
419 mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
420 reset(mRecoverableKeyStoreManager);
421
422 mService.verifyCredential(pattern.getBytes(), CREDENTIAL_TYPE_PATTERN, 1, PRIMARY_USER_ID);
423
424 // Parent sends its credentials for both the parent and profile.
425 verify(mRecoverableKeyStoreManager)
426 .lockScreenSecretAvailable(
427 CREDENTIAL_TYPE_PATTERN, pattern.getBytes(), PRIMARY_USER_ID);
428 verify(mRecoverableKeyStoreManager)
429 .lockScreenSecretAvailable(
430 CREDENTIAL_TYPE_PATTERN, pattern.getBytes(), MANAGED_PROFILE_USER_ID);
431 // Profile doesn't send its own random credentials.
432 verify(mRecoverableKeyStoreManager, never())
433 .lockScreenSecretAvailable(
434 eq(CREDENTIAL_TYPE_PASSWORD), any(), eq(MANAGED_PROFILE_USER_ID));
435 }
436
Adrian Roos7374d3a2017-03-31 14:14:53 -0700437 private void testCreateCredential(int userId, String credential, int type, int quality)
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000438 throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800439 mService.setLockCredential(credential.getBytes(), type, null, quality,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000440 userId, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000441 assertVerifyCredentials(userId, credential, type, -1);
442 }
443
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100444 private void testCreateCredentialFailsWithoutLockScreen(
445 int userId, String credential, int type, int quality) throws RemoteException {
446 mHasSecureLockScreen = false;
447
448 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800449 mService.setLockCredential(credential.getBytes(), type, null, quality,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000450 userId, false);
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100451 fail("An exception should have been thrown.");
452 } catch (UnsupportedOperationException e) {
453 // Success - the exception was expected.
454 }
455
456 assertFalse(mService.havePassword(userId));
457 assertFalse(mService.havePattern(userId));
458 }
459
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000460 private void testChangeCredentials(int userId, String newCredential, int newType,
Adrian Roos7374d3a2017-03-31 14:14:53 -0700461 String oldCredential, int oldType, int quality) throws RemoteException {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000462 final long sid = 1234;
463 initializeStorageWithCredential(userId, oldCredential, oldType, sid);
Rich Canningsf64ec632019-02-21 12:40:36 -0800464 mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000465 quality, userId, false);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000466 assertVerifyCredentials(userId, newCredential, newType, sid);
467 }
468
469 private void assertVerifyCredentials(int userId, String credential, int type, long sid)
470 throws RemoteException{
471 final long challenge = 54321;
Rich Canningsf64ec632019-02-21 12:40:36 -0800472 VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(),
473 type, challenge, userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000474
475 assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
476 if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
477 final int incorrectType;
478 if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
479 assertTrue(mService.havePassword(userId));
480 assertFalse(mService.havePattern(userId));
481 incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
482 } else if (type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
483 assertFalse(mService.havePassword(userId));
484 assertTrue(mService.havePattern(userId));
485 incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
486 } else {
487 assertFalse(mService.havePassword(userId));
488 assertFalse(mService.havePassword(userId));
489 incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
490 }
491 // check for bad type
Rich Canningsf64ec632019-02-21 12:40:36 -0800492 assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
493 credential.getBytes(), incorrectType, challenge, userId).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000494 // check for bad credential
Rich Canningsf64ec632019-02-21 12:40:36 -0800495 assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
496 ("0" + credential).getBytes(), type, challenge, userId).getResponseCode());
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000497 }
498
Rubin Xu16c823e2017-06-27 14:44:58 +0100499 private void initializeStorageWithCredential(int userId, String credential, int type, long sid)
500 throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800501 byte[] credentialBytes = credential == null ? null : credential.getBytes();
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000502 byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
Rubin Xu16c823e2017-06-27 14:44:58 +0100503 if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
Rich Canningsf64ec632019-02-21 12:40:36 -0800504 mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type,
Rubin Xu16c823e2017-06-27 14:44:58 +0100505 type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC
506 : PASSWORD_QUALITY_SOMETHING, userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000507 } else {
Rubin Xu16c823e2017-06-27 14:44:58 +0100508 if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
509 mStorage.writeCredentialHash(CredentialHash.create(oldHash,
510 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
511 } else {
512 mStorage.writeCredentialHash(CredentialHash.create(oldHash,
513 LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
514 }
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000515 }
516 }
517}