blob: d2a914527880446fd16f14c5064bd662b8a5a72c [file] [log] [blame]
Andrew Scull1416bd02018-01-05 18:33:58 +00001/*
2 * Copyright (C) 2018 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 */
16package com.android.server.locksettings;
17
18import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
19import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
20
Andrew Scull1416bd02018-01-05 18:33:58 +000021import static com.android.server.testutils.TestUtils.assertExpectException;
22
23import static org.mockito.Mockito.anyInt;
Andrew Sculle6527c12018-01-05 18:33:58 +000024import static org.mockito.Mockito.atLeastOnce;
Andrew Scull1416bd02018-01-05 18:33:58 +000025import static org.mockito.Mockito.verify;
Rich Canningsf64ec632019-02-21 12:40:36 -080026import static org.mockito.Mockito.when;
Andrew Scull1416bd02018-01-05 18:33:58 +000027
28import android.os.RemoteException;
Pavel Grafov57f1b662019-03-27 14:55:38 +000029import android.platform.test.annotations.Presubmit;
30
31import androidx.test.filters.SmallTest;
Andrew Scull1416bd02018-01-05 18:33:58 +000032
33import com.android.internal.widget.LockPatternUtils;
34import com.android.internal.widget.VerifyCredentialResponse;
Andrew Sculle6527c12018-01-05 18:33:58 +000035
36import org.mockito.ArgumentCaptor;
37
Rich Canningsf64ec632019-02-21 12:40:36 -080038import java.util.ArrayList;
39
Andrew Scull1416bd02018-01-05 18:33:58 +000040/**
41 * Run the synthetic password tests with caching enabled.
42 *
43 * By default, those tests run without caching. Untrusted credential reset depends on caching so
44 * this class included those tests.
45 */
Pavel Grafov57f1b662019-03-27 14:55:38 +000046@SmallTest
47@Presubmit
Andrew Scull1416bd02018-01-05 18:33:58 +000048public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
49
50 @Override
51 protected void setUp() throws Exception {
52 super.setUp();
53 enableSpCaching(true);
54 }
55
56 private void enableSpCaching(boolean enable) {
57 when(mDevicePolicyManagerInternal
58 .canUserHaveUntrustedCredentialReset(anyInt())).thenReturn(enable);
59 }
60
61 public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -080062 final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
63 final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
Andrew Scull1416bd02018-01-05 18:33:58 +000064
Rich Canningsf64ec632019-02-21 12:40:36 -080065 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Scull1416bd02018-01-05 18:33:58 +000066 long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
67 // clear password
68 mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +000069 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, true);
Andrew Scull1416bd02018-01-05 18:33:58 +000070 assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
71
72 // set a new password
Rich Canningsf64ec632019-02-21 12:40:36 -080073 mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +000074 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rich Canningsf64ec632019-02-21 12:40:36 -080075 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
76 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
77 .getResponseCode());
Andrew Scull1416bd02018-01-05 18:33:58 +000078 assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
79 }
80
81 public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -080082 final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
83 final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
Andrew Scull1416bd02018-01-05 18:33:58 +000084
Rich Canningsf64ec632019-02-21 12:40:36 -080085 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Scull1416bd02018-01-05 18:33:58 +000086 long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
87 // Untrusted change password
Rich Canningsf64ec632019-02-21 12:40:36 -080088 mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +000089 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
Andrew Scull1416bd02018-01-05 18:33:58 +000090 assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
91 assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
92
93 // Verify the password
Rich Canningsf64ec632019-02-21 12:40:36 -080094 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
95 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
Andrew Scull1416bd02018-01-05 18:33:58 +000096 }
97
Andrew Sculle6527c12018-01-05 18:33:58 +000098 public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -080099 final byte[] password =
100 "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes();
101 final byte[] newPassword =
102 "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes();
Andrew Sculle6527c12018-01-05 18:33:58 +0000103
Rich Canningsf64ec632019-02-21 12:40:36 -0800104 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Sculle6527c12018-01-05 18:33:58 +0000105 // Untrusted change password
Rich Canningsf64ec632019-02-21 12:40:36 -0800106 mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000107 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
Andrew Sculle6527c12018-01-05 18:33:58 +0000108
109 // Verify the password
Rich Canningsf64ec632019-02-21 12:40:36 -0800110 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
111 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
112 .getResponseCode());
Andrew Sculle6527c12018-01-05 18:33:58 +0000113
114 // Ensure the same secret was passed each time
115 ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
116 verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture());
117 assertEquals(1, secret.getAllValues().stream().distinct().count());
118 }
119
Andrew Scull1416bd02018-01-05 18:33:58 +0000120 public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800121 final byte[] password =
122 "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes();
123 final byte[] newPassword =
124 "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes();
Andrew Scull1416bd02018-01-05 18:33:58 +0000125
126 // Disable caching for this test
127 enableSpCaching(false);
128
Rich Canningsf64ec632019-02-21 12:40:36 -0800129 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Scull1416bd02018-01-05 18:33:58 +0000130 long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
131 // Untrusted change password
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000132 assertExpectException(
133 IllegalStateException.class,
134 /* messageRegex= */ "Untrusted credential reset not possible without cached SP",
Rich Canningsf64ec632019-02-21 12:40:36 -0800135 () -> mService.setLockCredential(newPassword,
136 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000137 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true));
Andrew Scull1416bd02018-01-05 18:33:58 +0000138 assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
139
140 // Verify the new password doesn't work but the old one still does
Rich Canningsf64ec632019-02-21 12:40:36 -0800141 assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword,
142 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
Andrew Scull1416bd02018-01-05 18:33:58 +0000143 .getResponseCode());
Rich Canningsf64ec632019-02-21 12:40:36 -0800144 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
145 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
Andrew Scull1416bd02018-01-05 18:33:58 +0000146 .getResponseCode());
147 }
148
149}