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 "chrome/browser/signin/android_profile_oauth2_token_service.h" 6 7 #include "base/android/jni_android.h" 8 #include "base/android/jni_string.h" 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "chrome/browser/signin/signin_manager.h" 12 #include "chrome/browser/signin/signin_manager_factory.h" 13 #include "chrome/browser/sync/profile_sync_service_android.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "jni/AndroidProfileOAuth2TokenServiceHelper_jni.h" 16 17 using base::android::AttachCurrentThread; 18 using base::android::CheckException; 19 using base::android::ConvertJavaStringToUTF8; 20 using base::android::ConvertUTF8ToJavaString; 21 using base::android::ScopedJavaLocalRef; 22 using content::BrowserThread; 23 24 namespace { 25 26 std::string CombineScopes(const OAuth2TokenService::ScopeSet& scopes) { 27 // The Android AccountManager supports multiple scopes separated by a space: 28 // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android 29 std::string scope; 30 for (OAuth2TokenService::ScopeSet::const_iterator it = scopes.begin(); 31 it != scopes.end(); ++it) { 32 if (!scope.empty()) 33 scope += " "; 34 scope += *it; 35 } 36 return scope; 37 } 38 39 } // namespace 40 41 AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() { 42 } 43 44 AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() { 45 } 46 47 scoped_ptr<OAuth2TokenService::Request> 48 AndroidProfileOAuth2TokenService::StartRequest( 49 const OAuth2TokenService::ScopeSet& scopes, 50 OAuth2TokenService::Consumer* consumer) { 51 const std::string& sync_username = 52 SigninManagerFactory::GetForProfile(profile())-> 53 GetAuthenticatedUsername(); 54 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 55 DCHECK(!sync_username.empty()); 56 return StartRequestForUsername(sync_username, scopes, consumer); 57 } 58 59 scoped_ptr<OAuth2TokenService::Request> 60 AndroidProfileOAuth2TokenService::StartRequestForUsername( 61 const std::string& username, 62 const OAuth2TokenService::ScopeSet& scopes, 63 OAuth2TokenService::Consumer* consumer) { 64 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 65 66 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); 67 FetchOAuth2Token( 68 username, 69 CombineScopes(scopes), 70 base::Bind(&RequestImpl::InformConsumer, request->AsWeakPtr())); 71 return request.PassAs<Request>(); 72 } 73 74 bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable() { 75 SigninManagerBase* signin_manager = 76 SigninManagerFactory::GetForProfile(profile()); 77 return !signin_manager->GetAuthenticatedUsername().empty(); 78 } 79 80 void AndroidProfileOAuth2TokenService::InvalidateToken( 81 const ScopeSet& scopes, 82 const std::string& invalid_token) { 83 OAuth2TokenService::InvalidateToken(scopes, invalid_token); 84 85 JNIEnv* env = AttachCurrentThread(); 86 ScopedJavaLocalRef<jstring> j_invalid_token = 87 ConvertUTF8ToJavaString(env, invalid_token); 88 Java_AndroidProfileOAuth2TokenServiceHelper_invalidateOAuth2AuthToken( 89 env, base::android::GetApplicationContext(), 90 j_invalid_token.obj()); 91 } 92 93 void AndroidProfileOAuth2TokenService::FetchOAuth2Token( 94 const std::string& username, 95 const std::string& scope, 96 const FetchOAuth2TokenCallback& callback) { 97 JNIEnv* env = AttachCurrentThread(); 98 ScopedJavaLocalRef<jstring> j_username = 99 ConvertUTF8ToJavaString(env, username); 100 ScopedJavaLocalRef<jstring> j_scope = 101 ConvertUTF8ToJavaString(env, scope); 102 103 // Allocate a copy of the callback on the heap, because the callback 104 // needs to be passed through JNI as an int. 105 // It will be passed back to OAuth2TokenFetched(), where it will be freed. 106 scoped_ptr<FetchOAuth2TokenCallback> heap_callback( 107 new FetchOAuth2TokenCallback(callback)); 108 109 // Call into Java to get a new token. 110 Java_AndroidProfileOAuth2TokenServiceHelper_getOAuth2AuthToken( 111 env, base::android::GetApplicationContext(), 112 j_username.obj(), 113 j_scope.obj(), 114 reinterpret_cast<int>(heap_callback.release())); 115 } 116 117 // Called from Java when fetching of an OAuth2 token is finished. The 118 // |authToken| param is only valid when |result| is true. 119 void OAuth2TokenFetched(JNIEnv* env, jclass clazz, 120 jstring authToken, 121 jboolean result, 122 jint nativeCallback) { 123 std::string token = ConvertJavaStringToUTF8(env, authToken); 124 scoped_ptr<AndroidProfileOAuth2TokenService::FetchOAuth2TokenCallback> 125 heap_callback( 126 reinterpret_cast< 127 AndroidProfileOAuth2TokenService::FetchOAuth2TokenCallback*>( 128 nativeCallback)); 129 // Android does not provide enough information to know if the credentials are 130 // wrong, so assume any error is transient by using CONNECTION_FAILED. 131 GoogleServiceAuthError err(result ? 132 GoogleServiceAuthError::NONE : 133 GoogleServiceAuthError::CONNECTION_FAILED); 134 heap_callback->Run(err, token, base::Time()); 135 } 136 137 // static 138 bool AndroidProfileOAuth2TokenService::Register(JNIEnv* env) { 139 return RegisterNativesImpl(env); 140 } 141