Skip to content

Commit d9640ec

Browse files
committed
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
1 parent c1cabdf commit d9640ec

File tree

4 files changed

+124
-37
lines changed

4 files changed

+124
-37
lines changed

core/java/android/accounts/AccountManager.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,55 @@ public Account[] getAccountsByType(String type) {
404404
}
405405
}
406406

407+
/**
408+
* Change whether or not an app (identified by its uid) is allowed to retrieve an authToken
409+
* for an account.
410+
* <p>
411+
* This is only meant to be used by system activities and is not in the SDK.
412+
* @param account The account whose permissions are being modified
413+
* @param authTokenType The type of token whose permissions are being modified
414+
* @param uid The uid that identifies the app which is being granted or revoked permission.
415+
* @param value true is permission is being granted, false for revoked
416+
* @hide
417+
*/
418+
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) {
419+
try {
420+
mService.updateAppPermission(account, authTokenType, uid, value);
421+
} catch (RemoteException e) {
422+
// won't ever happen
423+
throw new RuntimeException(e);
424+
}
425+
}
426+
427+
/**
428+
* Get the user-friendly label associated with an authenticator's auth token.
429+
* @param accountType the type of the authenticator. must not be null.
430+
* @param authTokenType the token type. must not be null.
431+
* @param callback callback to invoke when the result is available. may be null.
432+
* @param handler the handler on which to invoke the callback, or null for the main thread
433+
* @return a future containing the label string
434+
* @hide
435+
*/
436+
public AccountManagerFuture<String> getAuthTokenLabel(
437+
final String accountType, final String authTokenType,
438+
AccountManagerCallback<String> callback, Handler handler) {
439+
if (accountType == null) throw new IllegalArgumentException("accountType is null");
440+
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
441+
return new Future2Task<String>(handler, callback) {
442+
public void doWork() throws RemoteException {
443+
mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
444+
}
445+
446+
@Override
447+
public String bundleToResult(Bundle bundle) throws AuthenticatorException {
448+
if (!bundle.containsKey(KEY_AUTH_TOKEN_LABEL)) {
449+
throw new AuthenticatorException("no result in response");
450+
}
451+
return bundle.getString(KEY_AUTH_TOKEN_LABEL);
452+
}
453+
}.start();
454+
}
455+
407456
/**
408457
* Finds out whether a particular account has all the specified features.
409458
* Account features are authenticator-specific string tokens identifying

core/java/android/accounts/AccountManagerService.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -985,21 +985,25 @@ private void onResult(IAccountManagerResponse response, Bundle result) {
985985
}
986986
}
987987

988-
void getAuthTokenLabel(final IAccountManagerResponse response,
989-
final Account account,
990-
final String authTokenType, int uid) {
991-
if (account == null) throw new IllegalArgumentException("account is null");
988+
public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
989+
final String authTokenType)
990+
throws RemoteException {
991+
if (accountType == null) throw new IllegalArgumentException("accountType is null");
992992
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
993993

994-
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
995-
UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
994+
final int callingUid = getCallingUid();
995+
clearCallingIdentity();
996+
if (callingUid != android.os.Process.SYSTEM_UID) {
997+
throw new SecurityException("can only call from system");
998+
}
999+
UserAccounts accounts = getUserAccounts(UserId.getUserId(callingUid));
9961000
long identityToken = clearCallingIdentity();
9971001
try {
998-
new Session(accounts, response, account.type, false,
1002+
new Session(accounts, response, accountType, false,
9991003
false /* stripAuthTokenFromResult */) {
10001004
protected String toDebugString(long now) {
10011005
return super.toDebugString(now) + ", getAuthTokenLabel"
1002-
+ ", " + account
1006+
+ ", " + accountType
10031007
+ ", authTokenType " + authTokenType;
10041008
}
10051009

@@ -2230,14 +2234,29 @@ private void checkManageAccountsOrUseCredentialsPermissions() {
22302234
Manifest.permission.USE_CREDENTIALS);
22312235
}
22322236

2237+
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
2238+
throws RemoteException {
2239+
final int callingUid = getCallingUid();
2240+
2241+
if (callingUid != android.os.Process.SYSTEM_UID) {
2242+
throw new SecurityException();
2243+
}
2244+
2245+
if (value) {
2246+
grantAppPermission(account, authTokenType, uid);
2247+
} else {
2248+
revokeAppPermission(account, authTokenType, uid);
2249+
}
2250+
}
2251+
22332252
/**
22342253
* Allow callers with the given uid permission to get credentials for account/authTokenType.
22352254
* <p>
22362255
* Although this is public it can only be accessed via the AccountManagerService object
22372256
* which is in the system. This means we don't need to protect it with permissions.
22382257
* @hide
22392258
*/
2240-
public void grantAppPermission(Account account, String authTokenType, int uid) {
2259+
private void grantAppPermission(Account account, String authTokenType, int uid) {
22412260
if (account == null || authTokenType == null) {
22422261
Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
22432262
return;
@@ -2271,7 +2290,7 @@ public void grantAppPermission(Account account, String authTokenType, int uid) {
22712290
* which is in the system. This means we don't need to protect it with permissions.
22722291
* @hide
22732292
*/
2274-
public void revokeAppPermission(Account account, String authTokenType, int uid) {
2293+
private void revokeAppPermission(Account account, String authTokenType, int uid) {
22752294
if (account == null || authTokenType == null) {
22762295
Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
22772296
return;

core/java/android/accounts/GrantCredentialsPermissionActivity.java

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@
1616
package android.accounts;
1717

1818
import android.app.Activity;
19+
import android.content.pm.RegisteredServicesCache;
20+
import android.content.res.Resources;
1921
import android.os.Bundle;
20-
import android.os.RemoteException;
2122
import android.widget.TextView;
2223
import android.widget.LinearLayout;
23-
import android.widget.ImageView;
2424
import android.view.View;
2525
import android.view.LayoutInflater;
26-
import android.view.Window;
2726
import android.content.Context;
2827
import android.content.Intent;
2928
import android.content.pm.PackageManager;
30-
import android.content.pm.RegisteredServicesCache;
3129
import android.text.TextUtils;
32-
import android.graphics.drawable.Drawable;
3330
import com.android.internal.R;
3431

32+
import java.io.IOException;
33+
import java.net.Authenticator;
34+
3535
/**
3636
* @hide
3737
*/
@@ -48,7 +48,6 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
4848
private int mUid;
4949
private Bundle mResultBundle = null;
5050
protected LayoutInflater mInflater;
51-
private final AccountManagerService accountManagerService = AccountManagerService.getSingleton();
5251

5352
protected void onCreate(Bundle savedInstanceState) {
5453
super.onCreate(savedInstanceState);
@@ -81,7 +80,7 @@ protected void onCreate(Bundle savedInstanceState) {
8180

8281
String accountTypeLabel;
8382
try {
84-
accountTypeLabel = accountManagerService.getAccountLabel(mAccount.type);
83+
accountTypeLabel = getAccountLabel(mAccount);
8584
} catch (IllegalArgumentException e) {
8685
// label or resource was missing. abort the activity.
8786
setResult(Activity.RESULT_CANCELED);
@@ -92,28 +91,27 @@ protected void onCreate(Bundle savedInstanceState) {
9291
final TextView authTokenTypeView = (TextView) findViewById(R.id.authtoken_type);
9392
authTokenTypeView.setVisibility(View.GONE);
9493

95-
/** Handles the responses from the AccountManager */
96-
IAccountManagerResponse response = new IAccountManagerResponse.Stub() {
97-
public void onResult(Bundle bundle) {
98-
final String authTokenLabel =
99-
bundle.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
100-
if (!TextUtils.isEmpty(authTokenLabel)) {
101-
runOnUiThread(new Runnable() {
102-
public void run() {
103-
if (!isFinishing()) {
104-
authTokenTypeView.setText(authTokenLabel);
105-
authTokenTypeView.setVisibility(View.VISIBLE);
94+
final AccountManagerCallback<String> callback = new AccountManagerCallback<String>() {
95+
public void run(AccountManagerFuture<String> future) {
96+
try {
97+
final String authTokenLabel = future.getResult();
98+
if (!TextUtils.isEmpty(authTokenLabel)) {
99+
runOnUiThread(new Runnable() {
100+
public void run() {
101+
if (!isFinishing()) {
102+
authTokenTypeView.setText(authTokenLabel);
103+
authTokenTypeView.setVisibility(View.VISIBLE);
104+
}
106105
}
107-
}
108-
});
106+
});
107+
}
108+
} catch (OperationCanceledException e) {
109+
} catch (IOException e) {
110+
} catch (AuthenticatorException e) {
109111
}
110112
}
111-
112-
public void onError(int code, String message) {
113-
}
114113
};
115-
116-
accountManagerService.getAuthTokenLabel(response, mAccount, mAuthTokenType, mUid);
114+
AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
117115

118116
findViewById(R.id.allow_button).setOnClickListener(this);
119117
findViewById(R.id.deny_button).setOnClickListener(this);
@@ -134,6 +132,24 @@ public void onError(int code, String message) {
134132
((TextView) findViewById(R.id.account_type)).setText(accountTypeLabel);
135133
}
136134

135+
private String getAccountLabel(Account account) {
136+
final AuthenticatorDescription[] authenticatorTypes =
137+
AccountManager.get(this).getAuthenticatorTypes();
138+
for (int i = 0, N = authenticatorTypes.length; i < N; i++) {
139+
final AuthenticatorDescription desc = authenticatorTypes[i];
140+
if (desc.type.equals(account.type)) {
141+
try {
142+
return createPackageContext(desc.packageName, 0).getString(desc.labelId);
143+
} catch (PackageManager.NameNotFoundException e) {
144+
return account.type;
145+
} catch (Resources.NotFoundException e) {
146+
return account.type;
147+
}
148+
}
149+
}
150+
return account.type;
151+
}
152+
137153
private View newPackageView(String packageLabel) {
138154
View view = mInflater.inflate(R.layout.permissions_package_list_item, null);
139155
((TextView) view.findViewById(R.id.package_label)).setText(packageLabel);
@@ -143,15 +159,15 @@ private View newPackageView(String packageLabel) {
143159
public void onClick(View v) {
144160
switch (v.getId()) {
145161
case R.id.allow_button:
146-
accountManagerService.grantAppPermission(mAccount, mAuthTokenType, mUid);
162+
AccountManager.get(this).updateAppPermission(mAccount, mAuthTokenType, mUid, true);
147163
Intent result = new Intent();
148164
result.putExtra("retry", true);
149165
setResult(RESULT_OK, result);
150166
setAccountAuthenticatorResult(result.getExtras());
151167
break;
152168

153169
case R.id.deny_button:
154-
accountManagerService.revokeAppPermission(mAccount, mAuthTokenType, mUid);
170+
AccountManager.get(this).updateAppPermission(mAccount, mAuthTokenType, mUid, false);
155171
setResult(RESULT_CANCELED);
156172
break;
157173
}

core/java/android/accounts/IAccountManager.aidl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ interface IAccountManager {
4141
void setPassword(in Account account, String password);
4242
void clearPassword(in Account account);
4343
void setUserData(in Account account, String key, String value);
44+
void updateAppPermission(in Account account, String authTokenType, int uid, boolean value);
4445

4546
void getAuthToken(in IAccountManagerResponse response, in Account account,
4647
String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
@@ -54,4 +55,6 @@ interface IAccountManager {
5455
boolean expectActivityLaunch);
5556
void confirmCredentials(in IAccountManagerResponse response, in Account account,
5657
in Bundle options, boolean expectActivityLaunch);
58+
void getAuthTokenLabel(in IAccountManagerResponse response, String accountType,
59+
String authTokenType);
5760
}

0 commit comments

Comments
 (0)