Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/arc/arc_auth_context.h" | 5 #include "chrome/browser/chromeos/arc/arc_auth_context.h" |
| 6 | 6 |
| 7 #include "base/json/json_string_value_serializer.h" | |
| 8 #include "base/json/json_writer.h" | |
| 7 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/values.h" | |
| 8 #include "chrome/browser/chromeos/arc/arc_auth_context_delegate.h" | 11 #include "chrome/browser/chromeos/arc/arc_auth_context_delegate.h" |
| 9 #include "chrome/browser/chromeos/arc/arc_support_host.h" | 12 #include "chrome/browser/chromeos/arc/arc_support_host.h" |
| 10 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
| 11 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | 14 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
| 12 #include "chrome/browser/signin/signin_manager_factory.h" | 15 #include "chrome/browser/signin/signin_manager_factory.h" |
| 16 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" | |
| 17 #include "components/signin/core/account_id/account_id.h" | |
| 13 #include "components/signin/core/browser/profile_oauth2_token_service.h" | 18 #include "components/signin/core/browser/profile_oauth2_token_service.h" |
| 14 #include "components/signin/core/browser/signin_manager_base.h" | 19 #include "components/signin/core/browser/signin_manager_base.h" |
| 20 #include "components/user_manager/known_user.h" | |
| 15 #include "content/public/browser/browser_context.h" | 21 #include "content/public/browser/browser_context.h" |
| 16 #include "content/public/browser/storage_partition.h" | 22 #include "content/public/browser/storage_partition.h" |
| 17 #include "content/public/common/url_constants.h" | 23 #include "content/public/common/url_constants.h" |
| 18 #include "google_apis/gaia/gaia_auth_fetcher.h" | 24 #include "google_apis/gaia/gaia_auth_fetcher.h" |
| 19 #include "google_apis/gaia/gaia_constants.h" | 25 #include "google_apis/gaia/gaia_constants.h" |
| 26 #include "net/base/load_flags.h" | |
| 27 #include "net/http/http_status_code.h" | |
| 20 | 28 |
| 21 namespace arc { | 29 namespace arc { |
| 22 | 30 |
| 23 namespace { | 31 namespace { |
| 24 | 32 |
| 25 constexpr int kRefreshTokenTimeoutSeconds = 10; | 33 constexpr int kRefreshTokenTimeoutSeconds = 10; |
| 34 constexpr int kGetAuthCodeNetworkRetry = 3; | |
| 35 | |
| 36 constexpr char kConsumerName[] = "ArcAuthContext"; | |
| 37 constexpr char kToken[] = "token"; | |
| 38 constexpr char kDeviceId[] = "device_id"; | |
| 39 constexpr char kDeviceType[] = "device_type"; | |
| 40 constexpr char kDeviceTypeArc[] = "arc_plus_plus"; | |
| 41 constexpr char kLoginScopedToken[] = "login_scoped_token"; | |
| 42 constexpr char kGetAuthCodeHeaders[] = | |
| 43 "Content-Type: application/json; charset=utf-8"; | |
| 44 constexpr char kContentTypeJSON[] = "application/json"; | |
| 26 | 45 |
| 27 } // namespace | 46 } // namespace |
| 28 | 47 |
| 29 ArcAuthContext::ArcAuthContext(ArcAuthContextDelegate* delegate, | 48 ArcAuthContext::ArcAuthContext(ArcAuthContextDelegate* delegate, |
| 30 Profile* profile) | 49 Profile* profile) |
| 31 : delegate_(delegate) { | 50 : OAuth2TokenService::Consumer(kConsumerName), |
| 51 delegate_(delegate), | |
| 52 profile_(profile) { | |
| 32 // Reuse storage used in ARC OptIn platform app. | 53 // Reuse storage used in ARC OptIn platform app. |
| 33 const std::string site_url = base::StringPrintf( | 54 const std::string site_url = base::StringPrintf( |
| 34 "%s://%s/persist?%s", content::kGuestScheme, ArcSupportHost::kHostAppId, | 55 "%s://%s/persist?%s", content::kGuestScheme, ArcSupportHost::kHostAppId, |
| 35 ArcSupportHost::kStorageId); | 56 ArcSupportHost::kStorageId); |
| 36 storage_partition_ = content::BrowserContext::GetStoragePartitionForSite( | 57 storage_partition_ = content::BrowserContext::GetStoragePartitionForSite( |
| 37 profile, GURL(site_url)); | 58 profile_, GURL(site_url)); |
| 38 CHECK(storage_partition_); | 59 CHECK(storage_partition_); |
| 39 | 60 |
| 40 // Get token service and account ID to fetch auth tokens. | 61 // Get token service and account ID to fetch auth tokens. |
| 41 token_service_ = ProfileOAuth2TokenServiceFactory::GetForProfile(profile); | 62 token_service_ = ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); |
| 42 const SigninManagerBase* const signin_manager = | 63 const SigninManagerBase* const signin_manager = |
| 43 SigninManagerFactory::GetForProfile(profile); | 64 SigninManagerFactory::GetForProfile(profile_); |
| 44 CHECK(token_service_ && signin_manager); | 65 CHECK(token_service_ && signin_manager); |
| 45 account_id_ = signin_manager->GetAuthenticatedAccountId(); | 66 account_id_ = signin_manager->GetAuthenticatedAccountId(); |
| 46 } | 67 } |
| 47 | 68 |
| 48 ArcAuthContext::~ArcAuthContext() { | 69 ArcAuthContext::~ArcAuthContext() { |
| 49 token_service_->RemoveObserver(this); | 70 token_service_->RemoveObserver(this); |
| 50 } | 71 } |
| 51 | 72 |
| 52 void ArcAuthContext::OnRefreshTokenAvailable(const std::string& account_id) { | 73 void ArcAuthContext::OnRefreshTokenAvailable(const std::string& account_id) { |
| 53 if (account_id != account_id_) | 74 if (account_id != account_id_) |
| 54 return; | 75 return; |
| 55 OnRefreshTokensLoaded(); | 76 OnRefreshTokensLoaded(); |
| 56 } | 77 } |
| 57 | 78 |
| 58 void ArcAuthContext::OnRefreshTokensLoaded() { | 79 void ArcAuthContext::OnRefreshTokensLoaded() { |
| 59 token_service_->RemoveObserver(this); | 80 token_service_->RemoveObserver(this); |
| 60 refresh_token_timeout_.Stop(); | 81 refresh_token_timeout_.Stop(); |
| 61 StartFetchers(); | 82 StartFetchers(); |
| 62 } | 83 } |
| 63 | 84 |
| 64 void ArcAuthContext::OnRefreshTokenTimeout() { | 85 void ArcAuthContext::OnRefreshTokenTimeout() { |
| 65 VLOG(2) << "Failed to wait for refresh token."; | 86 VLOG(2) << "Failed to wait for refresh token."; |
| 66 token_service_->RemoveObserver(this); | 87 token_service_->RemoveObserver(this); |
| 67 delegate_->OnPrepareContextFailed(); | 88 delegate_->OnPrepareContextFailed(); |
| 68 } | 89 } |
| 69 | 90 |
| 91 void ArcAuthContext::OnGetTokenSuccess( | |
| 92 const OAuth2TokenService::Request* request, | |
| 93 const std::string& access_token, | |
| 94 const base::Time& expiration_time) { | |
| 95 ResetFetchers(); | |
| 96 | |
| 97 const std::string device_id = user_manager::known_user::GetDeviceId( | |
| 98 multi_user_util::GetAccountIdFromProfile(profile_)); | |
| 99 DCHECK(!device_id.empty()); | |
| 100 | |
| 101 base::DictionaryValue request_data; | |
| 102 request_data.SetString(kLoginScopedToken, access_token); | |
| 103 request_data.SetString(kDeviceType, kDeviceTypeArc); | |
| 104 request_data.SetString(kDeviceId, device_id); | |
| 105 std::string request_string; | |
| 106 base::JSONWriter::Write(request_data, &request_string); | |
| 107 | |
| 108 DCHECK(!auth_endpoint_.empty()); | |
| 109 auth_code_fetcher_ = net::URLFetcher::Create(0, GURL(auth_endpoint_), | |
| 110 net::URLFetcher::POST, this); | |
| 111 auth_code_fetcher_->SetRequestContext( | |
| 112 storage_partition_->GetURLRequestContext()); | |
| 113 auth_code_fetcher_->SetUploadData(kContentTypeJSON, request_string); | |
| 114 auth_code_fetcher_->SetLoadFlags(net::LOAD_NORMAL); | |
|
xiyuan
2016/09/07 21:07:55
We might want to use LOAD_DISABLE_CACHE | LOAD_BYP
khmel
2016/09/07 23:08:53
Done
| |
| 115 auth_code_fetcher_->SetAutomaticallyRetryOnNetworkChanges( | |
| 116 kGetAuthCodeNetworkRetry); | |
| 117 auth_code_fetcher_->SetExtraRequestHeaders(kGetAuthCodeHeaders); | |
| 118 auth_code_fetcher_->Start(); | |
| 119 } | |
| 120 | |
| 121 void ArcAuthContext::OnGetTokenFailure( | |
| 122 const OAuth2TokenService::Request* request, | |
| 123 const GoogleServiceAuthError& error) { | |
| 124 VLOG(2) << "Failed to get LST " << error.ToString() << "."; | |
| 125 ResetFetchers(); | |
| 126 | |
| 127 delegate_->OnAuthCodeFailed(); | |
| 128 } | |
| 129 | |
| 130 void ArcAuthContext::OnURLFetchComplete(const net::URLFetcher* source) { | |
| 131 const int response_code = source->GetResponseCode(); | |
| 132 std::string json_string; | |
| 133 source->GetResponseAsString(&json_string); | |
| 134 | |
| 135 ResetFetchers(); | |
| 136 | |
| 137 if (response_code != net::HTTP_OK) { | |
| 138 VLOG(2) << "Server returned wrong response code: " << response_code << "."; | |
| 139 delegate_->OnAuthCodeFailed(); | |
| 140 return; | |
| 141 } | |
| 142 | |
| 143 JSONStringValueDeserializer deserializer(json_string); | |
| 144 std::string error_msg; | |
| 145 std::unique_ptr<base::Value> auth_code_info = | |
| 146 deserializer.Deserialize(nullptr, &error_msg); | |
| 147 if (!auth_code_info) { | |
| 148 VLOG(2) << "Unable to deserialize auth code json data: " << error_msg | |
| 149 << "."; | |
| 150 delegate_->OnAuthCodeFailed(); | |
| 151 return; | |
| 152 } | |
| 153 | |
| 154 std::unique_ptr<base::DictionaryValue> auth_code_dictionary = | |
| 155 base::DictionaryValue::From(std::move(auth_code_info)); | |
| 156 if (!auth_code_dictionary) { | |
| 157 NOTREACHED(); | |
| 158 delegate_->OnAuthCodeFailed(); | |
| 159 return; | |
| 160 } | |
| 161 | |
| 162 std::string auth_code; | |
| 163 if (!auth_code_dictionary->GetString(kToken, &auth_code) || | |
| 164 auth_code.empty()) { | |
| 165 VLOG(2) << "Response does not contain auth code."; | |
| 166 delegate_->OnAuthCodeFailed(); | |
| 167 return; | |
| 168 } | |
| 169 | |
| 170 delegate_->OnAuthCodeRequested(auth_code); | |
| 171 } | |
| 172 | |
| 70 void ArcAuthContext::OnMergeSessionSuccess(const std::string& data) { | 173 void ArcAuthContext::OnMergeSessionSuccess(const std::string& data) { |
| 71 context_prepared_ = true; | 174 context_prepared_ = true; |
| 175 ResetFetchers(); | |
| 72 delegate_->OnContextReady(); | 176 delegate_->OnContextReady(); |
| 73 } | 177 } |
| 74 | 178 |
| 75 void ArcAuthContext::OnMergeSessionFailure( | 179 void ArcAuthContext::OnMergeSessionFailure( |
| 76 const GoogleServiceAuthError& error) { | 180 const GoogleServiceAuthError& error) { |
| 77 VLOG(2) << "Failed to merge gaia session " << error.ToString() << "."; | 181 VLOG(2) << "Failed to merge gaia session " << error.ToString() << "."; |
| 182 ResetFetchers(); | |
| 78 delegate_->OnPrepareContextFailed(); | 183 delegate_->OnPrepareContextFailed(); |
| 79 } | 184 } |
| 80 | 185 |
| 81 void ArcAuthContext::OnUbertokenSuccess(const std::string& token) { | 186 void ArcAuthContext::OnUbertokenSuccess(const std::string& token) { |
| 187 ResetFetchers(); | |
| 82 merger_fetcher_.reset( | 188 merger_fetcher_.reset( |
| 83 new GaiaAuthFetcher(this, GaiaConstants::kChromeOSSource, | 189 new GaiaAuthFetcher(this, GaiaConstants::kChromeOSSource, |
| 84 storage_partition_->GetURLRequestContext())); | 190 storage_partition_->GetURLRequestContext())); |
| 85 merger_fetcher_->StartMergeSession(token, std::string()); | 191 merger_fetcher_->StartMergeSession(token, std::string()); |
| 86 } | 192 } |
| 87 | 193 |
| 88 void ArcAuthContext::OnUbertokenFailure(const GoogleServiceAuthError& error) { | 194 void ArcAuthContext::OnUbertokenFailure(const GoogleServiceAuthError& error) { |
| 89 VLOG(2) << "Failed to get ubertoken " << error.ToString() << "."; | 195 VLOG(2) << "Failed to get ubertoken " << error.ToString() << "."; |
| 196 ResetFetchers(); | |
| 90 delegate_->OnPrepareContextFailed(); | 197 delegate_->OnPrepareContextFailed(); |
| 91 } | 198 } |
| 92 | 199 |
| 93 void ArcAuthContext::PrepareContext() { | 200 void ArcAuthContext::PrepareContext() { |
| 94 if (context_prepared_) { | 201 if (context_prepared_) { |
| 95 delegate_->OnContextReady(); | 202 delegate_->OnContextReady(); |
| 96 return; | 203 return; |
| 97 } | 204 } |
| 98 | 205 |
| 99 token_service_->RemoveObserver(this); | 206 token_service_->RemoveObserver(this); |
| 100 refresh_token_timeout_.Stop(); | 207 refresh_token_timeout_.Stop(); |
| 101 | 208 |
| 102 if (!token_service_->RefreshTokenIsAvailable(account_id_)) { | 209 if (!token_service_->RefreshTokenIsAvailable(account_id_)) { |
| 103 token_service_->AddObserver(this); | 210 token_service_->AddObserver(this); |
| 104 refresh_token_timeout_.Start( | 211 refresh_token_timeout_.Start( |
| 105 FROM_HERE, base::TimeDelta::FromSeconds(kRefreshTokenTimeoutSeconds), | 212 FROM_HERE, base::TimeDelta::FromSeconds(kRefreshTokenTimeoutSeconds), |
| 106 this, &ArcAuthContext::OnRefreshTokenTimeout); | 213 this, &ArcAuthContext::OnRefreshTokenTimeout); |
| 107 return; | 214 return; |
| 108 } | 215 } |
| 109 | 216 |
| 110 StartFetchers(); | 217 StartFetchers(); |
| 111 } | 218 } |
| 112 | 219 |
| 220 void ArcAuthContext::FetchAuthCode(const std::string& auth_endpoint) { | |
| 221 DCHECK(context_prepared_); | |
| 222 | |
| 223 ResetFetchers(); | |
| 224 auth_endpoint_ = auth_endpoint; | |
| 225 | |
| 226 OAuth2TokenService::ScopeSet scopes; | |
| 227 scopes.insert(GaiaConstants::kOAuth1LoginScope); | |
| 228 login_token_request_.reset( | |
| 229 token_service_->StartRequest(account_id_, scopes, this).release()); | |
| 230 } | |
| 231 | |
| 113 void ArcAuthContext::StartFetchers() { | 232 void ArcAuthContext::StartFetchers() { |
| 114 DCHECK(!refresh_token_timeout_.IsRunning()); | 233 DCHECK(!refresh_token_timeout_.IsRunning()); |
| 115 merger_fetcher_.reset(); | 234 ResetFetchers(); |
| 116 ubertoken_fetcher_.reset( | 235 ubertoken_fetcher_.reset( |
| 117 new UbertokenFetcher(token_service_, this, GaiaConstants::kChromeOSSource, | 236 new UbertokenFetcher(token_service_, this, GaiaConstants::kChromeOSSource, |
| 118 storage_partition_->GetURLRequestContext())); | 237 storage_partition_->GetURLRequestContext())); |
| 119 ubertoken_fetcher_->StartFetchingToken(account_id_); | 238 ubertoken_fetcher_->StartFetchingToken(account_id_); |
| 120 } | 239 } |
| 121 | 240 |
| 241 void ArcAuthContext::ResetFetchers() { | |
| 242 merger_fetcher_.reset(); | |
| 243 login_token_request_.reset(); | |
| 244 auth_code_fetcher_.reset(); | |
| 245 ubertoken_fetcher_.reset(); | |
| 246 } | |
| 247 | |
| 122 } // namespace arc | 248 } // namespace arc |
| OLD | NEW |