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 23namespace policy { 24 25// The key under which the hosted-domain value is stored in the UserInfo 26// response. 27const char kGetHostedDomainKey[] = "hd"; 28 29typedef 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. 35class 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 57CloudPolicyClientRegistrationHelper::TokenServiceHelper::TokenServiceHelper() 58 : OAuth2TokenService::Consumer("cloud_policy") {} 59 60void 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 78void 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 86void 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. 99class 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 119CloudPolicyClientRegistrationHelper::LoginTokenHelper::LoginTokenHelper() {} 120 121void 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 139void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenSuccess( 140 const std::string& access_token, 141 const base::Time& expiration_time) { 142 callback_.Run(access_token); 143} 144 145void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenFailure( 146 const GoogleServiceAuthError& error) { 147 callback_.Run(""); 148} 149 150#endif 151 152CloudPolicyClientRegistrationHelper::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 162CloudPolicyClientRegistrationHelper::~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 170void 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) 188void 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 205void 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 215std::vector<std::string> 216CloudPolicyClientRegistrationHelper::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 224void 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 247void 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 254void 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 278void CloudPolicyClientRegistrationHelper::OnPolicyFetched( 279 CloudPolicyClient* client) { 280 // Ignored. 281} 282 283void 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 291void CloudPolicyClientRegistrationHelper::OnClientError( 292 CloudPolicyClient* client) { 293 DVLOG(1) << "Client registration failed"; 294 DCHECK_EQ(client, client_); 295 RequestCompleted(); 296} 297 298void 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