Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / identity / web_auth_flow.cc
blob18cf29aa7f672b1b02c59c5385d3b17dbb885126
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
7 #include "base/base64.h"
8 #include "base/location.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/trace_event/trace_event.h"
13 #include "chrome/browser/extensions/component_loader.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/extensions/api/identity_private.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "components/guest_view/browser/guest_view_base.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/resource_request_details.h"
27 #include "content/public/browser/web_contents.h"
28 #include "crypto/random.h"
29 #include "extensions/browser/app_window/app_window.h"
30 #include "extensions/browser/event_router.h"
31 #include "extensions/browser/extension_system.h"
32 #include "grit/browser_resources.h"
33 #include "url/gurl.h"
35 using content::RenderViewHost;
36 using content::ResourceRedirectDetails;
37 using content::WebContents;
38 using content::WebContentsObserver;
39 using guest_view::GuestViewBase;
41 namespace extensions {
43 namespace identity_private = api::identity_private;
45 WebAuthFlow::WebAuthFlow(
46 Delegate* delegate,
47 Profile* profile,
48 const GURL& provider_url,
49 Mode mode)
50 : delegate_(delegate),
51 profile_(profile),
52 provider_url_(provider_url),
53 mode_(mode),
54 embedded_window_created_(false) {
57 WebAuthFlow::~WebAuthFlow() {
58 DCHECK(delegate_ == NULL);
60 // Stop listening to notifications first since some of the code
61 // below may generate notifications.
62 registrar_.RemoveAll();
63 WebContentsObserver::Observe(nullptr);
65 if (!app_window_key_.empty()) {
66 AppWindowRegistry::Get(profile_)->RemoveObserver(this);
68 if (app_window_ && app_window_->web_contents())
69 app_window_->web_contents()->Close();
73 void WebAuthFlow::Start() {
74 AppWindowRegistry::Get(profile_)->AddObserver(this);
76 // Attach a random ID string to the window so we can recognize it
77 // in OnAppWindowAdded.
78 std::string random_bytes;
79 crypto::RandBytes(base::WriteInto(&random_bytes, 33), 32);
80 base::Base64Encode(random_bytes, &app_window_key_);
82 // identityPrivate.onWebFlowRequest(app_window_key, provider_url_, mode_)
83 scoped_ptr<base::ListValue> args(new base::ListValue());
84 args->AppendString(app_window_key_);
85 args->AppendString(provider_url_.spec());
86 if (mode_ == WebAuthFlow::INTERACTIVE)
87 args->AppendString("interactive");
88 else
89 args->AppendString("silent");
91 scoped_ptr<Event> event(
92 new Event(events::IDENTITY_PRIVATE_ON_WEB_FLOW_REQUEST,
93 identity_private::OnWebFlowRequest::kEventName, args.Pass()));
94 event->restrict_to_browser_context = profile_;
95 ExtensionSystem* system = ExtensionSystem::Get(profile_);
97 extensions::ComponentLoader* component_loader =
98 system->extension_service()->component_loader();
99 if (!component_loader->Exists(extension_misc::kIdentityApiUiAppId)) {
100 component_loader->Add(
101 IDR_IDENTITY_API_SCOPE_APPROVAL_MANIFEST,
102 base::FilePath(FILE_PATH_LITERAL("identity_scope_approval_dialog")));
105 EventRouter::Get(profile_)->DispatchEventWithLazyListener(
106 extension_misc::kIdentityApiUiAppId, event.Pass());
109 void WebAuthFlow::DetachDelegateAndDelete() {
110 delegate_ = NULL;
111 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
114 void WebAuthFlow::OnAppWindowAdded(AppWindow* app_window) {
115 if (app_window->window_key() == app_window_key_ &&
116 app_window->extension_id() == extension_misc::kIdentityApiUiAppId) {
117 app_window_ = app_window;
118 WebContentsObserver::Observe(app_window->web_contents());
120 registrar_.Add(
121 this,
122 content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
123 content::NotificationService::AllBrowserContextsAndSources());
127 void WebAuthFlow::OnAppWindowRemoved(AppWindow* app_window) {
128 if (app_window->window_key() == app_window_key_ &&
129 app_window->extension_id() == extension_misc::kIdentityApiUiAppId) {
130 app_window_ = NULL;
131 registrar_.RemoveAll();
132 WebContentsObserver::Observe(nullptr);
134 if (delegate_)
135 delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
139 void WebAuthFlow::BeforeUrlLoaded(const GURL& url) {
140 if (delegate_ && embedded_window_created_)
141 delegate_->OnAuthFlowURLChange(url);
144 void WebAuthFlow::AfterUrlLoaded() {
145 if (delegate_ && embedded_window_created_ && mode_ == WebAuthFlow::SILENT)
146 delegate_->OnAuthFlowFailure(WebAuthFlow::INTERACTION_REQUIRED);
149 void WebAuthFlow::Observe(int type,
150 const content::NotificationSource& source,
151 const content::NotificationDetails& details) {
152 DCHECK(app_window_);
154 if (!delegate_)
155 return;
157 if (!embedded_window_created_) {
158 DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED);
160 RenderViewHost* render_view(
161 content::Details<RenderViewHost>(details).ptr());
162 WebContents* web_contents = WebContents::FromRenderViewHost(render_view);
163 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
164 WebContents* owner = guest ? guest->owner_web_contents() : NULL;
165 if (web_contents &&
166 (owner == WebContentsObserver::web_contents())) {
167 // Switch from watching the app window to the guest inside it.
168 embedded_window_created_ = true;
169 WebContentsObserver::Observe(web_contents);
171 registrar_.RemoveAll();
173 } else { // embedded_window_created_
174 NOTREACHED() << "Got a notification that we did not register for: " << type;
178 void WebAuthFlow::RenderProcessGone(base::TerminationStatus status) {
179 if (delegate_)
180 delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
183 void WebAuthFlow::DidStartProvisionalLoadForFrame(
184 content::RenderFrameHost* render_frame_host,
185 const GURL& validated_url,
186 bool is_error_page,
187 bool is_iframe_srcdoc) {
188 if (!render_frame_host->GetParent())
189 BeforeUrlLoaded(validated_url);
192 void WebAuthFlow::DidFailProvisionalLoad(
193 content::RenderFrameHost* render_frame_host,
194 const GURL& validated_url,
195 int error_code,
196 const base::string16& error_description,
197 bool was_ignored_by_handler) {
198 TRACE_EVENT_ASYNC_STEP_PAST1("identity",
199 "WebAuthFlow",
200 this,
201 "DidFailProvisionalLoad",
202 "error_code",
203 error_code);
204 if (delegate_)
205 delegate_->OnAuthFlowFailure(LOAD_FAILED);
208 void WebAuthFlow::DidGetRedirectForResourceRequest(
209 content::RenderFrameHost* render_frame_host,
210 const content::ResourceRedirectDetails& details) {
211 BeforeUrlLoaded(details.new_url);
214 void WebAuthFlow::TitleWasSet(content::NavigationEntry* entry,
215 bool explicit_set) {
216 delegate_->OnAuthFlowTitleChange(base::UTF16ToUTF8(entry->GetTitle()));
219 void WebAuthFlow::DidStopLoading() {
220 AfterUrlLoaded();
223 void WebAuthFlow::DidNavigateMainFrame(
224 const content::LoadCommittedDetails& details,
225 const content::FrameNavigateParams& params) {
226 if (delegate_ && details.http_status_code >= 400)
227 delegate_->OnAuthFlowFailure(LOAD_FAILED);
230 } // namespace extensions