Commit 52d1200f authored by Majid Valipour's avatar Majid Valipour Committed by Chromium LUCI CQ

[WebID] Initial implementation for Permission & IDP SignIn

Add basic UI on desktop for WebID. This includes:
- A modal dialog that loads web contents for the given signin URL
- infobars that are used for asking the user permission

The modal logic is mostly copied from goto@'s prototype here:
https://chromium-review.googlesource.com/c/chromium/src/+/2134593/


Bug: 1141125
Change-Id: Ie8982f785b8dd4597b02442366742342947375ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2572957Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarSam Goto <goto@chromium.org>
Commit-Queue: Majid Valipour <majidvp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#834746}
parent c547b0cd
......@@ -187,6 +187,7 @@ static_library("ui") {
"webauthn/authenticator_request_dialog.h",
"webid/identity_dialog_controller.cc",
"webid/identity_dialog_controller.h",
"webid/identity_dialogs.h",
"webui/about_ui.cc",
"webui/about_ui.h",
"webui/autofill_and_password_manager_internals/autofill_internals_ui.cc",
......@@ -756,6 +757,7 @@ static_library("ui") {
"android/tab_model/tab_model_observer_jni_bridge.h",
"android/toolbar/location_bar_model_android.cc",
"android/toolbar/location_bar_model_android.h",
"android/webid/identity_dialogs_android.cc",
"browser_otr_state_android.cc",
"javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.cc",
"javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h",
......@@ -4148,6 +4150,10 @@ static_library("ui") {
"views/webauthn/sheet_view_factory.h",
"views/webauthn/webauthn_hover_button.cc",
"views/webauthn/webauthn_hover_button.h",
"views/webid/webid_permission_infobar.cc",
"views/webid/webid_permission_infobar.h",
"views/webid/webid_signin_window.cc",
"views/webid/webid_signin_window.h",
"views/window_name_prompt.cc",
"webauthn/account_hover_list_model.cc",
"webauthn/account_hover_list_model.h",
......
file://content/browser/webid/OWNERS
// 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 "chrome/browser/ui/webid/identity_dialogs.h"
#include <string>
#include "base/callback.h"
#include "base/notreached.h"
#include "base/strings/string16.h"
#include "content/public/browser/identity_request_dialog_controller.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"
// Stub implementations for Identity UI on Android.
void ShowWebIDPermissionInfoBar(
content::WebContents* web_contents,
const base::string16& message,
content::IdentityRequestDialogController::InitialApprovalCallback
callback) {
NOTIMPLEMENTED();
}
void ShowWebIDSigninWindow(content::WebContents* web_contents,
const GURL& idp_signin_url,
base::OnceCallback<void(std::string)> on_done,
base::OnceCallback<void()> on_close) {
NOTIMPLEMENTED();
}
file://content/browser/webid/OWNERS
// 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 "chrome/browser/ui/views/webid/webid_permission_infobar.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/ui/webid/identity_dialogs.h"
#include "components/infobars/core/infobar.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
void ShowWebIDPermissionInfoBar(
content::WebContents* web_contents,
const base::string16& message,
WebIDPermissionInfoBarDelegate::Callback callback) {
InfoBarService* infobar_service =
InfoBarService::FromWebContents(web_contents);
auto delegate = std::make_unique<WebIDPermissionInfoBarDelegate>(
message, std::move(callback));
infobar_service->AddInfoBar(
infobar_service->CreateConfirmInfoBar(std::move(delegate)));
}
WebIDPermissionInfoBarDelegate::WebIDPermissionInfoBarDelegate(
const base::string16& message,
WebIDPermissionInfoBarDelegate::Callback callback)
: message_(message), callback_(std::move(callback)) {
DCHECK(callback_);
}
WebIDPermissionInfoBarDelegate::~WebIDPermissionInfoBarDelegate() {
if (callback_) {
// The infobar has closed without the user expressing an explicit
// preference. The current request should be denied.
std::move(callback_).Run(UserApproval::kDenied);
}
}
infobars::InfoBarDelegate::InfoBarIdentifier
WebIDPermissionInfoBarDelegate::GetIdentifier() const {
return WEBID_PERMISSION_INFOBAR_DELEGATE;
}
base::string16 WebIDPermissionInfoBarDelegate::GetMessageText() const {
return message_;
}
base::string16 WebIDPermissionInfoBarDelegate::GetButtonLabel(
InfoBarButton button) const {
return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_PERMISSION_ALLOW
: IDS_PERMISSION_DENY);
}
bool WebIDPermissionInfoBarDelegate::Accept() {
std::move(callback_).Run(UserApproval::kApproved);
return true;
}
bool WebIDPermissionInfoBarDelegate::Cancel() {
std::move(callback_).Run(UserApproval::kDenied);
return true;
}
// 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.
#ifndef CHROME_BROWSER_UI_VIEWS_WEBID_WEBID_PERMISSION_INFOBAR_H_
#define CHROME_BROWSER_UI_VIEWS_WEBID_WEBID_PERMISSION_INFOBAR_H_
#include "base/callback.h"
#include "base/strings/string16.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
#include "content/public/browser/identity_request_dialog_controller.h"
// Basic infobar that is used to ask for user approval in various WebID flows.
//
// Currently it is used to obtain user approval on initial information exchange
// between the Relying Party and Identity Provider to exchange informations.
class WebIDPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
public:
using UserApproval = content::IdentityRequestDialogController::UserApproval;
using Callback =
content::IdentityRequestDialogController::InitialApprovalCallback;
WebIDPermissionInfoBarDelegate(const base::string16& message,
Callback callback);
~WebIDPermissionInfoBarDelegate() override;
private:
// ConfirmInfoBarDelegate:
infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
base::string16 GetMessageText() const override;
base::string16 GetButtonLabel(InfoBarButton button) const override;
bool Accept() override;
bool Cancel() override;
const base::string16 message_;
Callback callback_;
};
#endif // CHROME_BROWSER_UI_VIEWS_WEBID_WEBID_PERMISSION_INFOBAR_H_
// 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 "chrome/browser/ui/views/webid/webid_signin_window.h"
#include "chrome/browser/ui/webid/identity_dialog_controller.h"
#include "chrome/browser/ui/webid/identity_dialogs.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/window/dialog_delegate.h"
// Dimensions of the dialog itself.
constexpr int kDialogMinWidth = 512;
constexpr int kDialogHeight = 450;
// Dimension of the header.
constexpr int kHeaderHeight = 75;
class ModalDialog : public views::DialogDelegateView {
public:
ModalDialog(content::WebContents* contents, const GURL& provider)
: initiator_web_contents_(contents), web_view_(nullptr) {
DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE);
SetModalType(ui::MODAL_TYPE_CHILD);
SetLayoutManager(std::make_unique<views::FillLayout>());
web_view_ = AddChildView(CreateWebView(provider));
SetInitiallyFocusedView(web_view_);
}
std::unique_ptr<views::WebView> CreateWebView(const GURL& provider) {
auto web_view = std::make_unique<views::WebView>(
initiator_web_contents_->GetBrowserContext());
web_view->LoadInitialURL(provider);
// The webview must get an explicitly set height otherwise the layout
// doesn't make it fill its container. This is likely because it has no
// content at the time of first layout (nothing has loaded yet). Because of
// this, set it to. total_dialog_height - header_height. On the other hand,
// the width will be properly set so it can be 0 here.
web_view->SetPreferredSize(
{kDialogMinWidth, kDialogHeight - kHeaderHeight});
return web_view;
}
void Show() {
// ShowWebModalDialogViews takes ownership of this, by way of the
// DeleteDelegate method.
constrained_window::ShowWebModalDialogViews(this, initiator_web_contents_);
}
private:
content::WebContents* initiator_web_contents_;
// The contents of the dialog, owned by the view hierarchy.
views::WebView* web_view_;
};
WebIDSigninWindow::WebIDSigninWindow(
content::WebContents* initiator_web_contents,
const GURL& provider,
base::OnceCallback<void(std::string)> on_done,
base::OnceCallback<void()> on_close)
: on_done_(std::move(on_done)) {
auto* modal = new ModalDialog(initiator_web_contents, provider);
modal->SetCloseCallback(std::move(on_close));
// TODO(majidvp): Actually call on_done callback once we have a token.
// ModalDialog is a WidgetDelegate, owned by its views::Widget. It is
// destroyed by `DeleteDelegate()` which is invoked by view hierarchy. Once
// modal is deleted we should delete the window class as well.
modal->RegisterDeleteDelegateCallback(
base::BindOnce([](WebIDSigninWindow* window) { delete window; },
base::Unretained(this)));
modal->Show();
}
WebIDSigninWindow::~WebIDSigninWindow() = default;
void ShowWebIDSigninWindow(content::WebContents* initiator_web_contents,
const GURL& provider,
base::OnceCallback<void(std::string)> on_done,
base::OnceCallback<void()> on_close) {
new WebIDSigninWindow(initiator_web_contents, provider, std::move(on_done),
std::move(on_close));
}
// 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.
#ifndef CHROME_BROWSER_UI_VIEWS_WEBID_WEBID_SIGNIN_WINDOW_H_
#define CHROME_BROWSER_UI_VIEWS_WEBID_WEBID_SIGNIN_WINDOW_H_
#include <memory>
#include <string>
#include "base/callback.h"
class GURL;
namespace content {
class WebContents;
}
// The WebIDSigninWindow loads Idp sign-in page in a modal allowing user to
// sign in. The modal may be closed by user or once Idp sign-in page has
// completed its process and have called the appropriate JS callback.
class WebIDSigninWindow {
public:
// Creates and shows the modal Signin Window. It takes two callbacks:
// - on_done: called when IDP has provided an id_token with the id_token as
// its parameter.
// - on_close: called when window is closed.
WebIDSigninWindow(content::WebContents* initiator_web_contents,
const GURL& provider,
base::OnceCallback<void(std::string)> on_done,
base::OnceCallback<void()> on_close);
WebIDSigninWindow(const WebIDSigninWindow&) = delete;
WebIDSigninWindow& operator=(const WebIDSigninWindow&) = delete;
private:
base::OnceCallback<void(std::string)> on_done_;
~WebIDSigninWindow();
};
#endif // CHROME_BROWSER_UI_VIEWS_WEBID_WEBID_SIGNIN_WINDOW_H_
monorail {
component: "Blink>Identity>WebID"
}
team_email: "web-identity@chromium.org"
\ No newline at end of file
......@@ -4,6 +4,9 @@
#include "chrome/browser/ui/webid/identity_dialog_controller.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/webid/identity_dialogs.h"
#include "components/infobars/core/infobar.h"
#include "url/gurl.h"
IdentityDialogController::IdentityDialogController() = default;
......@@ -11,18 +14,31 @@ IdentityDialogController::IdentityDialogController() = default;
IdentityDialogController::~IdentityDialogController() = default;
void IdentityDialogController::ShowInitialPermissionDialog(
content::WebContents* web_contents,
InitialApprovalCallback callback) {
// TODO(kenrb): Add UI permission dialog.
std::move(callback).Run(
content::IdentityRequestDialogController::UserApproval::kApproved);
// The WebContents should be that of RP page to make sure info bar is shown on
// the RP page.
// TODO(majidvp): Consider using a modal dialog instead of an Inforbar.
// http://crbug.com/1141125
// TODO(majidvp): Use a localized string. http://crbug.com/1141125
ShowWebIDPermissionInfoBar(
web_contents,
base::ASCIIToUTF16(
"WebID: Allow Identity provider to learn about this site?"),
std::move(callback));
}
void IdentityDialogController::ShowIdProviderWindow(
content::WebContents* web_contents,
const GURL& idp_signin_url,
IdProviderWindowClosedCallback callback) {
// TODO(kenrb): Add UI modal window to display the IDP UI and load the IDP
// page.
std::move(callback).Run();
// TODO(majidvp): Pass in a callback to receive the token.
// http://crbug.com/1141125
ShowWebIDSigninWindow(web_contents, idp_signin_url,
base::OnceCallback<void(std::string)>(),
std::move(callback));
}
void IdentityDialogController::ShowTokenExchangePermissionDialog(
......
......@@ -7,9 +7,11 @@
#include "base/callback.h"
#include "content/public/browser/identity_request_dialog_controller.h"
#include "content/public/browser/web_contents.h"
class GURL;
using UserApproval = content::IdentityRequestDialogController::UserApproval;
using InitialApprovalCallback =
content::IdentityRequestDialogController::InitialApprovalCallback;
using IdProviderWindowClosedCallback =
......@@ -30,9 +32,12 @@ class IdentityDialogController
~IdentityDialogController() override;
// content::IdentityRequestDelegate
void ShowInitialPermissionDialog(InitialApprovalCallback) override;
void ShowIdProviderWindow(const GURL& idp_signin_url,
void ShowInitialPermissionDialog(content::WebContents*,
InitialApprovalCallback) override;
void ShowIdProviderWindow(content::WebContents*,
const GURL& idp_signin_url,
IdProviderWindowClosedCallback) override;
void ShowTokenExchangePermissionDialog(
TokenExchangeApprovalCallback) override;
};
......
// 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.
#ifndef CHROME_BROWSER_UI_WEBID_IDENTITY_DIALOGS_H_
#define CHROME_BROWSER_UI_WEBID_IDENTITY_DIALOGS_H_
#include <string>
#include "base/callback.h"
#include "base/strings/string16.h"
#include "content/public/browser/identity_request_dialog_controller.h"
#include "url/gurl.h"
namespace content {
class WebContents;
} // namespace content
// Creates and shows a confirmation infobar and delegate and adds the infobar to
// |infobar_service|. The provided callback is called with appropriate status
// depending on whether user accepted or denied/closed the infobar.
void ShowWebIDPermissionInfoBar(
content::WebContents* web_contents,
const base::string16& message,
content::IdentityRequestDialogController::InitialApprovalCallback callback);
// Creates and shows a window that loads the identity provider sign in page at
// the given URL. It takes two callbacks:
// - on_done: called when IDP has provided an id_token with the id_token as
// its parameter.
// - on_close: called when window is closed.
void ShowWebIDSigninWindow(content::WebContents* web_contents,
const GURL& idp_signin_url,
base::OnceCallback<void(std::string)> on_done,
base::OnceCallback<void()> on_close);
#endif // CHROME_BROWSER_UI_WEBID_IDENTITY_DIALOGS_H_
......@@ -171,6 +171,7 @@ class InfoBarDelegate {
SYSTEM_INFOBAR_DELEGATE_MAC = 101,
EXPERIMENTAL_INFOBAR_DELEGATE_LACROS = 102,
ROSETTA_REQUIRED_INFOBAR_DELEGATE = 103,
WEBID_PERMISSION_INFOBAR_DELEGATE = 104,
};
// Describes navigation events, used to decide whether infobars should be
......
......@@ -126,10 +126,14 @@ void FederatedAuthRequestImpl::OnWellKnownFetched(
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
// Use the web contents of the page that initiated the WebID request (i.e.
// the Relying Party) for showing the initial permission dialog.
WebContents* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host());
request_dialog_controller_->ShowInitialPermissionDialog(
base::BindOnce(&FederatedAuthRequestImpl::OnSigninApproved,
weak_ptr_factory_.GetWeakPtr()));
web_contents, base::BindOnce(&FederatedAuthRequestImpl::OnSigninApproved,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::OnSigninApproved(
......@@ -157,8 +161,11 @@ void FederatedAuthRequestImpl::OnSigninResponseReceived(
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
WebContents* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host());
request_dialog_controller_->ShowIdProviderWindow(
idp_signin_page_url,
web_contents, idp_signin_page_url,
base::BindOnce(&FederatedAuthRequestImpl::OnIdpPageClosed,
weak_ptr_factory_.GetWeakPtr()));
return;
......
......@@ -11,6 +11,7 @@
class GURL;
namespace content {
class WebContents;
// IdentityRequestDialogController is in interface for control of the UI
// surfaces that are displayed to intermediate the exchange of ID tokens.
......@@ -35,8 +36,10 @@ class CONTENT_EXPORT IdentityRequestDialogController {
virtual ~IdentityRequestDialogController() = default;
// Permission-oriented flow methods.
virtual void ShowInitialPermissionDialog(InitialApprovalCallback) = 0;
virtual void ShowIdProviderWindow(const GURL& idp_signin_url,
virtual void ShowInitialPermissionDialog(WebContents*,
InitialApprovalCallback) = 0;
virtual void ShowIdProviderWindow(WebContents*,
const GURL& idp_signin_url,
IdProviderWindowClosedCallback) = 0;
virtual void ShowTokenExchangePermissionDialog(
TokenExchangeApprovalCallback) = 0;
......
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