root/components/policy/core/common/cloud/cloud_policy_client_registration_helper.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. FetchAccessToken
  2. OnGetTokenSuccess
  3. OnGetTokenFailure
  4. FetchAccessToken
  5. OnGetTokenSuccess
  6. OnGetTokenFailure
  7. registration_type_
  8. StartRegistration
  9. StartRegistrationWithLoginToken
  10. OnTokenFetched
  11. OnGetUserInfoFailure
  12. OnGetUserInfoSuccess
  13. OnPolicyFetched
  14. OnRegistrationStateChanged
  15. OnClientError
  16. RequestCompleted

// Copyright 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.

#include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h"

#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "base/values.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "net/url_request/url_request_context_getter.h"

#if !defined(OS_ANDROID)
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#endif

namespace policy {

// OAuth2 scope for the userinfo service.
const char kServiceScopeGetUserInfo[] =
    "https://www.googleapis.com/auth/userinfo.email";

// The key under which the hosted-domain value is stored in the UserInfo
// response.
const char kGetHostedDomainKey[] = "hd";

typedef base::Callback<void(const std::string&)> StringCallback;

// This class fetches an OAuth2 token scoped for the userinfo and DM services.
// On Android, we use a special API to allow us to fetch a token for an account
// that is not yet logged in to allow fetching the token before the sign-in
// process is finished.
class CloudPolicyClientRegistrationHelper::TokenServiceHelper
    : public OAuth2TokenService::Consumer {
 public:
  TokenServiceHelper();

  void FetchAccessToken(
      OAuth2TokenService* token_service,
      const std::string& username,
      const StringCallback& callback);

 private:
  // OAuth2TokenService::Consumer implementation:
  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
                                 const std::string& access_token,
                                 const base::Time& expiration_time) OVERRIDE;
  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
                                 const GoogleServiceAuthError& error) OVERRIDE;

  StringCallback callback_;
  scoped_ptr<OAuth2TokenService::Request> token_request_;
};

CloudPolicyClientRegistrationHelper::TokenServiceHelper::TokenServiceHelper()
    : OAuth2TokenService::Consumer("cloud_policy") {}

void CloudPolicyClientRegistrationHelper::TokenServiceHelper::FetchAccessToken(
    OAuth2TokenService* token_service,
    const std::string& account_id,
    const StringCallback& callback) {
  DCHECK(!token_request_);
  // Either the caller must supply a username, or the user must be signed in
  // already.
  DCHECK(!account_id.empty());
  DCHECK(token_service->RefreshTokenIsAvailable(account_id));

  callback_ = callback;

  OAuth2TokenService::ScopeSet scopes;
  scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
  scopes.insert(kServiceScopeGetUserInfo);
  token_request_ = token_service->StartRequest(account_id, scopes, this);
}

void CloudPolicyClientRegistrationHelper::TokenServiceHelper::OnGetTokenSuccess(
    const OAuth2TokenService::Request* request,
    const std::string& access_token,
    const base::Time& expiration_time) {
  DCHECK_EQ(token_request_.get(), request);
  callback_.Run(access_token);
}

void CloudPolicyClientRegistrationHelper::TokenServiceHelper::OnGetTokenFailure(
    const OAuth2TokenService::Request* request,
    const GoogleServiceAuthError& error) {
  DCHECK_EQ(token_request_.get(), request);
  callback_.Run("");
}

#if !defined(OS_ANDROID)
// This class fetches the OAuth2 token scoped for the userinfo and DM services.
// It uses an OAuth2AccessTokenFetcher to fetch it, given a login refresh token
// that can be used to authorize that request. This class is not needed on
// Android because we can use OAuth2TokenService to fetch tokens for accounts
// even before they are signed in.
class CloudPolicyClientRegistrationHelper::LoginTokenHelper
    : public OAuth2AccessTokenConsumer {
 public:
  LoginTokenHelper();

  void FetchAccessToken(const std::string& login_refresh_token,
                        net::URLRequestContextGetter* context,
                        const StringCallback& callback);

 private:
  // OAuth2AccessTokenConsumer implementation:
  virtual void OnGetTokenSuccess(const std::string& access_token,
                                 const base::Time& expiration_time) OVERRIDE;
  virtual void OnGetTokenFailure(
      const GoogleServiceAuthError& error) OVERRIDE;

  StringCallback callback_;
  scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
};

CloudPolicyClientRegistrationHelper::LoginTokenHelper::LoginTokenHelper() {}

void CloudPolicyClientRegistrationHelper::LoginTokenHelper::FetchAccessToken(
    const std::string& login_refresh_token,
    net::URLRequestContextGetter* context,
    const StringCallback& callback) {
  DCHECK(!oauth2_access_token_fetcher_);
  callback_ = callback;

  // Start fetching an OAuth2 access token for the device management and
  // userinfo services.
  oauth2_access_token_fetcher_.reset(
      new OAuth2AccessTokenFetcherImpl(this, context, login_refresh_token));
  std::vector<std::string> scopes;
  scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth);
  scopes.push_back(kServiceScopeGetUserInfo);
  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
  oauth2_access_token_fetcher_->Start(
      gaia_urls->oauth2_chrome_client_id(),
      gaia_urls->oauth2_chrome_client_secret(),
      scopes);
}

void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenSuccess(
    const std::string& access_token,
    const base::Time& expiration_time) {
  callback_.Run(access_token);
}

void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenFailure(
    const GoogleServiceAuthError& error) {
  callback_.Run("");
}

#endif

CloudPolicyClientRegistrationHelper::CloudPolicyClientRegistrationHelper(
    CloudPolicyClient* client,
    enterprise_management::DeviceRegisterRequest::Type registration_type)
    : context_(client->GetRequestContext()),
      client_(client),
      registration_type_(registration_type) {
  DCHECK(context_);
  DCHECK(client_);
}

CloudPolicyClientRegistrationHelper::~CloudPolicyClientRegistrationHelper() {
  // Clean up any pending observers in case the browser is shutdown while
  // trying to register for policy.
  if (client_)
    client_->RemoveObserver(this);
}


void CloudPolicyClientRegistrationHelper::StartRegistration(
    OAuth2TokenService* token_service,
    const std::string& account_id,
    const base::Closure& callback) {
  DVLOG(1) << "Starting registration process with username";
  DCHECK(!client_->is_registered());
  callback_ = callback;
  client_->AddObserver(this);

  token_service_helper_.reset(new TokenServiceHelper());
  token_service_helper_->FetchAccessToken(
      token_service,
      account_id,
      base::Bind(&CloudPolicyClientRegistrationHelper::OnTokenFetched,
                 base::Unretained(this)));
}

#if !defined(OS_ANDROID)
void CloudPolicyClientRegistrationHelper::StartRegistrationWithLoginToken(
    const std::string& login_refresh_token,
    const base::Closure& callback) {
  DVLOG(1) << "Starting registration process with login token";
  DCHECK(!client_->is_registered());
  callback_ = callback;
  client_->AddObserver(this);

  login_token_helper_.reset(
      new CloudPolicyClientRegistrationHelper::LoginTokenHelper());
  login_token_helper_->FetchAccessToken(
      login_refresh_token,
      context_,
      base::Bind(&CloudPolicyClientRegistrationHelper::OnTokenFetched,
                 base::Unretained(this)));
}
#endif

void CloudPolicyClientRegistrationHelper::OnTokenFetched(
    const std::string& access_token) {
#if !defined(OS_ANDROID)
  login_token_helper_.reset();
#endif
  token_service_helper_.reset();

  if (access_token.empty()) {
    DLOG(WARNING) << "Could not fetch access token for "
                  << GaiaConstants::kDeviceManagementServiceOAuth;
    RequestCompleted();
    return;
  }

  // Cache the access token to be used after the GetUserInfo call.
  oauth_access_token_ = access_token;
  DVLOG(1) << "Fetched new scoped OAuth token:" << oauth_access_token_;
  // Now we've gotten our access token - contact GAIA to see if this is a
  // hosted domain.
  user_info_fetcher_.reset(new UserInfoFetcher(this, context_));
  user_info_fetcher_->Start(oauth_access_token_);
}

void CloudPolicyClientRegistrationHelper::OnGetUserInfoFailure(
    const GoogleServiceAuthError& error) {
  DVLOG(1) << "Failed to fetch user info from GAIA: " << error.state();
  user_info_fetcher_.reset();
  RequestCompleted();
}

void CloudPolicyClientRegistrationHelper::OnGetUserInfoSuccess(
    const base::DictionaryValue* data) {
  user_info_fetcher_.reset();
  if (!data->HasKey(kGetHostedDomainKey)) {
    DVLOG(1) << "User not from a hosted domain - skipping registration";
    RequestCompleted();
    return;
  }
  DVLOG(1) << "Registering CloudPolicyClient for user from hosted domain";
  // The user is from a hosted domain, so it's OK to register the
  // CloudPolicyClient and make requests to DMServer.
  if (client_->is_registered()) {
    // Client should not be registered yet.
    NOTREACHED();
    RequestCompleted();
    return;
  }

  // Kick off registration of the CloudPolicyClient with our newly minted
  // oauth_access_token_.
  client_->Register(registration_type_, oauth_access_token_,
                    std::string(), false, std::string(), std::string());
}

void CloudPolicyClientRegistrationHelper::OnPolicyFetched(
    CloudPolicyClient* client) {
  // Ignored.
}

void CloudPolicyClientRegistrationHelper::OnRegistrationStateChanged(
    CloudPolicyClient* client) {
  DVLOG(1) << "Client registration succeeded";
  DCHECK_EQ(client, client_);
  DCHECK(client->is_registered());
  RequestCompleted();
}

void CloudPolicyClientRegistrationHelper::OnClientError(
    CloudPolicyClient* client) {
  DVLOG(1) << "Client registration failed";
  DCHECK_EQ(client, client_);
  RequestCompleted();
}

void CloudPolicyClientRegistrationHelper::RequestCompleted() {
  if (client_) {
    client_->RemoveObserver(this);
    // |client_| may be freed by the callback so clear it now.
    client_ = NULL;
    callback_.Run();
  }
}

}  // namespace policy

/* [<][>][^][v][top][bottom][index][help] */