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 |