blob: 73ab223b618cd0936dea5ae6752b131f5e6f2995 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.settings.security;
import static com.google.common.truth.Truth.assertThat;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.os.RemoteException;
import com.android.car.settings.CarSettingsRobolectricTestRunner;
import com.android.car.settings.setupservice.InitialLockSetupService;
import com.android.car.settings.testutils.ShadowLockPatternUtils;
import com.android.car.setupwizardlib.IInitialLockSetupService;
import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes;
import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes;
import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags;
import com.android.car.setupwizardlib.InitialLockSetupHelper;
import com.android.car.setupwizardlib.LockConfig;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowContextWrapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Tests that the {@link InitialLockSetupService} properly handles connections and lock requests.
*/
@Config(shadows = ShadowLockPatternUtils.class)
@RunWith(CarSettingsRobolectricTestRunner.class)
public class InitialLockSetupServiceTest {
private static final String LOCK_PERMISSION = "com.android.car.settings.SET_INITIAL_LOCK";
private InitialLockSetupService mInitialLockSetupService;
private Context mContext;
@Before
public void setupService() {
ShadowLockPatternUtils.reset();
mInitialLockSetupService = Robolectric.buildService(InitialLockSetupService.class)
.create()
.get();
mContext = RuntimeEnvironment.application;
ShadowContextWrapper shadowContextWrapper = Shadows.shadowOf((ContextWrapper) mContext);
shadowContextWrapper.grantPermissions(LOCK_PERMISSION);
}
@Test
public void testBindReturnsNull_ifLockSet() {
ShadowLockPatternUtils.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
assertThat(mInitialLockSetupService.onBind(new Intent())).isNull();
}
@Test
public void testBindReturnsInstanceOfServiceInterface_ifLockNotSet() throws RemoteException {
assertThat(mInitialLockSetupService.onBind(
new Intent()) instanceof IInitialLockSetupService.Stub).isTrue();
}
@Test
public void testGetLockConfig_returnsCorrectConfig() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
LockConfig pinConfig = service.getLockConfig(LockTypes.PIN);
assertThat(pinConfig.enabled).isTrue();
assertThat(pinConfig.minLockLength).isEqualTo(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
LockConfig patternConfig = service.getLockConfig(LockTypes.PATTERN);
assertThat(patternConfig.enabled).isTrue();
assertThat(patternConfig.minLockLength).isEqualTo(LockPatternUtils.MIN_LOCK_PATTERN_SIZE);
LockConfig passwordConfig = service.getLockConfig(LockTypes.PASSWORD);
assertThat(passwordConfig.enabled).isTrue();
assertThat(passwordConfig.minLockLength).isEqualTo(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
}
@Test
public void testCheckValidLock_tooShort() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
int result = service.checkValidLock(LockTypes.PASSWORD, "hi".getBytes());
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
.isEqualTo(ValidateLockFlags.INVALID_LENGTH);
}
@Test
public void testCheckValidLock_longEnough() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
int result = service.checkValidLock(LockTypes.PASSWORD, "password".getBytes());
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
.isNotEqualTo(ValidateLockFlags.INVALID_LENGTH);
}
@Test
public void testCheckValidLockPin_withLetters() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
int result = service.checkValidLock(LockTypes.PIN, "12a3".getBytes());
assertThat(result & ValidateLockFlags.INVALID_BAD_SYMBOLS)
.isEqualTo(ValidateLockFlags.INVALID_BAD_SYMBOLS);
}
@Test
public void testCheckValidLockPattern_tooShort() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
byte[] pattern = new byte[LockPatternUtils.MIN_LOCK_PATTERN_SIZE - 1];
for (int i = 0; i < pattern.length; i++) {
pattern[i] = (byte) i;
}
int result = service.checkValidLock(LockTypes.PATTERN, pattern);
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
.isEqualTo(ValidateLockFlags.INVALID_LENGTH);
}
@Test
public void testCheckValidLockPattern_longEnough() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
byte[] pattern = new byte[LockPatternUtils.MIN_LOCK_PATTERN_SIZE + 1];
for (int i = 0; i < pattern.length; i++) {
pattern[i] = (byte) i;
}
int result = service.checkValidLock(LockTypes.PATTERN, pattern);
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
.isNotEqualTo(ValidateLockFlags.INVALID_LENGTH);
}
@Test
public void testSetLockPassword_doesNotWorkWithExistingPassword() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
ShadowLockPatternUtils.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
int result = service.setLock(LockTypes.PASSWORD, "password".getBytes());
assertThat(result).isEqualTo(SetLockCodes.FAIL_LOCK_EXISTS);
}
@Test
public void testSetLockPassword_doesNotWorkWithInvalidPassword() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
int result = service.setLock(LockTypes.PASSWORD, "hi".getBytes());
assertThat(result).isEqualTo(SetLockCodes.FAIL_LOCK_INVALID);
}
@Test
public void testSetLockPassword_setsDevicePassword() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
byte[] password = "password".getBytes();
// Need copy since password is cleared.
byte[] expectedPassword = Arrays.copyOf(password, password.length);
int result = service.setLock(LockTypes.PASSWORD, password);
assertThat(result).isEqualTo(SetLockCodes.SUCCESS);
assertThat(Arrays.equals(ShadowLockPatternUtils.getSavedPassword(),
expectedPassword)).isTrue();
}
@Test
public void testSetLockPin_setsDevicePin() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
byte[] password = "1580".getBytes();
byte[] expectedPassword = Arrays.copyOf(password, password.length);
int result = service.setLock(LockTypes.PIN, password);
assertThat(result).isEqualTo(SetLockCodes.SUCCESS);
assertThat(Arrays.equals(ShadowLockPatternUtils.getSavedPassword(),
expectedPassword)).isTrue();
}
@Test
public void testSetLockPattern_setsDevicePattern() throws RemoteException {
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
mInitialLockSetupService.onBind(new Intent()));
List<LockPatternView.Cell> pattern = new ArrayList<>();
pattern.add(LockPatternView.Cell.of(0, 0));
pattern.add(LockPatternView.Cell.of(1, 0));
pattern.add(LockPatternView.Cell.of(2, 0));
pattern.add(LockPatternView.Cell.of(0, 1));
byte[] patternBytes = new byte[pattern.size()];
for (int i = 0; i < patternBytes.length; i++) {
LockPatternView.Cell cell = pattern.get(i);
patternBytes[i] = InitialLockSetupHelper.getByteFromPatternCell(cell.getRow(),
cell.getColumn());
}
int result = service.setLock(LockTypes.PATTERN, patternBytes);
assertThat(result).isEqualTo(SetLockCodes.SUCCESS);
List<LockPatternView.Cell> savedPattern = ShadowLockPatternUtils.getSavedPattern();
assertThat(savedPattern).containsExactlyElementsIn(pattern);
}
@Test
public void testBindFails_ifNoPermissionGranted() {
ShadowContextWrapper shadowContextWrapper = Shadows.shadowOf((ContextWrapper) mContext);
shadowContextWrapper.denyPermissions(LOCK_PERMISSION);
assertThat(mInitialLockSetupService.onBind(new Intent())).isNull();
}
}