From fbc2ec831f351c916a579aeee6ea8ddb9d81634e Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Wed, 22 Jul 2020 15:17:11 -0700 Subject: [PATCH 1/5] 2/n: Add setRequestGatekeeperPassword to ChooseLockSettingsHelper This change adds the plumbing on Settings side for ConfirmLock*. ChooseLock* will be done in a follow-up CL. The changes in this CL are not invoked by any code path yet. This will also be integrated in a follow-up CL. Bug: 161765592 Perform the following with a local change to use ChooseLockSettingsHelper#setRequestGatekeeperPassword(true) Test: GK PW is received when setRequestGatekeeperPassword(true) Test: GK PW + Challenge sent to GK, GK verifies and caller receives GK HAT successfully Change-Id: Ibd809784b5599343f34836bc5f3e709627b7f22a --- .../settings/password/ChooseLockPassword.java | 18 ++++--- .../settings/password/ChooseLockPattern.java | 18 ++++--- .../password/ChooseLockSettingsHelper.java | 39 +++++++++++--- .../ConfirmDeviceCredentialBaseFragment.java | 14 +++-- .../password/ConfirmLockPassword.java | 54 ++++++++++--------- .../settings/password/ConfirmLockPattern.java | 52 +++++++++--------- 6 files changed, 126 insertions(+), 69 deletions(-) diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index a2ac3d5d130..bcf82125d4d 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -77,6 +77,7 @@ import com.android.internal.widget.LockPatternUtils.RequestThrottledException; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.PasswordValidationError; import com.android.internal.widget.TextViewInputDisabler; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.EncryptionInterstitial; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -967,19 +968,24 @@ public class ChooseLockPassword extends SettingsActivity { } Intent result = null; if (success && mHasChallenge) { - byte[] token; + VerifyCredentialResponse response; try { - token = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId); + response = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId, + 0 /* flags */); } catch (RequestThrottledException e) { - token = null; + response = null; } - if (token == null) { - Log.e(TAG, "critical: no token returned for known good password."); + if (response == null) { + Log.e(TAG, "critical: null response for known good password"); + } else if (!response.isMatched() || response.getGatekeeperHAT() == null) { + Log.e(TAG, "critical: bad response or missing GK HAT for known good password: " + + response.toString()); } result = new Intent(); - result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); + result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, + response.getGatekeeperHAT()); } return Pair.create(success, result); } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 2c2d7bbe11a..8a51d5a7ae2 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -47,6 +47,7 @@ import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockPatternView.DisplayMode; import com.android.internal.widget.LockscreenCredential; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.EncryptionInterstitial; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -913,19 +914,24 @@ public class ChooseLockPattern extends SettingsActivity { } Intent result = null; if (success && mHasChallenge) { - byte[] token; + VerifyCredentialResponse response; try { - token = mUtils.verifyCredential(mChosenPattern, mChallenge, userId); + response = mUtils.verifyCredential(mChosenPattern, mChallenge, userId, + 0 /* flags */); } catch (RequestThrottledException e) { - token = null; + response = null; } - if (token == null) { - Log.e(TAG, "critical: no token returned for known good pattern"); + if (response == null) { + Log.e(TAG, "critial: null response for known good pattern"); + } else if (!response.isMatched() || response.getGatekeeperHAT() == null) { + Log.e(TAG, "critical: bad response or missing GK HAT for known good pattern: " + + response.toString()); } result = new Intent(); - result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); + result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, + response.getGatekeeperHAT()); } return Pair.create(success, result); } diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 962294b100c..04046553651 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -47,11 +47,16 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials"; public static final String EXTRA_KEY_HAS_CHALLENGE = "has_challenge"; public static final String EXTRA_KEY_CHALLENGE = "challenge"; + // Gatekeeper HardwareAuthToken public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token"; public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint"; public static final String EXTRA_KEY_FOR_FACE = "for_face"; public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot"; public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only"; + public static final String EXTRA_KEY_REQUEST_GK_PW = "request_gk_pw"; + // Gatekeeper password, which can subsequently be used to generate Gatekeeper + // HardwareAuthToken(s) via LockSettingsService#verifyGatekeeperPassword + public static final String EXTRA_KEY_GK_PW = "gk_pw"; /** * When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are @@ -119,6 +124,7 @@ public final class ChooseLockSettingsHelper { private boolean mAllowAnyUserId; // The challenge can be 0, which is different than "no challenge" @Nullable Long mChallenge; + boolean mRequestGatekeeperPassword; public Builder(@NonNull Activity activity) { mActivity = activity; @@ -174,7 +180,7 @@ public final class ChooseLockSettingsHelper { * @param returnCredentials if true, puts the following credentials into intent for * onActivityResult with the following keys: * {@link #EXTRA_KEY_TYPE}, {@link #EXTRA_KEY_PASSWORD}, - * {@link #EXTRA_KEY_CHALLENGE_TOKEN}. + * {@link #EXTRA_KEY_CHALLENGE_TOKEN}, {@link #EXTRA_KEY_GK_PW} * Note that if this is true, this can only be called internally. */ @NonNull public Builder setReturnCredentials(boolean returnCredentials) { @@ -231,6 +237,24 @@ public final class ChooseLockSettingsHelper { return this; } + /** + * Requests that LockSettingsService return the Gatekeeper Password (instead of the + * Gatekeeper HAT). This allows us to use a single entry of the user's credential + * to create multiple Gatekeeper HATs containing distinct challenges via + * {@link LockPatternUtils#verifyGatekeeperPassword(byte[], long, int)}. + * + * Upon confirmation of the user's password, the Gatekeeper Password will be returned via + * onActivityResult with the key being {@link #EXTRA_KEY_GK_PW}. + * @param requestGatekeeperPassword + * + * Note that invoking {@link #setChallenge(long)} will be treated as a no-op if Gatekeeper + * Password has been requested. + */ + @NonNull public Builder setRequestGatekeeperPassword(boolean requestGatekeeperPassword) { + mRequestGatekeeperPassword = requestGatekeeperPassword; + return this; + } + @NonNull public ChooseLockSettingsHelper build() { if (!mAllowAnyUserId && mUserId != LockPatternUtils.USER_FRP) { Utils.enforceSameOwner(mActivity, mUserId); @@ -265,14 +289,15 @@ public final class ChooseLockSettingsHelper { return launchConfirmationActivity(mBuilder.mRequestCode, mBuilder.mTitle, mBuilder.mHeader, mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal, mBuilder.mChallenge != null, challenge, mBuilder.mUserId, - mBuilder.mAlternateButton, mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly); + mBuilder.mAlternateButton, mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly, + mBuilder.mRequestGatekeeperPassword); } private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, @Nullable CharSequence alternateButton, - boolean allowAnyUser, boolean foregroundOnly) { + boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPassword) { final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId); boolean launched = false; @@ -283,7 +308,7 @@ public final class ChooseLockSettingsHelper { ? ConfirmLockPattern.InternalActivity.class : ConfirmLockPattern.class, returnCredentials, external, hasChallenge, challenge, userId, alternateButton, allowAnyUser, - foregroundOnly); + foregroundOnly, requestGatekeeperPassword); break; case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: @@ -296,7 +321,7 @@ public final class ChooseLockSettingsHelper { ? ConfirmLockPassword.InternalActivity.class : ConfirmLockPassword.class, returnCredentials, external, hasChallenge, challenge, userId, alternateButton, allowAnyUser, - foregroundOnly); + foregroundOnly, requestGatekeeperPassword); break; } return launched; @@ -306,7 +331,7 @@ public final class ChooseLockSettingsHelper { CharSequence message, Class activityClass, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, @Nullable CharSequence alternateButton, boolean allowAnyUser, - boolean foregroundOnly) { + boolean foregroundOnly, boolean requestGatekeeperPassword) { final Intent intent = new Intent(); intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header); @@ -323,6 +348,8 @@ public final class ChooseLockSettingsHelper { intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, + requestGatekeeperPassword); intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName()); if (external) { diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index b5f512dfa99..23320902059 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -71,6 +71,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr protected static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 3000; protected boolean mReturnCredentials = false; + protected boolean mReturnGatekeeperPassword = false; + protected boolean mVerifyChallenge = false; protected Button mCancelButton; /** Button allowing managed profile password reset, null when is not shown. */ @Nullable protected Button mForgotButton; @@ -93,12 +95,18 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mFrpAlternateButtonText = getActivity().getIntent().getCharSequenceExtra( + final Intent intent = getActivity().getIntent(); + mFrpAlternateButtonText = intent.getCharSequenceExtra( KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL); - mReturnCredentials = getActivity().getIntent().getBooleanExtra( + mReturnCredentials = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false); + + mReturnGatekeeperPassword = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false); + mVerifyChallenge = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); + // Only take this argument into account if it belongs to the current profile. - Intent intent = getActivity().getIntent(); mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(), isInternalActivity()); mFrp = (mUserId == LockPatternUtils.USER_FRP); diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index 8aa44e9780f..85f44fd5c69 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -49,6 +49,7 @@ import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.TextViewInputDisabler; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.R; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils; @@ -380,13 +381,18 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { : LockscreenCredential.createPin(passwordText); mPasswordEntryInputDisabler.setInputEnabled(false); - final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); Intent intent = new Intent(); - if (verifyChallenge) { + // TODO(b/161956762): Sanitize this + if (mReturnGatekeeperPassword) { if (isInternalActivity()) { - startVerifyPassword(credential, intent); + startVerifyPassword(credential, intent, + LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW); + return; + } + } else if (mVerifyChallenge) { + if (isInternalActivity()) { + startVerifyPassword(credential, intent, 0 /* flags */); return; } } else { @@ -401,34 +407,34 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { return getActivity() instanceof ConfirmLockPassword.InternalActivity; } - private void startVerifyPassword(LockscreenCredential credential, final Intent intent) { + private void startVerifyPassword(LockscreenCredential credential, final Intent intent, + @LockPatternUtils.VerifyFlag int flags) { long challenge = getActivity().getIntent().getLongExtra( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); final int localEffectiveUserId = mEffectiveUserId; final int localUserId = mUserId; - final LockPatternChecker.OnVerifyCallback onVerifyCallback = - new LockPatternChecker.OnVerifyCallback() { - @Override - public void onVerified(byte[] token, int timeoutMs) { - mPendingLockCheck = null; - boolean matched = false; - if (token != null) { - matched = true; - if (mReturnCredentials) { - intent.putExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, - token); - } - } - mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs, - localEffectiveUserId); - } + final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> { + mPendingLockCheck = null; + final boolean matched = response.isMatched(); + if (matched && mReturnCredentials) { + if ((flags & LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW) != 0) { + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW, + response.getGatekeeperPw()); + } else { + intent.putExtra( + ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, + response.getGatekeeperHAT()); + } + } + mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs, + localEffectiveUserId); }; mPendingLockCheck = (localEffectiveUserId == localUserId) ? LockPatternChecker.verifyCredential( - mLockPatternUtils, credential, challenge, localUserId, onVerifyCallback) + mLockPatternUtils, credential, challenge, localUserId, flags, + onVerifyCallback) : LockPatternChecker.verifyTiedProfileChallenge( - mLockPatternUtils, credential, challenge, localUserId, + mLockPatternUtils, credential, challenge, localUserId, flags, onVerifyCallback); } diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java index 48014cba3c8..5b11bfedc0d 100644 --- a/src/com/android/settings/password/ConfirmLockPattern.java +++ b/src/com/android/settings/password/ConfirmLockPattern.java @@ -40,6 +40,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockscreenCredential; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.R; import com.android.settingslib.animation.AppearAnimationCreator; import com.android.settingslib.animation.AppearAnimationUtils; @@ -422,14 +423,18 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { mLockPatternView.setEnabled(false); - final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); final LockscreenCredential credential = LockscreenCredential.createPattern(pattern); - //TODO: how to sanitize this? + // TODO(b/161956762): Sanitize this Intent intent = new Intent(); - if (verifyChallenge) { + if (mReturnGatekeeperPassword) { if (isInternalActivity()) { - startVerifyPattern(credential, intent); + startVerifyPattern(credential, intent, + LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW); + return; + } + } else if (mVerifyChallenge) { + if (isInternalActivity()) { + startVerifyPattern(credential, intent, 0 /* flags */); return; } } else { @@ -445,36 +450,35 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { } private void startVerifyPattern(final LockscreenCredential pattern, - final Intent intent) { + final Intent intent, @LockPatternUtils.VerifyFlag int flags) { final int localEffectiveUserId = mEffectiveUserId; final int localUserId = mUserId; long challenge = getActivity().getIntent().getLongExtra( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); final LockPatternChecker.OnVerifyCallback onVerifyCallback = - new LockPatternChecker.OnVerifyCallback() { - @Override - public void onVerified(byte[] token, int timeoutMs) { - mPendingLockCheck = null; - boolean matched = false; - if (token != null) { - matched = true; - if (mReturnCredentials) { - intent.putExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, - token); - } + (response, timeoutMs) -> { + mPendingLockCheck = null; + final boolean matched = response.isMatched(); + if (matched && mReturnCredentials) { + if ((flags & LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW) != 0) { + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW, + response.getGatekeeperPw()); + } else { + intent.putExtra( + ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, + response.getGatekeeperHAT()); } - mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs, - localEffectiveUserId); } - }; + mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs, + localEffectiveUserId); + }; mPendingLockCheck = (localEffectiveUserId == localUserId) ? LockPatternChecker.verifyCredential( - mLockPatternUtils, pattern, challenge, localUserId, + mLockPatternUtils, pattern, challenge, localUserId, flags, onVerifyCallback) : LockPatternChecker.verifyTiedProfileChallenge( - mLockPatternUtils, pattern, - challenge, localUserId, onVerifyCallback); + mLockPatternUtils, pattern, challenge, localUserId, flags, + onVerifyCallback); } private void startCheckPattern(final LockscreenCredential pattern, From e67a0afc41c2c551a10976e65c92de5265cbfb40 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 23 Jul 2020 17:32:43 -0700 Subject: [PATCH 2/5] 3/n: verifyCredential no longer returns RequestThrottledException Bug: 161765592 Test: Accept/Reject/Lockout on the following 1) Owner profile 2) Managed profile with separate challenge 3) Managed profile with unified challenge Change-Id: Ia7b670a29e9e8ee1fe65bd09965a454601a06871 --- .../settings/password/ChooseLockPassword.java | 14 +++----------- .../settings/password/ChooseLockPattern.java | 13 +++---------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index bcf82125d4d..2e21004639d 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -968,17 +968,9 @@ public class ChooseLockPassword extends SettingsActivity { } Intent result = null; if (success && mHasChallenge) { - VerifyCredentialResponse response; - try { - response = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId, - 0 /* flags */); - } catch (RequestThrottledException e) { - response = null; - } - - if (response == null) { - Log.e(TAG, "critical: null response for known good password"); - } else if (!response.isMatched() || response.getGatekeeperHAT() == null) { + final VerifyCredentialResponse response = mUtils.verifyCredential(mChosenPassword, + mChallenge, mUserId, 0 /* flags */); + if (!response.isMatched() || response.getGatekeeperHAT() == null) { Log.e(TAG, "critical: bad response or missing GK HAT for known good password: " + response.toString()); } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 8a51d5a7ae2..bf530969630 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -914,17 +914,10 @@ public class ChooseLockPattern extends SettingsActivity { } Intent result = null; if (success && mHasChallenge) { - VerifyCredentialResponse response; - try { - response = mUtils.verifyCredential(mChosenPattern, mChallenge, userId, - 0 /* flags */); - } catch (RequestThrottledException e) { - response = null; - } + final VerifyCredentialResponse response = mUtils.verifyCredential(mChosenPattern, + mChallenge, userId, 0 /* flags */); - if (response == null) { - Log.e(TAG, "critial: null response for known good pattern"); - } else if (!response.isMatched() || response.getGatekeeperHAT() == null) { + if (!response.isMatched() || response.getGatekeeperHAT() == null) { Log.e(TAG, "critical: bad response or missing GK HAT for known good pattern: " + response.toString()); } From 7b0867c6d37ba34a9b3559af83d05009a52edb51 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 23 Jul 2020 19:36:26 -0700 Subject: [PATCH 3/5] 4/n: Remove challenge from choose/confirm, use new path Biometric enrollment will not request a Gatekeeper HAT during initial credential setup or credential confirmation anymore. Instead, it is broken down into the following steps now. Bug: 161765592 1) Request credential setup / confirmation to return a Gatekeeper Password 2) Biometric enrollment will generate a challenge 3) Biometric enrollment will request LockSettingsService to verify(GatekeeperPassword, challenge), and upon verification, the Gatekeeper HAT will be returned. Since both LockSettingsService and Biometric enroll/settings make use of biometric challenges, this allows us to make the challenge ownership/lifecycle clear (vs. previously, where LockSettingsService has no idea who the challenge belongs to). Exempt-From-Owner-Approval:For files not owned by our team, (StorageWizard), this change is just a method rename Test: RunSettingsRoboTests Run the following on face/fingerprint devices Test: Remove credential adb shell am start -a android.app.action.SET_NEW_PASSWORD Set up credential + fingerprint Test: Remove credential, adb shell am start -a android.settings.FINGERPRINT_SETTINGS This tests the ChooseLock* logic in FingerprintSettings Test: Set up credential, adb shell am start -a android.settings.FINGERPRINT_SETTINGS This tests the ConfirmLock* logic in FingerprintSettings Test: Remove device credential, enroll fingerprint/face. Succeeds. This tests the ChooseLock* returning SP path from BiometricEnrollIntro Test: With credential and fingerprint/face enrolled, go to fingerprint/face settings and enroll. This tests the ConfirmLock* path in Fingerprint/FaceSettings Test: Remove device credential, enroll credential-only, enroll fingerprint/face separately. Succeeds. This tests the ConfirmLock* returning SP path in BiometricEnrollIntro Test: In SUW, set up credential, then biometric. This tests the ChooseLock* path in SUW Test: In SUW, set up credential, go back, then set up biometric. This tests the ConfirmLock* path in SUW Change-Id: Idf6fcb43f7497323d089eb9c37125294e7a7f5dc --- .../biometrics/BiometricEnrollActivity.java | 5 ++ .../biometrics/BiometricEnrollBase.java | 12 +++- .../BiometricEnrollIntroduction.java | 11 ++-- .../settings/biometrics/BiometricUtils.java | 58 ++++++++++++++++++ .../face/FaceEnrollIntroduction.java | 19 ++++-- .../biometrics/face/FaceSettings.java | 34 +++++------ .../FingerprintEnrollFindSensor.java | 14 +++++ .../fingerprint/FingerprintSettings.java | 18 +++--- .../StorageWizardMigrateConfirm.java | 2 +- .../deviceinfo/StorageWizardMoveConfirm.java | 2 +- .../settings/password/ChooseLockGeneric.java | 37 +++++++----- .../settings/password/ChooseLockPassword.java | 44 +++++++------- .../settings/password/ChooseLockPattern.java | 42 ++++++------- .../password/ChooseLockSettingsHelper.java | 60 +++++++++---------- .../ChooseLockTypeDialogFragment.java | 4 +- .../ConfirmDeviceCredentialActivity.java | 16 +---- .../ConfirmDeviceCredentialBaseFragment.java | 6 +- .../password/ConfirmLockPassword.java | 15 ++--- .../settings/password/ConfirmLockPattern.java | 9 +-- .../password/SaveChosenLockWorkerBase.java | 9 +-- .../password/SetNewPasswordController.java | 8 +-- .../password/ChooseLockPasswordTest.java | 15 ++--- .../password/ChooseLockPatternTest.java | 16 ++--- .../ChooseLockSettingsHelperTest.java | 23 +++---- .../SetNewPasswordControllerTest.java | 25 +++----- 25 files changed, 269 insertions(+), 235 deletions(-) create mode 100644 src/com/android/settings/biometrics/BiometricUtils.java diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index 4179ea3d96d..4f2f4e6c2a3 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -104,9 +104,14 @@ public class BiometricEnrollActivity extends InstrumentedActivity { .getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); final int userId = getIntent() .getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL); + final byte[] gkPw = getIntent().getByteArrayExtra( + ChooseLockSettingsHelper.EXTRA_KEY_GK_PW); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); intent.putExtra(Intent.EXTRA_USER_ID, userId); + if (gkPw != null) { + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW, gkPw); + } } startActivity(intent); diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java index 0017117fc6b..b905e3e3d21 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollBase.java +++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java @@ -88,7 +88,13 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mToken = getIntent().getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + // Don't need to retrieve the HAT if it already exists. In some cases, the extras do not + // contain EXTRA_KEY_CHALLENGE_TOKEN but contain EXTRA_KEY_GK_PW, in which case enrollment + // classes may request a HAT to be created (as opposed to being passed in) + if (mToken == null) { + mToken = getIntent().getByteArrayExtra( + ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + } mFromSettingsSummary = getIntent().getBooleanExtra(EXTRA_FROM_SETTINGS_SUMMARY, false); if (savedInstanceState != null && mToken == null) { mLaunchedConfirmLock = savedInstanceState.getBoolean(EXTRA_KEY_LAUNCHED_CONFIRM); @@ -180,11 +186,11 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { return intent; } - protected void launchConfirmLock(int titleResId, long challenge) { + protected void launchConfirmLock(int titleResId) { final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this); builder.setRequestCode(CONFIRM_REQUEST) .setTitle(getString(titleResId)) - .setChallenge(challenge) + .setRequestGatekeeperPassword(true) .setForegroundOnly(true) .setReturnCredentials(true); diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index 2e81974bee3..c97c4d98b7b 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -164,7 +164,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase // It's possible to have a token but mLaunchedConfirmLock == false, since // ChooseLockGeneric can pass us a token. mConfirmingCredentials = true; - launchConfirmLock(getConfirmLockTitleResId(), getChallenge()); + launchConfirmLock(getConfirmLockTitleResId()); } } } @@ -217,12 +217,10 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase private void launchChooseLock() { Intent intent = getChooseLockIntent(); - long challenge = getChallenge(); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, true); intent.putExtra(getExtraKeyForBiometric(), true); if (mUserId != UserHandle.USER_NULL) { intent.putExtra(Intent.EXTRA_USER_ID, mUserId); @@ -271,8 +269,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase } else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) { if (resultCode == RESULT_FINISHED) { updatePasswordQuality(); - mToken = data.getByteArrayExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, getChallenge()); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); mConfirmingCredentials = false; return; @@ -283,7 +280,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase } else if (requestCode == CONFIRM_REQUEST) { mConfirmingCredentials = false; if (resultCode == RESULT_OK && data != null) { - mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, getChallenge()); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); } else { setResult(resultCode, data); diff --git a/src/com/android/settings/biometrics/BiometricUtils.java b/src/com/android/settings/biometrics/BiometricUtils.java new file mode 100644 index 00000000000..f33c3c2974b --- /dev/null +++ b/src/com/android/settings/biometrics/BiometricUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 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.settings.biometrics; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.password.ChooseLockSettingsHelper; + +/** + * Common biometric utilities. + */ +public class BiometricUtils { + /** + * Given the result from confirming or choosing a credential, request Gatekeeper to generate + * a HardwareAuthToken with the Gatekeeper Password together with a biometric challenge. + * + * @param context Caller's context + * @param result The onActivityResult intent from ChooseLock* or ConfirmLock* + * @param userId User ID that the credential/biometric operation applies to + * @param challenge Unique biometric challenge from FingerprintManager/FaceManager + * @return + */ + public static byte[] requestGatekeeperHat(Context context, Intent result, int userId, + long challenge) { + final byte[] gkPassword = result.getByteArrayExtra( + ChooseLockSettingsHelper.EXTRA_KEY_GK_PW); + if (gkPassword == null) { + throw new IllegalStateException("Gatekeeper Password is null!!"); + } + + final LockPatternUtils utils = new LockPatternUtils(context); + return utils.verifyGatekeeperPassword(gkPassword, challenge, userId).getGatekeeperHAT(); + } + + public static boolean containsGatekeeperPassword(Intent data) { + if (data == null) { + return false; + } + return data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW) != null; + } +} diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index 780fb2e88a5..dbdf03de3bb 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -26,6 +26,7 @@ import android.widget.TextView; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollIntroduction; +import com.android.settings.biometrics.BiometricUtils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -38,16 +39,26 @@ import com.google.android.setupdesign.template.RequireScrollMixin; public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { - private static final String TAG = "FaceIntro"; + private static final String TAG = "FaceEnrollIntroduction"; private FaceManager mFaceManager; private FaceFeatureProvider mFaceFeatureProvider; @Override protected void onCreate(Bundle savedInstanceState) { + mFaceManager = Utils.getFaceManagerOrNull(this); + // Check if the Gateekeper Password exists. If so, request for a Gatekeeper HAT to be + // created. This needs to be cleaned up, since currently it's not very clear which + // superclass is responsible for what. Doing the check here is the least risky way. + if (mToken == null && BiometricUtils.containsGatekeeperPassword(getIntent())) { + // We either block on generateChallenge, or need to gray out the "next" button until + // the challenge is ready. Let's just do this for now. + final long challenge = mFaceManager.generateChallengeBlocking(); + mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge); + } + super.onCreate(savedInstanceState); - mFaceManager = Utils.getFaceManagerOrNull(this); mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext()) .getFaceFeatureProvider(); @@ -86,9 +97,7 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { RequireScrollMixin.class); requireScrollMixin.requireScrollWithButton(this, agreeButton, R.string.security_settings_face_enroll_introduction_more, - button -> { - onNextButtonClick(button); - }); + this::onNextButtonClick); } final TextView footer2 = findViewById(R.id.face_enroll_introduction_footer_part_2); diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index 1c984286c48..976c6e3237d 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -37,6 +37,7 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; +import com.android.settings.biometrics.BiometricUtils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; @@ -202,15 +203,11 @@ public class FaceSettings extends DashboardFragment { super.onResume(); if (mToken == null && !mConfirmingPassword) { - // Generate challenge in onResume instead of onCreate, since FaceSettings can be - // created while Keyguard is showing, in which case the resetLockout revokeChallenge - // will invalidate the too-early created challenge here. - final long challenge = mFaceManager.generateChallengeBlocking(); final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(getActivity(), this); final boolean launched = builder.setRequestCode(CONFIRM_REQUEST) .setTitle(getString(R.string.security_settings_face_preference_title)) - .setChallenge(challenge) + .setRequestGatekeeperPassword(true) .setUserId(mUserId) .setForegroundOnly(true) .setReturnCredentials(true) @@ -238,18 +235,22 @@ public class FaceSettings extends DashboardFragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); + + if (mToken == null && !BiometricUtils.containsGatekeeperPassword(data)) { + Log.e(TAG, "No credential"); + finish(); + } + if (requestCode == CONFIRM_REQUEST) { - mConfirmingPassword = false; if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) { // The pin/pattern/password was set. - if (data != null) { - mToken = data.getByteArrayExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); - if (mToken != null) { - mAttentionController.setToken(mToken); - mEnrollController.setToken(mToken); - } - } + mFaceManager.generateChallenge(challenge -> { + mToken = BiometricUtils.requestGatekeeperHat(getPrefContext(), data, mUserId, + challenge); + mAttentionController.setToken(mToken); + mEnrollController.setToken(mToken); + mConfirmingPassword = false; + }); } } else if (requestCode == ENROLL_REQUEST) { if (resultCode == RESULT_TIMEOUT) { @@ -257,11 +258,6 @@ public class FaceSettings extends DashboardFragment { finish(); } } - - if (mToken == null) { - // Didn't get an authentication, finishing - finish(); - } } @Override diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java index dbedb4a4ebd..00fdb0ae4f7 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java @@ -28,6 +28,7 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricEnrollSidecar.Listener; +import com.android.settings.biometrics.BiometricUtils; import com.android.settings.password.ChooseLockSettingsHelper; import com.google.android.setupcompat.template.FooterBarMixin; @@ -60,6 +61,16 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase { setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title); + if (mToken == null && BiometricUtils.containsGatekeeperPassword(getIntent())) { + final FingerprintManager fpm = getSystemService(FingerprintManager.class); + final long challenge = fpm.generateChallengeBlocking(); + mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge); + + // Put this into the intent. This is really just to work around the fact that the + // enrollment sidecar gets the HAT from the activity's intent, rather than having + // it passed in. + getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); + } startLookingForFingerprint(); // already confirmed, so start looking for fingerprint @@ -160,10 +171,13 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase { protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CONFIRM_REQUEST) { if (resultCode == RESULT_OK && data != null) { + throw new IllegalStateException("Pretty sure this is dead code"); + /* mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); startLookingForFingerprint(); + */ } else { finish(); } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 1fa9a4717b6..3eaf506f44d 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -54,6 +54,7 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SubSettings; import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollBase; +import com.android.settings.biometrics.BiometricUtils; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; @@ -565,14 +566,13 @@ public class FingerprintSettings extends SubSettings { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST - || requestCode == CONFIRM_REQUEST) { + if (requestCode == CONFIRM_REQUEST || requestCode == CHOOSE_LOCK_GENERIC_REQUEST) { mLaunchedConfirm = false; if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) { - // The lock pin/pattern/password was set. Start enrolling! if (data != null) { - mToken = data.getByteArrayExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + final long challenge = mFingerprintManager.generateChallengeBlocking(); + mToken = BiometricUtils.requestGatekeeperHat(getActivity(), data, mUserId, + challenge); } } } else if (requestCode == ADD_FINGERPRINT_REQUEST) { @@ -635,26 +635,26 @@ public class FingerprintSettings extends SubSettings { private void launchChooseOrConfirmLock() { final Intent intent = new Intent(); - final long challenge = mFingerprintManager.generateChallengeBlocking(); final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(getActivity(), this); final boolean launched = builder.setRequestCode(CONFIRM_REQUEST) .setTitle(getString(R.string.security_settings_fingerprint_preference_title)) - .setChallenge(challenge) + .setRequestGatekeeperPassword(true) .setUserId(mUserId) .setForegroundOnly(true) .setReturnCredentials(true) .show(); if (!launched) { + // TODO: This should be cleaned up. ChooseLockGeneric should provide a way of + // specifying arguments/requests, instead of relying on callers setting extras. intent.setClassName(SETTINGS_PACKAGE_NAME, ChooseLockGeneric.class.getName()); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, true); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST); } diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java index ec771266959..7d20aa715db 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java +++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java @@ -109,7 +109,7 @@ public class StorageWizardMigrateConfirm extends StorageWizardBase { .setDescription(description) .setUserId(user.id) .setAllowAnyUserId(true) - .setChallenge(0L) + .setForceVerifyPath(true) .show(); return; } diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java index ef406ff3703..034eb079fe2 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java +++ b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java @@ -90,7 +90,7 @@ public class StorageWizardMoveConfirm extends StorageWizardBase { builder.setRequestCode(REQUEST_CREDENTIAL) .setDescription(description) .setUserId(user.id) - .setChallenge(0L) + .setForceVerifyPath(true) .setAllowAnyUserId(true) .show(); return; diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 4d51591b56c..297a3945539 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -144,8 +144,7 @@ public class ChooseLockGeneric extends SettingsActivity { private LockPatternUtils mLockPatternUtils; private DevicePolicyManager mDpm; - private boolean mHasChallenge = false; - private long mChallenge; + private boolean mRequestGatekeeperPassword = false; private boolean mPasswordConfirmed = false; private boolean mWaitingForConfirmation = false; private boolean mForChangeCredRequiredForBoot = false; @@ -211,10 +210,8 @@ public class ChooseLockGeneric extends SettingsActivity { ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); } - mHasChallenge = intent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); - mChallenge = intent.getLongExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); + mRequestGatekeeperPassword = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false); mForFingerprint = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); mForFace = intent.getBooleanExtra( @@ -386,9 +383,12 @@ public class ChooseLockGeneric extends SettingsActivity { mForFingerprint); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, mForFace); + // If the caller requested Gatekeeper Password to be returned, we assume it came + // from biometric enrollment. This should be cleaned up, since requesting + // Gatekeeper Password should not imply it came from biometric setup/settings. startActivityForResult( intent, - mIsSetNewPassword && mHasChallenge + mIsSetNewPassword && mRequestGatekeeperPassword ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST : ENABLE_ENCRYPTION_REQUEST); } else { @@ -438,6 +438,10 @@ public class ChooseLockGeneric extends SettingsActivity { && resultCode == BiometricEnrollBase.RESULT_FINISHED) { Intent intent = getBiometricEnrollIntent(getActivity()); if (data != null) { + // ChooseLockGeneric should have requested that the Gatekeeper Password be + // returned, so that biometric enrollment(s) can subsequently request Gatekeeper + // to create HardwareAuthToken(s) wrapping biometric-specific challenges. Send + // the extras (including the GK Password) to the enrollment activity. intent.putExtras(data.getExtras()); } // Forward the target user id to fingerprint setup page. @@ -722,10 +726,8 @@ public class ChooseLockGeneric extends SettingsActivity { .setRequestedMinComplexity(mRequestedMinComplexity) .setForFingerprint(mForFingerprint) .setForFace(mForFace) - .setUserId(mUserId); - if (mHasChallenge) { - builder.setChallenge(mChallenge); - } + .setUserId(mUserId) + .setRequestGatekeeperPassword(mRequestGatekeeperPassword); if (mUserPassword != null) { builder.setPassword(mUserPassword); } @@ -740,10 +742,8 @@ public class ChooseLockGeneric extends SettingsActivity { new ChooseLockPattern.IntentBuilder(getContext()) .setForFingerprint(mForFingerprint) .setForFace(mForFace) - .setUserId(mUserId); - if (mHasChallenge) { - builder.setChallenge(mChallenge); - } + .setUserId(mUserId) + .setRequestGatekeeperPassword(mRequestGatekeeperPassword); if (mUserPassword != null) { builder.setPattern(mUserPassword); } @@ -784,8 +784,13 @@ public class ChooseLockGeneric extends SettingsActivity { intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped); } intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras()); + // If the caller requested Gatekeeper Password to be returned, we assume it came + // from biometric enrollment. onActivityResult will put the LockSettingsService + // into the extras and launch biometric enrollment. This should be cleaned up, + // since requesting Gatekeeper Password should not imply it came from biometric + // setup/settings. startActivityForResult(intent, - mIsSetNewPassword && mHasChallenge + mIsSetNewPassword && mRequestGatekeeperPassword ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST : CHOOSE_LOCK_REQUEST); return; diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index 2e21004639d..9e4c5974f9c 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -118,7 +118,6 @@ public class ChooseLockPassword extends SettingsActivity { mIntent = new Intent(context, ChooseLockPassword.class); mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false); mIntent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false); - mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); } public IntentBuilder setPasswordQuality(int quality) { @@ -131,9 +130,9 @@ public class ChooseLockPassword extends SettingsActivity { return this; } - public IntentBuilder setChallenge(long challenge) { - mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + public IntentBuilder setRequestGatekeeperPassword(boolean requestGatekeeperPassword) { + mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, + requestGatekeeperPassword); return this; } @@ -212,8 +211,7 @@ public class ChooseLockPassword extends SettingsActivity { private LockscreenCredential mCurrentCredential; private LockscreenCredential mChosenPassword; - private boolean mHasChallenge; - private long mChallenge; + private boolean mRequestGatekeeperPassword; private ImeAwareEditText mPasswordEntry; private TextViewInputDisabler mPasswordEntryInputDisabler; @@ -408,7 +406,8 @@ public class ChooseLockPassword extends SettingsActivity { w.setBlocking(true); w.setListener(this); - w.start(utils, required, false, 0, currentCredential, currentCredential, mUserId); + w.start(utils, required, false /* requestGatekeeperPassword */, currentCredential, + currentCredential, mUserId); } mTextChangedHandler = new TextChangedHandler(); } @@ -492,9 +491,8 @@ public class ChooseLockPassword extends SettingsActivity { ChooseLockGeneric.CONFIRM_CREDENTIALS, true); mCurrentCredential = intent.getParcelableExtra( ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); - mHasChallenge = intent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); - mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); + mRequestGatekeeperPassword = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false); if (savedInstanceState == null) { updateStage(Stage.Introduction); if (confirmCredentials) { @@ -503,6 +501,7 @@ public class ChooseLockPassword extends SettingsActivity { builder.setRequestCode(CONFIRM_EXISTING_REQUEST) .setTitle(getString(R.string.unlock_set_unlock_launch_picker_title)) .setReturnCredentials(true) + .setRequestGatekeeperPassword(mRequestGatekeeperPassword) .setUserId(mUserId) .show(); } @@ -886,7 +885,7 @@ public class ChooseLockPassword extends SettingsActivity { profileCredential); } } - mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge, + mSaveAndFinishWorker.start(mLockPatternUtils, required, mRequestGatekeeperPassword, mChosenPassword, mCurrentCredential, mUserId); } @@ -946,10 +945,9 @@ public class ChooseLockPassword extends SettingsActivity { private LockscreenCredential mCurrentCredential; public void start(LockPatternUtils utils, boolean required, - boolean hasChallenge, long challenge, - LockscreenCredential chosenPassword, LockscreenCredential currentCredential, - int userId) { - prepare(utils, required, hasChallenge, challenge, userId); + boolean requestGatekeeperPassword, LockscreenCredential chosenPassword, + LockscreenCredential currentCredential, int userId) { + prepare(utils, required, requestGatekeeperPassword, userId); mChosenPassword = chosenPassword; mCurrentCredential = currentCredential != null ? currentCredential @@ -967,17 +965,21 @@ public class ChooseLockPassword extends SettingsActivity { unifyProfileCredentialIfRequested(); } Intent result = null; - if (success && mHasChallenge) { + if (success && mRequestGatekeeperPassword) { + // If a Gatekeeper Password was requested, invoke the LockSettingsService code + // path to return a Gatekeeper Password based on the credential that the user + // chose. This should only be run if the credential was successfully set. final VerifyCredentialResponse response = mUtils.verifyCredential(mChosenPassword, - mChallenge, mUserId, 0 /* flags */); - if (!response.isMatched() || response.getGatekeeperHAT() == null) { - Log.e(TAG, "critical: bad response or missing GK HAT for known good password: " + mUserId, LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW); + + if (!response.isMatched() || response.getGatekeeperPw() == null) { + Log.e(TAG, "critical: bad response or missing GK PW for known good password: " + response.toString()); } result = new Intent(); - result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, - response.getGatekeeperHAT()); + result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW, + response.getGatekeeperPw()); } return Pair.create(success, result); } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index bf530969630..bac7450870b 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -42,7 +42,6 @@ import androidx.fragment.app.Fragment; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.LockPatternUtils.RequestThrottledException; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockPatternView.DisplayMode; @@ -55,7 +54,6 @@ import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; import com.android.settings.core.InstrumentedFragment; import com.android.settings.notification.RedactionInterstitial; -import com.android.settings.password.ChooseLockPassword.IntentBuilder; import com.google.android.collect.Lists; import com.google.android.setupcompat.template.FooterBarMixin; @@ -107,7 +105,6 @@ public class ChooseLockPattern extends SettingsActivity { mIntent = new Intent(context, ChooseLockPattern.class); mIntent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false); mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false); - mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); } public IntentBuilder setUserId(int userId) { @@ -115,9 +112,9 @@ public class ChooseLockPattern extends SettingsActivity { return this; } - public IntentBuilder setChallenge(long challenge) { - mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + public IntentBuilder setRequestGatekeeperPassword(boolean requestGatekeeperPassword) { + mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, + requestGatekeeperPassword); return this; } @@ -207,8 +204,7 @@ public class ChooseLockPattern extends SettingsActivity { private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker"; private LockscreenCredential mCurrentCredential; - private boolean mHasChallenge; - private long mChallenge; + private boolean mRequestGatekeeperPassword; protected TextView mTitleText; protected TextView mHeaderText; protected TextView mMessageText; @@ -484,7 +480,8 @@ public class ChooseLockPattern extends SettingsActivity { ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); w.setBlocking(true); w.setListener(this); - w.start(mLockPatternUtils, required, false, 0, current, current, mUserId); + w.start(mLockPatternUtils, required, false /* requestGatekeeperPassword */, current, + current, mUserId); } mForFingerprint = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); @@ -564,9 +561,8 @@ public class ChooseLockPattern extends SettingsActivity { Intent intent = getActivity().getIntent(); mCurrentCredential = intent.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); - mHasChallenge = intent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); - mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); + mRequestGatekeeperPassword = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false); if (savedInstanceState == null) { if (confirmCredentials) { @@ -579,6 +575,7 @@ public class ChooseLockPattern extends SettingsActivity { final boolean launched = builder.setRequestCode(CONFIRM_EXISTING_REQUEST) .setTitle(getString(R.string.unlock_set_unlock_launch_picker_title)) .setReturnCredentials(true) + .setRequestGatekeeperPassword(mRequestGatekeeperPassword) .setUserId(mUserId) .show(); @@ -859,7 +856,7 @@ public class ChooseLockPattern extends SettingsActivity { } } mSaveAndFinishWorker.start(mLockPatternUtils, required, - mHasChallenge, mChallenge, mChosenPattern, mCurrentCredential, mUserId); + mRequestGatekeeperPassword, mChosenPattern, mCurrentCredential, mUserId); } @Override @@ -889,10 +886,10 @@ public class ChooseLockPattern extends SettingsActivity { private LockscreenCredential mCurrentCredential; private boolean mLockVirgin; - public void start(LockPatternUtils utils, boolean credentialRequired, boolean hasChallenge, - long challenge, LockscreenCredential chosenPattern, + public void start(LockPatternUtils utils, boolean credentialRequired, + boolean requestGatekeeperPassword, LockscreenCredential chosenPattern, LockscreenCredential currentCredential, int userId) { - prepare(utils, credentialRequired, hasChallenge, challenge, userId); + prepare(utils, credentialRequired, requestGatekeeperPassword, userId); mCurrentCredential = currentCredential != null ? currentCredential : LockscreenCredential.createNone(); @@ -913,18 +910,21 @@ public class ChooseLockPattern extends SettingsActivity { unifyProfileCredentialIfRequested(); } Intent result = null; - if (success && mHasChallenge) { + if (success && mRequestGatekeeperPassword) { + // If a Gatekeeper Password was requested, invoke the LockSettingsService code + // path to return a Gatekeeper Password based on the credential that the user + // chose. This should only be run if the credential was successfully set. final VerifyCredentialResponse response = mUtils.verifyCredential(mChosenPattern, - mChallenge, userId, 0 /* flags */); + userId, LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW); - if (!response.isMatched() || response.getGatekeeperHAT() == null) { + if (!response.isMatched() || response.getGatekeeperPw() == null) { Log.e(TAG, "critical: bad response or missing GK HAT for known good pattern: " + response.toString()); } result = new Intent(); - result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, - response.getGatekeeperHAT()); + result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW, + response.getGatekeeperPw()); } return Pair.create(success, result); } diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 04046553651..cd705c4615b 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -31,7 +31,9 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; +import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockscreenCredential; import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; @@ -45,8 +47,9 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_TYPE = "type"; public static final String EXTRA_KEY_PASSWORD = "password"; public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials"; - public static final String EXTRA_KEY_HAS_CHALLENGE = "has_challenge"; - public static final String EXTRA_KEY_CHALLENGE = "challenge"; + // Force the verifyCredential path instead of checkCredential path. This will be removed + // after b/161956762 is resolved. + public static final String EXTRA_KEY_FORCE_VERIFY = "force_verify"; // Gatekeeper HardwareAuthToken public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token"; public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint"; @@ -122,8 +125,7 @@ public final class ChooseLockSettingsHelper { // ChooseLockSettingsHelper will determine the caller's userId if none provided. private int mUserId; private boolean mAllowAnyUserId; - // The challenge can be 0, which is different than "no challenge" - @Nullable Long mChallenge; + private boolean mForceVerifyPath; boolean mRequestGatekeeperPassword; public Builder(@NonNull Activity activity) { @@ -182,6 +184,10 @@ public final class ChooseLockSettingsHelper { * {@link #EXTRA_KEY_TYPE}, {@link #EXTRA_KEY_PASSWORD}, * {@link #EXTRA_KEY_CHALLENGE_TOKEN}, {@link #EXTRA_KEY_GK_PW} * Note that if this is true, this can only be called internally. + * + * This should also generally be set if + * {@link #setRequestGatekeeperPassword(boolean)} (boolean)} is + * set. */ @NonNull public Builder setReturnCredentials(boolean returnCredentials) { mReturnCredentials = returnCredentials; @@ -226,14 +232,11 @@ public final class ChooseLockSettingsHelper { } /** - * @param challenge an opaque payload that will be wrapped in the Gatekeeper's payload - * if authentication is successful. Common use case is for the caller's - * secure layer (e.g. Trusted Execution Environment) to 1) verify that - * the Gatekeeper HAT's HMAC is valid, and 2) if so, perform an operation - * based on the challenge. + * @param forceVerifyPath Forces the VerifyCredential path instead of the CheckCredential + * path. This will be removed after b/161956762 is resolved. */ - @NonNull public Builder setChallenge(long challenge) { - mChallenge = challenge; + @NonNull public Builder setForceVerifyPath(boolean forceVerifyPath) { + mForceVerifyPath = forceVerifyPath; return this; } @@ -246,9 +249,6 @@ public final class ChooseLockSettingsHelper { * Upon confirmation of the user's password, the Gatekeeper Password will be returned via * onActivityResult with the key being {@link #EXTRA_KEY_GK_PW}. * @param requestGatekeeperPassword - * - * Note that invoking {@link #setChallenge(long)} will be treated as a no-op if Gatekeeper - * Password has been requested. */ @NonNull public Builder setRequestGatekeeperPassword(boolean requestGatekeeperPassword) { mRequestGatekeeperPassword = requestGatekeeperPassword; @@ -266,10 +266,10 @@ public final class ChooseLockSettingsHelper { + " onActivityResult"); } - if (mChallenge != null && !mReturnCredentials) { + if (mRequestGatekeeperPassword && !mReturnCredentials) { // HAT containing the signed challenge will not be available to the caller. - Log.w(TAG, "Challenge set but not requesting ReturnCredentials. Are you sure this" - + " is what you want?"); + Log.w(TAG, "Requested gatekeeper password but not requesting ReturnCredentials. Are" + + " you sure this is what you want?"); } return new ChooseLockSettingsHelper(this, mActivity, mFragment); @@ -285,29 +285,28 @@ public final class ChooseLockSettingsHelper { * @return true if the confirmation activity is shown (e.g. user has a credential set up) */ public boolean launch() { - final long challenge = mBuilder.mChallenge != null ? mBuilder.mChallenge : 0L; return launchConfirmationActivity(mBuilder.mRequestCode, mBuilder.mTitle, mBuilder.mHeader, mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal, - mBuilder.mChallenge != null, challenge, mBuilder.mUserId, - mBuilder.mAlternateButton, mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly, + mBuilder.mForceVerifyPath, mBuilder.mUserId, mBuilder.mAlternateButton, + mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPassword); } private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, - boolean returnCredentials, boolean external, boolean hasChallenge, - long challenge, int userId, @Nullable CharSequence alternateButton, - boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPassword) { + boolean returnCredentials, boolean external, boolean forceVerifyPath, + int userId, @Nullable CharSequence alternateButton, boolean allowAnyUser, + boolean foregroundOnly, boolean requestGatekeeperPassword) { final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId); boolean launched = false; switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) { case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: launched = launchConfirmationActivity(request, title, header, description, - returnCredentials || hasChallenge + returnCredentials ? ConfirmLockPattern.InternalActivity.class : ConfirmLockPattern.class, returnCredentials, external, - hasChallenge, challenge, userId, alternateButton, allowAnyUser, + forceVerifyPath, userId, alternateButton, allowAnyUser, foregroundOnly, requestGatekeeperPassword); break; case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: @@ -317,10 +316,10 @@ public final class ChooseLockSettingsHelper { case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: launched = launchConfirmationActivity(request, title, header, description, - returnCredentials || hasChallenge + returnCredentials ? ConfirmLockPassword.InternalActivity.class : ConfirmLockPassword.class, returnCredentials, external, - hasChallenge, challenge, userId, alternateButton, allowAnyUser, + forceVerifyPath, userId, alternateButton, allowAnyUser, foregroundOnly, requestGatekeeperPassword); break; } @@ -329,8 +328,8 @@ public final class ChooseLockSettingsHelper { private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header, CharSequence message, Class activityClass, boolean returnCredentials, - boolean external, boolean hasChallenge, long challenge, - int userId, @Nullable CharSequence alternateButton, boolean allowAnyUser, + boolean external, boolean forceVerifyPath, int userId, + @Nullable CharSequence alternateButton, boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPassword) { final Intent intent = new Intent(); intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); @@ -342,8 +341,7 @@ public final class ChooseLockSettingsHelper { intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external); intent.putExtra(ConfirmDeviceCredentialBaseFragment.USE_FADE_ANIMATION, external); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, hasChallenge); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, forceVerifyPath); intent.putExtra(Intent.EXTRA_USER_ID, userId); intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly); diff --git a/src/com/android/settings/password/ChooseLockTypeDialogFragment.java b/src/com/android/settings/password/ChooseLockTypeDialogFragment.java index 8793471e206..d31524bf4dc 100644 --- a/src/com/android/settings/password/ChooseLockTypeDialogFragment.java +++ b/src/com/android/settings/password/ChooseLockTypeDialogFragment.java @@ -74,7 +74,7 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment // Copy the original extras into the new intent copyBooleanExtra(activityIntent, intent, - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); + ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false); copyBooleanExtra(activityIntent, intent, ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false); if (activityIntent.hasExtra( @@ -83,8 +83,6 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment ChooseLockGenericFragment.EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS)); } intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, selectedLockType.defaultQuality); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, - activityIntent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0)); WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent); activity.startActivity(intent); activity.finish(); diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index 9a2f525eb0b..6a97dcd1b45 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.hardware.biometrics.BiometricConstants; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback; import android.hardware.biometrics.PromptInfo; @@ -81,18 +80,6 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { return intent; } - public static Intent createIntent(CharSequence title, CharSequence details, long challenge) { - Intent intent = new Intent(); - intent.setClassName(SETTINGS_PACKAGE_NAME, - ConfirmDeviceCredentialActivity.class.getName()); - intent.putExtra(KeyguardManager.EXTRA_TITLE, title); - intent.putExtra(KeyguardManager.EXTRA_DESCRIPTION, details); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - return intent; - } - - private BiometricManager mBiometricManager; private BiometricFragment mBiometricFragment; private DevicePolicyManager mDevicePolicyManager; private LockPatternUtils mLockPatternUtils; @@ -181,7 +168,6 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); getWindow().setStatusBarColor(Color.TRANSPARENT); - mBiometricManager = getSystemService(BiometricManager.class); mDevicePolicyManager = getSystemService(DevicePolicyManager.class); mUserManager = UserManager.get(this); mTrustManager = getSystemService(TrustManager.class); @@ -394,7 +380,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { .setDescription(mDetails) .setExternal(true) .setUserId(mUserId) - .setChallenge(0L) + .setForceVerifyPath(true) .show(); } else if (mCredentialMode == CREDENTIAL_NORMAL) { final ChooseLockSettingsHelper.Builder builder = diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index 23320902059..ea4c992a5ac 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -72,7 +72,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr protected boolean mReturnCredentials = false; protected boolean mReturnGatekeeperPassword = false; - protected boolean mVerifyChallenge = false; + protected boolean mForceVerifyPath = false; protected Button mCancelButton; /** Button allowing managed profile password reset, null when is not shown. */ @Nullable protected Button mForgotButton; @@ -103,8 +103,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr mReturnGatekeeperPassword = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false); - mVerifyChallenge = intent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); + mForceVerifyPath = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, false); // Only take this argument into account if it belongs to the current profile. mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(), diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index 85f44fd5c69..c90103210a9 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -49,7 +49,6 @@ import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.TextViewInputDisabler; -import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.R; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils; @@ -390,7 +389,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW); return; } - } else if (mVerifyChallenge) { + } else if (mForceVerifyPath) { if (isInternalActivity()) { startVerifyPassword(credential, intent, 0 /* flags */); return; @@ -409,8 +408,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { private void startVerifyPassword(LockscreenCredential credential, final Intent intent, @LockPatternUtils.VerifyFlag int flags) { - long challenge = getActivity().getIntent().getLongExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); final int localEffectiveUserId = mEffectiveUserId; final int localUserId = mUserId; final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> { @@ -430,12 +427,10 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { localEffectiveUserId); }; mPendingLockCheck = (localEffectiveUserId == localUserId) - ? LockPatternChecker.verifyCredential( - mLockPatternUtils, credential, challenge, localUserId, flags, - onVerifyCallback) - : LockPatternChecker.verifyTiedProfileChallenge( - mLockPatternUtils, credential, challenge, localUserId, flags, - onVerifyCallback); + ? LockPatternChecker.verifyCredential(mLockPatternUtils, credential, + localUserId, flags, onVerifyCallback) + : LockPatternChecker.verifyTiedProfileChallenge(mLockPatternUtils, credential, + localUserId, flags, onVerifyCallback); } private void startCheckPassword(final LockscreenCredential credential, diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java index 5b11bfedc0d..a8099526acd 100644 --- a/src/com/android/settings/password/ConfirmLockPattern.java +++ b/src/com/android/settings/password/ConfirmLockPattern.java @@ -40,7 +40,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockscreenCredential; -import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.R; import com.android.settingslib.animation.AppearAnimationCreator; import com.android.settingslib.animation.AppearAnimationUtils; @@ -432,7 +431,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW); return; } - } else if (mVerifyChallenge) { + } else if (mForceVerifyPath) { if (isInternalActivity()) { startVerifyPattern(credential, intent, 0 /* flags */); return; @@ -453,8 +452,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { final Intent intent, @LockPatternUtils.VerifyFlag int flags) { final int localEffectiveUserId = mEffectiveUserId; final int localUserId = mUserId; - long challenge = getActivity().getIntent().getLongExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> { mPendingLockCheck = null; @@ -474,10 +471,10 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { }; mPendingLockCheck = (localEffectiveUserId == localUserId) ? LockPatternChecker.verifyCredential( - mLockPatternUtils, pattern, challenge, localUserId, flags, + mLockPatternUtils, pattern, localUserId, flags, onVerifyCallback) : LockPatternChecker.verifyTiedProfileChallenge( - mLockPatternUtils, pattern, challenge, localUserId, flags, + mLockPatternUtils, pattern, localUserId, flags, onVerifyCallback); } diff --git a/src/com/android/settings/password/SaveChosenLockWorkerBase.java b/src/com/android/settings/password/SaveChosenLockWorkerBase.java index 26e4d5aa8ad..cea908b4a77 100644 --- a/src/com/android/settings/password/SaveChosenLockWorkerBase.java +++ b/src/com/android/settings/password/SaveChosenLockWorkerBase.java @@ -42,8 +42,7 @@ abstract class SaveChosenLockWorkerBase extends Fragment { private Intent mResultData; protected LockPatternUtils mUtils; - protected boolean mHasChallenge; - protected long mChallenge; + protected boolean mRequestGatekeeperPassword; protected boolean mWasSecureBefore; protected int mUserId; protected int mUnificationProfileId = UserHandle.USER_NULL; @@ -69,12 +68,10 @@ abstract class SaveChosenLockWorkerBase extends Fragment { } protected void prepare(LockPatternUtils utils, boolean credentialRequired, - boolean hasChallenge, long challenge, int userId) { + boolean requestGatekeeperPassword, int userId) { mUtils = utils; mUserId = userId; - - mHasChallenge = hasChallenge; - mChallenge = challenge; + mRequestGatekeeperPassword = requestGatekeeperPassword; // This will be a no-op for non managed profiles. mWasSecureBefore = mUtils.isSecure(mUserId); diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java index 7f206a0b781..02d86b2239e 100644 --- a/src/com/android/settings/password/SetNewPasswordController.java +++ b/src/com/android/settings/password/SetNewPasswordController.java @@ -135,26 +135,22 @@ final class SetNewPasswordController { private Bundle getFingerprintChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - long challenge = mFingerprintManager.generateChallengeBlocking(); chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, PASSWORD_QUALITY_SOMETHING); chooseLockExtras.putBoolean( ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); - chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true); return chooseLockExtras; } private Bundle getFaceChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - long challenge = mFaceManager.generateChallengeBlocking(); chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, PASSWORD_QUALITY_SOMETHING); chooseLockExtras.putBoolean( ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); - chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true); return chooseLockExtras; } diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 5ec6f41abbf..abeb667a964 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -92,8 +92,8 @@ public class ChooseLockPasswordTest { .setUserId(123) .build(); - assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true)) - .named("EXTRA_KEY_HAS_CHALLENGE") + assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, false)) + .named("EXTRA_KEY_FORCE_VERIFY") .isFalse(); assertThat((LockscreenCredential) intent.getParcelableExtra( ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)) @@ -108,19 +108,16 @@ public class ChooseLockPasswordTest { } @Test - public void intentBuilder_setChallenge_shouldAddExtras() { + public void intentBuilder_setRequestGatekeeperPassword_shouldAddExtras() { Intent intent = new IntentBuilder(application) - .setChallenge(12345L) + .setRequestGatekeeperPassword(true) .setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC) .setUserId(123) .build(); - assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false)) - .named("EXTRA_KEY_HAS_CHALLENGE") + assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false)) + .named("EXTRA_KEY_REQUEST_GK_PW") .isTrue(); - assertThat(intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L)) - .named("EXTRA_KEY_CHALLENGE") - .isEqualTo(12345L); assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0)) .named("PASSWORD_TYPE_KEY") .isEqualTo(PASSWORD_QUALITY_ALPHANUMERIC); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java index 3f3dcd6d78c..f5f0e37da26 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java @@ -59,8 +59,8 @@ public class ChooseLockPatternTest { .build(); assertThat(intent - .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true)) - .named("EXTRA_KEY_HAS_CHALLENGE") + .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, false)) + .named("EXTRA_KEY_FORCE_VERIFY") .isFalse(); assertThat((LockscreenCredential) intent .getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)) @@ -72,20 +72,16 @@ public class ChooseLockPatternTest { } @Test - public void intentBuilder_setChallenge_shouldAddExtras() { + public void intentBuilder_setRequestGatekeeperPassword_shouldAddExtras() { Intent intent = new IntentBuilder(application) - .setChallenge(12345L) + .setRequestGatekeeperPassword(true) .setUserId(123) .build(); assertThat(intent - .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false)) - .named("EXTRA_KEY_HAS_CHALLENGE") + .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false)) + .named("EXTRA_KEY_REQUEST_GK_PW") .isTrue(); - assertThat(intent - .getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L)) - .named("EXTRA_KEY_CHALLENGE") - .isEqualTo(12345L); assertThat(intent .getIntExtra(Intent.EXTRA_USER_ID, 0)) .named("EXTRA_USER_ID") diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java index 978e4cd9433..d082bded9ab 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java @@ -36,7 +36,7 @@ import org.robolectric.shadows.ShadowActivity.IntentForResult; public class ChooseLockSettingsHelperTest { @Test - public void testLaunchConfirmationActivityWithExternalAndChallenge() { + public void testLaunchConfirmationActivityWithExternal() { final Activity activity = Robolectric.setupActivity(Activity.class); ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(activity); @@ -45,7 +45,6 @@ public class ChooseLockSettingsHelperTest { .setHeader("header") .setDescription("description") .setExternal(true) - .setChallenge(10000L) .setUserId(UserHandle.myUserId()); ChooseLockSettingsHelper helper = getChooseLockSettingsHelper(builder); helper.launch(); @@ -53,15 +52,10 @@ public class ChooseLockSettingsHelperTest { ShadowActivity shadowActivity = Shadows.shadowOf(activity); Intent startedIntent = shadowActivity.getNextStartedActivity(); - assertEquals(new ComponentName("com.android.settings", - ConfirmLockPattern.InternalActivity.class.getName()), + assertEquals(new ComponentName("com.android.settings", ConfirmLockPattern.class.getName()), startedIntent.getComponent()); assertFalse(startedIntent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false)); - assertTrue(startedIntent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false)); - assertEquals(10000L, startedIntent.getLongExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L)); assertTrue((startedIntent.getFlags() & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0); assertFalse(startedIntent.getBooleanExtra( ConfirmDeviceCredentialBaseFragment.DARK_THEME, false)); @@ -72,7 +66,7 @@ public class ChooseLockSettingsHelperTest { } @Test - public void testLaunchConfirmationActivityInternalAndChallenge() { + public void testLaunchConfirmationActivityInternal() { final Activity activity = Robolectric.setupActivity(Activity.class); ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(activity); @@ -80,7 +74,8 @@ public class ChooseLockSettingsHelperTest { .setTitle("title") .setHeader("header") .setDescription("description") - .setChallenge(10000L) + .setForceVerifyPath(true) + .setReturnCredentials(true) .setUserId(UserHandle.myUserId()); ChooseLockSettingsHelper helper = getChooseLockSettingsHelper(builder); helper.launch(); @@ -91,12 +86,10 @@ public class ChooseLockSettingsHelperTest { assertEquals(new ComponentName("com.android.settings", ConfirmLockPattern.InternalActivity.class.getName()), startedIntent.getComponent()); - assertFalse(startedIntent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false)); assertTrue(startedIntent.getBooleanExtra( - ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false)); - assertEquals(10000L, startedIntent.getLongExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L)); + ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, true)); + assertTrue(startedIntent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, true)); assertFalse((startedIntent.getFlags() & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0); assertFalse(startedIntent.getBooleanExtra( ConfirmDeviceCredentialBaseFragment.DARK_THEME, false)); diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java index d3832a4f91d..c745a1d4e94 100644 --- a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java @@ -19,14 +19,11 @@ package com.android.settings.password; import static android.content.pm.PackageManager.FEATURE_FACE; import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; -import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment - .HIDE_DISABLED_PREFS; -import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment - .MINIMUM_QUALITY_KEY; -import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE; +import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS; +import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT; -import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW; import static com.google.common.truth.Truth.assertThat; @@ -278,12 +275,8 @@ public final class SetNewPasswordControllerTest { "All disabled preference should be removed.", actualBundle.getBoolean(HIDE_DISABLED_PREFS)); assertTrue( - "There must be a fingerprint challenge.", - actualBundle.getBoolean(EXTRA_KEY_HAS_CHALLENGE)); - assertEquals( - "The fingerprint challenge must come from the FingerprintManager", - FINGERPRINT_CHALLENGE, - actualBundle.getLong(EXTRA_KEY_CHALLENGE)); + "Fingerprint enroll must request Gatekeeper Password.", + actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW)); assertTrue( "The request must be a fingerprint set up request.", actualBundle.getBoolean(EXTRA_KEY_FOR_FINGERPRINT)); @@ -302,12 +295,8 @@ public final class SetNewPasswordControllerTest { "All disabled preference should be removed.", actualBundle.getBoolean(HIDE_DISABLED_PREFS)); assertTrue( - "There must be a face challenge.", - actualBundle.getBoolean(EXTRA_KEY_HAS_CHALLENGE)); - assertEquals( - "The face challenge must come from the FaceManager", - FACE_CHALLENGE, - actualBundle.getLong(EXTRA_KEY_CHALLENGE)); + "Face enroll must request Gatekeeper Password", + actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW)); assertTrue( "The request must be a face set up request.", actualBundle.getBoolean(EXTRA_KEY_FOR_FACE)); From 66bfe45f993581d49d738899a760a133c9a15958 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 30 Jul 2020 14:04:20 -0700 Subject: [PATCH 4/5] BiometricEnrollIntro should use non-blocking generateChallenge GenerateChallenge used to block when showing the credential screen. Now that GenerateChallenge is moved to after the credential screen is shown, we need to delay the next button instead. This is generally non percievable to the user, but this is more robust against busy system server. Fixes: 161325267 Test: Enroll fingerprint/face device Change-Id: I0fbbef8bf469e32bed251acf22556ad2ea8e2933 --- .../BiometricEnrollIntroduction.java | 21 ++++++++++++++----- .../face/FaceEnrollIntroduction.java | 7 ++++--- .../FingerprintEnrollIntroduction.java | 7 ++++--- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index c97c4d98b7b..db2f2913342 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -101,7 +101,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase /** * @return the challenge generated by the biometric hardware */ - protected abstract long getChallenge(); + protected abstract void getChallenge(GenerateChallengeCallback callback); /** * @return one of the ChooseLockSettingsHelper#EXTRA_KEY_FOR_* constants @@ -125,6 +125,10 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase */ public abstract void onClick(LinkSpan span); + protected interface GenerateChallengeCallback { + void onChallengeGenerated(long challenge); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -267,12 +271,15 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase return; } } else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) { + mConfirmingCredentials = false; if (resultCode == RESULT_FINISHED) { updatePasswordQuality(); - mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, getChallenge()); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); - mConfirmingCredentials = false; - return; + getNextButton().setEnabled(false); + getChallenge((challenge -> { + mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, challenge); + getNextButton().setEnabled(true); + })); } else { setResult(resultCode, data); finish(); @@ -280,8 +287,12 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase } else if (requestCode == CONFIRM_REQUEST) { mConfirmingCredentials = false; if (resultCode == RESULT_OK && data != null) { - mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, getChallenge()); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); + getNextButton().setEnabled(false); + getChallenge((challenge -> { + mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, challenge); + getNextButton().setEnabled(true); + })); } else { setResult(resultCode, data); finish(); diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index dbdf03de3bb..378a3c12f5d 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -180,12 +180,13 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { } @Override - protected long getChallenge() { + protected void getChallenge(GenerateChallengeCallback callback) { mFaceManager = Utils.getFaceManagerOrNull(this); if (mFaceManager == null) { - return 0; + callback.onChallengeGenerated(0L); + return; } - return mFaceManager.generateChallengeBlocking(); + mFaceManager.generateChallenge(callback::onChallengeGenerated); } @Override diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java index ccfb0f26155..0b5c7b0ff77 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java @@ -131,12 +131,13 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction { } @Override - protected long getChallenge() { + protected void getChallenge(GenerateChallengeCallback callback) { mFingerprintManager = Utils.getFingerprintManagerOrNull(this); if (mFingerprintManager == null) { - return 0; + callback.onChallengeGenerated(0L); + return; } - return mFingerprintManager.generateChallengeBlocking(); + mFingerprintManager.generateChallenge(callback::onChallengeGenerated); } @Override From bee84e2daaf47afa262a43cbf21971e3696627c4 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 30 Jul 2020 15:38:54 -0700 Subject: [PATCH 5/5] Remove remainder of generateChallengeBlocking Test: make -j56 RunSettingsRoboTests Face Tests: Test: Open face settings, remove face, add face Test: Open face settings, but cancel credential confirmation. Face settings does not show up Test: adb shell am start -a android.app.action.SET_NEW_PASSWORD Able to enroll face Fingerprint Tests: Test: Open fingerprint settings, add button is shown Test: Open fingerprint settings, but cancel credential confirmation. Fingerprint settings does not show up Test: adb shell am start -a android.app.action.SET_NEW_PASSWORD Able to enroll fingerprint Bug: 162533680 Change-Id: Ie448ed086e73b0b545bd3a2e62437c543f7aad6c --- .../BiometricEnrollIntroduction.java | 2 +- .../face/FaceEnrollIntroduction.java | 24 +++++++++-------- .../FingerprintEnrollFindSensor.java | 22 ++++++++++------ .../fingerprint/FingerprintSettings.java | 26 +++++++++++-------- .../SetNewPasswordControllerTest.java | 6 ----- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index db2f2913342..8634441e9bb 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -164,7 +164,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase // No password registered, launch into enrollment wizard. mConfirmingCredentials = true; launchChooseLock(); - } else if (mToken == null) { + } else if (!BiometricUtils.containsGatekeeperPassword(getIntent()) && mToken == null) { // It's possible to have a token but mLaunchedConfirmLock == false, since // ChooseLockGeneric can pass us a token. mConfirmingCredentials = true; diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index 378a3c12f5d..3db51fec4c7 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -46,19 +46,9 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { @Override protected void onCreate(Bundle savedInstanceState) { - mFaceManager = Utils.getFaceManagerOrNull(this); - // Check if the Gateekeper Password exists. If so, request for a Gatekeeper HAT to be - // created. This needs to be cleaned up, since currently it's not very clear which - // superclass is responsible for what. Doing the check here is the least risky way. - if (mToken == null && BiometricUtils.containsGatekeeperPassword(getIntent())) { - // We either block on generateChallenge, or need to gray out the "next" button until - // the challenge is ready. Let's just do this for now. - final long challenge = mFaceManager.generateChallengeBlocking(); - mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge); - } - super.onCreate(savedInstanceState); + mFaceManager = Utils.getFaceManagerOrNull(this); mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext()) .getFaceFeatureProvider(); @@ -106,6 +96,18 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { ? R.string.security_settings_face_enroll_introduction_footer_part_2 : R.string.security_settings_face_settings_footer_attention_not_supported; footer2.setText(footer2TextResource); + + // This path is an entry point for SetNewPasswordController, e.g. + // adb shell am start -a android.app.action.SET_NEW_PASSWORD + if (mToken == null && BiometricUtils.containsGatekeeperPassword(getIntent())) { + mFooterBarMixin.getPrimaryButton().setEnabled(false); + // We either block on generateChallenge, or need to gray out the "next" button until + // the challenge is ready. Let's just do this for now. + mFaceManager.generateChallenge(challenge -> { + mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge); + mFooterBarMixin.getPrimaryButton().setEnabled(true); + }); + } } @Override diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java index 00fdb0ae4f7..8795f7f6f5b 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java @@ -61,19 +61,25 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase { setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title); + // This is an entry point for SetNewPasswordController, e.g. + // adb shell am start -a android.app.action.SET_NEW_PASSWORD if (mToken == null && BiometricUtils.containsGatekeeperPassword(getIntent())) { final FingerprintManager fpm = getSystemService(FingerprintManager.class); - final long challenge = fpm.generateChallengeBlocking(); - mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge); + fpm.generateChallenge(challenge -> { + mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge); - // Put this into the intent. This is really just to work around the fact that the - // enrollment sidecar gets the HAT from the activity's intent, rather than having - // it passed in. - getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); + // Put this into the intent. This is really just to work around the fact that the + // enrollment sidecar gets the HAT from the activity's intent, rather than having + // it passed in. + getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); + + startLookingForFingerprint(); + }); + } else if (mToken != null) { + // HAT passed in from somewhere else, such as FingerprintEnrollIntroduction + startLookingForFingerprint(); } - startLookingForFingerprint(); // already confirmed, so start looking for fingerprint - View animationView = findViewById(R.id.fingerprint_sensor_location_animation); if (animationView instanceof FingerprintFindSensorAnimation) { mAnimation = (FingerprintFindSensorAnimation) animationView; diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 3eaf506f44d..a2d67f41d86 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -411,6 +411,8 @@ public class FingerprintSettings extends SubSettings { private void updateAddPreference() { if (getActivity() == null) return; // Activity went away + final Preference addPreference = findPreference(KEY_FINGERPRINT_ADD); + /* Disable preference if too many fingerprints added */ final int max = getContext().getResources().getInteger( com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); @@ -420,9 +422,8 @@ public class FingerprintSettings extends SubSettings { final boolean removalInProgress = mRemovalSidecar.inProgress(); CharSequence maxSummary = tooMany ? getContext().getString(R.string.fingerprint_add_max, max) : ""; - Preference addPreference = findPreference(KEY_FINGERPRINT_ADD); addPreference.setSummary(maxSummary); - addPreference.setEnabled(!tooMany && !removalInProgress); + addPreference.setEnabled(!tooMany && !removalInProgress && mToken != null); } private void createFooterPreference(PreferenceGroup root) { @@ -569,11 +570,19 @@ public class FingerprintSettings extends SubSettings { if (requestCode == CONFIRM_REQUEST || requestCode == CHOOSE_LOCK_GENERIC_REQUEST) { mLaunchedConfirm = false; if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) { - if (data != null) { - final long challenge = mFingerprintManager.generateChallengeBlocking(); - mToken = BiometricUtils.requestGatekeeperHat(getActivity(), data, mUserId, - challenge); + if (data != null && BiometricUtils.containsGatekeeperPassword(data)) { + mFingerprintManager.generateChallenge(challenge -> { + mToken = BiometricUtils.requestGatekeeperHat(getActivity(), data, + mUserId, challenge); + updateAddPreference(); + }); + } else { + Log.d(TAG, "Data null or GK PW missing"); + finish(); } + } else { + Log.d(TAG, "Password not confirmed"); + finish(); } } else if (requestCode == ADD_FINGERPRINT_REQUEST) { mEnrollClicked = false; @@ -583,11 +592,6 @@ public class FingerprintSettings extends SubSettings { activity.finish(); } } - - if (mToken == null) { - // Didn't get an authentication, finishing - getActivity().finish(); - } } @Override diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java index c745a1d4e94..ce117b7ad72 100644 --- a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java @@ -54,8 +54,6 @@ import org.robolectric.RobolectricTestRunner; public final class SetNewPasswordControllerTest { private static final int CURRENT_USER_ID = 101; - private static final long FINGERPRINT_CHALLENGE = -9876512313131L; - private static final long FACE_CHALLENGE = 1352057789L; @Mock private PackageManager mPackageManager; @@ -76,11 +74,7 @@ public final class SetNewPasswordControllerTest { mSetNewPasswordController = new SetNewPasswordController( CURRENT_USER_ID, mPackageManager, mFingerprintManager, mFaceManager, mDevicePolicyManager, mUi); - - when(mFingerprintManager.generateChallengeBlocking()).thenReturn(FINGERPRINT_CHALLENGE); when(mPackageManager.hasSystemFeature(eq(FEATURE_FINGERPRINT))).thenReturn(true); - - when(mFaceManager.generateChallengeBlocking()).thenReturn(FACE_CHALLENGE); when(mPackageManager.hasSystemFeature(eq(FEATURE_FACE))).thenReturn(true); }