blob: 1e3607d9bd151556155eda7ef68c72c0c0485189 [file] [log] [blame]
// 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.
#include "ash/in_session_auth/in_session_auth_dialog_controller_impl.h"
#include "ash/in_session_auth/auth_dialog_contents_view.h"
#include "ash/in_session_auth/webauthn_request_registrar_impl.h"
#include "ash/public/cpp/in_session_auth_dialog_client.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/string_util.h"
#include "components/user_manager/known_user.h"
#include "ui/aura/window.h"
#include "ui/views/widget/widget.h"
namespace ash {
InSessionAuthDialogControllerImpl::InSessionAuthDialogControllerImpl()
: webauthn_request_registrar_(
std::make_unique<WebAuthnRequestRegistrarImpl>()) {}
InSessionAuthDialogControllerImpl::~InSessionAuthDialogControllerImpl() =
default;
void InSessionAuthDialogControllerImpl::SetClient(
InSessionAuthDialogClient* client) {
client_ = client;
}
void InSessionAuthDialogControllerImpl::ShowAuthenticationDialog(
aura::Window* source_window,
const std::string& origin_name,
FinishCallback finish_callback) {
DCHECK(client_);
// Concurrent requests are not supported.
DCHECK(!dialog_);
source_window_tracker_.Add(source_window);
finish_callback_ = std::move(finish_callback);
AccountId account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
// GAIA password option is not offered.
uint32_t auth_methods = 0;
if (client_->IsFingerprintAuthAvailable(account_id)) {
client_->StartFingerprintAuthSession(
account_id,
base::BindOnce(
&InSessionAuthDialogControllerImpl::OnStartFingerprintAuthSession,
weak_factory_.GetWeakPtr(), account_id, auth_methods, source_window,
origin_name));
// OnStartFingerprintAuthSession checks PIN availability.
return;
}
client_->CheckPinAuthAvailability(
account_id,
base::BindOnce(&InSessionAuthDialogControllerImpl::OnPinCanAuthenticate,
weak_factory_.GetWeakPtr(), auth_methods, source_window,
origin_name));
}
void InSessionAuthDialogControllerImpl::OnStartFingerprintAuthSession(
AccountId account_id,
uint32_t auth_methods,
aura::Window* source_window,
const std::string& origin_name,
bool success) {
if (success)
auth_methods |= AuthDialogContentsView::kAuthFingerprint;
client_->CheckPinAuthAvailability(
account_id,
base::BindOnce(&InSessionAuthDialogControllerImpl::OnPinCanAuthenticate,
weak_factory_.GetWeakPtr(), auth_methods, source_window,
origin_name));
}
void InSessionAuthDialogControllerImpl::OnPinCanAuthenticate(
uint32_t auth_methods,
aura::Window* source_window,
const std::string& origin_name,
bool pin_auth_available) {
if (pin_auth_available)
auth_methods |= AuthDialogContentsView::kAuthPin;
if (auth_methods == 0) {
// If neither fingerprint nor PIN is available, we shouldn't receive the
// request.
LOG(ERROR) << "Neither fingerprint nor PIN is available.";
Cancel();
return;
}
if (!source_window_tracker_.Contains(source_window)) {
LOG(ERROR) << "Source window is no longer available.";
Cancel();
return;
}
AccountId account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
const UserSession* session =
Shell::Get()->session_controller()->GetUserSessionByAccountId(account_id);
DCHECK(session);
UserAvatar avatar = session->user_info.avatar;
// TODO(b/156258540): move UserSelectionScreen::BuildAshUserAvatarForUser to
// somewhere that UserToUserSession could call, to support animated avatars.
AuthDialogContentsView::AuthMethodsMetadata auth_metadata;
auth_metadata.autosubmit_pin_length =
user_manager::known_user::GetUserPinLength(account_id);
source_window_tracker_.Remove(source_window);
dialog_ = std::make_unique<InSessionAuthDialog>(
auth_methods, source_window, origin_name, auth_metadata, avatar);
}
void InSessionAuthDialogControllerImpl::DestroyAuthenticationDialog() {
DCHECK(client_);
if (!dialog_)
return;
if (dialog_->GetAuthMethods() & AuthDialogContentsView::kAuthFingerprint)
client_->EndFingerprintAuthSession();
dialog_.reset();
source_window_tracker_.RemoveAll();
}
void InSessionAuthDialogControllerImpl::AuthenticateUserWithPin(
const std::string& pin,
OnAuthenticateCallback callback) {
DCHECK(client_);
// TODO(b/156258540): Check that PIN is enabled / set up for this user.
if (!base::ContainsOnlyChars(pin, "0123456789")) {
OnAuthenticateComplete(std::move(callback), false);
return;
}
client_->AuthenticateUserWithPasswordOrPin(
pin, true,
base::BindOnce(&InSessionAuthDialogControllerImpl::OnAuthenticateComplete,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void InSessionAuthDialogControllerImpl::AuthenticateUserWithFingerprint(
base::OnceCallback<void(bool, FingerprintState)> views_callback) {
DCHECK(client_);
client_->AuthenticateUserWithFingerprint(base::BindOnce(
&InSessionAuthDialogControllerImpl::OnFingerprintAuthComplete,
weak_factory_.GetWeakPtr(), std::move(views_callback)));
}
void InSessionAuthDialogControllerImpl::OnAuthenticateComplete(
OnAuthenticateCallback callback,
bool success) {
std::move(callback).Run(success);
if (success)
OnAuthSuccess();
}
void InSessionAuthDialogControllerImpl::OnFingerprintAuthComplete(
base::OnceCallback<void(bool, FingerprintState)> views_callback,
bool success,
FingerprintState fingerprint_state) {
// If success is false and retry is allowed, the view will start another
// fingerprint check.
std::move(views_callback).Run(success, fingerprint_state);
if (success)
OnAuthSuccess();
}
void InSessionAuthDialogControllerImpl::OnAuthSuccess() {
DestroyAuthenticationDialog();
if (finish_callback_)
std::move(finish_callback_).Run(true);
}
void InSessionAuthDialogControllerImpl::Cancel() {
DestroyAuthenticationDialog();
if (finish_callback_)
std::move(finish_callback_).Run(false);
}
void InSessionAuthDialogControllerImpl::OpenInSessionAuthHelpPage() {
DCHECK(client_);
client_->OpenInSessionAuthHelpPage();
}
void InSessionAuthDialogControllerImpl::CheckAvailability(
FinishCallback on_availability_checked) const {
// Assumes the requests are for the active user (no teleported window).
AccountId account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
if (client_->IsFingerprintAuthAvailable(account_id)) {
std::move(on_availability_checked).Run(true);
return;
}
client_->CheckPinAuthAvailability(account_id,
std::move(on_availability_checked));
}
} // namespace ash