blob: 6616c967ff9bda99b011d167677ad12e35a6d9c5 [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
Kenny Rootd01bb412019-11-22 09:34:03 -080023import static org.junit.Assert.assertEquals;
Andrew Scull1416bd02018-01-05 18:33:58 +000024import static org.mockito.Mockito.anyInt;
Andrew Sculle6527c12018-01-05 18:33:58 +000025import static org.mockito.Mockito.atLeastOnce;
Andrew Scull1416bd02018-01-05 18:33:58 +000026import static org.mockito.Mockito.verify;
Rich Canningsf64ec632019-02-21 12:40:36 -080027import static org.mockito.Mockito.when;
Andrew Scull1416bd02018-01-05 18:33:58 +000028
29import android.os.RemoteException;
Pavel Grafov57f1b662019-03-27 14:55:38 +000030import android.platform.test.annotations.Presubmit;
31
32import androidx.test.filters.SmallTest;
Kenny Rootd01bb412019-11-22 09:34:03 -080033import androidx.test.runner.AndroidJUnit4;
Andrew Scull1416bd02018-01-05 18:33:58 +000034
35import com.android.internal.widget.LockPatternUtils;
36import com.android.internal.widget.VerifyCredentialResponse;
Andrew Sculle6527c12018-01-05 18:33:58 +000037
Kenny Rootd01bb412019-11-22 09:34:03 -080038import org.junit.Before;
39import org.junit.Test;
40import org.junit.runner.RunWith;
Andrew Sculle6527c12018-01-05 18:33:58 +000041import org.mockito.ArgumentCaptor;
42
Rich Canningsf64ec632019-02-21 12:40:36 -080043import java.util.ArrayList;
44
Andrew Scull1416bd02018-01-05 18:33:58 +000045/**
46 * Run the synthetic password tests with caching enabled.
47 *
48 * By default, those tests run without caching. Untrusted credential reset depends on caching so
49 * this class included those tests.
50 */
Pavel Grafov57f1b662019-03-27 14:55:38 +000051@SmallTest
52@Presubmit
Kenny Rootd01bb412019-11-22 09:34:03 -080053@RunWith(AndroidJUnit4.class)
Andrew Scull1416bd02018-01-05 18:33:58 +000054public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
55
Kenny Rootd01bb412019-11-22 09:34:03 -080056 @Before
57 public void enableSpCache() throws Exception {
Andrew Scull1416bd02018-01-05 18:33:58 +000058 enableSpCaching(true);
59 }
60
61 private void enableSpCaching(boolean enable) {
62 when(mDevicePolicyManagerInternal
63 .canUserHaveUntrustedCredentialReset(anyInt())).thenReturn(enable);
64 }
65
Kenny Rootd01bb412019-11-22 09:34:03 -080066 @Test
Andrew Scull1416bd02018-01-05 18:33:58 +000067 public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -080068 final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
69 final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
Andrew Scull1416bd02018-01-05 18:33:58 +000070
Rich Canningsf64ec632019-02-21 12:40:36 -080071 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Scull1416bd02018-01-05 18:33:58 +000072 long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
73 // clear password
74 mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +000075 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, true);
Andrew Scull1416bd02018-01-05 18:33:58 +000076 assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
77
78 // set a new password
Rich Canningsf64ec632019-02-21 12:40:36 -080079 mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +000080 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
Rich Canningsf64ec632019-02-21 12:40:36 -080081 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
82 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
83 .getResponseCode());
Andrew Scull1416bd02018-01-05 18:33:58 +000084 assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
85 }
86
Kenny Rootd01bb412019-11-22 09:34:03 -080087 @Test
Andrew Scull1416bd02018-01-05 18:33:58 +000088 public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -080089 final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
90 final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
Andrew Scull1416bd02018-01-05 18:33:58 +000091
Rich Canningsf64ec632019-02-21 12:40:36 -080092 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Scull1416bd02018-01-05 18:33:58 +000093 long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
94 // Untrusted change password
Rich Canningsf64ec632019-02-21 12:40:36 -080095 mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +000096 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
Andrew Scull1416bd02018-01-05 18:33:58 +000097 assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
98 assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
99
100 // Verify the password
Rich Canningsf64ec632019-02-21 12:40:36 -0800101 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
102 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
Andrew Scull1416bd02018-01-05 18:33:58 +0000103 }
104
Kenny Rootd01bb412019-11-22 09:34:03 -0800105 @Test
Andrew Sculle6527c12018-01-05 18:33:58 +0000106 public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800107 final byte[] password =
108 "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes();
109 final byte[] newPassword =
110 "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes();
Andrew Sculle6527c12018-01-05 18:33:58 +0000111
Rich Canningsf64ec632019-02-21 12:40:36 -0800112 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Sculle6527c12018-01-05 18:33:58 +0000113 // Untrusted change password
Rich Canningsf64ec632019-02-21 12:40:36 -0800114 mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000115 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
Andrew Sculle6527c12018-01-05 18:33:58 +0000116
117 // Verify the password
Rich Canningsf64ec632019-02-21 12:40:36 -0800118 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
119 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
120 .getResponseCode());
Andrew Sculle6527c12018-01-05 18:33:58 +0000121
122 // Ensure the same secret was passed each time
123 ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
124 verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture());
125 assertEquals(1, secret.getAllValues().stream().distinct().count());
126 }
127
Kenny Rootd01bb412019-11-22 09:34:03 -0800128 @Test
Andrew Scull1416bd02018-01-05 18:33:58 +0000129 public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800130 final byte[] password =
131 "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes();
132 final byte[] newPassword =
133 "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes();
Andrew Scull1416bd02018-01-05 18:33:58 +0000134
135 // Disable caching for this test
136 enableSpCaching(false);
137
Rich Canningsf64ec632019-02-21 12:40:36 -0800138 initializeCredentialUnderSP(password, PRIMARY_USER_ID);
Andrew Scull1416bd02018-01-05 18:33:58 +0000139 long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
140 // Untrusted change password
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000141 assertExpectException(
142 IllegalStateException.class,
143 /* messageRegex= */ "Untrusted credential reset not possible without cached SP",
Rich Canningsf64ec632019-02-21 12:40:36 -0800144 () -> mService.setLockCredential(newPassword,
145 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000146 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true));
Andrew Scull1416bd02018-01-05 18:33:58 +0000147 assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
148
149 // Verify the new password doesn't work but the old one still does
Rich Canningsf64ec632019-02-21 12:40:36 -0800150 assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword,
151 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
Andrew Scull1416bd02018-01-05 18:33:58 +0000152 .getResponseCode());
Rich Canningsf64ec632019-02-21 12:40:36 -0800153 assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
154 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
Andrew Scull1416bd02018-01-05 18:33:58 +0000155 .getResponseCode());
156 }
157
158}