// Copyright (c) 2012 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/extensions/api/identity/experimental_web_auth_flow.h" #include "base/location.h" #include "base/message_loop/message_loop.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_navigator.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 "ui/base/window_open_disposition.h" #include "url/gurl.h" using content::LoadNotificationDetails; using content::NavigationController; using content::RenderViewHost; using content::ResourceRedirectDetails; using content::WebContents; using content::WebContentsObserver; namespace extensions { ExperimentalWebAuthFlow::ExperimentalWebAuthFlow( Delegate* delegate, Profile* profile, const GURL& provider_url, Mode mode, const gfx::Rect& initial_bounds, chrome::HostDesktopType host_desktop_type) : delegate_(delegate), profile_(profile), provider_url_(provider_url), mode_(mode), initial_bounds_(initial_bounds), host_desktop_type_(host_desktop_type), popup_shown_(false), contents_(NULL) { } ExperimentalWebAuthFlow::~ExperimentalWebAuthFlow() { DCHECK(delegate_ == NULL); // Stop listening to notifications first since some of the code // below may generate notifications. registrar_.RemoveAll(); WebContentsObserver::Observe(NULL); if (contents_) { // The popup owns the contents if it was displayed. if (popup_shown_) contents_->Close(); else delete contents_; } } void ExperimentalWebAuthFlow::Start() { contents_ = CreateWebContents(); WebContentsObserver::Observe(contents_); NavigationController* controller = &(contents_->GetController()); // Register for appropriate notifications to intercept navigation to the // redirect URLs. registrar_.Add( this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, content::Source(contents_)); controller->LoadURL( provider_url_, content::Referrer(), content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string()); } void ExperimentalWebAuthFlow::DetachDelegateAndDelete() { delegate_ = NULL; base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); } WebContents* ExperimentalWebAuthFlow::CreateWebContents() { return WebContents::Create(WebContents::CreateParams(profile_)); } void ExperimentalWebAuthFlow::ShowAuthFlowPopup() { Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile_, host_desktop_type_); browser_params.initial_bounds = initial_bounds_; Browser* browser = new Browser(browser_params); chrome::NavigateParams params(browser, contents_); params.disposition = CURRENT_TAB; params.window_action = chrome::NavigateParams::SHOW_WINDOW; chrome::Navigate(¶ms); // Observe method and WebContentsObserver::* methods will be called // for varous navigation events. That is where we check for redirect // to the right URL. popup_shown_ = true; } void ExperimentalWebAuthFlow::BeforeUrlLoaded(const GURL& url) { if (delegate_) delegate_->OnAuthFlowURLChange(url); } void ExperimentalWebAuthFlow::AfterUrlLoaded() { // Do nothing if a popup is already created. if (popup_shown_) return; // Report results directly if not in interactive mode. if (mode_ != ExperimentalWebAuthFlow::INTERACTIVE) { if (delegate_) { delegate_->OnAuthFlowFailure( ExperimentalWebAuthFlow::INTERACTION_REQUIRED); } return; } // We are in interactive mode and window is not shown yet; show the window. ShowAuthFlowPopup(); } void ExperimentalWebAuthFlow::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { ResourceRedirectDetails* redirect_details = content::Details(details).ptr(); if (redirect_details != NULL) BeforeUrlLoaded(redirect_details->new_url); } break; default: NOTREACHED() << "Got a notification that we did not register for: " << type; break; } } void ExperimentalWebAuthFlow::ProvisionalChangeToMainFrameUrl( const GURL& url, RenderViewHost* render_view_host) { BeforeUrlLoaded(url); } void ExperimentalWebAuthFlow::DidStopLoading(RenderViewHost* render_view_host) { AfterUrlLoaded(); } void ExperimentalWebAuthFlow::WebContentsDestroyed(WebContents* web_contents) { contents_ = NULL; if (delegate_) delegate_->OnAuthFlowFailure(ExperimentalWebAuthFlow::WINDOW_CLOSED); } } // namespace extensions