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