LockSettingsServiceTests.java revision 8e87af55337a19cf7242a1bf2f516bc26ae65f9e
1/*
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
17package com.android.server;
18
19import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
20import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
21import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
22
23import android.os.RemoteException;
24import android.service.gatekeeper.GateKeeperResponse;
25
26import com.android.internal.widget.LockPatternUtils;
27import com.android.internal.widget.VerifyCredentialResponse;
28import com.android.server.LockSettingsStorage.CredentialHash;
29import com.android.server.MockGateKeeperService.VerifyHandle;
30
31/**
32 * runtest frameworks-services -c com.android.server.LockSettingsServiceTests
33 */
34public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
35
36    @Override
37    protected void setUp() throws Exception {
38        super.setUp();
39    }
40
41    @Override
42    protected void tearDown() throws Exception {
43        super.tearDown();
44    }
45
46    public void testCreatePasswordPrimaryUser() throws RemoteException {
47        testCreateCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD);
48    }
49
50    public void testCreatePatternPrimaryUser() throws RemoteException {
51        testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN);
52    }
53
54    public void testChangePasswordPrimaryUser() throws RemoteException {
55        testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
56                "asdfghjk", CREDENTIAL_TYPE_PASSWORD);
57    }
58
59    public void testChangePatternPrimaryUser() throws RemoteException {
60        testChangeCredentials(PRIMARY_USER_ID, "!£$%^&*(())", CREDENTIAL_TYPE_PASSWORD,
61                "1596321", CREDENTIAL_TYPE_PATTERN);
62    }
63
64    public void testChangePasswordFailPrimaryUser() throws RemoteException {
65        final long sid = 1234;
66        final String FAILED_MESSAGE = "Failed to enroll password";
67        initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
68
69        try {
70            mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd",
71                    PRIMARY_USER_ID);
72            fail("Did not fail when enrolling using incorrect credential");
73        } catch (RemoteException expected) {
74            assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
75        }
76        try {
77            mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, null, PRIMARY_USER_ID);
78            fail("Did not fail when enrolling using incorrect credential");
79        } catch (RemoteException expected) {
80            assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
81        }
82        assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
83    }
84
85    public void testClearPasswordPrimaryUser() throws RemoteException {
86        final String PASSWORD = "password";
87        initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
88        mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD, PRIMARY_USER_ID);
89        assertFalse(mService.havePassword(PRIMARY_USER_ID));
90        assertFalse(mService.havePattern(PRIMARY_USER_ID));
91        assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
92    }
93
94    public void testManagedProfileUnifiedChallenge() throws RemoteException {
95        final String UnifiedPassword = "testManagedProfileUnifiedChallenge-pwd";
96        mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
97                PRIMARY_USER_ID);
98        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
99        final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
100        final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
101        final long turnedOffprofileSid =
102                mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID);
103        assertTrue(primarySid != 0);
104        assertTrue(profileSid != 0);
105        assertTrue(profileSid != primarySid);
106        assertTrue(turnedOffprofileSid != 0);
107        assertTrue(turnedOffprofileSid != primarySid);
108        assertTrue(turnedOffprofileSid != profileSid);
109
110        // clear auth token and wait for verify challenge from primary user to re-generate it.
111        mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
112        mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
113        // verify credential
114        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
115                UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
116                .getResponseCode());
117
118        // Verify that we have a new auth token for the profile
119        assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
120        assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
121
122        // Verify that profile which arent't running (e.g. turn off work) don't get unlocked
123        assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
124
125        /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
126         * credential as part of verifyCredential() before the new credential is committed in
127         * StorageManager. So we relax the check in our mock StorageManager to allow that.
128         */
129        mStorageManager.setIgnoreBadUnlock(true);
130        // Change primary password and verify that profile SID remains
131        mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
132                UnifiedPassword, PRIMARY_USER_ID);
133        mStorageManager.setIgnoreBadUnlock(false);
134        assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
135        assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
136
137        // Clear unified challenge
138        mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, UnifiedPassword,
139                PRIMARY_USER_ID);
140        assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
141        assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
142        assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
143    }
144
145    public void testManagedProfileSeparateChallenge() throws RemoteException {
146        final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
147        final String profilePassword = "testManagedProfileSeparateChallenge-profile";
148        mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
149                PRIMARY_USER_ID);
150        /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
151         * credential as part of verifyCredential() before the new credential is committed in
152         * StorageManager. So we relax the check in our mock StorageManager to allow that.
153         */
154        mStorageManager.setIgnoreBadUnlock(true);
155        mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
156                MANAGED_PROFILE_USER_ID);
157        mStorageManager.setIgnoreBadUnlock(false);
158
159        final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
160        final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
161        assertTrue(primarySid != 0);
162        assertTrue(profileSid != 0);
163        assertTrue(profileSid != primarySid);
164
165        // clear auth token and make sure verify challenge from primary user does not regenerate it.
166        mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
167        // verify primary credential
168        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
169                primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
170                .getResponseCode());
171        assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
172
173        // verify profile credential
174        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
175                profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
176                MANAGED_PROFILE_USER_ID).getResponseCode());
177        assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
178        assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
179
180        // Change primary credential and make sure we don't affect profile
181        mStorageManager.setIgnoreBadUnlock(true);
182        mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
183                primaryPassword, PRIMARY_USER_ID);
184        mStorageManager.setIgnoreBadUnlock(false);
185        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
186                profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
187                MANAGED_PROFILE_USER_ID).getResponseCode());
188        assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
189    }
190
191    private void testCreateCredential(int userId, String credential, int type)
192            throws RemoteException {
193        mService.setLockCredential(credential, type, null, userId);
194        assertVerifyCredentials(userId, credential, type, -1);
195    }
196
197    private void testChangeCredentials(int userId, String newCredential, int newType,
198            String oldCredential, int oldType) throws RemoteException {
199        final long sid = 1234;
200        initializeStorageWithCredential(userId, oldCredential, oldType, sid);
201        mService.setLockCredential(newCredential, newType, oldCredential, userId);
202        assertVerifyCredentials(userId, newCredential, newType, sid);
203    }
204
205    private void assertVerifyCredentials(int userId, String credential, int type, long sid)
206            throws RemoteException{
207        final long challenge = 54321;
208        VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge,
209                userId);
210
211        assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
212        if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
213        final int incorrectType;
214        if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
215            assertTrue(mService.havePassword(userId));
216            assertFalse(mService.havePattern(userId));
217            incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
218        } else if (type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
219            assertFalse(mService.havePassword(userId));
220            assertTrue(mService.havePattern(userId));
221            incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
222        } else {
223            assertFalse(mService.havePassword(userId));
224            assertFalse(mService.havePassword(userId));
225            incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
226        }
227        // check for bad type
228        assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential,
229                incorrectType, challenge, userId).getResponseCode());
230        // check for bad credential
231        assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential,
232                type, challenge, userId).getResponseCode());
233    }
234
235    private void initializeStorageWithCredential(int userId, String credential, int type, long sid) {
236        byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
237        if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
238            mStorage.writeCredentialHash(CredentialHash.create(oldHash,
239                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
240        } else {
241            mStorage.writeCredentialHash(CredentialHash.create(oldHash,
242                    LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
243        }
244    }
245}
246