0

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:
Elie Maamari
2024-08-29 15:41:29 +00:00
committed by Chromium LUCI CQ
parent b5b327b9da
commit 1d586d207c
26 changed files with 356 additions and 54 deletions

@ -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">