Home | History | Annotate | Download | only in identity
      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.
      4 
      5 #include "chrome/browser/extensions/api/identity/experimental_web_auth_flow.h"
      6 
      7 #include "base/location.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "chrome/browser/ui/browser.h"
     11 #include "chrome/browser/ui/browser_navigator.h"
     12 #include "content/public/browser/load_notification_details.h"
     13 #include "content/public/browser/navigation_controller.h"
     14 #include "content/public/browser/notification_details.h"
     15 #include "content/public/browser/notification_source.h"
     16 #include "content/public/browser/notification_types.h"
     17 #include "content/public/browser/resource_request_details.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/common/page_transition_types.h"
     20 #include "ui/base/window_open_disposition.h"
     21 #include "url/gurl.h"
     22 
     23 using content::LoadNotificationDetails;
     24 using content::NavigationController;
     25 using content::RenderViewHost;
     26 using content::ResourceRedirectDetails;
     27 using content::WebContents;
     28 using content::WebContentsObserver;
     29 
     30 namespace extensions {
     31 
     32 ExperimentalWebAuthFlow::ExperimentalWebAuthFlow(
     33     Delegate* delegate,
     34     Profile* profile,
     35     const GURL& provider_url,
     36     Mode mode,
     37     const gfx::Rect& initial_bounds,
     38     chrome::HostDesktopType host_desktop_type)
     39     : delegate_(delegate),
     40       profile_(profile),
     41       provider_url_(provider_url),
     42       mode_(mode),
     43       initial_bounds_(initial_bounds),
     44       host_desktop_type_(host_desktop_type),
     45       popup_shown_(false),
     46       contents_(NULL) {
     47 }
     48 
     49 ExperimentalWebAuthFlow::~ExperimentalWebAuthFlow() {
     50   DCHECK(delegate_ == NULL);
     51 
     52   // Stop listening to notifications first since some of the code
     53   // below may generate notifications.
     54   registrar_.RemoveAll();
     55   WebContentsObserver::Observe(NULL);
     56 
     57   if (contents_) {
     58     // The popup owns the contents if it was displayed.
     59     if (popup_shown_)
     60       contents_->Close();
     61     else
     62       delete contents_;
     63   }
     64 }
     65 
     66 void ExperimentalWebAuthFlow::Start() {
     67   contents_ = CreateWebContents();
     68   WebContentsObserver::Observe(contents_);
     69 
     70   NavigationController* controller = &(contents_->GetController());
     71 
     72   // Register for appropriate notifications to intercept navigation to the
     73   // redirect URLs.
     74   registrar_.Add(
     75       this,
     76       content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
     77       content::Source<WebContents>(contents_));
     78 
     79   controller->LoadURL(
     80       provider_url_,
     81       content::Referrer(),
     82       content::PAGE_TRANSITION_AUTO_TOPLEVEL,
     83       std::string());
     84 }
     85 
     86 void ExperimentalWebAuthFlow::DetachDelegateAndDelete() {
     87   delegate_ = NULL;
     88   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
     89 }
     90 
     91 WebContents* ExperimentalWebAuthFlow::CreateWebContents() {
     92   return WebContents::Create(WebContents::CreateParams(profile_));
     93 }
     94 
     95 void ExperimentalWebAuthFlow::ShowAuthFlowPopup() {
     96   Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile_,
     97                                        host_desktop_type_);
     98   browser_params.initial_bounds = initial_bounds_;
     99   Browser* browser = new Browser(browser_params);
    100   chrome::NavigateParams params(browser, contents_);
    101   params.disposition = CURRENT_TAB;
    102   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    103   chrome::Navigate(&params);
    104   // Observe method and WebContentsObserver::* methods will be called
    105   // for varous navigation events. That is where we check for redirect
    106   // to the right URL.
    107   popup_shown_ = true;
    108 }
    109 
    110 void ExperimentalWebAuthFlow::BeforeUrlLoaded(const GURL& url) {
    111   if (delegate_)
    112     delegate_->OnAuthFlowURLChange(url);
    113 }
    114 
    115 void ExperimentalWebAuthFlow::AfterUrlLoaded() {
    116   // Do nothing if a popup is already created.
    117   if (popup_shown_)
    118     return;
    119 
    120   // Report results directly if not in interactive mode.
    121   if (mode_ != ExperimentalWebAuthFlow::INTERACTIVE) {
    122     if (delegate_) {
    123       delegate_->OnAuthFlowFailure(
    124           ExperimentalWebAuthFlow::INTERACTION_REQUIRED);
    125     }
    126     return;
    127   }
    128 
    129   // We are in interactive mode and window is not shown yet; show the window.
    130   ShowAuthFlowPopup();
    131 }
    132 
    133 void ExperimentalWebAuthFlow::Observe(int type,
    134                           const content::NotificationSource& source,
    135                           const content::NotificationDetails& details) {
    136   switch (type) {
    137     case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
    138       ResourceRedirectDetails* redirect_details =
    139           content::Details<ResourceRedirectDetails>(details).ptr();
    140       if (redirect_details != NULL)
    141         BeforeUrlLoaded(redirect_details->new_url);
    142     }
    143     break;
    144     default:
    145       NOTREACHED() << "Got a notification that we did not register for: "
    146                    << type;
    147       break;
    148   }
    149 }
    150 
    151 void ExperimentalWebAuthFlow::ProvisionalChangeToMainFrameUrl(
    152     const GURL& url,
    153     RenderViewHost* render_view_host) {
    154   BeforeUrlLoaded(url);
    155 }
    156 
    157 void ExperimentalWebAuthFlow::DidStopLoading(RenderViewHost* render_view_host) {
    158   AfterUrlLoaded();
    159 }
    160 
    161 void ExperimentalWebAuthFlow::WebContentsDestroyed(WebContents* web_contents) {
    162   contents_ = NULL;
    163   if (delegate_)
    164     delegate_->OnAuthFlowFailure(ExperimentalWebAuthFlow::WINDOW_CLOSED);
    165 }
    166 
    167 }  // namespace extensions
    168