Skip to content

Commit 3c144c3

Browse files
fredquintanaAndroid (Google) Code Review
authored andcommitted
Merge "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." into jb-dev
2 parents f46bd06 + d9640ec commit 3c144c3

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)