Home | History | Annotate | Download | only in cloud
      1 // Copyright 2013 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 "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/logging.h"
     10 #include "base/time/time.h"
     11 #include "base/values.h"
     12 #include "google_apis/gaia/gaia_constants.h"
     13 #include "google_apis/gaia/gaia_urls.h"
     14 #include "google_apis/gaia/google_service_auth_error.h"
     15 #include "google_apis/gaia/oauth2_token_service.h"
     16 #include "net/url_request/url_request_context_getter.h"
     17 
     18 #if !defined(OS_ANDROID)
     19 #include "google_apis/gaia/oauth2_access_token_consumer.h"
     20 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
     21 #endif
     22 
     23 namespace policy {
     24 
     25 // The key under which the hosted-domain value is stored in the UserInfo
     26 // response.
     27 const char kGetHostedDomainKey[] = "hd";
     28 
     29 typedef base::Callback<void(const std::string&)> StringCallback;
     30 
     31 // This class fetches an OAuth2 token scoped for the userinfo and DM services.
     32 // On Android, we use a special API to allow us to fetch a token for an account
     33 // that is not yet logged in to allow fetching the token before the sign-in
     34 // process is finished.
     35 class CloudPolicyClientRegistrationHelper::TokenServiceHelper
     36     : public OAuth2TokenService::Consumer {
     37  public:
     38   TokenServiceHelper();
     39 
     40   void FetchAccessToken(
     41       OAuth2TokenService* token_service,
     42       const std::string& username,
     43       const StringCallback& callback);
     44 
     45  private:
     46   // OAuth2TokenService::Consumer implementation:
     47   virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
     48                                  const std::string& access_token,
     49                                  const base::Time& expiration_time) OVERRIDE;
     50   virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
     51                                  const GoogleServiceAuthError& error) OVERRIDE;
     52 
     53   StringCallback callback_;
     54   scoped_ptr<OAuth2TokenService::Request> token_request_;
     55 };
     56 
     57 CloudPolicyClientRegistrationHelper::TokenServiceHelper::TokenServiceHelper()
     58     : OAuth2TokenService::Consumer("cloud_policy") {}
     59 
     60 void CloudPolicyClientRegistrationHelper::TokenServiceHelper::FetchAccessToken(
     61     OAuth2TokenService* token_service,
     62     const std::string& account_id,
     63     const StringCallback& callback) {
     64   DCHECK(!token_request_);
     65   // Either the caller must supply a username, or the user must be signed in
     66   // already.
     67   DCHECK(!account_id.empty());
     68   DCHECK(token_service->RefreshTokenIsAvailable(account_id));
     69 
     70   callback_ = callback;
     71 
     72   OAuth2TokenService::ScopeSet scopes;
     73   scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
     74   scopes.insert(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
     75   token_request_ = token_service->StartRequest(account_id, scopes, this);
     76 }
     77 
     78 void CloudPolicyClientRegistrationHelper::TokenServiceHelper::OnGetTokenSuccess(
     79     const OAuth2TokenService::Request* request,
     80     const std::string& access_token,
     81     const base::Time& expiration_time) {
     82   DCHECK_EQ(token_request_.get(), request);
     83   callback_.Run(access_token);
     84 }
     85 
     86 void CloudPolicyClientRegistrationHelper::TokenServiceHelper::OnGetTokenFailure(
     87     const OAuth2TokenService::Request* request,
     88     const GoogleServiceAuthError& error) {
     89   DCHECK_EQ(token_request_.get(), request);
     90   callback_.Run("");
     91 }
     92 
     93 #if !defined(OS_ANDROID)
     94 // This class fetches the OAuth2 token scoped for the userinfo and DM services.
     95 // It uses an OAuth2AccessTokenFetcher to fetch it, given a login refresh token
     96 // that can be used to authorize that request. This class is not needed on
     97 // Android because we can use OAuth2TokenService to fetch tokens for accounts
     98 // even before they are signed in.
     99 class CloudPolicyClientRegistrationHelper::LoginTokenHelper
    100     : public OAuth2AccessTokenConsumer {
    101  public:
    102   LoginTokenHelper();
    103 
    104   void FetchAccessToken(const std::string& login_refresh_token,
    105                         net::URLRequestContextGetter* context,
    106                         const StringCallback& callback);
    107 
    108  private:
    109   // OAuth2AccessTokenConsumer implementation:
    110   virtual void OnGetTokenSuccess(const std::string& access_token,
    111                                  const base::Time& expiration_time) OVERRIDE;
    112   virtual void OnGetTokenFailure(
    113       const GoogleServiceAuthError& error) OVERRIDE;
    114 
    115   StringCallback callback_;
    116   scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
    117 };
    118 
    119 CloudPolicyClientRegistrationHelper::LoginTokenHelper::LoginTokenHelper() {}
    120 
    121 void CloudPolicyClientRegistrationHelper::LoginTokenHelper::FetchAccessToken(
    122     const std::string& login_refresh_token,
    123     net::URLRequestContextGetter* context,
    124     const StringCallback& callback) {
    125   DCHECK(!oauth2_access_token_fetcher_);
    126   callback_ = callback;
    127 
    128   // Start fetching an OAuth2 access token for the device management and
    129   // userinfo services.
    130   oauth2_access_token_fetcher_.reset(
    131       new OAuth2AccessTokenFetcherImpl(this, context, login_refresh_token));
    132   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
    133   oauth2_access_token_fetcher_->Start(
    134       gaia_urls->oauth2_chrome_client_id(),
    135       gaia_urls->oauth2_chrome_client_secret(),
    136       GetScopes());
    137 }
    138 
    139 void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenSuccess(
    140     const std::string& access_token,
    141     const base::Time& expiration_time) {
    142   callback_.Run(access_token);
    143 }
    144 
    145 void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenFailure(
    146     const GoogleServiceAuthError& error) {
    147   callback_.Run("");
    148 }
    149 
    150 #endif
    151 
    152 CloudPolicyClientRegistrationHelper::CloudPolicyClientRegistrationHelper(
    153     CloudPolicyClient* client,
    154     enterprise_management::DeviceRegisterRequest::Type registration_type)
    155     : context_(client->GetRequestContext()),
    156       client_(client),
    157       registration_type_(registration_type) {
    158   DCHECK(context_.get());
    159   DCHECK(client_);
    160 }
    161 
    162 CloudPolicyClientRegistrationHelper::~CloudPolicyClientRegistrationHelper() {
    163   // Clean up any pending observers in case the browser is shutdown while
    164   // trying to register for policy.
    165   if (client_)
    166     client_->RemoveObserver(this);
    167 }
    168 
    169 
    170 void CloudPolicyClientRegistrationHelper::StartRegistration(
    171     OAuth2TokenService* token_service,
    172     const std::string& account_id,
    173     const base::Closure& callback) {
    174   DVLOG(1) << "Starting registration process with username";
    175   DCHECK(!client_->is_registered());
    176   callback_ = callback;
    177   client_->AddObserver(this);
    178 
    179   token_service_helper_.reset(new TokenServiceHelper());
    180   token_service_helper_->FetchAccessToken(
    181       token_service,
    182       account_id,
    183       base::Bind(&CloudPolicyClientRegistrationHelper::OnTokenFetched,
    184                  base::Unretained(this)));
    185 }
    186 
    187 #if !defined(OS_ANDROID)
    188 void CloudPolicyClientRegistrationHelper::StartRegistrationWithLoginToken(
    189     const std::string& login_refresh_token,
    190     const base::Closure& callback) {
    191   DVLOG(1) << "Starting registration process with login token";
    192   DCHECK(!client_->is_registered());
    193   callback_ = callback;
    194   client_->AddObserver(this);
    195 
    196   login_token_helper_.reset(
    197       new CloudPolicyClientRegistrationHelper::LoginTokenHelper());
    198   login_token_helper_->FetchAccessToken(
    199       login_refresh_token,
    200       context_.get(),
    201       base::Bind(&CloudPolicyClientRegistrationHelper::OnTokenFetched,
    202                  base::Unretained(this)));
    203 }
    204 
    205 void CloudPolicyClientRegistrationHelper::StartRegistrationWithAccessToken(
    206     const std::string& access_token,
    207     const base::Closure& callback) {
    208   DCHECK(!client_->is_registered());
    209   callback_ = callback;
    210   client_->AddObserver(this);
    211   OnTokenFetched(access_token);
    212 }
    213 
    214 // static
    215 std::vector<std::string>
    216 CloudPolicyClientRegistrationHelper::GetScopes() {
    217   std::vector<std::string> scopes;
    218   scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth);
    219   scopes.push_back(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
    220   return scopes;
    221 }
    222 #endif
    223 
    224 void CloudPolicyClientRegistrationHelper::OnTokenFetched(
    225     const std::string& access_token) {
    226 #if !defined(OS_ANDROID)
    227   login_token_helper_.reset();
    228 #endif
    229   token_service_helper_.reset();
    230 
    231   if (access_token.empty()) {
    232     DLOG(WARNING) << "Could not fetch access token for "
    233                   << GaiaConstants::kDeviceManagementServiceOAuth;
    234     RequestCompleted();
    235     return;
    236   }
    237 
    238   // Cache the access token to be used after the GetUserInfo call.
    239   oauth_access_token_ = access_token;
    240   DVLOG(1) << "Fetched new scoped OAuth token:" << oauth_access_token_;
    241   // Now we've gotten our access token - contact GAIA to see if this is a
    242   // hosted domain.
    243   user_info_fetcher_.reset(new UserInfoFetcher(this, context_.get()));
    244   user_info_fetcher_->Start(oauth_access_token_);
    245 }
    246 
    247 void CloudPolicyClientRegistrationHelper::OnGetUserInfoFailure(
    248     const GoogleServiceAuthError& error) {
    249   DVLOG(1) << "Failed to fetch user info from GAIA: " << error.state();
    250   user_info_fetcher_.reset();
    251   RequestCompleted();
    252 }
    253 
    254 void CloudPolicyClientRegistrationHelper::OnGetUserInfoSuccess(
    255     const base::DictionaryValue* data) {
    256   user_info_fetcher_.reset();
    257   if (!data->HasKey(kGetHostedDomainKey)) {
    258     DVLOG(1) << "User not from a hosted domain - skipping registration";
    259     RequestCompleted();
    260     return;
    261   }
    262   DVLOG(1) << "Registering CloudPolicyClient for user from hosted domain";
    263   // The user is from a hosted domain, so it's OK to register the
    264   // CloudPolicyClient and make requests to DMServer.
    265   if (client_->is_registered()) {
    266     // Client should not be registered yet.
    267     NOTREACHED();
    268     RequestCompleted();
    269     return;
    270   }
    271 
    272   // Kick off registration of the CloudPolicyClient with our newly minted
    273   // oauth_access_token_.
    274   client_->Register(registration_type_, oauth_access_token_,
    275                     std::string(), false, std::string(), std::string());
    276 }
    277 
    278 void CloudPolicyClientRegistrationHelper::OnPolicyFetched(
    279     CloudPolicyClient* client) {
    280   // Ignored.
    281 }
    282 
    283 void CloudPolicyClientRegistrationHelper::OnRegistrationStateChanged(
    284     CloudPolicyClient* client) {
    285   DVLOG(1) << "Client registration succeeded";
    286   DCHECK_EQ(client, client_);
    287   DCHECK(client->is_registered());
    288   RequestCompleted();
    289 }
    290 
    291 void CloudPolicyClientRegistrationHelper::OnClientError(
    292     CloudPolicyClient* client) {
    293   DVLOG(1) << "Client registration failed";
    294   DCHECK_EQ(client, client_);
    295   RequestCompleted();
    296 }
    297 
    298 void CloudPolicyClientRegistrationHelper::RequestCompleted() {
    299   if (client_) {
    300     client_->RemoveObserver(this);
    301     // |client_| may be freed by the callback so clear it now.
    302     client_ = NULL;
    303     callback_.Run();
    304   }
    305 }
    306 
    307 }  // namespace policy
    308