Commit c05425f5 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[Passwords] Add BiometricAuthenticator JNI bridge

This change adds a JNI bridge for the BiometricAuthenticator and
implements BiometricAuthenticator::CanAuthenticate() in a backwards
compatible way.

Bug: 1031483
Change-Id: I273aa655879c4abfb0afedd841744a53f914c71a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2012024
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734562}
parent 5544bae6
......@@ -2729,6 +2729,7 @@ generate_jni("chrome_jni_headers") {
"java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java",
"java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java",
"java/src/org/chromium/chrome/browser/password_manager/AutoSigninSnackbarController.java",
"java/src/org/chromium/chrome/browser/password_manager/BiometricAuthenticatorBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/Credential.java",
"java/src/org/chromium/chrome/browser/password_manager/CredentialLeakDialogBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/OnboardingDialogBridge.java",
......
......@@ -1209,6 +1209,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java",
"java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java",
"java/src/org/chromium/chrome/browser/password_manager/AutoSigninSnackbarController.java",
"java/src/org/chromium/chrome/browser/password_manager/BiometricAuthenticatorBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/Credential.java",
"java/src/org/chromium/chrome/browser/password_manager/CredentialLeakDialogBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/GooglePasswordManagerUIProvider.java",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.password_manager;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_SUCCESS;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.os.Build;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.ui.base.WindowAndroid;
class BiometricAuthenticatorBridge {
private final Context mContext;
private BiometricAuthenticatorBridge(WindowAndroid windowAndroid) {
mContext = windowAndroid.getApplicationContext();
}
@CalledByNative
private static BiometricAuthenticatorBridge create(WindowAndroid windowAndroid) {
return new BiometricAuthenticatorBridge(windowAndroid);
}
@CalledByNative
public @BiometricsAvailability int canAuthenticate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
BiometricManager biometricManager = mContext.getSystemService(BiometricManager.class);
switch (biometricManager.canAuthenticate()) {
case BIOMETRIC_SUCCESS:
return BiometricsAvailability.AVAILABLE;
case BIOMETRIC_ERROR_NO_HARDWARE:
case BIOMETRIC_ERROR_HW_UNAVAILABLE:
return BiometricsAvailability.NO_HARDWARE;
case BIOMETRIC_ERROR_NONE_ENROLLED:
return BiometricsAvailability.NOT_ENROLLED;
default:
return BiometricsAvailability.NO_HARDWARE;
}
} else {
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.from(mContext);
if (!fingerprintManager.isHardwareDetected()) {
return BiometricsAvailability.NO_HARDWARE;
} else if (!fingerprintManager.hasEnrolledFingerprints()) {
return BiometricsAvailability.NOT_ENROLLED;
} else {
return BiometricsAvailability.AVAILABLE;
}
}
}
}
......@@ -7,24 +7,30 @@
#include <memory>
#include <utility>
#include "base/android/jni_android.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/location.h"
#include "base/task/post_task.h"
#include "chrome/android/chrome_jni_headers/BiometricAuthenticatorBridge_jni.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/password_manager/core/browser/biometric_authenticator.h"
#include "components/password_manager/core/browser/origin_credential_store.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/view_android.h"
using base::android::AttachCurrentThread;
using content::WebContents;
using password_manager::BiometricsAvailability;
using password_manager::UiCredential;
// static
std::unique_ptr<ChromeBiometricAuthenticator>
ChromeBiometricAuthenticator::Create() {
ChromeBiometricAuthenticator::Create(WebContents* web_contents) {
if (!base::FeatureList::IsEnabled(autofill::features::kAutofillTouchToFill))
return nullptr;
......@@ -33,16 +39,32 @@ ChromeBiometricAuthenticator::Create() {
return nullptr;
}
return std::make_unique<BiometicAuthenticatorAndroid>();
auto* window_android = web_contents->GetNativeView()->GetWindowAndroid();
if (!window_android) {
// GetWindowAndroid() can be null in tests.
return nullptr;
}
return std::make_unique<BiometricAuthenticatorAndroid>(window_android);
}
BiometricsAvailability BiometicAuthenticatorAndroid::CanAuthenticate() {
// TODO(crbug.com/1031483): Implement.
return BiometricsAvailability::kAvailable;
BiometricAuthenticatorAndroid::BiometricAuthenticatorAndroid(
ui::WindowAndroid* window_android) {
java_object_ = Java_BiometricAuthenticatorBridge_create(
AttachCurrentThread(), window_android->GetJavaObject());
}
BiometricAuthenticatorAndroid::~BiometricAuthenticatorAndroid() = default;
BiometricsAvailability BiometricAuthenticatorAndroid::CanAuthenticate() {
return static_cast<BiometricsAvailability>(
Java_BiometricAuthenticatorBridge_canAuthenticate(AttachCurrentThread(),
java_object_));
}
void BiometicAuthenticatorAndroid::Authenticate(const UiCredential& credential,
AuthenticateCallback callback) {
void BiometricAuthenticatorAndroid::Authenticate(
const UiCredential& credential,
AuthenticateCallback callback) {
// TODO(crbug.com/1031483): Implement.
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(std::move(callback), true));
......
......@@ -5,16 +5,26 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_BIOMETRIC_AUTHENTICATOR_ANDROID_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_BIOMETRIC_AUTHENTICATOR_ANDROID_H_
#include "base/android/scoped_java_ref.h"
#include "chrome/browser/password_manager/chrome_biometric_authenticator.h"
#include "components/password_manager/core/browser/biometric_authenticator.h"
#include "components/password_manager/core/browser/origin_credential_store.h"
#include "ui/android/window_android.h"
// Android implementation of the BiometricAuthenticator interface.
class BiometicAuthenticatorAndroid : public ChromeBiometricAuthenticator {
class BiometricAuthenticatorAndroid : public ChromeBiometricAuthenticator {
public:
explicit BiometricAuthenticatorAndroid(ui::WindowAndroid* window_android);
~BiometricAuthenticatorAndroid() override;
password_manager::BiometricsAvailability CanAuthenticate() override;
void Authenticate(const password_manager::UiCredential& credential,
AuthenticateCallback callback) override;
private:
// This object is an instance of BiometricAuthenticatorBridge, i.e. the Java
// counterpart to this class.
base::android::ScopedJavaGlobalRef<jobject> java_object_;
};
#endif // CHROME_BROWSER_PASSWORD_MANAGER_BIOMETRIC_AUTHENTICATOR_ANDROID_H_
......@@ -9,6 +9,10 @@
#include "components/password_manager/core/browser/biometric_authenticator.h"
namespace content {
class WebContents;
}
// Chrome wrapper around BiometricAuthenticator. Subclasses are expected to
// provide an implementation for Create(), instantiating authenticators for a
// given platform.
......@@ -18,7 +22,8 @@ class ChromeBiometricAuthenticator
// Create an instance of the ChromeBiometricAuthenticator. Trying to use this
// API on platforms that do not provide an implementation will result in a
// link error. So far only Android provides an implementation.
static std::unique_ptr<ChromeBiometricAuthenticator> Create();
static std::unique_ptr<ChromeBiometricAuthenticator> Create(
content::WebContents* web_contents);
};
#endif // CHROME_BROWSER_PASSWORD_MANAGER_CHROME_BIOMETRIC_AUTHENTICATOR_H_
......@@ -436,8 +436,10 @@ void ChromePasswordManagerClient::ShowTouchToFill(
password_manager::BiometricAuthenticator*
ChromePasswordManagerClient::GetBiometricAuthenticator() {
#if defined(OS_ANDROID)
if (!biometric_authenticator_)
biometric_authenticator_ = ChromeBiometricAuthenticator::Create();
if (!biometric_authenticator_) {
biometric_authenticator_ =
ChromeBiometricAuthenticator::Create(web_contents());
}
#endif
return biometric_authenticator_.get();
}
......
......@@ -757,46 +757,6 @@ TEST_F(ChromePasswordManagerClientTest, MissingUIDelegate) {
client->HideManualFallbackForSaving();
}
// Parameterized Touch To Fill features test.
class ChromePasswordManagerClientTouchToFillFeatureTest
: public ChromePasswordManagerClientTest,
public ::testing::WithParamInterface<std::tuple<bool, bool>> {
public:
ChromePasswordManagerClientTouchToFillFeatureTest() {
std::vector<base::Feature> enabled;
std::vector<base::Feature> disabled;
(IsTouchToFillEnabled() ? enabled : disabled)
.push_back(autofill::features::kAutofillTouchToFill);
(IsBiometricTouchToFillEnabled() ? enabled : disabled)
.push_back(password_manager::features::kBiometricTouchToFill);
feature_list_.InitWithFeatures(enabled, disabled);
}
protected:
bool IsTouchToFillEnabled() const { return std::get<0>(GetParam()); }
bool IsBiometricTouchToFillEnabled() const { return std::get<1>(GetParam()); }
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_P(ChromePasswordManagerClientTouchToFillFeatureTest,
GetBiometricAuthenticator) {
#if defined(OS_ANDROID)
EXPECT_EQ(IsTouchToFillEnabled() && IsBiometricTouchToFillEnabled(),
GetClient()->GetBiometricAuthenticator() != nullptr);
#else
EXPECT_EQ(nullptr, GetClient()->GetBiometricAuthenticator());
#endif
}
INSTANTIATE_TEST_SUITE_P(All,
ChromePasswordManagerClientTouchToFillFeatureTest,
::testing::Combine(::testing::Bool(),
::testing::Bool()));
#if defined(OS_ANDROID)
class ChromePasswordManagerClientAndroidTest
: public ChromePasswordManagerClientTest {
......
......@@ -377,6 +377,7 @@ static_library("password_generator") {
if (is_android) {
java_cpp_enum("password_manager_java_enums_srcjar") {
sources = [
"biometric_authenticator.h",
"manage_passwords_referrer.h",
"password_manager_metrics_util.h",
]
......
......@@ -14,6 +14,7 @@ class UiCredential;
// Different states for biometric availability for a given device. Either no
// biometric hardware is available, hardware is available but the user has no
// biometrics enrolled, or hardware is available and the user makes use of it.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.password_manager
enum class BiometricsAvailability {
kAvailable = 0,
kNoHardware = 1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment