diff options
author | Fred Quintana <fredq@google.com> | 2012-05-23 12:37:00 -0700 |
---|---|---|
committer | Fred Quintana <fredq@google.com> | 2012-05-24 14:34:43 -0700 |
commit | d9640ec712806508877868d08aafaa2d715ff441 (patch) | |
tree | 7f48982b04add7d3ebd4c82bf1cee0595a29d40a /core/java | |
parent | c1cabdfbbb5de2c286fc9a4fe995b7b630a74a0d (diff) | |
download | frameworks_base-d9640ec712806508877868d08aafaa2d715ff441.zip frameworks_base-d9640ec712806508877868d08aafaa2d715ff441.tar.gz frameworks_base-d9640ec712806508877868d08aafaa2d715ff441.tar.bz2 |
Add an updateAppPermission() API call to the AccountManagerService AIDL
and have the GrantCredentialsPermissionActivity call that instead of a
static so that it can be made to run in a different process than the
AccountManagerService. Protect this call by checking that the caller
has the same UID as the system process.
Bug: 6545417
Change-Id: I295e65cad68883349a47e7927c171af45c89b229
Diffstat (limited to 'core/java')
4 files changed, 124 insertions, 37 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 150880c..39e83e0 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -405,6 +405,55 @@ public class AccountManager { } /** + * Change whether or not an app (identified by its uid) is allowed to retrieve an authToken + * for an account. + * <p> + * This is only meant to be used by system activities and is not in the SDK. + * @param account The account whose permissions are being modified + * @param authTokenType The type of token whose permissions are being modified + * @param uid The uid that identifies the app which is being granted or revoked permission. + * @param value true is permission is being granted, false for revoked + * @hide + */ + public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) { + try { + mService.updateAppPermission(account, authTokenType, uid, value); + } catch (RemoteException e) { + // won't ever happen + throw new RuntimeException(e); + } + } + + /** + * Get the user-friendly label associated with an authenticator's auth token. + * @param accountType the type of the authenticator. must not be null. + * @param authTokenType the token type. must not be null. + * @param callback callback to invoke when the result is available. may be null. + * @param handler the handler on which to invoke the callback, or null for the main thread + * @return a future containing the label string + * @hide + */ + public AccountManagerFuture<String> getAuthTokenLabel( + final String accountType, final String authTokenType, + AccountManagerCallback<String> callback, Handler handler) { + if (accountType == null) throw new IllegalArgumentException("accountType is null"); + if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); + return new Future2Task<String>(handler, callback) { + public void doWork() throws RemoteException { + mService.getAuthTokenLabel(mResponse, accountType, authTokenType); + } + + @Override + public String bundleToResult(Bundle bundle) throws AuthenticatorException { + if (!bundle.containsKey(KEY_AUTH_TOKEN_LABEL)) { + throw new AuthenticatorException("no result in response"); + } + return bundle.getString(KEY_AUTH_TOKEN_LABEL); + } + }.start(); + } + + /** * Finds out whether a particular account has all the specified features. * Account features are authenticator-specific string tokens identifying * boolean account properties. For example, features are used to tell diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 2b643c2..ad4b58f 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -985,21 +985,25 @@ public class AccountManagerService } } - void getAuthTokenLabel(final IAccountManagerResponse response, - final Account account, - final String authTokenType, int uid) { - if (account == null) throw new IllegalArgumentException("account is null"); + public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType, + final String authTokenType) + throws RemoteException { + if (accountType == null) throw new IllegalArgumentException("accountType is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); - checkBinderPermission(Manifest.permission.USE_CREDENTIALS); - UserAccounts accounts = getUserAccounts(UserId.getUserId(uid)); + final int callingUid = getCallingUid(); + clearCallingIdentity(); + if (callingUid != android.os.Process.SYSTEM_UID) { + throw new SecurityException("can only call from system"); + } + UserAccounts accounts = getUserAccounts(UserId.getUserId(callingUid)); long identityToken = clearCallingIdentity(); try { - new Session(accounts, response, account.type, false, + new Session(accounts, response, accountType, false, false /* stripAuthTokenFromResult */) { protected String toDebugString(long now) { return super.toDebugString(now) + ", getAuthTokenLabel" - + ", " + account + + ", " + accountType + ", authTokenType " + authTokenType; } @@ -2230,6 +2234,21 @@ public class AccountManagerService Manifest.permission.USE_CREDENTIALS); } + public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) + throws RemoteException { + final int callingUid = getCallingUid(); + + if (callingUid != android.os.Process.SYSTEM_UID) { + throw new SecurityException(); + } + + if (value) { + grantAppPermission(account, authTokenType, uid); + } else { + revokeAppPermission(account, authTokenType, uid); + } + } + /** * Allow callers with the given uid permission to get credentials for account/authTokenType. * <p> @@ -2237,7 +2256,7 @@ public class AccountManagerService * which is in the system. This means we don't need to protect it with permissions. * @hide */ - public void grantAppPermission(Account account, String authTokenType, int uid) { + private void grantAppPermission(Account account, String authTokenType, int uid) { if (account == null || authTokenType == null) { Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception()); return; @@ -2271,7 +2290,7 @@ public class AccountManagerService * which is in the system. This means we don't need to protect it with permissions. * @hide */ - public void revokeAppPermission(Account account, String authTokenType, int uid) { + private void revokeAppPermission(Account account, String authTokenType, int uid) { if (account == null || authTokenType == null) { Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception()); return; diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java index 4419c8c..8b01c6a 100644 --- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java +++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java @@ -16,22 +16,22 @@ package android.accounts; import android.app.Activity; +import android.content.pm.RegisteredServicesCache; +import android.content.res.Resources; import android.os.Bundle; -import android.os.RemoteException; import android.widget.TextView; import android.widget.LinearLayout; -import android.widget.ImageView; import android.view.View; import android.view.LayoutInflater; -import android.view.Window; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.pm.RegisteredServicesCache; import android.text.TextUtils; -import android.graphics.drawable.Drawable; import com.android.internal.R; +import java.io.IOException; +import java.net.Authenticator; + /** * @hide */ @@ -48,7 +48,6 @@ public class GrantCredentialsPermissionActivity extends Activity implements View private int mUid; private Bundle mResultBundle = null; protected LayoutInflater mInflater; - private final AccountManagerService accountManagerService = AccountManagerService.getSingleton(); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -81,7 +80,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View String accountTypeLabel; try { - accountTypeLabel = accountManagerService.getAccountLabel(mAccount.type); + accountTypeLabel = getAccountLabel(mAccount); } catch (IllegalArgumentException e) { // label or resource was missing. abort the activity. setResult(Activity.RESULT_CANCELED); @@ -92,28 +91,27 @@ public class GrantCredentialsPermissionActivity extends Activity implements View final TextView authTokenTypeView = (TextView) findViewById(R.id.authtoken_type); authTokenTypeView.setVisibility(View.GONE); - /** Handles the responses from the AccountManager */ - IAccountManagerResponse response = new IAccountManagerResponse.Stub() { - public void onResult(Bundle bundle) { - final String authTokenLabel = - bundle.getString(AccountManager.KEY_AUTH_TOKEN_LABEL); - if (!TextUtils.isEmpty(authTokenLabel)) { - runOnUiThread(new Runnable() { - public void run() { - if (!isFinishing()) { - authTokenTypeView.setText(authTokenLabel); - authTokenTypeView.setVisibility(View.VISIBLE); + final AccountManagerCallback<String> callback = new AccountManagerCallback<String>() { + public void run(AccountManagerFuture<String> future) { + try { + final String authTokenLabel = future.getResult(); + if (!TextUtils.isEmpty(authTokenLabel)) { + runOnUiThread(new Runnable() { + public void run() { + if (!isFinishing()) { + authTokenTypeView.setText(authTokenLabel); + authTokenTypeView.setVisibility(View.VISIBLE); + } } - } - }); + }); + } + } catch (OperationCanceledException e) { + } catch (IOException e) { + } catch (AuthenticatorException e) { } } - - public void onError(int code, String message) { - } }; - - accountManagerService.getAuthTokenLabel(response, mAccount, mAuthTokenType, mUid); + AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null); findViewById(R.id.allow_button).setOnClickListener(this); findViewById(R.id.deny_button).setOnClickListener(this); @@ -134,6 +132,24 @@ public class GrantCredentialsPermissionActivity extends Activity implements View ((TextView) findViewById(R.id.account_type)).setText(accountTypeLabel); } + private String getAccountLabel(Account account) { + final AuthenticatorDescription[] authenticatorTypes = + AccountManager.get(this).getAuthenticatorTypes(); + for (int i = 0, N = authenticatorTypes.length; i < N; i++) { + final AuthenticatorDescription desc = authenticatorTypes[i]; + if (desc.type.equals(account.type)) { + try { + return createPackageContext(desc.packageName, 0).getString(desc.labelId); + } catch (PackageManager.NameNotFoundException e) { + return account.type; + } catch (Resources.NotFoundException e) { + return account.type; + } + } + } + return account.type; + } + private View newPackageView(String packageLabel) { View view = mInflater.inflate(R.layout.permissions_package_list_item, null); ((TextView) view.findViewById(R.id.package_label)).setText(packageLabel); @@ -143,7 +159,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View public void onClick(View v) { switch (v.getId()) { case R.id.allow_button: - accountManagerService.grantAppPermission(mAccount, mAuthTokenType, mUid); + AccountManager.get(this).updateAppPermission(mAccount, mAuthTokenType, mUid, true); Intent result = new Intent(); result.putExtra("retry", true); setResult(RESULT_OK, result); @@ -151,7 +167,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View break; case R.id.deny_button: - accountManagerService.revokeAppPermission(mAccount, mAuthTokenType, mUid); + AccountManager.get(this).updateAppPermission(mAccount, mAuthTokenType, mUid, false); setResult(RESULT_CANCELED); break; } diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 36a5653..6007321 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -41,6 +41,7 @@ interface IAccountManager { void setPassword(in Account account, String password); void clearPassword(in Account account); void setUserData(in Account account, String key, String value); + void updateAppPermission(in Account account, String authTokenType, int uid, boolean value); void getAuthToken(in IAccountManagerResponse response, in Account account, String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch, @@ -54,4 +55,6 @@ interface IAccountManager { boolean expectActivityLaunch); void confirmCredentials(in IAccountManagerResponse response, in Account account, in Bundle options, boolean expectActivityLaunch); + void getAuthTokenLabel(in IAccountManagerResponse response, String accountType, + String authTokenType); } |