| Index: chrome/browser/extensions/api/identity/web_auth_flow.cc
|
| ===================================================================
|
| --- chrome/browser/extensions/api/identity/web_auth_flow.cc (revision 149223)
|
| +++ chrome/browser/extensions/api/identity/web_auth_flow.cc (working copy)
|
| @@ -10,15 +10,27 @@
|
| #include "base/message_loop.h"
|
| #include "base/stringprintf.h"
|
| #include "base/string_util.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/ui/browser.h"
|
| +#include "chrome/browser/ui/browser_navigator.h"
|
| +#include "chrome/browser/ui/tab_contents/tab_contents.h"
|
| #include "chrome/common/chrome_switches.h"
|
| -#include "content/public/browser/invalidate_type.h"
|
| +#include "content/public/browser/load_notification_details.h"
|
| #include "content/public/browser/navigation_controller.h"
|
| +#include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_source.h"
|
| +#include "content/public/browser/notification_types.h"
|
| +#include "content/public/browser/resource_request_details.h"
|
| #include "content/public/browser/web_contents.h"
|
| +#include "content/public/common/page_transition_types.h"
|
| +#include "googleurl/src/gurl.h"
|
| +#include "webkit/glue/window_open_disposition.h"
|
| #include "ipc/ipc_message.h"
|
|
|
| -using content::BrowserContext;
|
| +using content::LoadNotificationDetails;
|
| +using content::NavigationController;
|
| +using content::ResourceRedirectDetails;
|
| using content::WebContents;
|
| -using content::WebContentsDelegate;
|
|
|
| namespace {
|
|
|
| @@ -33,24 +45,24 @@
|
|
|
| WebAuthFlow::WebAuthFlow(
|
| Delegate* delegate,
|
| - BrowserContext* browser_context,
|
| + Profile* profile,
|
| const std::string& extension_id,
|
| const GURL& provider_url,
|
| Mode mode)
|
| : delegate_(delegate),
|
| - browser_context_(browser_context),
|
| + profile_(profile),
|
| provider_url_(provider_url),
|
| mode_(mode),
|
| contents_(NULL),
|
| - window_(NULL) {
|
| + tab_contents_(NULL) {
|
| InitValidRedirectUrlPrefixes(extension_id);
|
| }
|
|
|
| WebAuthFlow::~WebAuthFlow() {
|
| - if (window_)
|
| - delete window_;
|
| + if (tab_contents_) {
|
| + tab_contents_->web_contents()->Close();
|
| + }
|
| if (contents_) {
|
| - contents_->SetDelegate(NULL);
|
| contents_->Stop();
|
| // Tell message loop to delete contents_ instead of deleting it
|
| // directly since destructor can run in response to a callback from
|
| @@ -61,48 +73,64 @@
|
|
|
| void WebAuthFlow::Start() {
|
| contents_ = CreateWebContents();
|
| - contents_->SetDelegate(this);
|
| - contents_->GetController().LoadURL(
|
| +
|
| + NavigationController* controller = &(contents_->GetController());
|
| +
|
| + // Register for appropriate notifications to intercept navigation to the
|
| + // redirect URLs.
|
| + registrar_.Add(
|
| + this,
|
| + content::NOTIFICATION_LOAD_START,
|
| + content::Source<NavigationController>(controller));
|
| + registrar_.Add(
|
| + this,
|
| + content::NOTIFICATION_LOAD_STOP,
|
| + content::Source<NavigationController>(controller));
|
| + registrar_.Add(
|
| + this,
|
| + content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
|
| + content::Source<WebContents>(contents_));
|
| + registrar_.Add(
|
| + this,
|
| + content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
|
| + content::Source<WebContents>(contents_));
|
| +
|
| + controller->LoadURL(
|
| provider_url_,
|
| content::Referrer(),
|
| content::PAGE_TRANSITION_START_PAGE,
|
| std::string());
|
| }
|
|
|
| -void WebAuthFlow::LoadingStateChanged(WebContents* source) {
|
| - if (source->IsLoading())
|
| - return;
|
| - OnUrlLoaded();
|
| +WebContents* WebAuthFlow::CreateWebContents() {
|
| + return WebContents::Create(profile_, NULL, MSG_ROUTING_NONE, NULL, NULL);
|
| }
|
|
|
| -void WebAuthFlow::NavigationStateChanged(
|
| - const WebContents* source, unsigned changed_flags) {
|
| - // If the URL has not changed, do not perform the check again (for
|
| - // efficiency).
|
| - if ((changed_flags & content::INVALIDATE_TYPE_URL) == 0)
|
| - return;
|
| +void WebAuthFlow::ShowAuthFlowPopup() {
|
| + // Pass ownership of WebContents to TabContents.
|
| + tab_contents_ = new TabContents(contents_);
|
| + contents_ = NULL;
|
| + Browser* browser = new Browser(Browser::CreateParams(
|
| + Browser::TYPE_POPUP, profile_));
|
| + chrome::NavigateParams params(browser, tab_contents_);
|
| + params.disposition = CURRENT_TAB;
|
| + params.window_action = chrome::NavigateParams::SHOW_WINDOW;
|
| + chrome::Navigate(¶ms);
|
| + // Observe method will be called before URLs are loaded. That is where
|
| + // we check for redirect to the right URL.
|
| +}
|
|
|
| - // If the URL is a valid extension redirect URL, capture the
|
| - // results and end the flow.
|
| - const GURL& url = source->GetURL();
|
| -
|
| +bool WebAuthFlow::BeforeUrlLoaded(const GURL& url) {
|
| if (IsValidRedirectUrl(url)) {
|
| ReportResult(url);
|
| + return true;
|
| }
|
| + return false;
|
| }
|
|
|
| -WebContents* WebAuthFlow::CreateWebContents() {
|
| - return WebContents::Create(
|
| - browser_context_, NULL, MSG_ROUTING_NONE, NULL, NULL);
|
| -}
|
| -
|
| -WebAuthFlowWindow* WebAuthFlow::CreateAuthWindow() {
|
| - return WebAuthFlowWindow::Create(this, browser_context_, contents_);
|
| -}
|
| -
|
| -void WebAuthFlow::OnUrlLoaded() {
|
| - // Do nothing if a window is already created.
|
| - if (window_)
|
| +void WebAuthFlow::AfterUrlLoaded() {
|
| + // Do nothing if a popup is already created.
|
| + if (tab_contents_)
|
| return;
|
|
|
| // Report results directly if not in interactive mode.
|
| @@ -111,27 +139,58 @@
|
| return;
|
| }
|
|
|
| - // We are in interactive mode and window is not shown yet; create
|
| - // and show the window.
|
| - window_ = CreateAuthWindow();
|
| - window_->Show();
|
| + // We are in interactive mode and window is not shown yet; show the window.
|
| + ShowAuthFlowPopup();
|
| }
|
|
|
| -void WebAuthFlow::OnClose() {
|
| - ReportResult(GURL());
|
| +void WebAuthFlow::Observe(int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| + switch (type) {
|
| + case content::NOTIFICATION_LOAD_START: {
|
| + LoadNotificationDetails* load_details =
|
| + content::Details<LoadNotificationDetails>(details).ptr();
|
| + if (load_details != NULL)
|
| + BeforeUrlLoaded(load_details->url);
|
| + }
|
| + break;
|
| + case content::NOTIFICATION_LOAD_STOP: {
|
| + LoadNotificationDetails* load_details =
|
| + content::Details<LoadNotificationDetails>(details).ptr();
|
| + if (load_details != NULL)
|
| + AfterUrlLoaded();
|
| + }
|
| + break;
|
| + case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
|
| + ResourceRedirectDetails* redirect_details =
|
| + content::Details<ResourceRedirectDetails>(details).ptr();
|
| + if (redirect_details != NULL)
|
| + BeforeUrlLoaded(redirect_details->new_url);
|
| + }
|
| + break;
|
| + case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
|
| + // User closed the auth flow window; report a failure.
|
| + ReportResult(GURL());
|
| + }
|
| + break;
|
| + default:
|
| + NOTREACHED() << "Got a notification that we did not register for: "
|
| + << type;
|
| + break;
|
| + }
|
| }
|
|
|
| -void WebAuthFlow::ReportResult(const GURL& result) {
|
| +void WebAuthFlow::ReportResult(const GURL& url) {
|
| if (!delegate_)
|
| return;
|
|
|
| - if (result.is_empty()) {
|
| + if (url.is_empty()) {
|
| delegate_->OnAuthFlowFailure();
|
| } else {
|
| // TODO(munjal): Consider adding code to parse out access token
|
| // from some common places (e.g. URL fragment) so the apps don't
|
| // have to do that work.
|
| - delegate_->OnAuthFlowSuccess(result.spec());
|
| + delegate_->OnAuthFlowSuccess(url.spec());
|
| }
|
|
|
| // IMPORTANT: Do not access any members after calling the delegate
|
| @@ -139,6 +198,16 @@
|
| // all data members are invalid after that.
|
| }
|
|
|
| +bool WebAuthFlow::IsValidRedirectUrl(const GURL& url) const {
|
| + std::vector<std::string>::const_iterator iter;
|
| + for (iter = valid_prefixes_.begin(); iter != valid_prefixes_.end(); ++iter) {
|
| + if (StartsWithASCII(url.spec(), *iter, false)) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| void WebAuthFlow::InitValidRedirectUrlPrefixes(
|
| const std::string& extension_id) {
|
| valid_prefixes_.push_back(base::StringPrintf(
|
| @@ -147,13 +216,4 @@
|
| kChromiumDomainRedirectUrlPattern, extension_id.c_str()));
|
| }
|
|
|
| -bool WebAuthFlow::IsValidRedirectUrl(const GURL& url) const {
|
| - std::vector<std::string>::const_iterator iter;
|
| - for (iter = valid_prefixes_.begin(); iter != valid_prefixes_.end(); ++iter) {
|
| - if (StartsWithASCII(url.spec(), *iter, false))
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| } // namespace extensions
|
|
|