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 17 package com.android.server.locksettings; 18 19 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH; 20 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW; 21 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM; 22 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; 23 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 24 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 25 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 26 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 27 28 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; 29 30 import static junit.framework.Assert.assertEquals; 31 32 import static org.mockito.ArgumentMatchers.anyInt; 33 import static org.mockito.Mockito.any; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.verifyNoMoreInteractions; 37 import static org.mockito.Mockito.when; 38 39 import static java.io.FileDescriptor.err; 40 import static java.io.FileDescriptor.in; 41 import static java.io.FileDescriptor.out; 42 43 import android.app.ActivityManager; 44 import android.app.admin.PasswordMetrics; 45 import android.app.admin.PasswordPolicy; 46 import android.content.Context; 47 import android.os.Binder; 48 import android.os.Handler; 49 import android.os.Looper; 50 import android.os.Process; 51 import android.os.ResultReceiver; 52 import android.os.ShellCallback; 53 import android.os.UserHandle; 54 import android.platform.test.annotations.Presubmit; 55 56 import androidx.test.InstrumentationRegistry; 57 import androidx.test.filters.SmallTest; 58 import androidx.test.runner.AndroidJUnit4; 59 60 import com.android.internal.widget.LockPatternUtils; 61 import com.android.internal.widget.LockPatternView; 62 import com.android.internal.widget.LockscreenCredential; 63 64 import org.junit.Before; 65 import org.junit.Test; 66 import org.junit.runner.RunWith; 67 import org.mockito.Mock; 68 import org.mockito.MockitoAnnotations; 69 70 import java.util.List; 71 72 /** 73 * Test class for {@link LockSettingsShellCommand}. 74 * 75 * runtest frameworks-services -c com.android.server.locksettings.LockSettingsShellCommandTest 76 */ 77 @SmallTest 78 @Presubmit 79 @RunWith(AndroidJUnit4.class) 80 public class LockSettingsShellCommandTest { 81 82 private LockSettingsShellCommand mCommand; 83 84 private @Mock LockPatternUtils mLockPatternUtils; 85 private int mUserId; 86 private final Binder mBinder = new Binder(); 87 private final ShellCallback mShellCallback = new ShellCallback(); 88 private final ResultReceiver mResultReceiver = new ResultReceiver( 89 new Handler(Looper.getMainLooper())); 90 91 @Before setUp()92 public void setUp() throws Exception { 93 MockitoAnnotations.initMocks(this); 94 final Context context = InstrumentationRegistry.getTargetContext(); 95 mUserId = ActivityManager.getCurrentUser(); 96 mCommand = new LockSettingsShellCommand(mLockPatternUtils, context, 0, 97 Process.SHELL_UID); 98 when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true); 99 } 100 101 @Test testWrongPassword()102 public void testWrongPassword() throws Exception { 103 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 104 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 105 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 106 when(mLockPatternUtils.checkCredential( 107 LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(false); 108 assertEquals(-1, mCommand.exec(mBinder, in, out, err, 109 new String[] { "set-pin", "--old", "1234" }, 110 mShellCallback, mResultReceiver)); 111 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 112 } 113 114 @Test testChangePin()115 public void testChangePin() throws Exception { 116 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 117 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 118 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 119 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn( 120 PASSWORD_QUALITY_NUMERIC); 121 when(mLockPatternUtils.checkCredential( 122 LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true); 123 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 124 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_NUMERIC)); 125 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 126 new String[] { "set-pin", "--old", "1234", "4321" }, 127 mShellCallback, mResultReceiver)); 128 verify(mLockPatternUtils).setLockCredential( 129 LockscreenCredential.createPin("4321"), 130 LockscreenCredential.createPin("1234"), 131 mUserId); 132 } 133 134 @Test testChangePin_nonCompliant()135 public void testChangePin_nonCompliant() throws Exception { 136 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 137 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 138 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 139 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn( 140 PASSWORD_QUALITY_NUMERIC); 141 when(mLockPatternUtils.checkCredential( 142 LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true); 143 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 144 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_ALPHABETIC)); 145 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 146 new String[] { "set-pin", "--old", "1234", "4321" }, 147 mShellCallback, mResultReceiver)); 148 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 149 } 150 151 @Test testChangePin_noLockScreen()152 public void testChangePin_noLockScreen() throws Exception { 153 when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false); 154 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 155 new String[] { "set-pin", "--old", "1234", "4321" }, 156 mShellCallback, mResultReceiver)); 157 verify(mLockPatternUtils).hasSecureLockScreen(); 158 verifyNoMoreInteractions(mLockPatternUtils); 159 } 160 161 @Test testChangePassword()162 public void testChangePassword() throws Exception { 163 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 164 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 165 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 166 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn( 167 PASSWORD_QUALITY_ALPHABETIC); 168 when(mLockPatternUtils.checkCredential( 169 LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(true); 170 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 171 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_ALPHABETIC)); 172 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 173 new String[] { "set-password", "--old", "1234", "abcd" }, 174 mShellCallback, mResultReceiver)); 175 verify(mLockPatternUtils).setLockCredential( 176 LockscreenCredential.createPassword("abcd"), 177 LockscreenCredential.createPassword("1234"), 178 mUserId); 179 } 180 181 @Test testChangePassword_nonCompliant()182 public void testChangePassword_nonCompliant() throws Exception { 183 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 184 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 185 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 186 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn( 187 PASSWORD_QUALITY_ALPHABETIC); 188 when(mLockPatternUtils.checkCredential( 189 LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(true); 190 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 191 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_COMPLEX)); 192 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 193 new String[] { "set-password", "--old", "1234", "weakpassword" }, 194 mShellCallback, mResultReceiver)); 195 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 196 } 197 198 @Test testChangePassword_noLockScreen()199 public void testChangePassword_noLockScreen() throws Exception { 200 when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false); 201 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 202 new String[] { "set-password", "--old", "1234", "4321" }, 203 mShellCallback, mResultReceiver)); 204 verify(mLockPatternUtils).hasSecureLockScreen(); 205 verifyNoMoreInteractions(mLockPatternUtils); 206 } 207 208 @Test testChangePattern()209 public void testChangePattern() throws Exception { 210 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 211 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); 212 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); 213 when(mLockPatternUtils.checkCredential( 214 LockscreenCredential.createPattern(stringToPattern("1234")), 215 mUserId, null)).thenReturn(true); 216 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 217 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_SOMETHING)); 218 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 219 new String[] { "set-pattern", "--old", "1234", "4321" }, 220 mShellCallback, mResultReceiver)); 221 verify(mLockPatternUtils).setLockCredential( 222 LockscreenCredential.createPattern(stringToPattern("4321")), 223 LockscreenCredential.createPattern(stringToPattern("1234")), 224 mUserId); 225 } 226 227 @Test testChangePattern_nonCompliant()228 public void testChangePattern_nonCompliant() throws Exception { 229 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 230 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); 231 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); 232 when(mLockPatternUtils.checkCredential( 233 LockscreenCredential.createPattern(stringToPattern("1234")), 234 mUserId, null)).thenReturn(true); 235 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 236 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_NUMERIC)); 237 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 238 new String[] { "set-pattern", "--old", "1234", "4321" }, 239 mShellCallback, mResultReceiver)); 240 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 241 } 242 243 @Test testChangePattern_noLockScreen()244 public void testChangePattern_noLockScreen() throws Exception { 245 when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false); 246 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 247 new String[] { "set-pattern", "--old", "1234", "4321" }, 248 mShellCallback, mResultReceiver)); 249 verify(mLockPatternUtils).hasSecureLockScreen(); 250 verifyNoMoreInteractions(mLockPatternUtils); 251 } 252 253 @Test testClear()254 public void testClear() throws Exception { 255 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 256 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); 257 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); 258 when(mLockPatternUtils.checkCredential( 259 LockscreenCredential.createPattern(stringToPattern("1234")), 260 mUserId, null)).thenReturn(true); 261 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 262 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED)); 263 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 264 new String[] { "clear", "--old", "1234" }, 265 mShellCallback, mResultReceiver)); 266 verify(mLockPatternUtils).setLockCredential( 267 LockscreenCredential.createNone(), 268 LockscreenCredential.createPattern(stringToPattern("1234")), 269 mUserId); 270 } 271 272 @Test testClear_nonCompliant()273 public void testClear_nonCompliant() throws Exception { 274 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 275 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); 276 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); 277 when(mLockPatternUtils.checkCredential( 278 LockscreenCredential.createPattern(stringToPattern("1234")), 279 mUserId, null)).thenReturn(true); 280 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 281 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_SOMETHING)); 282 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 283 new String[] { "clear", "--old", "1234" }, 284 mShellCallback, mResultReceiver)); 285 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 286 } 287 288 @Test testSetPin_nonCompliantWithComplexity()289 public void testSetPin_nonCompliantWithComplexity() throws Exception { 290 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 291 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 292 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 293 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn( 294 PASSWORD_QUALITY_NUMERIC); 295 when(mLockPatternUtils.checkCredential( 296 LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true); 297 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 298 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED)); 299 when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId)) 300 .thenReturn(PASSWORD_COMPLEXITY_MEDIUM); 301 302 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 303 new String[] { "set-pin", "--old", "1234", "4321" }, 304 mShellCallback, mResultReceiver)); 305 306 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 307 } 308 309 @Test testSetPin_compliantWithComplexity()310 public void testSetPin_compliantWithComplexity() throws Exception { 311 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 312 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); 313 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); 314 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn( 315 PASSWORD_QUALITY_NUMERIC); 316 when(mLockPatternUtils.checkCredential( 317 LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true); 318 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 319 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED)); 320 when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId)) 321 .thenReturn(PASSWORD_COMPLEXITY_MEDIUM); 322 323 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 324 new String[] { "set-pin", "--old", "1234", "4231" }, 325 mShellCallback, mResultReceiver)); 326 327 verify(mLockPatternUtils).setLockCredential( 328 LockscreenCredential.createPin("4231"), 329 LockscreenCredential.createPin("1234"), 330 mUserId); 331 } 332 333 @Test testSetPattern_nonCompliantWithComplexity()334 public void testSetPattern_nonCompliantWithComplexity() throws Exception { 335 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 336 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); 337 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); 338 when(mLockPatternUtils.checkCredential( 339 LockscreenCredential.createPattern(stringToPattern("1234")), 340 mUserId, null)).thenReturn(true); 341 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 342 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED)); 343 when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId)) 344 .thenReturn(PASSWORD_COMPLEXITY_HIGH); 345 346 assertEquals(-1, mCommand.exec(new Binder(), in, out, err, 347 new String[] { "set-pattern", "--old", "1234", "4321" }, 348 mShellCallback, mResultReceiver)); 349 350 verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt()); 351 } 352 353 @Test testSetPattern_compliantWithComplexity()354 public void testSetPattern_compliantWithComplexity() throws Exception { 355 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 356 when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); 357 when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); 358 when(mLockPatternUtils.checkCredential( 359 LockscreenCredential.createPattern(stringToPattern("1234")), 360 mUserId, null)).thenReturn(true); 361 when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId)) 362 .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED)); 363 when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId)) 364 .thenReturn(PASSWORD_COMPLEXITY_LOW); 365 366 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 367 new String[] { "set-pattern", "--old", "1234", "4321" }, 368 mShellCallback, mResultReceiver)); 369 370 verify(mLockPatternUtils).setLockCredential( 371 LockscreenCredential.createPattern(stringToPattern("4321")), 372 LockscreenCredential.createPattern(stringToPattern("1234")), 373 mUserId); 374 } 375 376 @Test testRequireStrongAuth_STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN()377 public void testRequireStrongAuth_STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN() throws Exception { 378 when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true); 379 380 assertEquals(0, mCommand.exec(new Binder(), in, out, err, 381 new String[] { "require-strong-auth", "STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN"}, 382 mShellCallback, mResultReceiver)); 383 384 verify(mLockPatternUtils).requireStrongAuth( 385 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, 386 UserHandle.USER_ALL); 387 } 388 stringToPattern(String str)389 private List<LockPatternView.Cell> stringToPattern(String str) { 390 return LockPatternUtils.byteArrayToPattern(str.getBytes()); 391 } 392 metricsForAdminQuality(int quality)393 private PasswordMetrics metricsForAdminQuality(int quality) { 394 PasswordPolicy policy = new PasswordPolicy(); 395 policy.quality = quality; 396 return policy.getMinMetrics(); 397 } 398 } 399