OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 package org.chromium.chrome.browser.signin; | 5 package org.chromium.chrome.browser.signin; |
6 | 6 |
7 import android.accounts.Account; | 7 import android.accounts.Account; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.os.StrictMode; | 9 import android.os.StrictMode; |
10 import android.util.Log; | 10 import android.util.Log; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 * implement this interface and register with {@link #addObserver}. | 44 * implement this interface and register with {@link #addObserver}. |
45 */ | 45 */ |
46 public interface OAuth2TokenServiceObserver { | 46 public interface OAuth2TokenServiceObserver { |
47 void onRefreshTokenAvailable(Account account); | 47 void onRefreshTokenAvailable(Account account); |
48 void onRefreshTokenRevoked(Account account); | 48 void onRefreshTokenRevoked(Account account); |
49 void onRefreshTokensLoaded(); | 49 void onRefreshTokensLoaded(); |
50 } | 50 } |
51 | 51 |
52 private static final String OAUTH2_SCOPE_PREFIX = "oauth2:"; | 52 private static final String OAUTH2_SCOPE_PREFIX = "oauth2:"; |
53 | 53 |
54 private Context mPendingValidationContext; | 54 private boolean mPendingValidation; |
55 private boolean mPendingValidationForceNotifications; | 55 private boolean mPendingValidationForceNotifications; |
56 | 56 |
57 private final long mNativeOAuth2TokenServiceDelegateAndroid; | 57 private final long mNativeOAuth2TokenServiceDelegateAndroid; |
58 private final ObserverList<OAuth2TokenServiceObserver> mObservers; | 58 private final ObserverList<OAuth2TokenServiceObserver> mObservers; |
59 | 59 |
60 private OAuth2TokenService(Context context, long nativeOAuth2Service) { | 60 private OAuth2TokenService(long nativeOAuth2Service) { |
61 mNativeOAuth2TokenServiceDelegateAndroid = nativeOAuth2Service; | 61 mNativeOAuth2TokenServiceDelegateAndroid = nativeOAuth2Service; |
62 mObservers = new ObserverList<OAuth2TokenServiceObserver>(); | 62 mObservers = new ObserverList<OAuth2TokenServiceObserver>(); |
63 AccountTrackerService.get(context).addSystemAccountsSeededListener(this)
; | 63 AccountTrackerService.get().addSystemAccountsSeededListener(this); |
64 } | 64 } |
65 | 65 |
66 public static OAuth2TokenService getForProfile(Profile profile) { | 66 public static OAuth2TokenService getForProfile(Profile profile) { |
67 ThreadUtils.assertOnUiThread(); | 67 ThreadUtils.assertOnUiThread(); |
68 return (OAuth2TokenService) nativeGetForProfile(profile); | 68 return (OAuth2TokenService) nativeGetForProfile(profile); |
69 } | 69 } |
70 | 70 |
71 @CalledByNative | 71 @CalledByNative |
72 private static OAuth2TokenService create(Context context, long nativeOAuth2S
ervice) { | 72 private static OAuth2TokenService create(long nativeOAuth2Service) { |
73 ThreadUtils.assertOnUiThread(); | 73 ThreadUtils.assertOnUiThread(); |
74 return new OAuth2TokenService(context, nativeOAuth2Service); | 74 return new OAuth2TokenService(nativeOAuth2Service); |
75 } | 75 } |
76 | 76 |
77 @VisibleForTesting | 77 @VisibleForTesting |
78 public void addObserver(OAuth2TokenServiceObserver observer) { | 78 public void addObserver(OAuth2TokenServiceObserver observer) { |
79 ThreadUtils.assertOnUiThread(); | 79 ThreadUtils.assertOnUiThread(); |
80 mObservers.addObserver(observer); | 80 mObservers.addObserver(observer); |
81 } | 81 } |
82 | 82 |
83 @VisibleForTesting | 83 @VisibleForTesting |
84 public void removeObserver(OAuth2TokenServiceObserver observer) { | 84 public void removeObserver(OAuth2TokenServiceObserver observer) { |
85 ThreadUtils.assertOnUiThread(); | 85 ThreadUtils.assertOnUiThread(); |
86 mObservers.removeObserver(observer); | 86 mObservers.removeObserver(observer); |
87 } | 87 } |
88 | 88 |
89 private static Account getAccountOrNullFromUsername(Context context, String
username) { | 89 private static Account getAccountOrNullFromUsername(String username) { |
90 if (username == null) { | 90 if (username == null) { |
91 Log.e(TAG, "Username is null"); | 91 Log.e(TAG, "Username is null"); |
92 return null; | 92 return null; |
93 } | 93 } |
94 | 94 |
95 AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(con
text); | 95 AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(); |
96 Account account = accountManagerHelper.getAccountFromName(username); | 96 Account account = accountManagerHelper.getAccountFromName(username); |
97 if (account == null) { | 97 if (account == null) { |
98 Log.e(TAG, "Account not found for provided username."); | 98 Log.e(TAG, "Account not found for provided username."); |
99 return null; | 99 return null; |
100 } | 100 } |
101 return account; | 101 return account; |
102 } | 102 } |
103 | 103 |
104 /** | 104 /** |
105 * Called by native to list the activite account names in the OS. | 105 * Called by native to list the activite account names in the OS. |
106 */ | 106 */ |
107 @VisibleForTesting | 107 @VisibleForTesting |
108 @CalledByNative | 108 @CalledByNative |
109 public static String[] getSystemAccountNames(Context context) { | 109 public static String[] getSystemAccountNames() { |
110 AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(con
text); | 110 AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(); |
111 java.util.List<String> accountNames = accountManagerHelper.getGoogleAcco
untNames(); | 111 java.util.List<String> accountNames = accountManagerHelper.getGoogleAcco
untNames(); |
112 return accountNames.toArray(new String[accountNames.size()]); | 112 return accountNames.toArray(new String[accountNames.size()]); |
113 } | 113 } |
114 | 114 |
115 /** | 115 /** |
116 * Called by native to list the accounts Id with OAuth2 refresh tokens. | 116 * Called by native to list the accounts Id with OAuth2 refresh tokens. |
117 * This can differ from getSystemAccountNames as the user add/remove account
s | 117 * This can differ from getSystemAccountNames as the user add/remove account
s |
118 * from the OS. validateAccounts should be called to keep these two | 118 * from the OS. validateAccounts should be called to keep these two |
119 * in sync. | 119 * in sync. |
120 */ | 120 */ |
121 @CalledByNative | 121 @CalledByNative |
122 public static String[] getAccounts(Context context) { | 122 public static String[] getAccounts() { |
123 return getStoredAccounts(context); | 123 return getStoredAccounts(); |
124 } | 124 } |
125 | 125 |
126 /** | 126 /** |
127 * Called by native to retrieve OAuth2 tokens. | 127 * Called by native to retrieve OAuth2 tokens. |
128 * | 128 * @param username The native username (full address). |
129 * @param username The native username (full address). | |
130 * @param scope The scope to get an auth token for (without Android-style 'o
auth2:' prefix). | 129 * @param scope The scope to get an auth token for (without Android-style 'o
auth2:' prefix). |
131 * @param nativeCallback The pointer to the native callback that should be r
un upon completion. | 130 * @param nativeCallback The pointer to the native callback that should be r
un upon completion. |
132 */ | 131 */ |
133 @CalledByNative | 132 @CalledByNative |
134 public static void getOAuth2AuthToken( | 133 public static void getOAuth2AuthToken( |
135 Context context, String username, String scope, final long nativeCal
lback) { | 134 String username, String scope, final long nativeCallback) { |
136 Account account = getAccountOrNullFromUsername(context, username); | 135 Account account = getAccountOrNullFromUsername(username); |
137 if (account == null) { | 136 if (account == null) { |
138 ThreadUtils.postOnUiThread(new Runnable() { | 137 ThreadUtils.postOnUiThread(new Runnable() { |
139 @Override | 138 @Override |
140 public void run() { | 139 public void run() { |
141 nativeOAuth2TokenFetched(null, false, nativeCallback); | 140 nativeOAuth2TokenFetched(null, false, nativeCallback); |
142 } | 141 } |
143 }); | 142 }); |
144 return; | 143 return; |
145 } | 144 } |
146 String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; | 145 String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; |
147 | 146 |
148 AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(con
text); | 147 AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(); |
149 accountManagerHelper.getAuthToken( | 148 accountManagerHelper.getAuthToken( |
150 account, oauth2Scope, new AccountManagerHelper.GetAuthTokenCallb
ack() { | 149 account, oauth2Scope, new AccountManagerHelper.GetAuthTokenCallb
ack() { |
151 @Override | 150 @Override |
152 public void tokenAvailable(String token) { | 151 public void tokenAvailable(String token) { |
153 nativeOAuth2TokenFetched(token, false, nativeCallback); | 152 nativeOAuth2TokenFetched(token, false, nativeCallback); |
154 } | 153 } |
155 | 154 |
156 @Override | 155 @Override |
157 public void tokenUnavailable(boolean isTransientError) { | 156 public void tokenUnavailable(boolean isTransientError) { |
158 nativeOAuth2TokenFetched(null, isTransientError, nativeC
allback); | 157 nativeOAuth2TokenFetched(null, isTransientError, nativeC
allback); |
159 } | 158 } |
160 }); | 159 }); |
161 } | 160 } |
162 | 161 |
163 /** | 162 /** |
164 * Call this method to retrieve an OAuth2 access token for the given account
and scope. | 163 * Call this method to retrieve an OAuth2 access token for the given account
and scope. |
165 * | 164 * |
166 * @param account the account to get the access token for. | 165 * @param account the account to get the access token for. |
167 * @param scope The scope to get an auth token for (without Android-style 'o
auth2:' prefix). | 166 * @param scope The scope to get an auth token for (without Android-style 'o
auth2:' prefix). |
168 * @param callback called on successful and unsuccessful fetching of auth to
ken. | 167 * @param callback called on successful and unsuccessful fetching of auth to
ken. |
169 */ | 168 */ |
170 public static void getOAuth2AccessToken(Context context, Account account, St
ring scope, | 169 public static void getOAuth2AccessToken(Context context, Account account, St
ring scope, |
171 AccountManagerHelper.GetAuthTokenCallback callback) { | 170 AccountManagerHelper.GetAuthTokenCallback callback) { |
172 String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; | 171 String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; |
173 AccountManagerHelper.get(context).getAuthToken(account, oauth2Scope, cal
lback); | 172 AccountManagerHelper.get().getAuthToken(account, oauth2Scope, callback); |
174 } | 173 } |
175 | 174 |
176 /** | 175 /** |
177 * Call this method to retrieve an OAuth2 access token for the given account
and scope. This | 176 * Call this method to retrieve an OAuth2 access token for the given account
and scope. This |
178 * method times out after the specified timeout, and will return null if tha
t happens. | 177 * method times out after the specified timeout, and will return null if tha
t happens. |
179 * | 178 * |
180 * Given that this is a blocking method call, this should never be called fr
om the UI thread. | 179 * Given that this is a blocking method call, this should never be called fr
om the UI thread. |
181 * | 180 * |
182 * @param account the account to get the access token for. | 181 * @param account the account to get the access token for. |
183 * @param scope The scope to get an auth token for (without Android-style 'o
auth2:' prefix). | 182 * @param scope The scope to get an auth token for (without Android-style 'o
auth2:' prefix). |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 } catch (InterruptedException e) { | 214 } catch (InterruptedException e) { |
216 Log.w(TAG, "Got interrupted while waiting for auth token"); | 215 Log.w(TAG, "Got interrupted while waiting for auth token"); |
217 return null; | 216 return null; |
218 } | 217 } |
219 } | 218 } |
220 | 219 |
221 /** | 220 /** |
222 * Called by native to check wether the account has an OAuth2 refresh token. | 221 * Called by native to check wether the account has an OAuth2 refresh token. |
223 */ | 222 */ |
224 @CalledByNative | 223 @CalledByNative |
225 public static boolean hasOAuth2RefreshToken(Context context, String accountN
ame) { | 224 public static boolean hasOAuth2RefreshToken(String accountName) { |
226 // Temporarily allowing disk read while fixing. TODO: http://crbug.com/6
18096. | 225 // Temporarily allowing disk read while fixing. TODO: http://crbug.com/6
18096. |
227 // This function is called in RefreshTokenIsAvailable of OAuth2TokenServ
ice which is | 226 // This function is called in RefreshTokenIsAvailable of OAuth2TokenServ
ice which is |
228 // expected to be called in the UI thread synchronously. | 227 // expected to be called in the UI thread synchronously. |
229 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); | 228 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); |
230 try { | 229 try { |
231 return AccountManagerHelper.get(context).hasAccountForName(accountNa
me); | 230 return AccountManagerHelper.get().hasAccountForName(accountName); |
232 } finally { | 231 } finally { |
233 StrictMode.setThreadPolicy(oldPolicy); | 232 StrictMode.setThreadPolicy(oldPolicy); |
234 } | 233 } |
235 } | 234 } |
236 | 235 |
237 /** | 236 /** |
238 * Called by native to invalidate an OAuth2 token. | 237 * Called by native to invalidate an OAuth2 token. |
239 */ | 238 */ |
240 @CalledByNative | 239 @CalledByNative |
241 public static void invalidateOAuth2AuthToken(Context context, String accessT
oken) { | 240 public static void invalidateOAuth2AuthToken(String accessToken) { |
242 if (accessToken != null) { | 241 if (accessToken != null) { |
243 AccountManagerHelper.get(context).invalidateAuthToken(accessToken); | 242 AccountManagerHelper.get().invalidateAuthToken(accessToken); |
244 } | 243 } |
245 } | 244 } |
246 | 245 |
247 /** | 246 /** |
248 * Continue pending accounts validation after system accounts have been seede
d into | 247 * Continue pending accounts validation after system accounts have been seede
d into |
249 * AccountTrackerService. | 248 * AccountTrackerService. |
250 */ | 249 */ |
251 @Override | 250 @Override |
252 public void onSystemAccountsSeedingComplete() { | 251 public void onSystemAccountsSeedingComplete() { |
253 if (mPendingValidationContext != null) { | 252 if (mPendingValidation) { |
254 validateAccountsWithSignedInAccountName( | 253 validateAccountsWithSignedInAccountName(mPendingValidationForceNotif
ications); |
255 mPendingValidationContext, mPendingValidationForceNotificati
ons); | 254 mPendingValidation = false; |
256 mPendingValidationContext = null; | |
257 mPendingValidationForceNotifications = false; | 255 mPendingValidationForceNotifications = false; |
258 } | 256 } |
259 } | 257 } |
260 | 258 |
261 /** | 259 /** |
262 * Clear pending accounts validation when system accounts in AccountTrackerSe
rvice were | 260 * Clear pending accounts validation when system accounts in AccountTrackerSe
rvice were |
263 * refreshed. | 261 * refreshed. |
264 */ | 262 */ |
265 @Override | 263 @Override |
266 public void onSystemAccountsChanged() { | 264 public void onSystemAccountsChanged() { |
267 mPendingValidationContext = null; | |
268 mPendingValidationForceNotifications = false; | 265 mPendingValidationForceNotifications = false; |
269 } | 266 } |
270 | 267 |
271 @CalledByNative | 268 @CalledByNative |
272 public void validateAccounts(Context context, boolean forceNotifications) { | 269 public void validateAccounts(boolean forceNotifications) { |
273 ThreadUtils.assertOnUiThread(); | 270 ThreadUtils.assertOnUiThread(); |
274 if (!AccountTrackerService.get(context).checkAndSeedSystemAccounts()) { | 271 if (!AccountTrackerService.get().checkAndSeedSystemAccounts()) { |
275 mPendingValidationContext = context; | 272 mPendingValidation = true; |
276 mPendingValidationForceNotifications = forceNotifications; | 273 mPendingValidationForceNotifications = forceNotifications; |
277 return; | 274 return; |
278 } | 275 } |
279 | 276 |
280 validateAccountsWithSignedInAccountName(context, forceNotifications); | 277 validateAccountsWithSignedInAccountName(forceNotifications); |
281 } | 278 } |
282 | 279 |
283 private void validateAccountsWithSignedInAccountName( | 280 private void validateAccountsWithSignedInAccountName(boolean forceNotificati
ons) { |
284 Context context, boolean forceNotifications) { | 281 String currentlySignedInAccount = ChromeSigninController.get().getSigned
InAccountName(); |
285 String currentlySignedInAccount = | |
286 ChromeSigninController.get(context).getSignedInAccountName(); | |
287 if (currentlySignedInAccount != null | 282 if (currentlySignedInAccount != null |
288 && isSignedInAccountChanged(context, currentlySignedInAccount))
{ | 283 && isSignedInAccountChanged(currentlySignedInAccount)) { |
289 // Set currentlySignedInAccount to null for validation if signed-in
account was changed | 284 // Set currentlySignedInAccount to null for validation if signed-in
account was changed |
290 // (renamed or removed from the device), this will cause all credent
ials in token | 285 // (renamed or removed from the device), this will cause all credent
ials in token |
291 // service be revoked. | 286 // service be revoked. |
292 // Could only get here during Chrome cold startup. | 287 // Could only get here during Chrome cold startup. |
293 // After chrome started, SigninHelper and AccountsChangedReceiver wi
ll handle account | 288 // After chrome started, SigninHelper and AccountsChangedReceiver wi
ll handle account |
294 // change (re-signin or sign out signed-in account). | 289 // change (re-signin or sign out signed-in account). |
295 currentlySignedInAccount = null; | 290 currentlySignedInAccount = null; |
296 } | 291 } |
297 nativeValidateAccounts(mNativeOAuth2TokenServiceDelegateAndroid, current
lySignedInAccount, | 292 nativeValidateAccounts(mNativeOAuth2TokenServiceDelegateAndroid, current
lySignedInAccount, |
298 forceNotifications); | 293 forceNotifications); |
299 } | 294 } |
300 | 295 |
301 private boolean isSignedInAccountChanged(Context context, String signedInAcc
ountName) { | 296 private boolean isSignedInAccountChanged(String signedInAccountName) { |
302 String[] accountNames = getSystemAccountNames(context); | 297 String[] accountNames = getSystemAccountNames(); |
303 for (String accountName : accountNames) { | 298 for (String accountName : accountNames) { |
304 if (accountName.equals(signedInAccountName)) return false; | 299 if (accountName.equals(signedInAccountName)) return false; |
305 } | 300 } |
306 return true; | 301 return true; |
307 } | 302 } |
308 | 303 |
309 /** | 304 /** |
310 * Triggers a notification to all observers of the native and Java instance
of the | 305 * Triggers a notification to all observers of the native and Java instance
of the |
311 * OAuth2TokenService that a refresh token is now available. This may cause
observers to retry | 306 * OAuth2TokenService that a refresh token is now available. This may cause
observers to retry |
312 * operations that require authentication. | 307 * operations that require authentication. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 nativeFireRefreshTokensLoadedFromJava(mNativeOAuth2TokenServiceDelegateA
ndroid); | 354 nativeFireRefreshTokensLoadedFromJava(mNativeOAuth2TokenServiceDelegateA
ndroid); |
360 } | 355 } |
361 | 356 |
362 @CalledByNative | 357 @CalledByNative |
363 public void notifyRefreshTokensLoaded() { | 358 public void notifyRefreshTokensLoaded() { |
364 for (OAuth2TokenServiceObserver observer : mObservers) { | 359 for (OAuth2TokenServiceObserver observer : mObservers) { |
365 observer.onRefreshTokensLoaded(); | 360 observer.onRefreshTokensLoaded(); |
366 } | 361 } |
367 } | 362 } |
368 | 363 |
369 private static String[] getStoredAccounts(Context context) { | 364 private static String[] getStoredAccounts() { |
370 Set<String> accounts = | 365 Set<String> accounts = |
371 ContextUtils.getAppSharedPreferences() | 366 ContextUtils.getAppSharedPreferences().getStringSet(STORED_ACCOU
NTS_KEY, null); |
372 .getStringSet(STORED_ACCOUNTS_KEY, null); | |
373 return accounts == null ? new String[]{} : accounts.toArray(new String[a
ccounts.size()]); | 367 return accounts == null ? new String[]{} : accounts.toArray(new String[a
ccounts.size()]); |
374 } | 368 } |
375 | 369 |
376 @CalledByNative | 370 @CalledByNative |
377 private static void saveStoredAccounts(Context context, String[] accounts) { | 371 private static void saveStoredAccounts(String[] accounts) { |
378 Set<String> set = new HashSet<String>(Arrays.asList(accounts)); | 372 Set<String> set = new HashSet<String>(Arrays.asList(accounts)); |
379 ContextUtils.getAppSharedPreferences().edit() | 373 ContextUtils.getAppSharedPreferences().edit() |
380 .putStringSet(STORED_ACCOUNTS_KEY, set).apply(); | 374 .putStringSet(STORED_ACCOUNTS_KEY, set).apply(); |
381 } | 375 } |
382 | 376 |
383 private static native Object nativeGetForProfile(Profile profile); | 377 private static native Object nativeGetForProfile(Profile profile); |
384 private static native void nativeOAuth2TokenFetched( | 378 private static native void nativeOAuth2TokenFetched( |
385 String authToken, boolean isTransientError, long nativeCallback); | 379 String authToken, boolean isTransientError, long nativeCallback); |
386 private native void nativeValidateAccounts(long nativeOAuth2TokenServiceDele
gateAndroid, | 380 private native void nativeValidateAccounts(long nativeOAuth2TokenServiceDele
gateAndroid, |
387 String currentlySignedInAccount, boolean forceNotifications); | 381 String currentlySignedInAccount, boolean forceNotifications); |
388 private native void nativeFireRefreshTokenAvailableFromJava( | 382 private native void nativeFireRefreshTokenAvailableFromJava( |
389 long nativeOAuth2TokenServiceDelegateAndroid, String accountName); | 383 long nativeOAuth2TokenServiceDelegateAndroid, String accountName); |
390 private native void nativeFireRefreshTokenRevokedFromJava( | 384 private native void nativeFireRefreshTokenRevokedFromJava( |
391 long nativeOAuth2TokenServiceDelegateAndroid, String accountName); | 385 long nativeOAuth2TokenServiceDelegateAndroid, String accountName); |
392 private native void nativeFireRefreshTokensLoadedFromJava( | 386 private native void nativeFireRefreshTokensLoadedFromJava( |
393 long nativeOAuth2TokenServiceDelegateAndroid); | 387 long nativeOAuth2TokenServiceDelegateAndroid); |
394 } | 388 } |
OLD | NEW |