| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 
 | // Copyright (c) 2013 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_GAIA_WEB_AUTH_FLOW_H_
#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_GAIA_WEB_AUTH_FLOW_H_
#include "base/macros.h"
#include "chrome/browser/extensions/api/identity/extension_token_key.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "google_apis/gaia/ubertoken_fetcher.h"
#include "net/http/http_cache.h"
namespace net {
class HttpNetworkSession;
class TrivialURLRequestContextGetter;
}
namespace extensions {
// Implements a web-based OAuth2 scope approval dialog. This flow has
// four parts:
// 1. Fetch an ubertoken for a signed-in user.
// 2. Use the ubertoken to get session cookies using MergeSession.
// 3. Start the OAuth flow and wait for final redirect.
// 4. Parse results from the fragment component of the final redirect URI.
//
// The OAuth flow is a special version of the OAuth2 out-of-band flow
// where the final response page's title contains the
// redirect_uri. The redirect URI has an unusual format to prevent its
// use in other contexts. The scheme of the URI is a reversed version
// of the OAuth client ID, and the path starts with the Chrome
// extension ID. For example, an app with the OAuth client ID
// "32610281651.apps.googleusercontent.com" and a Chrome app ID
// "kbinjhdkhikmpjoejcfofghmjjpidcnj", would get redirected to:
//
// com.googleusercontent.apps.32610281651:/kbinjhdkhikmpjoejcfofghmjjpidcnj
//
// Arriving at this URI completes the flow. The last response from
// gaia does a JavaScript redirect to the special URI, but also
// includes the same URI in its title. The navigation to this URI gets
// filtered out because of its unusual protocol scheme, so
// GaiaWebAuthFlow pulls it out of the window title instead.
class GaiaWebAuthFlow : public UbertokenConsumer, public WebAuthFlow::Delegate {
 public:
  enum Failure {
    WINDOW_CLOSED,  // Window closed by user.
    INVALID_REDIRECT,  // Redirect parse error.
    SERVICE_AUTH_ERROR,  // Non-OAuth related authentication error
    OAUTH_ERROR,  // Flow reached final redirect, which contained an error.
    LOAD_FAILED  // An auth flow page failed to load.
  };
  class Delegate {
   public:
    // Called when the flow fails prior to the final OAuth redirect,
    // TODO(courage): LOAD_FAILURE descriptions?
    virtual void OnGaiaFlowFailure(Failure failure,
                                   GoogleServiceAuthError service_error,
                                   const std::string& oauth_error) = 0;
    // Called when the OAuth2 flow completes.
    virtual void OnGaiaFlowCompleted(const std::string& access_token,
                                     const std::string& expiration) = 0;
  };
  GaiaWebAuthFlow(Delegate* delegate,
                  Profile* profile,
                  const ExtensionTokenKey* token_key,
                  const std::string& oauth2_client_id,
                  const std::string& locale);
  ~GaiaWebAuthFlow() override;
  // Starts the flow by fetching an ubertoken. Can override for testing.
  virtual void Start();
  // UbertokenConsumer implementation:
  void OnUbertokenSuccess(const std::string& token) override;
  void OnUbertokenFailure(const GoogleServiceAuthError& error) override;
  // WebAuthFlow::Delegate implementation.
  void OnAuthFlowFailure(WebAuthFlow::Failure failure) override;
  void OnAuthFlowURLChange(const GURL& redirect_url) override;
  void OnAuthFlowTitleChange(const std::string& title) override;
 private:
  // Creates a WebAuthFlow, which will navigate to |url|. Can override
  // for testing. Used to kick off the MergeSession (step #2).
  virtual std::unique_ptr<WebAuthFlow> CreateWebAuthFlow(GURL url);
  class IOHelper {
   public:
    IOHelper(base::WeakPtr<GaiaWebAuthFlow> gaia_web_auth_flow,
             net::URLRequestContextGetter* main_context);
    ~IOHelper();
    void PrepareRequestContext();
    void Cleanup();
    net::URLRequestContext* ubertoken_request_context() {
      return ubertoken_request_context_.get();
    }
   private:
    std::unique_ptr<net::HttpCache::BackendFactory> app_backend_;
    std::unique_ptr<net::HttpNetworkSession> http_network_session_;
    std::unique_ptr<net::HttpCache> app_http_cache_;
    std::unique_ptr<net::URLRequestContext> ubertoken_request_context_;
    base::WeakPtr<GaiaWebAuthFlow> gaia_web_auth_flow_;
    net::URLRequestContextGetter* main_context_;
  };
  void StartUberTokenFetch();
  Delegate* delegate_;
  Profile* profile_;
  std::string account_id_;
  std::string redirect_scheme_;
  std::string redirect_path_prefix_;
  GURL auth_url_;
  std::unique_ptr<IOHelper> io_helper_;
  std::unique_ptr<UbertokenFetcher> ubertoken_fetcher_;
  std::unique_ptr<WebAuthFlow> web_flow_;
  scoped_refptr<net::TrivialURLRequestContextGetter> context_getter_;
  base::WeakPtrFactory<GaiaWebAuthFlow> weak_ptr_factory_;
  DISALLOW_COPY_AND_ASSIGN(GaiaWebAuthFlow);
};
}  // namespace extensions
#endif  // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_GAIA_WEB_AUTH_FLOW_H_
 |