use of android.accounts.AuthenticatorDescription in project android_frameworks_base by crdroidandroid.
the class AccountManagerService method getAuthToken.
@Override
public void getAuthToken(IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, final boolean expectActivityLaunch, final Bundle loginOptions) {
Bundle.setDefusable(loginOptions, true);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthToken: " + account + ", response " + response + ", authTokenType " + authTokenType + ", notifyOnAuthFailure " + notifyOnAuthFailure + ", expectActivityLaunch " + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid());
}
if (response == null)
throw new IllegalArgumentException("response is null");
try {
if (account == null) {
Slog.w(TAG, "getAuthToken called with null account");
response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
return;
}
if (authTokenType == null) {
Slog.w(TAG, "getAuthToken called with null authTokenType");
response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
return;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report error back to the client." + e);
return;
}
int userId = UserHandle.getCallingUserId();
long ident = Binder.clearCallingIdentity();
final UserAccounts accounts;
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
try {
accounts = getUserAccounts(userId);
authenticatorInfo = mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(account.type), accounts.userId);
} finally {
Binder.restoreCallingIdentity(ident);
}
final boolean customTokens = authenticatorInfo != null && authenticatorInfo.type.customTokens;
// skip the check if customTokens
final int callerUid = Binder.getCallingUid();
final boolean permissionGranted = customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
// Get the calling package. We will use it for the purpose of caching.
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
List<String> callerOwnedPackageNames;
ident = Binder.clearCallingIdentity();
try {
callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
} finally {
Binder.restoreCallingIdentity(ident);
}
if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
String msg = String.format("Uid %s is attempting to illegally masquerade as package %s!", callerUid, callerPkg);
throw new SecurityException(msg);
}
// let authenticator know the identity of the caller
loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
if (notifyOnAuthFailure) {
loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
}
long identityToken = clearCallingIdentity();
try {
// Distill the caller's package signatures into a single digest.
final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
// route of starting a Session
if (!customTokens && permissionGranted) {
String authToken = readAuthTokenInternal(accounts, account, authTokenType);
if (authToken != null) {
Bundle result = new Bundle();
result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
onResult(response, result);
return;
}
}
if (customTokens) {
/*
* Look up tokens in the new cache only if the loginOptions don't have parameters
* outside of those expected to be injected by the AccountManager, e.g.
* ANDORID_PACKAGE_NAME.
*/
String token = readCachedTokenInternal(accounts, account, authTokenType, callerPkg, callerPkgSigDigest);
if (token != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
}
Bundle result = new Bundle();
result.putString(AccountManager.KEY_AUTHTOKEN, token);
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
onResult(response, result);
return;
}
}
new Session(accounts, response, account.type, expectActivityLaunch, false, /* stripAuthTokenFromResult */
account.name, false) {
/* authDetailsRequired */
@Override
protected String toDebugString(long now) {
if (loginOptions != null)
loginOptions.keySet();
return super.toDebugString(now) + ", getAuthToken" + ", " + account + ", authTokenType " + authTokenType + ", loginOptions " + loginOptions + ", notifyOnAuthFailure " + notifyOnAuthFailure;
}
@Override
public void run() throws RemoteException {
// "grant permission" intent instead of the "getAuthToken" intent.
if (!permissionGranted) {
mAuthenticator.getAuthTokenLabel(this, authTokenType);
} else {
mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
}
}
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
if (result != null) {
if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Intent intent = newGrantCredentialsPermissionIntent(account, null, callerUid, new AccountAuthenticatorResponse(this), authTokenType, true);
Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
onResult(bundle);
return;
}
String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (authToken != null) {
String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "the type and name should not be empty");
return;
}
Account resultAccount = new Account(name, type);
if (!customTokens) {
saveAuthTokenToDatabase(mAccounts, resultAccount, authTokenType, authToken);
}
long expiryMillis = result.getLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
if (customTokens && expiryMillis > System.currentTimeMillis()) {
saveCachedToken(mAccounts, account, callerPkg, callerPkgSigDigest, authTokenType, authToken, expiryMillis);
}
}
Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
if (intent != null && notifyOnAuthFailure && !customTokens) {
/*
* Make sure that the supplied intent is owned by the authenticator
* giving it to the system. Otherwise a malicious authenticator could
* have users launching arbitrary activities by tricking users to
* interact with malicious notifications.
*/
checkKeyIntent(Binder.getCallingUid(), intent);
doNotification(mAccounts, account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE), intent, "android", accounts.userId);
}
}
super.onResult(result);
}
}.bind();
} finally {
restoreCallingIdentity(identityToken);
}
}
use of android.accounts.AuthenticatorDescription in project android_frameworks_base by crdroidandroid.
the class AccountAuthenticatorCache method parseServiceAttributes.
public AuthenticatorDescription parseServiceAttributes(Resources res, String packageName, AttributeSet attrs) {
TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AccountAuthenticator);
try {
final String accountType = sa.getString(com.android.internal.R.styleable.AccountAuthenticator_accountType);
final int labelId = sa.getResourceId(com.android.internal.R.styleable.AccountAuthenticator_label, 0);
final int iconId = sa.getResourceId(com.android.internal.R.styleable.AccountAuthenticator_icon, 0);
final int smallIconId = sa.getResourceId(com.android.internal.R.styleable.AccountAuthenticator_smallIcon, 0);
final int prefId = sa.getResourceId(com.android.internal.R.styleable.AccountAuthenticator_accountPreferences, 0);
final boolean customTokens = sa.getBoolean(com.android.internal.R.styleable.AccountAuthenticator_customTokens, false);
if (TextUtils.isEmpty(accountType)) {
return null;
}
return new AuthenticatorDescription(accountType, packageName, labelId, iconId, smallIconId, prefId, customTokens);
} finally {
sa.recycle();
}
}
Aggregations