From 27db46850b708070452c0ce49daf5f79503fbde6 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Sat, 30 Mar 2013 17:07:47 -0700 Subject: [PATCH] Block access to accounts for limited users. Make sure that apps that have access to restricted accounts can see them. If they don't have access, they shouldn't be able to add a new account either. Show an error message in the account picker if the user/app is not authorized. Change-Id: I117c0b14d7d06c5ac4e66506df156b174567f5f3 --- api/current.txt | 1 + .../java/android/accounts/AccountManager.java | 21 ++++- .../ChooseTypeAndAccountActivity.java | 49 ++++++++++-- .../android/accounts/IAccountManager.aidl | 5 +- core/java/android/os/UserManager.java | 8 ++ core/res/res/layout/app_not_authorized.xml | 56 +++++++++++++ core/res/res/values/strings.xml | 7 +- core/res/res/values/symbols.xml | 3 +- .../providers/settings/SettingsProvider.java | 2 +- .../statusbar/phone/QuickSettings.java | 6 +- .../accounts/AccountManagerService.java | 80 +++++++++++++------ 11 files changed, 197 insertions(+), 41 deletions(-) create mode 100644 core/res/res/layout/app_not_authorized.xml diff --git a/api/current.txt b/api/current.txt index 6f0575c88a821..31acb354cfdf5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -16984,6 +16984,7 @@ package android.os { } public class UserManager { + method public static synchronized android.os.UserManager get(android.content.Context); method public long getSerialNumberForUser(android.os.UserHandle); method public int getUserCount(); method public android.os.UserHandle getUserForSerialNumber(long); diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index bdc882ac7fe65..241a64af65ae1 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -387,6 +387,23 @@ public class AccountManager { } } + /** + * @hide + * For use by internal activities. Returns the list of accounts that the calling package + * is authorized to use, particularly for shared accounts. + * @param packageName package name of the calling app. + * @param uid the uid of the calling app. + * @return the accounts that are available to this package and user. + */ + public Account[] getAccountsForPackage(String packageName, int uid) { + try { + return mService.getAccountsForPackage(packageName, uid); + } catch (RemoteException re) { + // possible security exception + throw new RuntimeException(re); + } + } + /** * Lists all accounts of a particular type. The account type is a * string token corresponding to the authenticator and useful domain @@ -575,7 +592,7 @@ public class AccountManager { public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { if (account == null) throw new IllegalArgumentException("account is null"); try { - return mService.addAccount(account, password, userdata); + return mService.addAccountExplicitly(account, password, userdata); } catch (RemoteException e) { // won't ever happen throw new RuntimeException(e); @@ -1123,7 +1140,7 @@ public class AccountManager { return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { - mService.addAcount(mResponse, accountType, authTokenType, + mService.addAccount(mResponse, accountType, authTokenType, requiredFeatures, activity != null, optionsIn); } }.start(); diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index 5358bc796ab94..2aba16339a34b 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -18,9 +18,14 @@ package android.accounts; import com.google.android.collect.Sets; import android.app.Activity; +import android.app.ActivityManagerNative; import android.content.Intent; import android.os.Bundle; +import android.os.IBinder; import android.os.Parcelable; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -29,6 +34,7 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import com.android.internal.R; @@ -119,6 +125,9 @@ public class ChooseTypeAndAccountActivity extends Activity private Parcelable[] mExistingAccounts = null; private int mSelectedItemIndex; private Button mOkButton; + private int mCallingUid; + private String mCallingPackage; + private boolean mDisallowAddAccounts; @Override public void onCreate(Bundle savedInstanceState) { @@ -128,6 +137,24 @@ public class ChooseTypeAndAccountActivity extends Activity + savedInstanceState + ")"); } + String message = null; + + try { + IBinder activityToken = getActivityToken(); + mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken); + mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( + activityToken); + if (mCallingUid != 0 && mCallingPackage != null) { + Bundle restrictions = UserManager.get(this) + .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid))); + mDisallowAddAccounts = + restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false); + } + } catch (RemoteException re) { + // Couldn't figure out caller details + Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re); + } + // save some items we use frequently final Intent intent = getIntent(); @@ -179,6 +206,11 @@ public class ChooseTypeAndAccountActivity extends Activity // If there are no relevant accounts and only one relevant account type go directly to // add account. Otherwise let the user choose. if (mAccounts.isEmpty()) { + if (mDisallowAddAccounts) { + setContentView(R.layout.app_not_authorized); + setTitle(R.string.error_message_title); + return; + } if (mSetOfRelevantAccountTypes.size() == 1) { runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next()); } else { @@ -296,7 +328,8 @@ public class ChooseTypeAndAccountActivity extends Activity } if (accountName == null || accountType == null) { - Account[] currentAccounts = AccountManager.get(this).getAccounts(); + Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage( + mCallingPackage, mCallingUid); Set preExistingAccounts = new HashSet(); for (Parcelable accountParcel : mExistingAccounts) { preExistingAccounts.add((Account) accountParcel); @@ -347,7 +380,8 @@ public class ChooseTypeAndAccountActivity extends Activity AccountManager.KEY_INTENT); if (intent != null) { mPendingRequest = REQUEST_ADD_ACCOUNT; - mExistingAccounts = AccountManager.get(this).getAccounts(); + mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage, + mCallingUid); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(intent, REQUEST_ADD_ACCOUNT); return; @@ -424,12 +458,14 @@ public class ChooseTypeAndAccountActivity extends Activity private String[] getListOfDisplayableOptions(ArrayList accounts) { // List of options includes all accounts found together with "Add new account" as the // last item in the list. - String[] listItems = new String[accounts.size() + 1]; + String[] listItems = new String[accounts.size() + (mDisallowAddAccounts ? 0 : 1)]; for (int i = 0; i < accounts.size(); i++) { listItems[i] = accounts.get(i).name; } - listItems[accounts.size()] = getResources().getString( - R.string.add_account_button_label); + if (!mDisallowAddAccounts) { + listItems[accounts.size()] = getResources().getString( + R.string.add_account_button_label); + } return listItems; } @@ -439,7 +475,8 @@ public class ChooseTypeAndAccountActivity extends Activity * allowable accounts, if provided. */ private ArrayList getAcceptableAccountChoices(AccountManager accountManager) { - final Account[] accounts = accountManager.getAccounts(); + final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage, + mCallingUid); ArrayList accountsToPopulate = new ArrayList(accounts.length); for (Account account : accounts) { if (mSetOfAllowableAccounts != null diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 47b257d7241a3..81418132d5c8b 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -31,10 +31,11 @@ interface IAccountManager { String getUserData(in Account account, String key); AuthenticatorDescription[] getAuthenticatorTypes(); Account[] getAccounts(String accountType); + Account[] getAccountsForPackage(String packageName, int uid); Account[] getAccountsAsUser(String accountType, int userId); void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features); void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features); - boolean addAccount(in Account account, String password, in Bundle extras); + boolean addAccountExplicitly(in Account account, String password, in Bundle extras); void removeAccount(in IAccountManagerResponse response, in Account account); void invalidateAuthToken(String accountType, String authToken); String peekAuthToken(in Account account, String authTokenType); @@ -47,7 +48,7 @@ interface IAccountManager { void getAuthToken(in IAccountManagerResponse response, in Account account, String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch, in Bundle options); - void addAcount(in IAccountManagerResponse response, String accountType, + void addAccount(in IAccountManagerResponse response, String accountType, String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch, in Bundle options); void updateCredentials(in IAccountManagerResponse response, in Account account, diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1ba16bd1430df..b9b8f083ba1a3 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -121,6 +121,14 @@ public class UserManager { */ public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; + private static UserManager sInstance = null; + + public synchronized static UserManager get(Context context) { + if (sInstance == null) { + sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE); + } + return sInstance; + } /** @hide */ public UserManager(Context context, IUserManager service) { diff --git a/core/res/res/layout/app_not_authorized.xml b/core/res/res/layout/app_not_authorized.xml new file mode 100644 index 0000000000000..bd40eeb0b31d6 --- /dev/null +++ b/core/res/res/layout/app_not_authorized.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + +