Implement WebAuthN auth request for ActiveSessionAuthController
This CL adds a new type of request we can pass to ActiveSessionAuthController, that will modify it's behavior to properly interface with WebAuthN based authentication requests. Bug: b:360919706 Change-Id: I2a7005babe86607ffc651039cdaa256e640fdee7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5803213 Reviewed-by: Xiyuan Xia <xiyuan@chromium.org> Commit-Queue: Hardik Goyal <hardikgoyal@chromium.org> Reviewed-by: Hardik Goyal <hardikgoyal@chromium.org> Cr-Commit-Position: refs/heads/main@{#1348656}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b5b327b9da
commit
1d586d207c
ash
chrome/browser/webauthn
chromeos
enclave_manager.ccenclave_manager.hgpm_enclave_controller.ccunexportable_key_utils.hunexportable_key_utils_chromeos.ccunexportable_key_utils_chromeos_unittest.ccchromeos
ash
components
components
in_session_auth
tools/metrics/histograms/metadata/ash
@ -5314,6 +5314,9 @@ No devices connected.
|
||||
<message name="IDS_ASH_IN_SESSION_AUTH_ACCESSIBLE_TITLE" desc="Accessibility text read by chromevox to indicate which website / app we are authenticating for.">
|
||||
Verify your identity: <ph name="ORIGIN_NAME">$1<ex>example.com</ex></ph> would like to confirm it's you
|
||||
</message>
|
||||
<message name="IDS_ASH_IN_SESSION_WEBAUTHN_PROMPT" desc="Prompt for WebAuthN in the auth dialog">
|
||||
<ph name="ORIGIN_NAME">$1<ex>example.com</ex></ph> would like to confirm it's you
|
||||
</message>
|
||||
<message name="IDS_ASH_IN_SESSION_AUTH_SETTINGS_PROMPT" desc="Text shown in the settings auth dialog.">
|
||||
ChromeOS Settings would like to confirm it's you
|
||||
</message>
|
||||
|
@ -0,0 +1 @@
|
||||
80aad9678ed04f983f6d4e22a85578212457c47d
|
@ -92,6 +92,8 @@ const char* ReasonToString(AuthRequest::Reason reason) {
|
||||
return "PasswordManager";
|
||||
case AuthRequest::Reason::kSettings:
|
||||
return "Settings";
|
||||
case AuthRequest::Reason::kWebAuthN:
|
||||
return "WebAuthN";
|
||||
}
|
||||
NOTREACHED();
|
||||
}
|
||||
@ -196,7 +198,7 @@ bool ActiveSessionAuthControllerImpl::ShowAuthDialog(
|
||||
auth_request_ = std::move(auth_request);
|
||||
|
||||
title_ = l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_TITLE);
|
||||
description_ = l10n_util::GetStringUTF16(auth_request_->GetDescription());
|
||||
description_ = auth_request_->GetDescription();
|
||||
auth_factor_editor_ =
|
||||
std::make_unique<AuthFactorEditor>(UserDataAuthClient::Get());
|
||||
auth_performer_ = std::make_unique<AuthPerformer>(UserDataAuthClient::Get());
|
||||
|
@ -3084,6 +3084,13 @@ BASE_FEATURE(kAllowPinTimeoutSetup,
|
||||
"AllowPinTimeoutSetup",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
// This features controls whether or not we'll show the legacy WebAuthNDialog,
|
||||
// that lives in ash/in_session_auth/auth_dialog_contents_view or
|
||||
// the new dialog that's also shared with Settings and Password Manager,
|
||||
// that lives in ash/auth/view/active_session_auth_view
|
||||
BASE_FEATURE(kWebAuthNAuthDialogMerge,
|
||||
"WebAuthNAuthDialogMerge",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
// Use the staging URL as part of the "Messages" feature under "Connected
|
||||
// Devices" settings.
|
||||
@ -5021,6 +5028,10 @@ bool IsAllowPinTimeoutSetupEnabled() {
|
||||
return base::FeatureList::IsEnabled(kAllowPinTimeoutSetup);
|
||||
}
|
||||
|
||||
bool IsWebAuthNAuthDialogMergeEnabled() {
|
||||
return base::FeatureList::IsEnabled(kWebAuthNAuthDialogMerge);
|
||||
}
|
||||
|
||||
bool ShouldEnterOverviewFromWallpaper() {
|
||||
return base::FeatureList::IsEnabled(kEnterOverviewFromWallpaper);
|
||||
}
|
||||
|
@ -995,6 +995,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUseAnnotatedAccountId);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUseAuthPanelInSession);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAllowPasswordlessSetup);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAllowPinTimeoutSetup);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kWebAuthNAuthDialogMerge);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS)
|
||||
BASE_DECLARE_FEATURE(kActiveSessionAuth);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUseLoginShelfWidget);
|
||||
@ -1466,6 +1467,7 @@ bool IsUnmanagedDeviceDeviceTrustConnectorFeatureEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseAuthPanelInSessionEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAllowPasswordlessSetupEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAllowPinTimeoutSetupEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWebAuthNAuthDialogMergeEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUserEducationEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsLiveCaptionUserMicrophoneEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUpstreamTrustedReportsFirmwareEnabled();
|
||||
|
@ -6,10 +6,13 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/public/cpp/auth/active_session_auth_controller.h"
|
||||
#include "ash/public/cpp/webauthn_dialog_controller.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h"
|
||||
#include "chromeos/components/webauthn/webauthn_request_registrar.h"
|
||||
#include "dbus/bus.h"
|
||||
#include "dbus/message.h"
|
||||
@ -64,8 +67,8 @@ void UserAuthenticationServiceProvider::ShowAuthDialog(
|
||||
dbus::MethodCall* method_call,
|
||||
dbus::ExportedObject::ResponseSender response_sender) {
|
||||
dbus::MessageReader reader(method_call);
|
||||
std::string origin_name;
|
||||
if (!reader.PopString(&origin_name)) {
|
||||
std::string rp_id;
|
||||
if (!reader.PopString(&rp_id)) {
|
||||
LOG(ERROR) << "Unable to parse origin name";
|
||||
OnAuthFlowComplete(method_call, std::move(response_sender), false);
|
||||
return;
|
||||
@ -93,9 +96,21 @@ void UserAuthenticationServiceProvider::ShowAuthDialog(
|
||||
return;
|
||||
}
|
||||
|
||||
if (ash::features::IsWebAuthNAuthDialogMergeEnabled()) {
|
||||
auto* active_session_auth_controller = ActiveSessionAuthController::Get();
|
||||
auto webauthn_auth_request = std::make_unique<WebAuthNAuthRequest>(
|
||||
rp_id,
|
||||
base::BindOnce(&UserAuthenticationServiceProvider::OnAuthFlowComplete,
|
||||
weak_ptr_factory_.GetWeakPtr(), method_call,
|
||||
std::move(response_sender)));
|
||||
active_session_auth_controller->ShowAuthDialog(
|
||||
std::move(webauthn_auth_request));
|
||||
return;
|
||||
}
|
||||
|
||||
auto* webauthn_dialog_controller = WebAuthNDialogController::Get();
|
||||
webauthn_dialog_controller->ShowAuthenticationDialog(
|
||||
source_window, origin_name,
|
||||
source_window, rp_id,
|
||||
base::BindOnce(&UserAuthenticationServiceProvider::OnAuthFlowComplete,
|
||||
weak_ptr_factory_.GetWeakPtr(), method_call,
|
||||
std::move(response_sender)));
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/notimplemented.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h"
|
||||
#include "components/device_event_log/device_event_log.h"
|
||||
#include "ui/aura/window.h"
|
||||
|
||||
@ -44,6 +45,14 @@ class PasskeyInSessionAuthProviderImpl : public PasskeyInSessionAuthProvider {
|
||||
aura::Window* window,
|
||||
const std::string& rp_id,
|
||||
base::OnceCallback<void(bool)> result_callback) override {
|
||||
if (ash::features::IsWebAuthNAuthDialogMergeEnabled()) {
|
||||
auto webauthn_auth_request = std::make_unique<ash::WebAuthNAuthRequest>(
|
||||
rp_id, std::move(result_callback));
|
||||
ash::ActiveSessionAuthController::Get()->ShowAuthDialog(
|
||||
std::move(webauthn_auth_request));
|
||||
return;
|
||||
}
|
||||
|
||||
ash::Shell::Get()->webauthn_dialog_controller()->ShowAuthenticationDialog(
|
||||
window, rp_id, std::move(result_callback));
|
||||
}
|
||||
|
@ -901,8 +901,9 @@ base::flat_map<int32_t, std::vector<uint8_t>> GetNewSecretsToStore(
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
UserVerifyingKeyProviderConfigChromeos MakeUserVerifyingKeyConfig(
|
||||
EnclaveManager::UVKeyOptions options) {
|
||||
UserVerifyingKeyProviderConfigChromeos config{
|
||||
.dialog_controller = options.dialog_controller, .rp_id = options.rp_id};
|
||||
UserVerifyingKeyProviderConfigChromeos config{options.dialog_controller,
|
||||
/*window=*/nullptr,
|
||||
options.rp_id};
|
||||
if (options.render_frame_host_id) {
|
||||
auto* rfh = content::RenderFrameHost::FromID(options.render_frame_host_id);
|
||||
// This is ultimately invoked from GpmEnclaveController, which can't outlive
|
||||
|
@ -120,7 +120,9 @@ class EnclaveManager : public EnclaveManagerInterface {
|
||||
content::GlobalRenderFrameHostId render_frame_host_id;
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
raw_ptr<ash::WebAuthNDialogController> dialog_controller;
|
||||
std::variant<raw_ptr<ash::WebAuthNDialogController>,
|
||||
raw_ptr<ash::ActiveSessionAuthController>>
|
||||
dialog_controller;
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/public/cpp/auth/active_session_auth_controller.h"
|
||||
#include "base/check.h"
|
||||
#include "base/check_op.h"
|
||||
#include "base/containers/span.h"
|
||||
@ -1315,7 +1317,11 @@ void GPMEnclaveController::StartEnclaveTransaction(
|
||||
uv_options.lacontext = std::move(model_->lacontext);
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
uv_options.dialog_controller = ash::WebAuthNDialogController::Get();
|
||||
if (ash::features::IsWebAuthNAuthDialogMergeEnabled()) {
|
||||
uv_options.dialog_controller = ash::ActiveSessionAuthController::Get();
|
||||
} else {
|
||||
uv_options.dialog_controller = ash::WebAuthNDialogController::Get();
|
||||
}
|
||||
#endif
|
||||
request->signing_callback =
|
||||
enclave_manager_->UserVerifyingKeySigningCallback(
|
||||
|
@ -16,6 +16,7 @@
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
namespace ash {
|
||||
class WebAuthNDialogController;
|
||||
class ActiveSessionAuthController;
|
||||
}
|
||||
|
||||
namespace aura {
|
||||
@ -32,7 +33,20 @@ GetWebAuthnUnexportableKeyProvider();
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
struct UserVerifyingKeyProviderConfigChromeos {
|
||||
raw_ptr<ash::WebAuthNDialogController> dialog_controller;
|
||||
using AuthDialogController =
|
||||
std::variant<raw_ptr<ash::WebAuthNDialogController>,
|
||||
raw_ptr<ash::ActiveSessionAuthController>>;
|
||||
|
||||
UserVerifyingKeyProviderConfigChromeos(AuthDialogController dialog_controller,
|
||||
aura::Window* window,
|
||||
std::string rp_id);
|
||||
UserVerifyingKeyProviderConfigChromeos(
|
||||
const UserVerifyingKeyProviderConfigChromeos&);
|
||||
UserVerifyingKeyProviderConfigChromeos& operator=(
|
||||
const UserVerifyingKeyProviderConfigChromeos&);
|
||||
~UserVerifyingKeyProviderConfigChromeos();
|
||||
|
||||
AuthDialogController dialog_controller;
|
||||
|
||||
// The source window to which to anchor the dialog.
|
||||
raw_ptr<aura::Window> window;
|
||||
|
@ -7,10 +7,14 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/public/cpp/auth/active_session_auth_controller.h"
|
||||
#include "ash/public/cpp/webauthn_dialog_controller.h"
|
||||
#include "base/base64.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/functional/overloaded.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h"
|
||||
#include "crypto/unexportable_key.h"
|
||||
#include "crypto/user_verifying_key.h"
|
||||
#include "ui/aura/window.h"
|
||||
@ -39,7 +43,6 @@ class UserVerifyingSigningKeyCros : public crypto::UserVerifyingSigningKey {
|
||||
|
||||
void Sign(base::span<const uint8_t> data,
|
||||
UserVerifyingKeySignatureCallback callback) override {
|
||||
CHECK(config_.dialog_controller);
|
||||
CHECK(config_.window);
|
||||
VerifyUser(base::BindOnce(
|
||||
&UserVerifyingSigningKeyCros::DoSign, weak_factory_.GetWeakPtr(),
|
||||
@ -56,8 +59,25 @@ class UserVerifyingSigningKeyCros : public crypto::UserVerifyingSigningKey {
|
||||
|
||||
private:
|
||||
void VerifyUser(base::OnceCallback<void(bool)> callback) {
|
||||
config_.dialog_controller->ShowAuthenticationDialog(
|
||||
config_.window, config_.rp_id, std::move(callback));
|
||||
auto visitor = base::Overloaded(
|
||||
// Legacy code path.
|
||||
[&](raw_ptr<ash::WebAuthNDialogController> controller) {
|
||||
CHECK(controller);
|
||||
controller->ShowAuthenticationDialog(config_.window, config_.rp_id,
|
||||
std::move(callback));
|
||||
},
|
||||
|
||||
// New code path.
|
||||
[&](raw_ptr<ash::ActiveSessionAuthController> controller) {
|
||||
CHECK(controller);
|
||||
auto webauthn_auth_request =
|
||||
std::make_unique<ash::WebAuthNAuthRequest>(config_.rp_id,
|
||||
std::move(callback));
|
||||
|
||||
controller->ShowAuthDialog(std::move(webauthn_auth_request));
|
||||
});
|
||||
|
||||
std::visit(visitor, config_.dialog_controller);
|
||||
}
|
||||
|
||||
void DoSign(std::vector<uint8_t> data,
|
||||
@ -135,6 +155,26 @@ class UserVerifyingKeyProviderCros : public crypto::UserVerifyingKeyProvider {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
UserVerifyingKeyProviderConfigChromeos::UserVerifyingKeyProviderConfigChromeos(
|
||||
AuthDialogController dialog_controller,
|
||||
aura::Window* window,
|
||||
std::string rp_id)
|
||||
: dialog_controller(dialog_controller),
|
||||
window(window),
|
||||
rp_id(std::move(rp_id)) {}
|
||||
|
||||
UserVerifyingKeyProviderConfigChromeos::
|
||||
~UserVerifyingKeyProviderConfigChromeos() = default;
|
||||
|
||||
UserVerifyingKeyProviderConfigChromeos::UserVerifyingKeyProviderConfigChromeos(
|
||||
const UserVerifyingKeyProviderConfigChromeos&) = default;
|
||||
|
||||
UserVerifyingKeyProviderConfigChromeos&
|
||||
UserVerifyingKeyProviderConfigChromeos::operator=(
|
||||
const UserVerifyingKeyProviderConfigChromeos&) = default;
|
||||
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
|
||||
std::unique_ptr<crypto::UserVerifyingKeyProvider>
|
||||
GetWebAuthnUserVerifyingKeyProvider(
|
||||
UserVerifyingKeyProviderConfigChromeos config) {
|
||||
|
@ -7,8 +7,15 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/public/cpp/auth/active_session_auth_controller.h"
|
||||
#include "ash/public/cpp/webauthn_dialog_controller.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "chromeos/ash/components/login/auth/public/user_context.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h"
|
||||
#include "chromeos/ash/components/osauth/public/request/auth_request.h"
|
||||
#include "crypto/signature_verifier.h"
|
||||
#include "crypto/user_verifying_key.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
@ -18,6 +25,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kRpId[] = "";
|
||||
|
||||
using testing::_;
|
||||
|
||||
class MockWebAuthNDialogController : public ash::WebAuthNDialogController {
|
||||
@ -52,15 +61,74 @@ class MockWebAuthNDialogController : public ash::WebAuthNDialogController {
|
||||
(const, override));
|
||||
};
|
||||
|
||||
TEST(UserVerifyingKeyUtilsCrosTest,
|
||||
UserVerifyingKeyProvider_GeneratedKeyCanBeImported) {
|
||||
MockWebAuthNDialogController dialog_controller;
|
||||
class MockActiveSessionAuthController
|
||||
: public ash::ActiveSessionAuthController {
|
||||
public:
|
||||
MockActiveSessionAuthController() = default;
|
||||
|
||||
~MockActiveSessionAuthController() override = default;
|
||||
|
||||
MOCK_METHOD(bool,
|
||||
ShowAuthDialog,
|
||||
(std::unique_ptr<ash::AuthRequest> auth_request),
|
||||
(override));
|
||||
MOCK_METHOD(bool, IsShown, (), (const override));
|
||||
};
|
||||
|
||||
class UserVerifyingKeyUtilsCrosTest
|
||||
: public ::testing::Test,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
public:
|
||||
UserVerifyingKeyUtilsCrosTest() = default;
|
||||
~UserVerifyingKeyUtilsCrosTest() override = default;
|
||||
UserVerifyingKeyUtilsCrosTest(const UserVerifyingKeyUtilsCrosTest&) = delete;
|
||||
UserVerifyingKeyUtilsCrosTest& operator=(
|
||||
const UserVerifyingKeyUtilsCrosTest&) = delete;
|
||||
|
||||
void SetUp() override {
|
||||
if (GetParam()) {
|
||||
feature_list_.InitAndEnableFeature(
|
||||
ash::features::kWebAuthNAuthDialogMerge);
|
||||
return;
|
||||
}
|
||||
|
||||
feature_list_.InitAndDisableFeature(
|
||||
ash::features::kWebAuthNAuthDialogMerge);
|
||||
}
|
||||
|
||||
UserVerifyingKeyProviderConfigChromeos MakeKeyProviderConfig(
|
||||
aura::Window* window) {
|
||||
if (GetParam()) {
|
||||
return UserVerifyingKeyProviderConfigChromeos{&dialog_controller_, window,
|
||||
kRpId};
|
||||
}
|
||||
|
||||
return UserVerifyingKeyProviderConfigChromeos{&legacy_dialog_controller_,
|
||||
window, kRpId};
|
||||
}
|
||||
|
||||
void AssertRequestContainsRpId(ash::AuthRequest* request) {
|
||||
ASSERT_EQ(static_cast<ash::WebAuthNAuthRequest*>(request)->GetRpId(),
|
||||
kRpId);
|
||||
}
|
||||
|
||||
protected:
|
||||
MockWebAuthNDialogController legacy_dialog_controller_;
|
||||
MockActiveSessionAuthController dialog_controller_;
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(UnexportableKeyUtils,
|
||||
UserVerifyingKeyUtilsCrosTest,
|
||||
testing::Bool());
|
||||
|
||||
TEST_P(UserVerifyingKeyUtilsCrosTest,
|
||||
UserVerifyingKeyProvider_GeneratedKeyCanBeImported) {
|
||||
std::unique_ptr<aura::Window> window(
|
||||
aura::test::CreateTestWindowWithId(1, nullptr));
|
||||
std::unique_ptr<crypto::UserVerifyingKeyProvider> provider =
|
||||
GetWebAuthnUserVerifyingKeyProvider(
|
||||
UserVerifyingKeyProviderConfigChromeos{
|
||||
.dialog_controller = &dialog_controller, .window = window.get()});
|
||||
GetWebAuthnUserVerifyingKeyProvider(MakeKeyProviderConfig(window.get()));
|
||||
ASSERT_TRUE(provider);
|
||||
base::test::TestFuture<
|
||||
base::expected<std::unique_ptr<crypto::UserVerifyingSigningKey>,
|
||||
@ -81,23 +149,31 @@ TEST(UserVerifyingKeyUtilsCrosTest,
|
||||
EXPECT_EQ(signing_key.GetPublicKey(), imported_signing_key.GetPublicKey());
|
||||
}
|
||||
|
||||
TEST(UserVerifyingKeyUtilsCrosTest,
|
||||
UserVerifyingKeyProvider_SigningShowsInSessionAuthChallenge) {
|
||||
MockWebAuthNDialogController dialog_controller;
|
||||
TEST_P(UserVerifyingKeyUtilsCrosTest,
|
||||
UserVerifyingKeyProvider_SigningShowsInSessionAuthChallenge) {
|
||||
std::unique_ptr<aura::Window> window(
|
||||
aura::test::CreateTestWindowWithId(1, nullptr));
|
||||
std::unique_ptr<crypto::UserVerifyingKeyProvider> provider =
|
||||
GetWebAuthnUserVerifyingKeyProvider(
|
||||
UserVerifyingKeyProviderConfigChromeos{
|
||||
.dialog_controller = &dialog_controller, .window = window.get()});
|
||||
GetWebAuthnUserVerifyingKeyProvider(MakeKeyProviderConfig(window.get()));
|
||||
ASSERT_TRUE(provider);
|
||||
|
||||
// Simulate successful in-session auth.
|
||||
EXPECT_CALL(dialog_controller, ShowAuthenticationDialog(window.get(), "", _))
|
||||
.WillOnce([](aura::Window*, const std::string&,
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
std::move(callback).Run(true);
|
||||
});
|
||||
if (GetParam()) {
|
||||
EXPECT_CALL(dialog_controller_, ShowAuthDialog(_))
|
||||
.WillOnce([this](std::unique_ptr<ash::AuthRequest> request) {
|
||||
AssertRequestContainsRpId(request.get());
|
||||
request->NotifyAuthSuccess(nullptr);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
EXPECT_CALL(legacy_dialog_controller_,
|
||||
ShowAuthenticationDialog(window.get(), "", _))
|
||||
.WillOnce([](aura::Window*, const std::string& rp_id,
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
ASSERT_EQ(rp_id, kRpId);
|
||||
std::move(callback).Run(true);
|
||||
});
|
||||
}
|
||||
|
||||
base::test::TestFuture<
|
||||
base::expected<std::unique_ptr<crypto::UserVerifyingSigningKey>,
|
||||
@ -114,23 +190,31 @@ TEST(UserVerifyingKeyUtilsCrosTest,
|
||||
EXPECT_FALSE(signature_future.Get()->empty());
|
||||
}
|
||||
|
||||
TEST(UserVerifyingKeyUtilsCrosTest,
|
||||
UserVerifyingKeyProvider_SigningWithoutUvYieldsNullopt) {
|
||||
MockWebAuthNDialogController dialog_controller;
|
||||
TEST_P(UserVerifyingKeyUtilsCrosTest,
|
||||
UserVerifyingKeyProvider_SigningWithoutUvYieldsNullopt) {
|
||||
std::unique_ptr<aura::Window> window(
|
||||
aura::test::CreateTestWindowWithId(1, nullptr));
|
||||
std::unique_ptr<crypto::UserVerifyingKeyProvider> provider =
|
||||
GetWebAuthnUserVerifyingKeyProvider(
|
||||
UserVerifyingKeyProviderConfigChromeos{
|
||||
.dialog_controller = &dialog_controller, .window = window.get()});
|
||||
GetWebAuthnUserVerifyingKeyProvider(MakeKeyProviderConfig(window.get()));
|
||||
ASSERT_TRUE(provider);
|
||||
|
||||
// Simulate failed in-session auth.
|
||||
EXPECT_CALL(dialog_controller, ShowAuthenticationDialog(window.get(), "", _))
|
||||
.WillOnce([](aura::Window*, const std::string&,
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
std::move(callback).Run(false);
|
||||
});
|
||||
if (GetParam()) {
|
||||
EXPECT_CALL(dialog_controller_, ShowAuthDialog(_))
|
||||
.WillOnce([this](std::unique_ptr<ash::AuthRequest> request) -> bool {
|
||||
AssertRequestContainsRpId(request.get());
|
||||
request->NotifyAuthFailure();
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
EXPECT_CALL(legacy_dialog_controller_,
|
||||
ShowAuthenticationDialog(window.get(), "", _))
|
||||
.WillOnce([](aura::Window*, const std::string& rp_id,
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
ASSERT_EQ(rp_id, kRpId);
|
||||
std::move(callback).Run(false);
|
||||
});
|
||||
}
|
||||
|
||||
base::test::TestFuture<
|
||||
base::expected<std::unique_ptr<crypto::UserVerifyingSigningKey>,
|
||||
@ -147,14 +231,11 @@ TEST(UserVerifyingKeyUtilsCrosTest,
|
||||
EXPECT_FALSE(signature_future.Get().has_value());
|
||||
}
|
||||
|
||||
TEST(UserVerifyingKeyUtilsCrosTest, UserVerifyingKeyProvider_DeleteIsANoOp) {
|
||||
MockWebAuthNDialogController dialog_controller;
|
||||
TEST_P(UserVerifyingKeyUtilsCrosTest, UserVerifyingKeyProvider_DeleteIsANoOp) {
|
||||
std::unique_ptr<aura::Window> w1(
|
||||
aura::test::CreateTestWindowWithId(1, nullptr));
|
||||
std::unique_ptr<crypto::UserVerifyingKeyProvider> provider =
|
||||
GetWebAuthnUserVerifyingKeyProvider(
|
||||
UserVerifyingKeyProviderConfigChromeos{
|
||||
.dialog_controller = &dialog_controller, .window = w1.get()});
|
||||
GetWebAuthnUserVerifyingKeyProvider(MakeKeyProviderConfig(w1.get()));
|
||||
ASSERT_TRUE(provider);
|
||||
base::test::TestFuture<bool> future;
|
||||
provider->DeleteUserVerifyingKey("test key label", future.GetCallback());
|
||||
|
@ -24,6 +24,7 @@ component("impl") {
|
||||
"//chromeos/ash/components/login/auth/public:authpublic",
|
||||
"//components/prefs:prefs",
|
||||
"//components/user_manager",
|
||||
"//ui/base",
|
||||
]
|
||||
sources = [
|
||||
"auth_engine_api_impl.cc",
|
||||
@ -72,6 +73,8 @@ component("impl") {
|
||||
"request/settings_auth_request.h",
|
||||
"request/token_based_auth_request.cc",
|
||||
"request/token_based_auth_request.h",
|
||||
"request/webauthn_auth_request.cc",
|
||||
"request/webauthn_auth_request.h",
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
include_rules = [
|
||||
"+ash/strings",
|
||||
"+ui/base",
|
||||
"+ash/public/cpp",
|
||||
"+chromeos/ash/components/cryptohome",
|
||||
"+chromeos/ash/components/login",
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "chromeos/ash/components/osauth/impl/request/password_manager_auth_request.h"
|
||||
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
@ -21,8 +22,9 @@ AuthRequest::Reason PasswordManagerAuthRequest::GetAuthReason() const {
|
||||
return AuthRequest::Reason::kPasswordManager;
|
||||
}
|
||||
|
||||
int PasswordManagerAuthRequest::GetDescription() const {
|
||||
return IDS_ASH_IN_SESSION_AUTH_PASSWORD_MANAGER_PROMPT;
|
||||
const std::u16string PasswordManagerAuthRequest::GetDescription() const {
|
||||
return l10n_util::GetStringUTF16(
|
||||
IDS_ASH_IN_SESSION_AUTH_PASSWORD_MANAGER_PROMPT);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -24,7 +24,7 @@ class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH)
|
||||
// AuthRequest:
|
||||
AuthSessionIntent GetAuthSessionIntent() const override;
|
||||
AuthRequest::Reason GetAuthReason() const override;
|
||||
int GetDescription() const override;
|
||||
const std::u16string GetDescription() const override;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "chromeos/ash/components/osauth/impl/request/settings_auth_request.h"
|
||||
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
@ -22,8 +23,8 @@ AuthRequest::Reason SettingsAuthRequest::GetAuthReason() const {
|
||||
return AuthRequest::Reason::kSettings;
|
||||
}
|
||||
|
||||
int SettingsAuthRequest::GetDescription() const {
|
||||
return IDS_ASH_IN_SESSION_AUTH_SETTINGS_PROMPT;
|
||||
const std::u16string SettingsAuthRequest::GetDescription() const {
|
||||
return l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_SETTINGS_PROMPT);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -23,7 +23,7 @@ class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH) SettingsAuthRequest
|
||||
// AuthRequest:
|
||||
AuthSessionIntent GetAuthSessionIntent() const override;
|
||||
AuthRequest::Reason GetAuthReason() const override;
|
||||
int GetDescription() const override;
|
||||
const std::u16string GetDescription() const override;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "chromeos/ash/components/osauth/impl/request/token_based_auth_request.h"
|
||||
|
||||
#include "chromeos/ash/components/cryptohome/constants.h"
|
||||
#include "chromeos/ash/components/login/auth/public/user_context.h"
|
||||
#include "chromeos/ash/components/osauth/public/auth_session_storage.h"
|
||||
#include "chromeos/ash/components/osauth/public/common_types.h"
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "chromeos/ash/components/osauth/public/common_types.h"
|
||||
#include "chromeos/ash/components/osauth/public/request/auth_request.h"
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h"
|
||||
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "chromeos/ash/components/login/auth/public/user_context.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
WebAuthNAuthRequest::WebAuthNAuthRequest(const std::string& rp_id,
|
||||
FinishCallback callback)
|
||||
: finish_callback_(std::move(callback)), rp_id_(rp_id) {}
|
||||
WebAuthNAuthRequest::~WebAuthNAuthRequest() = default;
|
||||
|
||||
AuthSessionIntent WebAuthNAuthRequest::GetAuthSessionIntent() const {
|
||||
return AuthSessionIntent::kWebAuthn;
|
||||
}
|
||||
|
||||
AuthRequest::Reason WebAuthNAuthRequest::GetAuthReason() const {
|
||||
return AuthRequest::Reason::kWebAuthN;
|
||||
}
|
||||
|
||||
const std::u16string WebAuthNAuthRequest::GetDescription() const {
|
||||
return l10n_util::GetStringFUTF16(IDS_ASH_IN_SESSION_WEBAUTHN_PROMPT,
|
||||
base::UTF8ToUTF16(rp_id_));
|
||||
}
|
||||
|
||||
void WebAuthNAuthRequest::NotifyAuthSuccess(
|
||||
std::unique_ptr<UserContext> user_context) {
|
||||
CHECK(finish_callback_);
|
||||
std::move(finish_callback_).Run(true);
|
||||
}
|
||||
|
||||
void WebAuthNAuthRequest::NotifyAuthFailure() {
|
||||
CHECK(finish_callback_);
|
||||
std::move(finish_callback_).Run(false);
|
||||
}
|
||||
|
||||
const std::string WebAuthNAuthRequest::GetRpId() const {
|
||||
return rp_id_;
|
||||
}
|
||||
|
||||
} // namespace ash
|
@ -0,0 +1,43 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROMEOS_ASH_COMPONENTS_OSAUTH_IMPL_REQUEST_WEBAUTHN_AUTH_REQUEST_H_
|
||||
#define CHROMEOS_ASH_COMPONENTS_OSAUTH_IMPL_REQUEST_WEBAUTHN_AUTH_REQUEST_H_
|
||||
|
||||
#include "base/component_export.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "chromeos/ash/components/osauth/public/request/auth_request.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
// Passed to `ActiveSessionAuthController::ShowAuthDialog` when authenticating
|
||||
// with WebAuthN, handles behavior specific to those requests.
|
||||
class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH) WebAuthNAuthRequest
|
||||
: public AuthRequest {
|
||||
public:
|
||||
// Callback for overall authentication flow result.
|
||||
using FinishCallback = base::OnceCallback<void(bool success)>;
|
||||
|
||||
WebAuthNAuthRequest(const std::string& rp_id, FinishCallback callback);
|
||||
~WebAuthNAuthRequest() override;
|
||||
WebAuthNAuthRequest(const WebAuthNAuthRequest&) = delete;
|
||||
WebAuthNAuthRequest& operator=(const WebAuthNAuthRequest&) = delete;
|
||||
|
||||
// AuthRequest:
|
||||
AuthSessionIntent GetAuthSessionIntent() const override;
|
||||
AuthRequest::Reason GetAuthReason() const override;
|
||||
const std::u16string GetDescription() const override;
|
||||
void NotifyAuthSuccess(std::unique_ptr<UserContext> user_context) override;
|
||||
void NotifyAuthFailure() override;
|
||||
|
||||
const std::string GetRpId() const;
|
||||
|
||||
private:
|
||||
FinishCallback finish_callback_;
|
||||
const std::string rp_id_;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // CHROMEOS_ASH_COMPONENTS_OSAUTH_IMPL_REQUEST_WEBAUTHN_AUTH_REQUEST_H_
|
@ -8,10 +8,11 @@
|
||||
#include <memory>
|
||||
|
||||
#include "chromeos/ash/components/login/auth/public/auth_session_intent.h"
|
||||
#include "chromeos/ash/components/login/auth/public/user_context.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
class UserContext;
|
||||
|
||||
// This class encapsulates logic that governs behaviors specific to
|
||||
// a given `ActiveSessionAuthController::Reason`.
|
||||
// `AuthRequest` is passed to `ActiveSessionAuthController::ShowAuthDialog`
|
||||
@ -25,7 +26,8 @@ class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH) AuthRequest {
|
||||
enum class Reason {
|
||||
kPasswordManager = 0,
|
||||
kSettings = 1,
|
||||
kMaxValue = kSettings
|
||||
kWebAuthN = 2,
|
||||
kMaxValue = kWebAuthN
|
||||
};
|
||||
|
||||
// Returns the AuthSession intent to be used for the AuthRequest.
|
||||
@ -42,7 +44,7 @@ class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_OSAUTH) AuthRequest {
|
||||
// Returns a description to attach under the dialog's Titlebar,
|
||||
// describing the purpose of the authentication. i.e "ChromeOS
|
||||
// settings would like to know it's you".
|
||||
virtual int GetDescription() const = 0;
|
||||
virtual const std::u16string GetDescription() const = 0;
|
||||
|
||||
// Notified clients of the authentication of success or failure.
|
||||
virtual void NotifyAuthSuccess(std::unique_ptr<UserContext> user_context) = 0;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/notreached.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/password_manager_auth_request.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/settings_auth_request.h"
|
||||
#include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h"
|
||||
#include "chromeos/ash/components/osauth/public/auth_session_storage.h"
|
||||
#include "chromeos/ash/components/osauth/public/request/auth_request.h"
|
||||
|
||||
@ -61,6 +62,10 @@ std::unique_ptr<ash::AuthRequest> InSessionAuth::AuthRequestFromReason(
|
||||
return std::make_unique<ash::SettingsAuthRequest>(
|
||||
base::BindOnce(&InSessionAuth::OnAuthComplete,
|
||||
weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
case ash::AuthRequest::Reason::kWebAuthN:
|
||||
// WebAuthN authentication requests are not made using this
|
||||
// mojo method.
|
||||
NOTREACHED();
|
||||
}
|
||||
NOTREACHED();
|
||||
}
|
||||
@ -102,6 +107,14 @@ void InSessionAuth::RequestLegacyWebAuthn(
|
||||
const std::string& rp_id,
|
||||
const std::string& window_id,
|
||||
RequestLegacyWebAuthnCallback callback) {
|
||||
if (ash::features::IsWebAuthNAuthDialogMergeEnabled()) {
|
||||
auto webauthn_auth_request =
|
||||
std::make_unique<ash::WebAuthNAuthRequest>(rp_id, std::move(callback));
|
||||
ash::ActiveSessionAuthController::Get()->ShowAuthDialog(
|
||||
std::move(webauthn_auth_request));
|
||||
return;
|
||||
}
|
||||
|
||||
ash::InSessionAuthDialogController::Get()->ShowLegacyWebAuthnDialog(
|
||||
rp_id, window_id, std::move(callback));
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ chromium-metrics-reviews@google.com.
|
||||
<enum name="ActiveSessionAuthControllerReason">
|
||||
<int value="0" label="PasswordManager"/>
|
||||
<int value="1" label="Settings"/>
|
||||
<int value="2" label="WebAuthN"/>
|
||||
</enum>
|
||||
|
||||
<enum name="AltTabMode">
|
||||
|
Reference in New Issue
Block a user