Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(555)

Side by Side Diff: chrome/browser/extensions/api/identity/web_auth_flow.cc

Issue 14081014: Identity API: Change WebAuthFlow to use <webview> instead of a normal browser pop-up. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: chrome.identity side-by-side with chrome.experimental.identity Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/identity/web_auth_flow.h" 5 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
6 6
7 #include "base/base64.h"
7 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/string_util.h"
10 #include "chrome/browser/extensions/event_router.h"
11 #include "chrome/browser/extensions/extension_system.h"
8 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_navigator.h" 14 #include "chrome/browser/ui/browser_navigator.h"
15 #include "chrome/browser/ui/extensions/shell_window.h"
16 #include "chrome/common/extensions/extension_constants.h"
11 #include "content/public/browser/load_notification_details.h" 17 #include "content/public/browser/load_notification_details.h"
12 #include "content/public/browser/navigation_controller.h" 18 #include "content/public/browser/navigation_controller.h"
13 #include "content/public/browser/notification_details.h" 19 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_source.h" 20 #include "content/public/browser/notification_source.h"
15 #include "content/public/browser/notification_types.h" 21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/resource_request_details.h" 24 #include "content/public/browser/resource_request_details.h"
17 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/page_transition_types.h" 26 #include "content/public/common/page_transition_types.h"
27 #include "crypto/random.h"
19 #include "googleurl/src/gurl.h" 28 #include "googleurl/src/gurl.h"
20 #include "ui/base/window_open_disposition.h" 29 #include "ui/base/window_open_disposition.h"
21 30
22 using content::LoadNotificationDetails; 31 using content::LoadNotificationDetails;
23 using content::NavigationController; 32 using content::NavigationController;
24 using content::RenderViewHost; 33 using content::RenderViewHost;
25 using content::ResourceRedirectDetails; 34 using content::ResourceRedirectDetails;
26 using content::WebContents; 35 using content::WebContents;
27 using content::WebContentsObserver; 36 using content::WebContentsObserver;
28 37
29 namespace extensions { 38 namespace extensions {
30 39
31 WebAuthFlow::WebAuthFlow( 40 WebAuthFlow::WebAuthFlow(
32 Delegate* delegate, 41 Delegate* delegate,
33 Profile* profile, 42 Profile* profile,
34 const GURL& provider_url, 43 const GURL& provider_url,
35 Mode mode, 44 Mode mode)
36 const gfx::Rect& initial_bounds,
37 chrome::HostDesktopType host_desktop_type)
38 : delegate_(delegate), 45 : delegate_(delegate),
46 closed_(false),
39 profile_(profile), 47 profile_(profile),
40 provider_url_(provider_url), 48 provider_url_(provider_url),
41 mode_(mode), 49 mode_(mode),
42 initial_bounds_(initial_bounds), 50 shell_window_loaded_(false) {
43 host_desktop_type_(host_desktop_type),
44 popup_shown_(false),
45 contents_(NULL) {
46 } 51 }
47 52
48 WebAuthFlow::~WebAuthFlow() { 53 WebAuthFlow::~WebAuthFlow() {
54 DCHECK(closed_);
55 }
56
57 void WebAuthFlow::Start() {
58 ShellWindowRegistry::Get(profile_)->AddObserver(this);
59
60 std::string random_bytes;
61 crypto::RandBytes(WriteInto(&random_bytes, 33), 32);
62 std::string key;
63 bool success = base::Base64Encode(random_bytes, &shell_window_key_);
64 DCHECK(success);
65
66 scoped_ptr<ListValue> args(new ListValue());
67 args->AppendString(shell_window_key_);
68 args->AppendString(provider_url_.spec());
69 if (mode_ == WebAuthFlow::INTERACTIVE)
70 args->AppendString("interactive");
71 else
72 args->AppendString("silent");
73
74 scoped_ptr<Event> event(new Event("identityPrivate.onWebFlowRequest",
75 args.Pass()));
76 event->restrict_to_profile = profile_;
77 ExtensionSystem* system = ExtensionSystem::Get(profile_);
78 system->event_router()->AddLazyEventListener(
79 "identityPrivate.onWebFlowRequest", extension_misc::kIdentityApiUiAppId);
80 system->event_router()->DispatchEventToExtension(
81 extension_misc::kIdentityApiUiAppId, event.Pass());
82 system->event_router()->RemoveLazyEventListener(
83 "identityPrivate.onWebFlowRequest", extension_misc::kIdentityApiUiAppId);
84 }
85
86 void WebAuthFlow::Close() {
87 CHECK(!closed_);
88 closed_ = true;
89
90 // Chances are good that we are currently inside an observer callback, so
91 // detaching listeners now is dangerous. Use a task to unwind the stack
92 // before cleaning up.
93 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
94 &WebAuthFlow::DeferredClose, base::Unretained(this)));
95 }
96
97 void WebAuthFlow::DeferredClose() {
98 DCHECK(closed_);
99
49 // Stop listening to notifications first since some of the code 100 // Stop listening to notifications first since some of the code
50 // below may generate notifications. 101 // below may generate notifications.
102 WebContentsObserver::Observe(NULL);
51 registrar_.RemoveAll(); 103 registrar_.RemoveAll();
52 WebContentsObserver::Observe(NULL); 104 ShellWindowRegistry::Get(profile_)->RemoveObserver(this);
53 105
54 if (contents_) { 106 if (shell_window_ && shell_window_->web_contents())
55 // The popup owns the contents if it was displayed. 107 shell_window_->web_contents()->Close();
56 if (popup_shown_) 108
57 contents_->Close(); 109 delegate_->OnAuthFlowClosed();
58 else 110 }
59 delete contents_; 111
112 void WebAuthFlow::OnShellWindowAdded(ShellWindow* shell_window) {
113 if (closed_)
114 return;
115
116 if (shell_window->window_key() == shell_window_key_ &&
117 shell_window->extension()->id() == extension_misc::kIdentityApiUiAppId) {
118 shell_window_ = shell_window;
119 WebContentsObserver::Observe(shell_window->web_contents());
120
121 registrar_.Add(
122 this,
123 content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
124 content::NotificationService::AllBrowserContextsAndSources());
60 } 125 }
61 } 126 }
62 127
63 void WebAuthFlow::Start() { 128 void WebAuthFlow::OnShellWindowRemoved(ShellWindow* shell_window) {
64 contents_ = CreateWebContents(); 129 if (closed_)
65 WebContentsObserver::Observe(contents_); 130 return;
66 131
67 NavigationController* controller = &(contents_->GetController()); 132 if (shell_window->window_key() == shell_window_key_ &&
68 133 shell_window->extension()->id() == extension_misc::kIdentityApiUiAppId) {
69 // Register for appropriate notifications to intercept navigation to the 134 shell_window_ = NULL;
70 // redirect URLs. 135 if (!closed_)
71 registrar_.Add( 136 delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
72 this, 137 }
73 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
74 content::Source<WebContents>(contents_));
75
76 controller->LoadURL(
77 provider_url_,
78 content::Referrer(),
79 content::PAGE_TRANSITION_AUTO_TOPLEVEL,
80 std::string());
81 }
82
83 WebContents* WebAuthFlow::CreateWebContents() {
84 return WebContents::Create(WebContents::CreateParams(profile_));
85 }
86
87 void WebAuthFlow::ShowAuthFlowPopup() {
88 Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile_,
89 host_desktop_type_);
90 browser_params.initial_bounds = initial_bounds_;
91 Browser* browser = new Browser(browser_params);
92 chrome::NavigateParams params(browser, contents_);
93 params.disposition = CURRENT_TAB;
94 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
95 chrome::Navigate(&params);
96 // Observe method and WebContentsObserver::* methods will be called
97 // for varous navigation events. That is where we check for redirect
98 // to the right URL.
99 popup_shown_ = true;
100 } 138 }
101 139
102 void WebAuthFlow::BeforeUrlLoaded(const GURL& url) { 140 void WebAuthFlow::BeforeUrlLoaded(const GURL& url) {
103 delegate_->OnAuthFlowURLChange(url); 141 delegate_->OnAuthFlowURLChange(url);
104 } 142 }
105 143
106 void WebAuthFlow::AfterUrlLoaded() { 144 void WebAuthFlow::AfterUrlLoaded() {
107 // Do nothing if a popup is already created. 145 if (shell_window_loaded_ && mode_ == WebAuthFlow::SILENT) {
108 if (popup_shown_)
109 return;
110
111 // Report results directly if not in interactive mode.
112 if (mode_ != WebAuthFlow::INTERACTIVE) {
113 delegate_->OnAuthFlowFailure(WebAuthFlow::INTERACTION_REQUIRED); 146 delegate_->OnAuthFlowFailure(WebAuthFlow::INTERACTION_REQUIRED);
114 return; 147 return;
115 } 148 }
116
117 // We are in interactive mode and window is not shown yet; show the window.
118 ShowAuthFlowPopup();
119 } 149 }
120 150
121 void WebAuthFlow::Observe(int type, 151 void WebAuthFlow::Observe(int type,
122 const content::NotificationSource& source, 152 const content::NotificationSource& source,
123 const content::NotificationDetails& details) { 153 const content::NotificationDetails& details) {
154 if (closed_)
155 return;
156
124 switch (type) { 157 switch (type) {
158 case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
159 RenderViewHost* render_view(
160 content::Details<RenderViewHost>(details).ptr());
161 WebContents* web_contents = WebContents::FromRenderViewHost(render_view);
162
163 if (web_contents &&
164 (web_contents->GetEmbedderWebContents() ==
165 WebContentsObserver::web_contents())) {
166 // Switch from watching the shell window to the guest inside it.
167 shell_window_loaded_ = true;
168 registrar_.RemoveAll();
169 WebContentsObserver::Observe(web_contents);
170
171 registrar_.Add(
172 this,
173 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
174 content::Source<WebContents>(web_contents));
175 }
176 }
177 break;
125 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { 178 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
126 ResourceRedirectDetails* redirect_details = 179 ResourceRedirectDetails* redirect_details =
127 content::Details<ResourceRedirectDetails>(details).ptr(); 180 content::Details<ResourceRedirectDetails>(details).ptr();
128 if (redirect_details != NULL) 181 if (redirect_details != NULL)
129 BeforeUrlLoaded(redirect_details->new_url); 182 BeforeUrlLoaded(redirect_details->new_url);
130 } 183 }
131 break; 184 break;
132 default: 185 default:
133 NOTREACHED() << "Got a notification that we did not register for: " 186 NOTREACHED() << "Got a notification that we did not register for: "
134 << type; 187 << type;
135 break; 188 break;
136 } 189 }
137 } 190 }
138 191
139 void WebAuthFlow::ProvisionalChangeToMainFrameUrl( 192 void WebAuthFlow::RenderViewGone(base::TerminationStatus status) {
140 const GURL& url, 193 if (closed_)
194 return;
195
196 delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
197 }
198
199 void WebAuthFlow::DidStartProvisionalLoadForFrame(
200 int64 frame_id,
201 int64 parent_frame_id,
202 bool is_main_frame,
203 const GURL& validated_url,
204 bool is_error_page,
205 bool is_iframe_srcdoc,
141 RenderViewHost* render_view_host) { 206 RenderViewHost* render_view_host) {
142 BeforeUrlLoaded(url); 207 if (closed_)
208 return;
209
210 if (is_main_frame)
211 BeforeUrlLoaded(validated_url);
212 }
213
214 void WebAuthFlow::DidFailProvisionalLoad(int64 frame_id,
215 bool is_main_frame,
216 const GURL& validated_url,
217 int error_code,
218 const string16& error_description,
219 RenderViewHost* render_view_host) {
220 if (closed_)
221 return;
222
223 delegate_->OnAuthFlowFailure(LOAD_FAILED);
224 }
225
226 void WebAuthFlow::DidFailLoad(int64 frame_id,
227 const GURL& validated_url,
228 bool is_main_frame,
229 int error_code,
230 const string16& error_description,
231 RenderViewHost* render_view_host) {
232 if (closed_)
233 return;
234
235 delegate_->OnAuthFlowFailure(LOAD_FAILED);
143 } 236 }
144 237
145 void WebAuthFlow::DidStopLoading(RenderViewHost* render_view_host) { 238 void WebAuthFlow::DidStopLoading(RenderViewHost* render_view_host) {
239 if (closed_)
240 return;
241
146 AfterUrlLoaded(); 242 AfterUrlLoaded();
147 } 243 }
148 244
149 void WebAuthFlow::WebContentsDestroyed(WebContents* web_contents) {
150 contents_ = NULL;
151 delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
152 }
153
154 } // namespace extensions 245 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698