summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Valdivia <carlosvaldivia@google.com>2015-06-11 20:04:31 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-06-11 20:04:44 +0000
commitd0041e5f474f4e795d6bc9e5eeaec4098949897c (patch)
tree253f82ccd582d44409c73074ca5eff89523f14e2
parentc8488e99e85ae5252e6078c00d123f1364aef25d (diff)
parentdcddc476651deb72a27798de56eef584e5be5d32 (diff)
downloadframeworks_base-d0041e5f474f4e795d6bc9e5eeaec4098949897c.zip
frameworks_base-d0041e5f474f4e795d6bc9e5eeaec4098949897c.tar.gz
frameworks_base-d0041e5f474f4e795d6bc9e5eeaec4098949897c.tar.bz2
Merge "Revert "Permissions: Fix account related permissions."" into mnc-dev
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--core/java/android/accounts/AccountManager.java155
-rw-r--r--core/res/AndroidManifest.xml24
-rw-r--r--core/res/res/values/strings.xml21
-rw-r--r--docs/html/training/sync-adapters/creating-sync-adapter.jd7
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java301
7 files changed, 284 insertions, 230 deletions
diff --git a/api/current.txt b/api/current.txt
index ec56ce0..cfb9398 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17,6 +17,7 @@ package android {
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
+ field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -85,6 +86,7 @@ package android {
field public static final java.lang.String INTERNET = "android.permission.INTERNET";
field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
+ field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
@@ -143,6 +145,7 @@ package android {
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
+ field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
diff --git a/api/system-current.txt b/api/system-current.txt
index 5ec8a62..6035ef2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24,6 +24,7 @@ package android {
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
+ field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -116,6 +117,7 @@ package android {
field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
+ field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
@@ -215,6 +217,7 @@ package android {
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
+ field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 993b53d..31e129b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -51,7 +51,10 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import static android.Manifest.permission.AUTHENTICATE_ACCOUNTS;
import static android.Manifest.permission.GET_ACCOUNTS;
+import static android.Manifest.permission.MANAGE_ACCOUNTS;
+import static android.Manifest.permission.USE_CREDENTIALS;
/**
* This class provides access to a centralized registry of the user's
@@ -316,12 +319,14 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that owns the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
*
- * @param account The account to query for a password. Must not be {@code null}.
+ * @param account The account to query for a password
* @return The account's password, null if none or if the account doesn't exist
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String getPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -340,12 +345,14 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that owns the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
*
* @param account The account to query for user data
* @return The user data, null if the account or key doesn't exist
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String getUserData(final Account account, final String key) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
@@ -655,8 +662,10 @@ public class AccountManager {
* wizards associated with authenticators, not directly by applications.
*
* <p>It is safe to call this method from the main thread.
- * <p>This method requires the caller to have a signature match with the
- * authenticator that owns the specified account.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the added account's authenticator.
*
* @param account The {@link Account} to add
* @param password The password to associate with the account, null for none
@@ -664,6 +673,7 @@ public class AccountManager {
* @return True if the account was successfully added, false if the account
* already exists, the account is null, or another error occurs.
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -682,13 +692,14 @@ public class AccountManager {
* <p>
* It is not safe to call this method from the main thread. As such, call it
* from another thread.
- * <p>This method requires the caller to have a signature match with the
- * authenticator that owns the specified account.
+ * <p>
+ * This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and should be
+ * called from the account's authenticator.
*
* @param account The {@link Account} to be updated.
- * @return boolean {@code true} if the authentication of the account has been successfully
- * acknowledged. Otherwise {@code false}.
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean notifyAccountAuthenticated(Account account) {
if (account == null)
throw new IllegalArgumentException("account is null");
@@ -706,8 +717,9 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and have the same UID as the account's authenticator.
*
* @param account The {@link Account} to rename
* @param newName String name to be associated with the account.
@@ -719,6 +731,7 @@ public class AccountManager {
* after the name change. If successful the account's name will be the
* specified new name.
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public AccountManagerFuture<Account> renameAccount(
final Account account,
@Size(min = 1) final String newName,
@@ -770,8 +783,11 @@ public class AccountManager {
* The authenticator may have its own policies preventing account
* deletion, in which case the account will not be deleted.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The {@link Account} to remove
* @param callback Callback to invoke when the request completes,
@@ -784,16 +800,15 @@ public class AccountManager {
* {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
* instead
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
@Deprecated
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new Future2Task<Boolean>(handler, callback) {
- @Override
public void doWork() throws RemoteException {
mService.removeAccount(mResponse, account, false);
}
- @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -812,8 +827,8 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The {@link Account} to remove
* @param activity The {@link Activity} context to use for launching a new
@@ -840,11 +855,11 @@ public class AccountManager {
* adding accounts (of this type) has been disabled by policy
* </ul>
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
- @Override
public void doWork() throws RemoteException {
mService.removeAccount(mResponse, account, activity != null);
}
@@ -865,11 +880,9 @@ public class AccountManager {
if (account == null) throw new IllegalArgumentException("account is null");
if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
return new Future2Task<Boolean>(handler, callback) {
- @Override
public void doWork() throws RemoteException {
mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
}
- @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -905,14 +918,17 @@ public class AccountManager {
* in which case the account will not be deleted.
* <p>
* It is safe to call this method from the main thread.
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>
+ * This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and to have the
+ * same UID or signature as the account's authenticator.
*
* @param account The {@link Account} to delete.
* @return True if the account was successfully deleted, false if the
* account did not exist, the account is null, or another error
* occurs.
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean removeAccountExplicitly(Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -932,9 +948,14 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or
+ * {@link android.Manifest.permission#USE_CREDENTIALS}
+ *
* @param accountType The account type of the auth token to invalidate, must not be null
* @param authToken The auth token to invalidate, may be null
*/
+ @RequiresPermission(anyOf = {MANAGE_ACCOUNTS, USE_CREDENTIALS})
public void invalidateAuthToken(final String accountType, final String authToken) {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
try {
@@ -955,15 +976,16 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
*
- * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
- * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
+ * @param account The account to fetch an auth token for
+ * @param authTokenType The type of auth token to fetch, see {#getAuthToken}
* @return The cached auth token for this account and type, or null if
* no auth token is cached or the account does not exist.
- * @see #getAuthToken
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String peekAuthToken(final Account account, final String authTokenType) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
@@ -983,12 +1005,14 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and have the same UID as the account's authenticator.
*
- * @param account The account whose password is to be set. Cannot be {@code null}.
+ * @param account The account to set a password for
* @param password The password to set, null to clear the password
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setPassword(final Account account, final String password) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -1006,14 +1030,14 @@ public class AccountManager {
* permissions, and may be used by applications or management interfaces
* to "sign out" from an account.
*
- * <p>This method only successfully clear the account's password when the
- * caller has the same signature as the authenticator that owns the
- * specified account. Otherwise, this method will silently fail.
- *
* <p>It is safe to call this method from the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}
+ *
* @param account The account whose password to clear
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public void clearPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -1031,13 +1055,15 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
*
- * @param account Account whose user data is to be set. Must not be {@code null}.
- * @param key String user data key to set. Must not be null
- * @param value String value to set, {@code null} to clear this user data key
+ * @param account The account to set the userdata for
+ * @param key The userdata key to set. Must not be null
+ * @param value The value to set, null to clear this userdata key
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setUserData(final Account account, final String key, final String value) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
@@ -1057,13 +1083,15 @@ public class AccountManager {
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to have a signature match with the
- * authenticator that manages the specified account.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
*
* @param account The account to set an auth token for
* @param authTokenType The type of the auth token, see {#getAuthToken}
* @param authToken The auth token to add to the cache
*/
+ @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setAuthToken(Account account, final String authTokenType, final String authToken) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
@@ -1082,6 +1110,9 @@ public class AccountManager {
* <p>This method may block while a network request completes, and must
* never be made from the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
* @param notifyAuthFailure If true, display a notification and return null
@@ -1095,6 +1126,7 @@ public class AccountManager {
* @throws java.io.IOException if the authenticator experienced an I/O problem
* creating a new auth token, usually because of network trouble
*/
+ @RequiresPermission(USE_CREDENTIALS)
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure)
throws OperationCanceledException, IOException, AuthenticatorException {
@@ -1133,6 +1165,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1166,6 +1201,7 @@ public class AccountManager {
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
+ @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
@@ -1217,6 +1253,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1253,6 +1292,7 @@ public class AccountManager {
* boolean, AccountManagerCallback, android.os.Handler)} instead
*/
@Deprecated
+ @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType,
final boolean notifyAuthFailure,
@@ -1293,6 +1333,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1328,6 +1371,7 @@ public class AccountManager {
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
+ @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final boolean notifyAuthFailure,
@@ -1357,6 +1401,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
* @param accountType The type of account to add; must not be null
* @param authTokenType The type of auth token (see {@link #getAuthToken})
* this account will need to be able to generate, null for none
@@ -1394,6 +1441,7 @@ public class AccountManager {
* creating a new account, usually because of network trouble
* </ul>
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> addAccount(final String accountType,
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
@@ -1538,6 +1586,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
* @param account The account to confirm password knowledge for
* @param options Authenticator-specific options for the request;
* if the {@link #KEY_PASSWORD} string field is present, the
@@ -1564,11 +1615,11 @@ public class AccountManager {
* If no activity or password was specified, the returned Bundle contains
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
* password prompt.
- *
+ *
* <p>Also the returning Bundle may contain {@link
* #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
* credential was validated/created.
- *
+ *
* If an error occurred,{@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
@@ -1578,6 +1629,7 @@ public class AccountManager {
* verifying the password, usually because of network trouble
* </ul>
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
final Bundle options,
final Activity activity,
@@ -1616,6 +1668,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
* @param account The account to update credentials for
* @param authTokenType The credentials entered must allow an auth token
* of this type to be created (but no actual auth token is returned);
@@ -1651,6 +1706,7 @@ public class AccountManager {
* verifying the password, usually because of network trouble
* </ul>
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> updateCredentials(final Account account,
final String authTokenType,
final Bundle options, final Activity activity,
@@ -1673,8 +1729,8 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to have the same signature as the
- * authenticator associated with the specified account type.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param accountType The account type associated with the authenticator
* to adjust
@@ -1702,6 +1758,7 @@ public class AccountManager {
* updating settings, usually because of network trouble
* </ul>
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
final Handler handler) {
@@ -2196,6 +2253,9 @@ public class AccountManager {
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
* @param accountType The account type required
* (see {@link #getAccountsByType}), must not be null
* @param authTokenType The desired auth token type
@@ -2232,6 +2292,7 @@ public class AccountManager {
* updating settings, usually because of network trouble
* </ul>
*/
+ @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
final String accountType, final String authTokenType, final String[] features,
final Activity activity, final Bundle addAccountOptions,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a16a2f4..54123f5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -980,11 +980,33 @@
<!-- Allows access to the list of accounts in the Accounts Service -->
<permission android:name="android.permission.GET_ACCOUNTS"
- android:permissionGroup="android.permission-group.CONTACTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
android:protectionLevel="normal"
android:description="@string/permdesc_getAccounts"
android:label="@string/permlab_getAccounts" />
+ <!-- Allows an application to act as an AccountAuthenticator for
+ the AccountManager -->
+ <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_authenticateAccounts"
+ android:description="@string/permdesc_authenticateAccounts" />
+
+ <!-- Allows an application to request authtokens from the AccountManager -->
+ <permission android:name="android.permission.USE_CREDENTIALS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_useCredentials"
+ android:description="@string/permdesc_useCredentials" />
+
+ <!-- Allows an application to manage the list of accounts in the AccountManager -->
+ <permission android:name="android.permission.MANAGE_ACCOUNTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_manageAccounts"
+ android:description="@string/permdesc_manageAccounts" />
+
<!-- @SystemApi Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f6af19c..675d3e2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1113,6 +1113,27 @@
the list of accounts known by the phone. This may include any accounts
created by applications you have installed.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_authenticateAccounts">create accounts and set passwords</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_authenticateAccounts">Allows the app
+ to use the account authenticator capabilities of the
+ AccountManager, including creating accounts and getting and
+ setting their passwords.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_manageAccounts">add or remove accounts</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_manageAccounts">Allows the app to
+ perform operations like adding and removing accounts, and deleting
+ their password.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_useCredentials">use accounts on the device</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_useCredentials">Allows the app to request authentication tokens.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessNetworkState">view network connections</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/docs/html/training/sync-adapters/creating-sync-adapter.jd b/docs/html/training/sync-adapters/creating-sync-adapter.jd
index 9bd17ba..b13ce07 100644
--- a/docs/html/training/sync-adapters/creating-sync-adapter.jd
+++ b/docs/html/training/sync-adapters/creating-sync-adapter.jd
@@ -583,6 +583,13 @@ public class MainActivity extends FragmentActivity {
running the sync adapter, see <a href="running-sync-adapter.html"
>Running A Sync Adapter</a>.
</dd>
+ <dt>
+{@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS android.permission.AUTHENTICATE_ACCOUNTS}
+ </dt>
+ <dd>
+ Allows you to use the authenticator component you created in the lesson
+ <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
+ </dd>
</dl>
<p>
The following snippet shows how to add the permissions:
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 49d9988..21f96c9 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -87,8 +87,11 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -97,6 +100,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -522,20 +526,14 @@ public class AccountManagerService
@Override
public String getPassword(Account account) {
- int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getPassword: " + account
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot get secrets for accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
+
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -619,21 +617,15 @@ public class AccountManagerService
@Override
public String getUserData(Account account, String key) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
- account, key, callingUid, Binder.getCallingPid());
- Log.v(TAG, msg);
+ Log.v(TAG, "getUserData: " + account
+ + ", key " + key
+ + ", caller's uid " + Binder.getCallingUid()
+ + ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot get user data for accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -684,20 +676,13 @@ public class AccountManagerService
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "addAccountExplicitly: " + account
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot explicitly add accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
/*
* Child users are not allowed to add accounts. Only the accounts that are
* shared by the parent profile can be added to child profile.
@@ -773,24 +758,10 @@ public class AccountManagerService
@Override
public boolean accountAuthenticated(final Account account) {
- final int callingUid = Binder.getCallingUid();
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- String msg = String.format(
- "accountAuthenticated( account: %s, callerUid: %s)",
- account,
- callingUid);
- Log.v(TAG, msg);
- }
if (account == null) {
throw new IllegalArgumentException("account is null");
}
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot notify authentication for accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
int userId = Binder.getCallingUserHandle().getIdentifier();
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
return false;
@@ -1036,21 +1007,16 @@ public class AccountManagerService
@Override
public void renameAccount(
IAccountManagerResponse response, Account accountToRename, String newName) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (accountToRename == null) throw new IllegalArgumentException("account is null");
- if (!isAccountOwnedByCallingUid(accountToRename.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot rename accounts of type: %s",
- callingUid,
- accountToRename.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(accountToRename);
UserAccounts accounts = getUserAccountsForCaller();
+
+ int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName,
@@ -1159,21 +1125,65 @@ public class AccountManagerService
@Override
public void removeAccount(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch) {
- removeAccountAsUser(
- response,
- account,
- expectActivityLaunch,
- UserHandle.getCallingUserId());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "removeAccount: " + account
+ + ", response " + response
+ + ", 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");
+ checkManageAccountsPermission();
+ UserHandle user = Binder.getCallingUserHandle();
+ UserAccounts accounts = getUserAccountsForCaller();
+ int userId = Binder.getCallingUserHandle().getIdentifier();
+ if (!canUserModifyAccounts(userId)) {
+ try {
+ // TODO: This should be ERROR_CODE_USER_RESTRICTED instead. See http://b/16322768
+ response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "User cannot modify accounts");
+ } catch (RemoteException re) {
+ }
+ return;
+ }
+ if (!canUserModifyAccountsForType(userId, account.type)) {
+ try {
+ response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+ "User cannot modify accounts of this type (policy).");
+ } catch (RemoteException re) {
+ }
+ return;
+ }
+
+ long identityToken = clearCallingIdentity();
+
+ cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
+ synchronized (accounts.credentialsPermissionNotificationIds) {
+ for (Pair<Pair<Account, String>, Integer> pair:
+ accounts.credentialsPermissionNotificationIds.keySet()) {
+ if (account.equals(pair.first.first)) {
+ int id = accounts.credentialsPermissionNotificationIds.get(pair);
+ cancelNotification(id, user);
+ }
+ }
+ }
+
+ logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
+
+ try {
+ new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
}
@Override
public void removeAccountAsUser(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch, int userId) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccount: " + account
+ ", response " + response
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid()
+ ", for user id " + userId);
}
@@ -1183,18 +1193,7 @@ public class AccountManagerService
// Only allow the system process to modify accounts of other users
enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ " trying to remove account for " + userId);
- /*
- * Only the system or authenticator should be allowed to remove accounts for that
- * authenticator. This will let users remove accounts (via Settings in the system) but not
- * arbitrary applications (like competing authenticators).
- */
- if (!isAccountOwnedByCallingUid(account.type, callingUid) && !isSystemUid(callingUid)) {
- String msg = String.format(
- "uid %s cannot remove accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkManageAccountsPermission();
UserAccounts accounts = getUserAccounts(userId);
if (!canUserModifyAccounts(userId)) {
@@ -1239,26 +1238,13 @@ public class AccountManagerService
@Override
public boolean removeAccountExplicitly(Account account) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccountExplicitly: " + account
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- if (account == null) {
- /*
- * Null accounts should result in returning false, as per
- * AccountManage.addAccountExplicitly(...) java doc.
- */
- Log.e(TAG, "account is null");
- return false;
- } else if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot explicitly add accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ if (account == null) throw new IllegalArgumentException("account is null");
+ checkAuthenticateAccountsPermission(account);
UserAccounts accounts = getUserAccountsForCaller();
int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -1371,6 +1357,7 @@ public class AccountManagerService
}
if (accountType == null) throw new IllegalArgumentException("accountType is null");
if (authToken == null) throw new IllegalArgumentException("authToken is null");
+ checkManageAccountsOrUseCredentialsPermissions();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1503,22 +1490,15 @@ public class AccountManagerService
@Override
public String peekAuthToken(Account account, String authTokenType) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "peekAuthToken: " + account
+ ", authTokenType " + authTokenType
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot peek the authtokens associated with accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1530,22 +1510,15 @@ public class AccountManagerService
@Override
public void setAuthToken(Account account, String authTokenType, String authToken) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
+ ", authTokenType " + authTokenType
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot set auth tokens associated with accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1557,21 +1530,15 @@ public class AccountManagerService
@Override
public void setPassword(Account account, String password) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot set secrets for accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
UserAccounts accounts = getUserAccountsForCaller();
+ int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
setPasswordInternal(accounts, account, password, callingUid);
@@ -1627,21 +1594,16 @@ public class AccountManagerService
@Override
public void clearPassword(Account account) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearPassword: " + account
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot clear passwords for accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkManageAccountsPermission();
UserAccounts accounts = getUserAccountsForCaller();
+
+ int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
setPasswordInternal(accounts, account, null, callingUid);
@@ -1652,22 +1614,15 @@ public class AccountManagerService
@Override
public void setUserData(Account account, String key, String value) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setUserData: " + account
+ ", key " + key
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (key == null) throw new IllegalArgumentException("key is null");
if (account == null) throw new IllegalArgumentException("account is null");
- if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
- String msg = String.format(
- "uid %s cannot set user data for accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
+ checkAuthenticateAccountsPermission(account);
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1814,6 +1769,7 @@ public class AccountManagerService
return;
}
+ checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
final UserAccounts accounts = getUserAccountsForCaller();
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
authenticatorInfo = mAuthenticatorCache.getServiceInfo(
@@ -2091,6 +2047,7 @@ public class AccountManagerService
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ checkManageAccountsPermission();
// Is user disallowed from modifying accounts?
int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -2165,6 +2122,7 @@ public class AccountManagerService
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ checkManageAccountsPermission();
// Only allow the system process to add accounts of other users
enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
@@ -2255,6 +2213,7 @@ public class AccountManagerService
}
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
+ checkManageAccountsPermission();
UserAccounts accounts = getUserAccounts(userId);
long identityToken = clearCallingIdentity();
try {
@@ -2291,6 +2250,7 @@ public class AccountManagerService
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");
+ checkManageAccountsPermission();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -2318,23 +2278,16 @@ public class AccountManagerService
@Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {
- final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "editProperties: accountType " + accountType
+ ", response " + response
+ ", expectActivityLaunch " + expectActivityLaunch
- + ", caller's uid " + callingUid
+ + ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- if (!isAccountOwnedByCallingUid(accountType, callingUid) && !isSystemUid(callingUid)) {
- String msg = String.format(
- "uid %s cannot edit authenticator properites for account type: %s",
- callingUid,
- accountType);
- throw new SecurityException(msg);
- }
+ checkManageAccountsPermission();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -3635,7 +3588,7 @@ public class AccountManagerService
private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
final boolean isPrivileged = isPrivileged(callerUid);
final boolean fromAuthenticator = account != null
- && isAccountManagedByCaller(account.type, callerUid);
+ && hasAuthenticatorUid(account.type, callerUid);
final boolean hasExplicitGrants = account != null
&& hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -3647,17 +3600,14 @@ public class AccountManagerService
return fromAuthenticator || hasExplicitGrants || isPrivileged;
}
- private boolean isAccountManagedByCaller(String accountType, int callingUid) {
+ private boolean hasAuthenticatorUid(String accountType, int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
mAuthenticatorCache.getAllServices(callingUserId)) {
if (serviceInfo.type.type.equals(accountType)) {
- /*
- * We can't simply compare uids because uids can be recycled before the
- * authenticator cache is updated.
- */
- final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
- return sigChk == PackageManager.SIGNATURE_MATCH;
+ return (serviceInfo.uid == callingUid) ||
+ (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
+ == PackageManager.SIGNATURE_MATCH);
}
}
return false;
@@ -3698,49 +3648,36 @@ public class AccountManagerService
}
}
- private boolean isSystemUid(int callingUid) {
- String[] packages = null;
- long ident = Binder.clearCallingIdentity();
- try {
- packages = mPackageManager.getPackagesForUid(callingUid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- if (packages != null) {
- for (String name : packages) {
- try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
- if (packageInfo != null
- && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
- != 0) {
- return true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, String.format("Could not find package [%s]", name), e);
- }
- }
- } else {
- Log.w(TAG, "No known packages with uid " + callingUid);
- }
- return false;
- }
-
- private boolean isAccountOwnedByCallingUid(String accountType, int callingUid) {
- if (!isAccountManagedByCaller(accountType, callingUid)) {
- String msg = "caller uid " + callingUid + " is different than the authenticator's uid";
+ private void checkCallingUidAgainstAuthenticator(Account account) {
+ final int uid = Binder.getCallingUid();
+ if (account == null || !hasAuthenticatorUid(account.type, uid)) {
+ String msg = "caller uid " + uid + " is different than the authenticator's uid";
Log.w(TAG, msg);
- return false;
+ throw new SecurityException(msg);
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "caller uid " + callingUid + " is the same as the authenticator's uid");
+ Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
}
- return true;
+ }
+
+ private void checkAuthenticateAccountsPermission(Account account) {
+ checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
+ checkCallingUidAgainstAuthenticator(account);
}
private void checkReadAccountsPermission() {
checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
}
+ private void checkManageAccountsPermission() {
+ checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
+ }
+
+ private void checkManageAccountsOrUseCredentialsPermissions() {
+ checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
+ Manifest.permission.USE_CREDENTIALS);
+ }
+
private boolean canUserModifyAccounts(int userId) {
if (getUserManager().getUserRestrictions(new UserHandle(userId))
.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {