| 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 | package org.chromium.chrome.browser.signin; |
| 6 | |
| 7 | import android.accounts.Account; |
| 8 | import android.app.Activity; |
| 9 | import android.content.Context; |
| 10 | import android.util.Log; |
| 11 | |
| 12 | import org.chromium.base.CalledByNative; |
| 13 | import org.chromium.base.ThreadUtils; |
| 14 | import org.chromium.sync.signin.AccountManagerHelper; |
| 15 | |
| 16 | import java.util.concurrent.Semaphore; |
| 17 | import java.util.concurrent.TimeUnit; |
| 18 | import java.util.concurrent.atomic.AtomicReference; |
| 19 | |
| 20 | import javax.annotation.Nullable; |
| 21 | |
| 22 | /** |
| 23 | * Helper class for working with access tokens from native code. |
| 24 | * <p/> |
| 25 | * This class forwards calls to request or invalidate access tokens made by native code to |
| 26 | * AccountManagerHelper and forwards callbacks to native code. |
| 27 | * <p/> |
| 28 | */ |
| 29 | public final class AndroidProfileOAuth2TokenServiceHelper { |
| 30 | |
| 31 | private static final String TAG = "AndroidProfileOAuth2TokenServiceHelper"; |
| 32 | |
| 33 | private static final String OAUTH2_SCOPE_PREFIX = "oauth2:"; |
| 34 | |
| 35 | private AndroidProfileOAuth2TokenServiceHelper() { |
| 36 | } |
| 37 | |
| 38 | private static Account getAccountOrNullFromUsername(Context context, String username) { |
| 39 | if (username == null) { |
| 40 | Log.e(TAG, "Username is null"); |
| 41 | return null; |
| 42 | } |
| 43 | |
| 44 | AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context); |
| 45 | Account account = accountManagerHelper.getAccountFromName(username); |
| 46 | if (account == null) { |
| 47 | Log.e(TAG, "Account not found for provided username."); |
| 48 | return null; |
| 49 | } |
| 50 | return account; |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * Called by native to retrieve OAuth2 tokens. |
| 55 | * |
| 56 | * @param username The native username (full address). |
| 57 | * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix). |
| 58 | * @param nativeCallback The pointer to the native callback that should be run upon completion. |
| 59 | */ |
| 60 | @CalledByNative |
| 61 | public static void getOAuth2AuthToken( |
| 62 | Context context, String username, String scope, final int nativeCallback) { |
| 63 | Account account = getAccountOrNullFromUsername(context, username); |
| 64 | if (account == null) { |
| 65 | nativeOAuth2TokenFetched(null, false, nativeCallback); |
| 66 | return; |
| 67 | } |
| 68 | String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; |
| 69 | |
| 70 | AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context); |
| 71 | accountManagerHelper.getAuthTokenFromForeground( |
| 72 | null, account, oauth2Scope, new AccountManagerHelper.GetAuthTokenCallback() { |
| 73 | @Override |
| 74 | public void tokenAvailable(String token) { |
| 75 | nativeOAuth2TokenFetched( |
| 76 | token, token != null, nativeCallback); |
| 77 | } |
| 78 | }); |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * Call this method to retrieve an OAuth2 access token for the given account and scope. |
| 83 | * |
| 84 | * @param activity the current activity. May be null. |
| 85 | * @param account the account to get the access token for. |
| 86 | * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix). |
| 87 | * @param callback called on successful and unsuccessful fetching of auth token. |
| 88 | */ |
| 89 | public static void getOAuth2AccessToken(Context context, @Nullable Activity activity, |
| 90 | Account account, String scope, |
| 91 | AccountManagerHelper.GetAuthTokenCallback callback) { |
| 92 | String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; |
| 93 | AccountManagerHelper.get(context).getAuthTokenFromForeground( |
| 94 | activity, account, oauth2Scope, callback); |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * Call this method to retrieve an OAuth2 access token for the given account and scope. This |
| 99 | * method times out after the specified timeout, and will return null if that happens. |
| 100 | * |
| 101 | * Given that this is a blocking method call, this should never be called from the UI thread. |
| 102 | * |
| 103 | * @param activity the current activity. May be null. |
| 104 | * @param account the account to get the access token for. |
| 105 | * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix). |
| 106 | * @param timeout the timeout. |
| 107 | * @param unit the unit for |timeout|. |
| 108 | */ |
| 109 | public static String getOAuth2AccessTokenWithTimeout( |
| 110 | Context context, @Nullable Activity activity, Account account, String scope, |
| 111 | long timeout, TimeUnit unit) { |
| 112 | assert !ThreadUtils.runningOnUiThread(); |
| 113 | final AtomicReference<String> result = new AtomicReference<String>(); |
| 114 | final Semaphore semaphore = new Semaphore(0); |
| 115 | getOAuth2AccessToken( |
| 116 | context, activity, account, scope, |
| 117 | new AccountManagerHelper.GetAuthTokenCallback() { |
| 118 | @Override |
| 119 | public void tokenAvailable(String token) { |
| 120 | result.set(token); |
| 121 | semaphore.release(); |
| 122 | } |
| 123 | }); |
| 124 | try { |
| 125 | if (semaphore.tryAcquire(timeout, unit)) { |
| 126 | return result.get(); |
| 127 | } else { |
| 128 | Log.d(TAG, "Failed to retrieve auth token within timeout (" + |
| 129 | timeout + " + " + unit.name() + ")"); |
| 130 | return null; |
| 131 | } |
| 132 | } catch (InterruptedException e) { |
| 133 | Log.w(TAG, "Got interrupted while waiting for auth token"); |
| 134 | return null; |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | /** |
| 139 | * Called by native to invalidate an OAuth2 token. |
| 140 | */ |
| 141 | @CalledByNative |
| 142 | public static void invalidateOAuth2AuthToken(Context context, String accessToken) { |
| 143 | if (accessToken != null) { |
| 144 | AccountManagerHelper.get(context).invalidateAuthToken(accessToken); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | private static native void nativeOAuth2TokenFetched( |
| 149 | String authToken, boolean result, int nativeCallback); |
| 150 | |
| 151 | } |