Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / signin / oauth2_token_service_delegate_android.cc
blob58d6f6e0af121b65302f407332981110f93a855f
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.
5 #include "chrome/browser/signin/oauth2_token_service_delegate_android.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "chrome/browser/profiles/profile_android.h"
13 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
14 #include "chrome/browser/sync/profile_sync_service_android.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "google_apis/gaia/gaia_auth_util.h"
17 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
18 #include "jni/OAuth2TokenService_jni.h"
20 using base::android::AttachCurrentThread;
21 using base::android::ConvertJavaStringToUTF8;
22 using base::android::ConvertUTF8ToJavaString;
23 using base::android::ScopedJavaLocalRef;
24 using content::BrowserThread;
26 namespace {
28 // Callback from FetchOAuth2TokenWithUsername().
29 // Arguments:
30 // - the error, or NONE if the token fetch was successful.
31 // - the OAuth2 access token.
32 // - the expiry time of the token (may be null, indicating that the expiry
33 // time is unknown.
34 typedef base::Callback<void(const GoogleServiceAuthError&,
35 const std::string&,
36 const base::Time&)> FetchOAuth2TokenCallback;
38 class AndroidAccessTokenFetcher : public OAuth2AccessTokenFetcher {
39 public:
40 AndroidAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
41 const std::string& account_id);
42 ~AndroidAccessTokenFetcher() override;
44 // Overrides from OAuth2AccessTokenFetcher:
45 void Start(const std::string& client_id,
46 const std::string& client_secret,
47 const std::vector<std::string>& scopes) override;
48 void CancelRequest() override;
50 // Handles an access token response.
51 void OnAccessTokenResponse(const GoogleServiceAuthError& error,
52 const std::string& access_token,
53 const base::Time& expiration_time);
55 private:
56 std::string CombineScopes(const std::vector<std::string>& scopes);
58 std::string account_id_;
59 bool request_was_cancelled_;
60 base::WeakPtrFactory<AndroidAccessTokenFetcher> weak_factory_;
62 DISALLOW_COPY_AND_ASSIGN(AndroidAccessTokenFetcher);
65 AndroidAccessTokenFetcher::AndroidAccessTokenFetcher(
66 OAuth2AccessTokenConsumer* consumer,
67 const std::string& account_id)
68 : OAuth2AccessTokenFetcher(consumer),
69 account_id_(account_id),
70 request_was_cancelled_(false),
71 weak_factory_(this) {
74 AndroidAccessTokenFetcher::~AndroidAccessTokenFetcher() {
77 void AndroidAccessTokenFetcher::Start(const std::string& client_id,
78 const std::string& client_secret,
79 const std::vector<std::string>& scopes) {
80 JNIEnv* env = AttachCurrentThread();
81 std::string scope = CombineScopes(scopes);
82 ScopedJavaLocalRef<jstring> j_username =
83 ConvertUTF8ToJavaString(env, account_id_);
84 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope);
85 scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
86 new FetchOAuth2TokenCallback(
87 base::Bind(&AndroidAccessTokenFetcher::OnAccessTokenResponse,
88 weak_factory_.GetWeakPtr())));
90 // Call into Java to get a new token.
91 Java_OAuth2TokenService_getOAuth2AuthToken(
92 env, base::android::GetApplicationContext(), j_username.obj(),
93 j_scope.obj(), reinterpret_cast<intptr_t>(heap_callback.release()));
96 void AndroidAccessTokenFetcher::CancelRequest() {
97 request_was_cancelled_ = true;
100 void AndroidAccessTokenFetcher::OnAccessTokenResponse(
101 const GoogleServiceAuthError& error,
102 const std::string& access_token,
103 const base::Time& expiration_time) {
104 if (request_was_cancelled_) {
105 // Ignore the callback if the request was cancelled.
106 return;
108 if (error.state() == GoogleServiceAuthError::NONE) {
109 FireOnGetTokenSuccess(access_token, expiration_time);
110 } else {
111 FireOnGetTokenFailure(error);
115 // static
116 std::string AndroidAccessTokenFetcher::CombineScopes(
117 const std::vector<std::string>& scopes) {
118 // The Android AccountManager supports multiple scopes separated by a space:
119 // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
120 std::string scope;
121 for (std::vector<std::string>::const_iterator it = scopes.begin();
122 it != scopes.end(); ++it) {
123 if (!scope.empty())
124 scope += " ";
125 scope += *it;
127 return scope;
130 } // namespace
132 bool OAuth2TokenServiceDelegateAndroid::is_testing_profile_ = false;
134 OAuth2TokenServiceDelegateAndroid::ErrorInfo::ErrorInfo()
135 : error(GoogleServiceAuthError::NONE) {}
137 OAuth2TokenServiceDelegateAndroid::ErrorInfo::ErrorInfo(
138 const GoogleServiceAuthError& error)
139 : error(error) {}
141 OAuth2TokenServiceDelegateAndroid::OAuth2TokenServiceDelegateAndroid() {
142 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ctor";
143 JNIEnv* env = AttachCurrentThread();
144 base::android::ScopedJavaLocalRef<jobject> local_java_ref =
145 Java_OAuth2TokenService_create(env, reinterpret_cast<intptr_t>(this));
146 java_ref_.Reset(env, local_java_ref.obj());
149 OAuth2TokenServiceDelegateAndroid::~OAuth2TokenServiceDelegateAndroid() {
152 // static
153 ScopedJavaLocalRef<jobject> OAuth2TokenServiceDelegateAndroid::GetForProfile(
154 JNIEnv* env,
155 jclass clazz,
156 jobject j_profile_android) {
157 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android);
158 ProfileOAuth2TokenService* service =
159 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
160 OAuth2TokenServiceDelegate* delegate = service->GetDelegate();
161 return ScopedJavaLocalRef<jobject>(
162 static_cast<OAuth2TokenServiceDelegateAndroid*>(delegate)->java_ref_);
165 static ScopedJavaLocalRef<jobject> GetForProfile(
166 JNIEnv* env,
167 const JavaParamRef<jclass>& clazz,
168 const JavaParamRef<jobject>& j_profile_android) {
169 return OAuth2TokenServiceDelegateAndroid::GetForProfile(env, clazz,
170 j_profile_android);
173 void OAuth2TokenServiceDelegateAndroid::Initialize() {
174 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::Initialize";
175 if (!is_testing_profile_) {
176 Java_OAuth2TokenService_validateAccounts(
177 AttachCurrentThread(), java_ref_.obj(),
178 base::android::GetApplicationContext(), JNI_TRUE);
182 bool OAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable(
183 const std::string& account_id) const {
184 JNIEnv* env = AttachCurrentThread();
185 ScopedJavaLocalRef<jstring> j_account_id =
186 ConvertUTF8ToJavaString(env, account_id);
187 jboolean refresh_token_is_available =
188 Java_OAuth2TokenService_hasOAuth2RefreshToken(
189 env, base::android::GetApplicationContext(), j_account_id.obj());
190 return refresh_token_is_available == JNI_TRUE;
193 bool OAuth2TokenServiceDelegateAndroid::RefreshTokenHasError(
194 const std::string& account_id) const {
195 auto it = errors_.find(account_id);
196 // TODO(rogerta): should we distinguish between transient and persistent?
197 return it == errors_.end() ? false : IsError(it->second.error);
200 void OAuth2TokenServiceDelegateAndroid::UpdateAuthError(
201 const std::string& account_id,
202 const GoogleServiceAuthError& error) {
203 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::UpdateAuthError"
204 << " account=" << account_id
205 << " error=" << error.ToString();
206 if (error.state() == GoogleServiceAuthError::NONE) {
207 errors_.erase(account_id);
208 } else {
209 // TODO(rogerta): should we distinguish between transient and persistent?
210 errors_[account_id] = ErrorInfo(error);
214 std::vector<std::string> OAuth2TokenServiceDelegateAndroid::GetAccounts() {
215 std::vector<std::string> accounts;
216 JNIEnv* env = AttachCurrentThread();
217 ScopedJavaLocalRef<jobjectArray> j_accounts =
218 Java_OAuth2TokenService_getAccounts(
219 env, base::android::GetApplicationContext());
220 // TODO(fgorski): We may decide to filter out some of the accounts.
221 base::android::AppendJavaStringArrayToStringVector(env, j_accounts.obj(),
222 &accounts);
223 return accounts;
226 std::vector<std::string>
227 OAuth2TokenServiceDelegateAndroid::GetSystemAccounts() {
228 std::vector<std::string> accounts;
229 JNIEnv* env = AttachCurrentThread();
230 ScopedJavaLocalRef<jobjectArray> j_accounts =
231 Java_OAuth2TokenService_getSystemAccounts(
232 env, base::android::GetApplicationContext());
233 base::android::AppendJavaStringArrayToStringVector(env, j_accounts.obj(),
234 &accounts);
235 return accounts;
238 OAuth2AccessTokenFetcher*
239 OAuth2TokenServiceDelegateAndroid::CreateAccessTokenFetcher(
240 const std::string& account_id,
241 net::URLRequestContextGetter* getter,
242 OAuth2AccessTokenConsumer* consumer) {
243 ValidateAccountId(account_id);
244 return new AndroidAccessTokenFetcher(consumer, account_id);
247 void OAuth2TokenServiceDelegateAndroid::InvalidateAccessToken(
248 const std::string& account_id,
249 const std::string& client_id,
250 const OAuth2TokenService::ScopeSet& scopes,
251 const std::string& access_token) {
252 ValidateAccountId(account_id);
253 JNIEnv* env = AttachCurrentThread();
254 ScopedJavaLocalRef<jstring> j_access_token =
255 ConvertUTF8ToJavaString(env, access_token);
256 Java_OAuth2TokenService_invalidateOAuth2AuthToken(
257 env, base::android::GetApplicationContext(), j_access_token.obj());
260 void OAuth2TokenServiceDelegateAndroid::ValidateAccounts(
261 JNIEnv* env,
262 jobject obj,
263 jstring j_current_acc,
264 jboolean j_force_notifications) {
265 std::string signed_in_account;
266 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts from java";
267 if (j_current_acc)
268 signed_in_account = ConvertJavaStringToUTF8(env, j_current_acc);
269 if (!signed_in_account.empty())
270 signed_in_account = gaia::CanonicalizeEmail(signed_in_account);
272 // Clear any auth errors so that client can retry to get access tokens.
273 errors_.clear();
275 ValidateAccounts(signed_in_account, j_force_notifications != JNI_FALSE);
278 void OAuth2TokenServiceDelegateAndroid::ValidateAccounts(
279 const std::string& signed_in_account,
280 bool force_notifications) {
281 std::vector<std::string> prev_ids = GetAccounts();
282 std::vector<std::string> curr_ids = GetSystemAccounts();
283 std::vector<std::string> refreshed_ids;
284 std::vector<std::string> revoked_ids;
286 // Canonicalize system accounts. |prev_ids| is already done.
287 for (size_t i = 0; i < curr_ids.size(); ++i)
288 curr_ids[i] = gaia::CanonicalizeEmail(curr_ids[i]);
289 for (size_t i = 0; i < prev_ids.size(); ++i)
290 ValidateAccountId(prev_ids[i]);
292 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
293 << " sigined_in_account=" << signed_in_account
294 << " prev_ids=" << prev_ids.size() << " curr_ids=" << curr_ids.size()
295 << " force=" << (force_notifications ? "true" : "false");
297 if (!ValidateAccounts(signed_in_account, prev_ids, curr_ids, refreshed_ids,
298 revoked_ids, force_notifications)) {
299 curr_ids.clear();
302 ScopedBatchChange batch(this);
304 JNIEnv* env = AttachCurrentThread();
305 ScopedJavaLocalRef<jobjectArray> java_accounts(
306 base::android::ToJavaArrayOfStrings(env, curr_ids));
307 Java_OAuth2TokenService_saveStoredAccounts(
308 env, base::android::GetApplicationContext(), java_accounts.obj());
310 for (std::vector<std::string>::iterator it = refreshed_ids.begin();
311 it != refreshed_ids.end(); it++) {
312 FireRefreshTokenAvailable(*it);
315 for (std::vector<std::string>::iterator it = revoked_ids.begin();
316 it != revoked_ids.end(); it++) {
317 FireRefreshTokenRevoked(*it);
321 bool OAuth2TokenServiceDelegateAndroid::ValidateAccounts(
322 const std::string& signed_in_account,
323 const std::vector<std::string>& prev_account_ids,
324 const std::vector<std::string>& curr_account_ids,
325 std::vector<std::string>& refreshed_ids,
326 std::vector<std::string>& revoked_ids,
327 bool force_notifications) {
328 if (std::find(curr_account_ids.begin(), curr_account_ids.end(),
329 signed_in_account) != curr_account_ids.end()) {
330 // Test to see if an account is removed from the Android AccountManager.
331 // If so, invoke FireRefreshTokenRevoked to notify the reconcilor.
332 for (std::vector<std::string>::const_iterator it = prev_account_ids.begin();
333 it != prev_account_ids.end(); it++) {
334 if (*it == signed_in_account)
335 continue;
337 if (std::find(curr_account_ids.begin(), curr_account_ids.end(), *it) ==
338 curr_account_ids.end()) {
339 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
340 << "revoked=" << *it;
341 revoked_ids.push_back(*it);
345 if (force_notifications ||
346 std::find(prev_account_ids.begin(), prev_account_ids.end(),
347 signed_in_account) == prev_account_ids.end()) {
348 // Always fire the primary signed in account first.
349 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
350 << "refreshed=" << signed_in_account;
351 refreshed_ids.push_back(signed_in_account);
354 for (std::vector<std::string>::const_iterator it = curr_account_ids.begin();
355 it != curr_account_ids.end(); it++) {
356 if (*it != signed_in_account) {
357 if (force_notifications ||
358 std::find(prev_account_ids.begin(), prev_account_ids.end(), *it) ==
359 prev_account_ids.end()) {
360 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
361 << "refreshed=" << *it;
362 refreshed_ids.push_back(*it);
366 return true;
367 } else {
368 // Currently signed in account does not any longer exist among accounts on
369 // system together with all other accounts.
370 if (std::find(prev_account_ids.begin(), prev_account_ids.end(),
371 signed_in_account) != prev_account_ids.end()) {
372 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
373 << "revoked=" << signed_in_account;
374 revoked_ids.push_back(signed_in_account);
376 for (std::vector<std::string>::const_iterator it = prev_account_ids.begin();
377 it != prev_account_ids.end(); it++) {
378 if (*it == signed_in_account)
379 continue;
380 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
381 << "revoked=" << *it;
382 revoked_ids.push_back(*it);
384 return false;
388 void OAuth2TokenServiceDelegateAndroid::FireRefreshTokenAvailableFromJava(
389 JNIEnv* env,
390 jobject obj,
391 const jstring account_name) {
392 std::string account_id = ConvertJavaStringToUTF8(env, account_name);
393 // Notify native observers.
394 FireRefreshTokenAvailable(account_id);
397 void OAuth2TokenServiceDelegateAndroid::FireRefreshTokenAvailable(
398 const std::string& account_id) {
399 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::FireRefreshTokenAvailable id="
400 << account_id;
401 JNIEnv* env = AttachCurrentThread();
402 ScopedJavaLocalRef<jstring> account_name =
403 ConvertUTF8ToJavaString(env, account_id);
404 Java_OAuth2TokenService_notifyRefreshTokenAvailable(env, java_ref_.obj(),
405 account_name.obj());
406 OAuth2TokenServiceDelegate::FireRefreshTokenAvailable(account_id);
409 void OAuth2TokenServiceDelegateAndroid::FireRefreshTokenRevokedFromJava(
410 JNIEnv* env,
411 jobject obj,
412 const jstring account_name) {
413 std::string account_id = ConvertJavaStringToUTF8(env, account_name);
414 // Notify native observers.
415 FireRefreshTokenRevoked(account_id);
418 void OAuth2TokenServiceDelegateAndroid::FireRefreshTokenRevoked(
419 const std::string& account_id) {
420 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::FireRefreshTokenRevoked id="
421 << account_id;
422 JNIEnv* env = AttachCurrentThread();
423 ScopedJavaLocalRef<jstring> account_name =
424 ConvertUTF8ToJavaString(env, account_id);
425 Java_OAuth2TokenService_notifyRefreshTokenRevoked(env, java_ref_.obj(),
426 account_name.obj());
427 OAuth2TokenServiceDelegate::FireRefreshTokenRevoked(account_id);
430 void OAuth2TokenServiceDelegateAndroid::FireRefreshTokensLoadedFromJava(
431 JNIEnv* env,
432 jobject obj) {
433 // Notify native observers.
434 FireRefreshTokensLoaded();
437 void OAuth2TokenServiceDelegateAndroid::FireRefreshTokensLoaded() {
438 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::FireRefreshTokensLoaded";
439 JNIEnv* env = AttachCurrentThread();
440 Java_OAuth2TokenService_notifyRefreshTokensLoaded(env, java_ref_.obj());
441 OAuth2TokenServiceDelegate::FireRefreshTokensLoaded();
444 void OAuth2TokenServiceDelegateAndroid::RevokeAllCredentials() {
445 DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::RevokeAllCredentials";
446 ScopedBatchChange batch(this);
447 std::vector<std::string> accounts = GetAccounts();
448 for (std::vector<std::string>::iterator it = accounts.begin();
449 it != accounts.end(); it++) {
450 FireRefreshTokenRevoked(*it);
453 // Clear everything on the Java side as well.
454 std::vector<std::string> empty;
455 JNIEnv* env = AttachCurrentThread();
456 ScopedJavaLocalRef<jobjectArray> java_accounts(
457 base::android::ToJavaArrayOfStrings(env, empty));
458 Java_OAuth2TokenService_saveStoredAccounts(
459 env, base::android::GetApplicationContext(), java_accounts.obj());
462 // Called from Java when fetching of an OAuth2 token is finished. The
463 // |authToken| param is only valid when |result| is true.
464 void OAuth2TokenFetched(JNIEnv* env,
465 const JavaParamRef<jclass>& clazz,
466 const JavaParamRef<jstring>& authToken,
467 jboolean isTransientError,
468 jlong nativeCallback) {
469 std::string token;
470 if (authToken)
471 token = ConvertJavaStringToUTF8(env, authToken);
472 scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
473 reinterpret_cast<FetchOAuth2TokenCallback*>(nativeCallback));
474 GoogleServiceAuthError
475 err(authToken
476 ? GoogleServiceAuthError::NONE
477 : isTransientError
478 ? GoogleServiceAuthError::CONNECTION_FAILED
479 : GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
480 heap_callback->Run(err, token, base::Time());
483 // static
484 bool OAuth2TokenServiceDelegateAndroid::Register(JNIEnv* env) {
485 return RegisterNativesImpl(env);