Search in sources :

Example 1 with AuthenticatorDescription

use of android.accounts.AuthenticatorDescription in project android_frameworks_base by ParanoidAndroid.

the class AccountManagerService method getAuthToken.

public void getAuthToken(IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, final boolean expectActivityLaunch, Bundle loginOptionsIn) {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "getAuthToken: " + account + ", response " + response + ", authTokenType " + authTokenType + ", notifyOnAuthFailure " + notifyOnAuthFailure + ", expectActivityLaunch " + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid());
    }
    if (response == null)
        throw new IllegalArgumentException("response is null");
    if (account == null)
        throw new IllegalArgumentException("account is null");
    if (authTokenType == null)
        throw new IllegalArgumentException("authTokenType is null");
    checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
    final UserAccounts accounts = getUserAccountsForCaller();
    final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
    authenticatorInfo = mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(account.type), accounts.userId);
    final boolean customTokens = authenticatorInfo != null && authenticatorInfo.type.customTokens;
    // restricted account.
    if (!ArrayUtils.contains(getAccounts((String) null), account)) {
        throw new IllegalArgumentException("no such account");
    }
    // skip the check if customTokens
    final int callerUid = Binder.getCallingUid();
    final boolean permissionGranted = customTokens || permissionIsGranted(account, authTokenType, callerUid);
    final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() : loginOptionsIn;
    // let authenticator know the identity of the caller
    loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
    loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
    if (notifyOnAuthFailure) {
        loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
    }
    long identityToken = clearCallingIdentity();
    try {
        // route of starting a Session
        if (!customTokens && permissionGranted) {
            String authToken = readAuthTokenInternal(accounts, account, authTokenType);
            if (authToken != null) {
                Bundle result = new Bundle();
                result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
                result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
                result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
                onResult(response, result);
                return;
            }
        }
        new Session(accounts, response, account.type, expectActivityLaunch, false) {

            /* stripAuthTokenFromResult */
            protected String toDebugString(long now) {
                if (loginOptions != null)
                    loginOptions.keySet();
                return super.toDebugString(now) + ", getAuthToken" + ", " + account + ", authTokenType " + authTokenType + ", loginOptions " + loginOptions + ", notifyOnAuthFailure " + notifyOnAuthFailure;
            }

            public void run() throws RemoteException {
                // "grant permission" intent instead of the "getAuthToken" intent.
                if (!permissionGranted) {
                    mAuthenticator.getAuthTokenLabel(this, authTokenType);
                } else {
                    mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
                }
            }

            public void onResult(Bundle result) {
                if (result != null) {
                    if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
                        Intent intent = newGrantCredentialsPermissionIntent(account, callerUid, new AccountAuthenticatorResponse(this), authTokenType, result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
                        Bundle bundle = new Bundle();
                        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
                        onResult(bundle);
                        return;
                    }
                    String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
                    if (authToken != null) {
                        String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
                        String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
                        if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
                            onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "the type and name should not be empty");
                            return;
                        }
                        if (!customTokens) {
                            saveAuthTokenToDatabase(mAccounts, new Account(name, type), authTokenType, authToken);
                        }
                    }
                    Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
                    if (intent != null && notifyOnAuthFailure && !customTokens) {
                        doNotification(mAccounts, account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE), intent, accounts.userId);
                    }
                }
                super.onResult(result);
            }
        }.bind();
    } finally {
        restoreCallingIdentity(identityToken);
    }
}
Also used : Account(android.accounts.Account) Bundle(android.os.Bundle) IAccountAuthenticatorResponse(android.accounts.IAccountAuthenticatorResponse) AccountAuthenticatorResponse(android.accounts.AccountAuthenticatorResponse) PendingIntent(android.app.PendingIntent) Intent(android.content.Intent) AuthenticatorDescription(android.accounts.AuthenticatorDescription) RemoteException(android.os.RemoteException) RegisteredServicesCache(android.content.pm.RegisteredServicesCache)

Example 2 with AuthenticatorDescription

use of android.accounts.AuthenticatorDescription in project android_frameworks_base by ParanoidAndroid.

the class AccountManagerService method validateAccountsInternal.

/**
     * Validate internal set of accounts against installed authenticators for
     * given user. Clear cached authenticators before validating when requested.
     */
private void validateAccountsInternal(UserAccounts accounts, boolean invalidateAuthenticatorCache) {
    if (invalidateAuthenticatorCache) {
        mAuthenticatorCache.invalidateCache(accounts.userId);
    }
    final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
    for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : mAuthenticatorCache.getAllServices(accounts.userId)) {
        knownAuth.add(service.type);
    }
    synchronized (accounts.cacheLock) {
        final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
        boolean accountDeleted = false;
        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[] { ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME }, null, null, null, null, null);
        try {
            accounts.accountCache.clear();
            final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<String, ArrayList<String>>();
            while (cursor.moveToNext()) {
                final long accountId = cursor.getLong(0);
                final String accountType = cursor.getString(1);
                final String accountName = cursor.getString(2);
                if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
                    Slog.w(TAG, "deleting account " + accountName + " because type " + accountType + " no longer has a registered authenticator");
                    db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
                    accountDeleted = true;
                    final Account account = new Account(accountName, accountType);
                    accounts.userDataCache.remove(account);
                    accounts.authTokenCache.remove(account);
                } else {
                    ArrayList<String> accountNames = accountNamesByType.get(accountType);
                    if (accountNames == null) {
                        accountNames = new ArrayList<String>();
                        accountNamesByType.put(accountType, accountNames);
                    }
                    accountNames.add(accountName);
                }
            }
            for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
                final String accountType = cur.getKey();
                final ArrayList<String> accountNames = cur.getValue();
                final Account[] accountsForType = new Account[accountNames.size()];
                int i = 0;
                for (String accountName : accountNames) {
                    accountsForType[i] = new Account(accountName, accountType);
                    ++i;
                }
                accounts.accountCache.put(accountType, accountsForType);
            }
        } finally {
            cursor.close();
            if (accountDeleted) {
                sendAccountsChangedBroadcast(accounts.userId);
            }
        }
    }
}
Also used : Account(android.accounts.Account) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) LinkedHashMap(java.util.LinkedHashMap) AuthenticatorDescription(android.accounts.AuthenticatorDescription) SQLiteDatabase(android.database.sqlite.SQLiteDatabase) Map(java.util.Map) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) RegisteredServicesCache(android.content.pm.RegisteredServicesCache)

Example 3 with AuthenticatorDescription

use of android.accounts.AuthenticatorDescription in project XPrivacy by M66B.

the class XAccountManager method after.

@Override
@SuppressWarnings("unchecked")
protected void after(XParam param) throws Throwable {
    int uid = Binder.getCallingUid();
    switch(mMethod) {
        case addOnAccountsUpdatedListener:
            // Do nothing
            break;
        case blockingGetAuthToken:
            if (param.getResult() != null && param.args.length > 0 && param.args[0] != null) {
                Account account = (Account) param.args[0];
                if (isRestrictedExtra(param, account == null ? null : account.name))
                    if (!isAccountAllowed(account, uid))
                        param.setResult(null);
            }
            break;
        case getAccounts:
            if (param.getResult() != null && isRestricted(param)) {
                Account[] accounts = (Account[]) param.getResult();
                param.setResult(filterAccounts(accounts, uid));
            }
            break;
        case getAccountsByType:
        case getAccountsByTypeForPackage:
            if (param.getResult() != null && param.args.length > 0)
                if (isRestrictedExtra(param, (String) param.args[0])) {
                    Account[] accounts = (Account[]) param.getResult();
                    param.setResult(filterAccounts(accounts, uid));
                }
            break;
        case getAccountsByTypeAndFeatures:
            if (param.getResult() != null && param.args.length > 0)
                if (isRestrictedExtra(param, (String) param.args[0])) {
                    AccountManagerFuture<Account[]> future = (AccountManagerFuture<Account[]>) param.getResult();
                    param.setResult(new XFutureAccount(future, uid));
                }
            break;
        case getAuthenticatorTypes:
            if (param.getResult() != null && isRestricted(param))
                param.setResult(new AuthenticatorDescription[0]);
            break;
        case getAuthToken:
            if (param.getResult() != null && param.args.length > 0) {
                Account account = (Account) param.args[0];
                if (isRestrictedExtra(param, account == null ? null : account.name)) {
                    AccountManagerFuture<Bundle> future = (AccountManagerFuture<Bundle>) param.getResult();
                    param.setResult(new XFutureBundle(future, uid));
                }
            }
            break;
        case getAuthTokenByFeatures:
            if (param.getResult() != null)
                if (isRestrictedExtra(param, (String) param.args[0])) {
                    AccountManagerFuture<Bundle> future = (AccountManagerFuture<Bundle>) param.getResult();
                    param.setResult(new XFutureBundle(future, uid));
                }
            break;
        case hasFeatures:
            if (param.getResult() != null && param.args.length > 0 && param.args[0] != null) {
                Account account = (Account) param.args[0];
                if (isRestrictedExtra(param, account == null ? null : account.name))
                    if (!isAccountAllowed(account, uid))
                        param.setResult(new XFutureBoolean());
            }
            break;
        case removeOnAccountsUpdatedListener:
            // Do nothing
            break;
        case Srv_getAccounts:
        case Srv_getAccountsAsUser:
        case Srv_getAccountsForPackage:
        case Srv_getSharedAccountsAsUser:
            // Filter account list
            String extra = null;
            if (mMethod == Methods.Srv_getAccounts || mMethod == Methods.Srv_getAccountsAsUser || mMethod == Methods.Srv_getAccountsForPackage)
                if (param.args.length > 0 && param.args[0] instanceof String)
                    extra = (String) param.args[0];
            if (param.getResult() instanceof Account[])
                if (isRestrictedExtra(param, extra)) {
                    Account[] accounts = (Account[]) param.getResult();
                    param.setResult(filterAccounts(accounts, uid));
                }
            break;
        case Srv_getAccountsByFeatures:
            // Do nothing
            break;
    }
}
Also used : Account(android.accounts.Account) AuthenticatorDescription(android.accounts.AuthenticatorDescription) Bundle(android.os.Bundle) AccountManagerFuture(android.accounts.AccountManagerFuture)

Example 4 with AuthenticatorDescription

use of android.accounts.AuthenticatorDescription in project PocketHub by pockethub.

the class AccountUtils method hasAuthenticator.

/**
     * Verify authenticator registered for account type matches the package name
     * of this application
     *
     * @param manager
     * @return true is authenticator registered, false otherwise
     */
public static boolean hasAuthenticator(final AccountManager manager) {
    if (!AUTHENTICATOR_CHECKED) {
        final AuthenticatorDescription[] types = manager.getAuthenticatorTypes();
        if (types != null && types.length > 0) {
            for (AuthenticatorDescription descriptor : types) {
                if (descriptor != null && ACCOUNT_TYPE.equals(descriptor.type)) {
                    HAS_AUTHENTICATOR = "com.github.pockethub.android".equals(descriptor.packageName);
                    break;
                }
            }
        }
        AUTHENTICATOR_CHECKED = true;
    }
    return HAS_AUTHENTICATOR;
}
Also used : AuthenticatorDescription(android.accounts.AuthenticatorDescription)

Example 5 with AuthenticatorDescription

use of android.accounts.AuthenticatorDescription in project platform_frameworks_base by android.

the class AccountManagerService method getAuthToken.

@Override
public void getAuthToken(IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, final boolean expectActivityLaunch, final Bundle loginOptions) {
    Bundle.setDefusable(loginOptions, true);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "getAuthToken: " + account + ", response " + response + ", authTokenType " + authTokenType + ", notifyOnAuthFailure " + notifyOnAuthFailure + ", expectActivityLaunch " + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid());
    }
    if (response == null)
        throw new IllegalArgumentException("response is null");
    try {
        if (account == null) {
            Slog.w(TAG, "getAuthToken called with null account");
            response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
            return;
        }
        if (authTokenType == null) {
            Slog.w(TAG, "getAuthToken called with null authTokenType");
            response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
            return;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Failed to report error back to the client." + e);
        return;
    }
    int userId = UserHandle.getCallingUserId();
    long ident = Binder.clearCallingIdentity();
    final UserAccounts accounts;
    final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
    try {
        accounts = getUserAccounts(userId);
        authenticatorInfo = mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(account.type), accounts.userId);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
    final boolean customTokens = authenticatorInfo != null && authenticatorInfo.type.customTokens;
    // skip the check if customTokens
    final int callerUid = Binder.getCallingUid();
    final boolean permissionGranted = customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
    // Get the calling package. We will use it for the purpose of caching.
    final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
    List<String> callerOwnedPackageNames;
    ident = Binder.clearCallingIdentity();
    try {
        callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
    if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
        String msg = String.format("Uid %s is attempting to illegally masquerade as package %s!", callerUid, callerPkg);
        throw new SecurityException(msg);
    }
    // let authenticator know the identity of the caller
    loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
    loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
    if (notifyOnAuthFailure) {
        loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
    }
    long identityToken = clearCallingIdentity();
    try {
        // Distill the caller's package signatures into a single digest.
        final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
        // route of starting a Session
        if (!customTokens && permissionGranted) {
            String authToken = readAuthTokenInternal(accounts, account, authTokenType);
            if (authToken != null) {
                Bundle result = new Bundle();
                result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
                result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
                result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
                onResult(response, result);
                return;
            }
        }
        if (customTokens) {
            /*
                 * Look up tokens in the new cache only if the loginOptions don't have parameters
                 * outside of those expected to be injected by the AccountManager, e.g.
                 * ANDORID_PACKAGE_NAME.
                 */
            String token = readCachedTokenInternal(accounts, account, authTokenType, callerPkg, callerPkgSigDigest);
            if (token != null) {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
                }
                Bundle result = new Bundle();
                result.putString(AccountManager.KEY_AUTHTOKEN, token);
                result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
                result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
                onResult(response, result);
                return;
            }
        }
        new Session(accounts, response, account.type, expectActivityLaunch, false, /* stripAuthTokenFromResult */
        account.name, false) {

            /* authDetailsRequired */
            @Override
            protected String toDebugString(long now) {
                if (loginOptions != null)
                    loginOptions.keySet();
                return super.toDebugString(now) + ", getAuthToken" + ", " + account + ", authTokenType " + authTokenType + ", loginOptions " + loginOptions + ", notifyOnAuthFailure " + notifyOnAuthFailure;
            }

            @Override
            public void run() throws RemoteException {
                // "grant permission" intent instead of the "getAuthToken" intent.
                if (!permissionGranted) {
                    mAuthenticator.getAuthTokenLabel(this, authTokenType);
                } else {
                    mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
                }
            }

            @Override
            public void onResult(Bundle result) {
                Bundle.setDefusable(result, true);
                if (result != null) {
                    if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
                        Intent intent = newGrantCredentialsPermissionIntent(account, null, callerUid, new AccountAuthenticatorResponse(this), authTokenType, true);
                        Bundle bundle = new Bundle();
                        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
                        onResult(bundle);
                        return;
                    }
                    String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
                    if (authToken != null) {
                        String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
                        String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
                        if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
                            onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "the type and name should not be empty");
                            return;
                        }
                        Account resultAccount = new Account(name, type);
                        if (!customTokens) {
                            saveAuthTokenToDatabase(mAccounts, resultAccount, authTokenType, authToken);
                        }
                        long expiryMillis = result.getLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
                        if (customTokens && expiryMillis > System.currentTimeMillis()) {
                            saveCachedToken(mAccounts, account, callerPkg, callerPkgSigDigest, authTokenType, authToken, expiryMillis);
                        }
                    }
                    Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
                    if (intent != null && notifyOnAuthFailure && !customTokens) {
                        /*
                             * Make sure that the supplied intent is owned by the authenticator
                             * giving it to the system. Otherwise a malicious authenticator could
                             * have users launching arbitrary activities by tricking users to
                             * interact with malicious notifications.
                             */
                        checkKeyIntent(Binder.getCallingUid(), intent);
                        doNotification(mAccounts, account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE), intent, "android", accounts.userId);
                    }
                }
                super.onResult(result);
            }
        }.bind();
    } finally {
        restoreCallingIdentity(identityToken);
    }
}
Also used : Account(android.accounts.Account) Bundle(android.os.Bundle) IAccountAuthenticatorResponse(android.accounts.IAccountAuthenticatorResponse) AccountAuthenticatorResponse(android.accounts.AccountAuthenticatorResponse) GeneralSecurityException(java.security.GeneralSecurityException) PendingIntent(android.app.PendingIntent) Intent(android.content.Intent) AuthenticatorDescription(android.accounts.AuthenticatorDescription) RemoteException(android.os.RemoteException) RegisteredServicesCache(android.content.pm.RegisteredServicesCache)

Aggregations

AuthenticatorDescription (android.accounts.AuthenticatorDescription)37 Context (android.content.Context)17 PackageManager (android.content.pm.PackageManager)12 Resources (android.content.res.Resources)11 Account (android.accounts.Account)10 Drawable (android.graphics.drawable.Drawable)9 RegisteredServicesCache (android.content.pm.RegisteredServicesCache)7 TypedArray (android.content.res.TypedArray)7 Bundle (android.os.Bundle)7 RemoteException (android.os.RemoteException)7 AccountAuthenticatorResponse (android.accounts.AccountAuthenticatorResponse)6 IAccountAuthenticatorResponse (android.accounts.IAccountAuthenticatorResponse)6 PendingIntent (android.app.PendingIntent)6 Intent (android.content.Intent)6 GeneralSecurityException (java.security.GeneralSecurityException)5 ResolveInfo (android.content.pm.ResolveInfo)2 AccountManager (android.accounts.AccountManager)1 AccountManagerFuture (android.accounts.AccountManagerFuture)1 ActivityInfo (android.content.pm.ActivityInfo)1 ApplicationInfo (android.content.pm.ApplicationInfo)1