AndroidProfileOAuth2TokenServiceHelper.java revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// found in the LICENSE file.
47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochpackage org.chromium.chrome.browser.signin;
67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.accounts.Account;
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.app.Activity;
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.content.Context;
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.util.Log;
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport org.chromium.base.CalledByNative;
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport org.chromium.base.ThreadUtils;
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport org.chromium.sync.signin.AccountManagerHelper;
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import java.util.concurrent.Semaphore;
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport java.util.concurrent.TimeUnit;
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import java.util.concurrent.atomic.AtomicReference;
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport javax.annotation.Nullable;
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch/**
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * Helper class for working with access tokens from native code.
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * <p/>
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * This class forwards calls to request or invalidate access tokens made by native code to
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * AccountManagerHelper and forwards callbacks to native code.
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * <p/>
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch */
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)public final class AndroidProfileOAuth2TokenServiceHelper {
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private static final String TAG = "AndroidProfileOAuth2TokenServiceHelper";
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private static final String OAUTH2_SCOPE_PREFIX = "oauth2:";
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    private AndroidProfileOAuth2TokenServiceHelper() {
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private static Account getAccountOrNullFromUsername(Context context, String username) {
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (username == null) {
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            Log.e(TAG, "Username is null");
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            return null;
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        Account account = accountManagerHelper.getAccountFromName(username);
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (account == null) {
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            Log.e(TAG, "Account not found for provided username.");
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            return null;
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        return account;
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    /**
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     * Called by native to list the accounts with OAuth2 refresh tokens.
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     */
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    @CalledByNative
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    public static String[] getAccounts(Context context) {
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        java.util.List<String> accountNames = accountManagerHelper.getGoogleAccountNames();
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        return accountNames.toArray(new String[accountNames.size()]);
6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    /**
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * Called by native to retrieve OAuth2 tokens.
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     *
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param username The native username (full address).
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param nativeCallback The pointer to the native callback that should be run upon completion.
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     */
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    @CalledByNative
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    public static void getOAuth2AuthToken(
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            Context context, String username, String scope, final int nativeCallback) {
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        Account account = getAccountOrNullFromUsername(context, username);
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (account == null) {
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            nativeOAuth2TokenFetched(null, false, nativeCallback);
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            return;
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        accountManagerHelper.getAuthTokenFromForeground(
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            null, account, oauth2Scope, new AccountManagerHelper.GetAuthTokenCallback() {
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                @Override
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                public void tokenAvailable(String token) {
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    nativeOAuth2TokenFetched(
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        token, token != null, nativeCallback);
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                }
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            });
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    /**
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * Call this method to retrieve an OAuth2 access token for the given account and scope.
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     *
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param activity the current activity. May be null.
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param account the account to get the access token for.
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param callback called on successful and unsuccessful fetching of auth token.
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     */
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    public static void getOAuth2AccessToken(Context context, @Nullable Activity activity,
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                            Account account, String scope,
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                            AccountManagerHelper.GetAuthTokenCallback callback) {
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        AccountManagerHelper.get(context).getAuthTokenFromForeground(
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                activity, account, oauth2Scope, callback);
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    /**
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * Call this method to retrieve an OAuth2 access token for the given account and scope. This
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * method times out after the specified timeout, and will return null if that happens.
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     *
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * Given that this is a blocking method call, this should never be called from the UI thread.
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     *
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param activity the current activity. May be null.
1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param account the account to get the access token for.
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param timeout the timeout.
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param unit the unit for |timeout|.
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     */
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    public static String getOAuth2AccessTokenWithTimeout(
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            Context context, @Nullable Activity activity, Account account, String scope,
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            long timeout, TimeUnit unit) {
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        assert !ThreadUtils.runningOnUiThread();
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        final AtomicReference<String> result = new AtomicReference<String>();
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        final Semaphore semaphore = new Semaphore(0);
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        getOAuth2AccessToken(
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                context, activity, account, scope,
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                new AccountManagerHelper.GetAuthTokenCallback() {
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    @Override
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    public void tokenAvailable(String token) {
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                        result.set(token);
131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                        semaphore.release();
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    }
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                });
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        try {
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            if (semaphore.tryAcquire(timeout, unit)) {
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                return result.get();
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            } else {
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                Log.d(TAG, "Failed to retrieve auth token within timeout (" +
139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                        timeout + " + " + unit.name() + ")");
140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                return null;
141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            }
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        } catch (InterruptedException e) {
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            Log.w(TAG, "Got interrupted while waiting for auth token");
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            return null;
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    /**
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     * Called by native to check wether the account has an OAuth2 refresh token.
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     */
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    @CalledByNative
15268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    public static boolean hasOAuth2RefreshToken(Context context, String accountName) {
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        return AccountManagerHelper.get(context).hasAccountForName(accountName);
15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    /**
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    * Called by native to invalidate an OAuth2 token.
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    */
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    @CalledByNative
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    public static void invalidateOAuth2AuthToken(Context context, String accessToken) {
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (accessToken != null) {
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            AccountManagerHelper.get(context).invalidateAuthToken(accessToken);
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private static native void nativeOAuth2TokenFetched(
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            String authToken, boolean result, int nativeCallback);
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
170