Merge "Enforce device policy in credential manager (framework)"

This commit is contained in:
TreeHugger Robot
2023-02-15 01:23:54 +00:00
committed by Android (Google) Code Review
6 changed files with 451 additions and 90 deletions

View File

@@ -21,6 +21,7 @@ import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN;
import static java.util.Objects.requireNonNull;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -30,6 +31,7 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.ServiceInfo;
import android.os.CancellationSignal;
import android.os.ICancellationSignal;
import android.os.OutcomeReceiver;
@@ -37,6 +39,8 @@ import android.os.RemoteException;
import android.provider.DeviceConfig;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.concurrent.Executor;
@@ -54,6 +58,39 @@ import java.util.concurrent.Executor;
public final class CredentialManager {
private static final String TAG = "CredentialManager";
/** @hide */
@IntDef(
flag = true,
prefix = {"PROVIDER_FILTER_"},
value = {
PROVIDER_FILTER_ALL_PROVIDERS,
PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY,
PROVIDER_FILTER_USER_PROVIDERS_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProviderFilter {}
/**
* Returns both system and user credential providers.
*
* @hide
*/
public static final int PROVIDER_FILTER_ALL_PROVIDERS = 0;
/**
* Returns system credential providers only.
*
* @hide
*/
public static final int PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY = 1;
/**
* Returns user credential providers only.
*
* @hide
*/
public static final int PROVIDER_FILTER_USER_PROVIDERS_ONLY = 2;
private final Context mContext;
private final ICredentialManager mService;
@@ -404,6 +441,42 @@ public final class CredentialManager {
}
}
/**
* Returns the list of ServiceInfo for all discovered credential providers on this device.
*
* @hide
*/
@NonNull
@RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS)
public List<ServiceInfo> getCredentialProviderServicesForTesting(
@ProviderFilter int providerFilter) {
try {
return mService.getCredentialProviderServices(
mContext.getUserId(),
/* disableSystemAppVerificationForTests= */ true,
providerFilter);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns the list of ServiceInfo for all discovered credential providers on this device.
*
* @hide
*/
@NonNull
@RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS)
public List<ServiceInfo> getCredentialProviderServices(
int userId, @ProviderFilter int providerFilter) {
try {
return mService.getCredentialProviderServices(
userId, /* disableSystemAppVerificationForTests= */ false, providerFilter);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns whether the service is enabled.
*

View File

@@ -18,6 +18,7 @@ package android.credentials;
import java.util.List;
import android.content.pm.ServiceInfo;
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
@@ -57,5 +58,7 @@ interface ICredentialManager {
void unregisterCredentialDescription(in UnregisterCredentialDescriptionRequest request, String callingPackage);
boolean isEnabledCredentialProviderService(in ComponentName componentName, String callingPackage);
List<ServiceInfo> getCredentialProviderServices(in int userId, in boolean disableSystemAppVerificationForTests, in int providerFilter);
}

View File

@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
import android.app.admin.PackagePolicy;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +31,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.credentials.CredentialManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
@@ -38,7 +41,10 @@ import android.util.Slog;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* {@link ServiceInfo} and meta-data about a credential provider.
@@ -74,39 +80,124 @@ public final class CredentialProviderInfo {
public CredentialProviderInfo(@NonNull Context context,
@NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider)
throws PackageManager.NameNotFoundException {
this(context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider);
this(
context,
getServiceInfoOrThrow(serviceComponent, userId),
isSystemProvider,
/* disableSystemAppVerificationForTests= */ false);
}
/**
* Constructs an information instance of the credential provider.
*
* @param context the context object
* @param serviceInfo the service info for the provider app. This must be retrieved from the
* {@code PackageManager}
* @param isSystemProvider whether the provider is a system app or not
* {@code PackageManager}
* @param isSystemProvider whether the provider app is a system provider
* @param disableSystemAppVerificationForTests whether to disable system app permission
* verification so that tests can install system providers
* @throws SecurityException If provider does not require the relevant permission
*/
public CredentialProviderInfo(@NonNull Context context,
public CredentialProviderInfo(
@NonNull Context context,
@NonNull ServiceInfo serviceInfo,
boolean isSystemProvider) {
if (!Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE.equals(serviceInfo.permission)) {
Log.i(TAG, "Credential Provider Service from : " + serviceInfo.packageName
+ "does not require permission"
+ Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE);
throw new SecurityException("Service does not require the expected permission : "
+ Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE);
boolean isSystemProvider,
boolean disableSystemAppVerificationForTests) {
verifyProviderPermission(serviceInfo);
if (isSystemProvider) {
if (!isValidSystemProvider(
context, serviceInfo, disableSystemAppVerificationForTests)) {
Slog.e(TAG, "Provider is not a valid system provider: " + serviceInfo);
throw new SecurityException(
"Provider is not a valid system provider: " + serviceInfo);
}
}
mIsSystemProvider = isSystemProvider;
mContext = context;
mServiceInfo = serviceInfo;
mCapabilities = new ArrayList<>();
mIcon = mServiceInfo.loadIcon(mContext.getPackageManager());
mLabel = mServiceInfo.loadSafeLabel(
mContext.getPackageManager(), 0 /* do not ellipsize */,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
mIsSystemProvider = isSystemProvider;
Log.i(TAG, "mLabel is : " + mLabel + ", for: " + mServiceInfo.getComponentName()
.flattenToString());
mLabel =
mServiceInfo.loadSafeLabel(
mContext.getPackageManager(),
0 /* do not ellipsize */,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
Log.i(
TAG,
"mLabel is : "
+ mLabel
+ ", for: "
+ mServiceInfo.getComponentName().flattenToString());
populateProviderCapabilities(context, serviceInfo);
}
private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException {
final String permission = Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE;
if (permission.equals(serviceInfo.permission)) {
return;
}
Slog.e(
TAG,
"Credential Provider Service from : "
+ serviceInfo.packageName
+ "does not require permission"
+ permission);
throw new SecurityException(
"Service does not require the expected permission : " + permission);
}
private static boolean isSystemProviderWithValidPermission(
ServiceInfo serviceInfo, Context context) {
final String permission = Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE;
try {
ApplicationInfo appInfo =
context.getPackageManager()
.getApplicationInfo(
serviceInfo.packageName,
PackageManager.ApplicationInfoFlags.of(
PackageManager.MATCH_SYSTEM_ONLY));
if (appInfo != null
&& context.checkPermission(permission, /* pid= */ -1, appInfo.uid)
== PackageManager.PERMISSION_GRANTED) {
Slog.i(TAG, "SYS permission granted for: " + serviceInfo.packageName);
return true;
} else {
Slog.i(TAG, "SYS permission failed for: " + serviceInfo.packageName);
}
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
}
return false;
}
private static boolean isValidSystemProvider(
Context context,
ServiceInfo serviceInfo,
boolean disableSystemAppVerificationForTests) {
boolean isValidSystemTestProvider =
isTestSystemProvider(serviceInfo, disableSystemAppVerificationForTests);
if (isValidSystemTestProvider) {
return true;
}
return isSystemProviderWithValidPermission(serviceInfo, context);
}
private static boolean isTestSystemProvider(
ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests) {
if (!disableSystemAppVerificationForTests) {
return false;
}
Bundle metadata = serviceInfo.metaData;
if (metadata == null) {
Slog.e(TAG, "metadata is null: " + serviceInfo);
return false;
}
return metadata.getBoolean(CredentialProviderService.TEST_SYSTEM_PROVIDER_META_DATA_KEY);
}
private void populateProviderCapabilities(@NonNull Context context, ServiceInfo serviceInfo) {
final PackageManager pm = context.getPackageManager();
try {
@@ -133,7 +224,9 @@ public final class CredentialProviderInfo {
mCapabilities.add(capability);
}
} catch (PackageManager.NameNotFoundException e) {
Slog.i(TAG, e.getMessage());
Slog.e(TAG, e.getMessage());
} catch (Resources.NotFoundException e) {
Slog.e(TAG, e.getMessage());
}
}
@@ -154,40 +247,80 @@ public final class CredentialProviderInfo {
}
/**
* Returns the valid credential provider services available for the user with the
* given {@code userId}.
* Returns the valid credential provider services available for the user with the given {@code
* userId}.
*/
@NonNull
private static List<ServiceInfo> getAvailableSystemServiceInfos(
@NonNull Context context,
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests) {
final List<ServiceInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos = new ArrayList<>();
resolveInfos.addAll(
context.getPackageManager()
.queryIntentServicesAsUser(
new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE),
PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA),
userId));
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
try {
PackageManager.ApplicationInfoFlags appInfoFlags =
disableSystemAppVerificationForTests
? PackageManager.ApplicationInfoFlags.of(0)
: PackageManager.ApplicationInfoFlags.of(
PackageManager.MATCH_SYSTEM_ONLY);
ApplicationInfo appInfo =
context.getPackageManager()
.getApplicationInfo(serviceInfo.packageName, appInfoFlags);
if (appInfo == null || serviceInfo == null) {
continue;
}
services.add(serviceInfo);
} catch (SecurityException e) {
Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
}
}
return services;
}
/**
* Returns the valid credential provider services available for the user with the given {@code
* userId}.
*/
@NonNull
public static List<CredentialProviderInfo> getAvailableSystemServices(
@NonNull Context context,
@UserIdInt int userId) {
final List<CredentialProviderInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos =
context.getPackageManager().queryIntentServicesAsUser(
new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE),
PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA),
userId);
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests) {
final List<CredentialProviderInfo> providerInfos = new ArrayList<>();
for (ServiceInfo si :
getAvailableSystemServiceInfos(
context, userId, disableSystemAppVerificationForTests)) {
try {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
serviceInfo.packageName,
PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY));
if (appInfo != null
&& context.checkPermission(
Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE,
/*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) {
services.add(new CredentialProviderInfo(context, serviceInfo,
/*isSystemProvider=*/true));
CredentialProviderInfo cpi =
new CredentialProviderInfo(
context,
si,
/* isSystemProvider= */ true,
disableSystemAppVerificationForTests);
if (cpi.isSystemProvider()) {
providerInfos.add(cpi);
} else {
Slog.e(TAG, "Non system provider was in system provider list.");
}
} catch (SecurityException e) {
Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e);
} catch (PackageManager.NameNotFoundException e) {
Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e);
Slog.e(TAG, "Failed to create CredentialProviderInfo: " + e);
}
}
return services;
return providerInfos;
}
/**
@@ -226,47 +359,153 @@ public final class CredentialProviderInfo {
return Collections.unmodifiableList(mCapabilities);
}
private static @Nullable PackagePolicy getDeviceManagerPolicy(@NonNull Context context) {
try {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
return dpm.getCredentialManagerPolicy();
} catch (SecurityException e) {
// If the current user is not enrolled in DPM then this can throw a security error.
Log.e(TAG, "Failed to get device policy: " + e);
}
return null;
}
/**
* Returns the valid credential provider services available for the user with the
* given {@code userId}.
* Returns the valid credential provider services available for the user with the given {@code
* userId}.
*/
@NonNull
public static List<CredentialProviderInfo> getAvailableServices(@NonNull Context context,
@UserIdInt int userId) {
final List<CredentialProviderInfo> services = new ArrayList<>();
public static List<CredentialProviderInfo> getCredentialProviderServices(
@NonNull Context context,
int userId,
boolean disableSystemAppVerificationForTests,
int providerFilter) {
// Get the device policy.
PackagePolicy pp = getDeviceManagerPolicy(context);
// Generate the provider list.
ProviderGenerator generator =
new ProviderGenerator(
context, pp, disableSystemAppVerificationForTests, providerFilter);
generator.addUserProviders(
getUserProviders(context, userId, disableSystemAppVerificationForTests));
generator.addSystemProviders(
getAvailableSystemServices(context, userId, disableSystemAppVerificationForTests));
return generator.getProviders();
}
private static class ProviderGenerator {
private final Context mContext;
private final PackagePolicy mPp;
private final boolean mDisableSystemAppVerificationForTests;
private final Map<String, CredentialProviderInfo> mServices = new HashMap();
private final int mProviderFilter;
ProviderGenerator(
Context context,
PackagePolicy pp,
boolean disableSystemAppVerificationForTests,
int providerFilter) {
this.mContext = context;
this.mPp = pp;
this.mDisableSystemAppVerificationForTests = disableSystemAppVerificationForTests;
this.mProviderFilter = providerFilter;
}
private boolean isPackageAllowed(boolean isSystemProvider, String packageName) {
if (mPp == null) {
return true;
}
if (isSystemProvider) {
return mPp.getPolicyType() == PackagePolicy.PACKAGE_POLICY_ALLOWLIST_AND_SYSTEM;
}
return mPp.isPackageAllowed(packageName, new HashSet<>());
}
public List<CredentialProviderInfo> getProviders() {
return new ArrayList<>(mServices.values());
}
public void addUserProviders(List<CredentialProviderInfo> providers) {
for (CredentialProviderInfo cpi : providers) {
if (!cpi.isSystemProvider()) {
addProvider(cpi);
}
}
}
public void addSystemProviders(List<CredentialProviderInfo> providers) {
for (CredentialProviderInfo cpi : providers) {
if (cpi.isSystemProvider()) {
addProvider(cpi);
}
}
}
private boolean isProviderAllowedWithFilter(CredentialProviderInfo cpi) {
if (mProviderFilter == CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS) {
return true;
}
if (cpi.isSystemProvider()) {
return mProviderFilter == CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY;
} else {
return mProviderFilter == CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY;
}
}
private void addProvider(CredentialProviderInfo cpi) {
final String componentNameString =
cpi.getServiceInfo().getComponentName().flattenToString();
if (!isProviderAllowedWithFilter(cpi)) {
return;
}
if (!isPackageAllowed(cpi.isSystemProvider(), cpi.getServiceInfo().packageName)) {
return;
}
mServices.put(componentNameString, cpi);
}
}
/**
* Returns the valid credential provider services available for the user with the given {@code
* userId}.
*/
@NonNull
private static List<CredentialProviderInfo> getUserProviders(
@NonNull Context context,
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests) {
final List<CredentialProviderInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos =
context.getPackageManager().queryIntentServicesAsUser(
new Intent(CredentialProviderService.SERVICE_INTERFACE),
PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA),
userId);
context.getPackageManager()
.queryIntentServicesAsUser(
new Intent(CredentialProviderService.SERVICE_INTERFACE),
PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA),
userId);
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
try {
services.add(new CredentialProviderInfo(context,
serviceInfo, false));
CredentialProviderInfo cpi =
new CredentialProviderInfo(
context,
serviceInfo,
/* isSystemProvider= */ false,
disableSystemAppVerificationForTests);
if (!cpi.isSystemProvider()) {
services.add(cpi);
}
} catch (SecurityException e) {
Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
} catch (Exception e) {
Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
}
}
return services;
}
/**
* Returns the valid credential provider services available for the user, that can
* support the given {@code credentialType}.
*/
@NonNull
public static List<CredentialProviderInfo> getAvailableServicesForCapability(
@NonNull Context context, @UserIdInt int userId, @NonNull String credentialType) {
List<CredentialProviderInfo> servicesForCapability = new ArrayList<>();
final List<CredentialProviderInfo> services = getAvailableServices(context, userId);
for (CredentialProviderInfo service : services) {
if (service.hasCapability(credentialType)) {
servicesForCapability.add(service);
}
}
return servicesForCapability;
}
}

View File

@@ -157,6 +157,10 @@ public abstract class CredentialProviderService extends Service {
public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities";
/** @hide */
public static final String TEST_SYSTEM_PROVIDER_META_DATA_KEY =
"android.credentials.testsystemprovider";
private Handler mHandler;
/**

View File

@@ -28,10 +28,12 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
import android.credentials.CredentialDescription;
import android.credentials.CredentialManager;
import android.credentials.CredentialOption;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
@@ -110,9 +112,12 @@ public final class CredentialManagerService
private List<CredentialManagerServiceImpl> constructSystemServiceListLocked(
int resolvedUserId) {
List<CredentialManagerServiceImpl> services = new ArrayList<>();
List<CredentialProviderInfo> credentialProviderInfos =
CredentialProviderInfo.getAvailableSystemServices(mContext, resolvedUserId);
credentialProviderInfos.forEach(
List<CredentialProviderInfo> serviceInfos =
CredentialProviderInfo.getAvailableSystemServices(
mContext,
resolvedUserId,
/* disableSystemAppVerificationForTests= */ false);
serviceInfos.forEach(
info -> {
services.add(
new CredentialManagerServiceImpl(this, mLock, resolvedUserId, info));
@@ -209,11 +214,20 @@ public final class CredentialManagerService
}
private boolean hasWriteSecureSettingsPermission() {
final String permission = android.Manifest.permission.WRITE_SECURE_SETTINGS;
return hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
private void verifyPermission(String permission) throws SecurityException {
if (!hasPermission(permission)) {
throw new SecurityException("Caller is missing permission: " + permission);
}
}
private boolean hasPermission(String permission) {
final boolean result =
mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
if (!result) {
Slog.e(TAG, "Caller does not have WRITE_SECURE_SETTINGS permission.");
Slog.e(TAG, "Caller does not have permission: " + permission);
}
return result;
}
@@ -224,7 +238,7 @@ public final class CredentialManagerService
try {
synchronized (mLock) {
final List<CredentialManagerServiceImpl> services =
getAllCredentialProviderServicesLocked(userId);
getCredentialProviderServicesLocked(userId);
for (CredentialManagerServiceImpl s : services) {
c.accept(s);
}
@@ -235,7 +249,7 @@ public final class CredentialManagerService
}
@GuardedBy("mLock")
private List<CredentialManagerServiceImpl> getAllCredentialProviderServicesLocked(int userId) {
private List<CredentialManagerServiceImpl> getCredentialProviderServicesLocked(int userId) {
List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>();
List<CredentialManagerServiceImpl> userConfigurableServices =
getServiceListForUserLocked(userId);
@@ -693,6 +707,23 @@ public final class CredentialManagerService
return false;
}
@Override
public List<ServiceInfo> getCredentialProviderServices(
int userId, boolean disableSystemAppVerificationForTests, int providerFilter) {
Log.i(TAG, "getCredentialProviderServices");
verifyPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS);
List<ServiceInfo> services = new ArrayList<>();
List<CredentialProviderInfo> providers =
CredentialProviderInfo.getCredentialProviderServices(
mContext, userId, disableSystemAppVerificationForTests, providerFilter);
for (CredentialProviderInfo p : providers) {
services.add(p.getServiceInfo());
}
return services;
}
@Override
public ICancellationSignal clearCredentialState(
ClearCredentialStateRequest request,
@@ -748,8 +779,7 @@ public final class CredentialManagerService
enforceCallingPackage(callingPackage, Binder.getCallingUid());
List<CredentialProviderInfo> services =
CredentialProviderInfo.getAvailableServices(
mContext, UserHandle.getCallingUserId());
getServicesForCredentialDescription(UserHandle.getCallingUserId());
List<String> providers =
services.stream()
@@ -801,8 +831,7 @@ public final class CredentialManagerService
enforceCallingPackage(callingPackage, Binder.getCallingUid());
List<CredentialProviderInfo> services =
CredentialProviderInfo.getAvailableServices(
mContext, UserHandle.getCallingUserId());
getServicesForCredentialDescription(UserHandle.getCallingUserId());
List<String> providers =
services.stream()
@@ -820,6 +849,14 @@ public final class CredentialManagerService
session.executeUnregisterRequest(request, callingPackage);
}
private List<CredentialProviderInfo> getServicesForCredentialDescription(int userId) {
return CredentialProviderInfo.getCredentialProviderServices(
mContext,
userId,
/* disableSystemAppVerificationForTests= */ false,
CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS);
}
}
private void enforceCallingPackage(String callingPackage, int callingUid) {

View File

@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.ui.DisabledProviderData;
import android.credentials.ui.IntentFactory;
import android.credentials.ui.ProviderData;
@@ -116,13 +117,17 @@ public class CredentialManagerUi {
Set<String> enabledProviders = providerDataList.stream()
.map(ProviderData::getProviderFlattenedComponentName)
.collect(Collectors.toUnmodifiableSet());
// TODO("Filter out non user configurable providers")
Set<String> allProviders =
CredentialProviderInfo.getAvailableServices(mContext, mUserId).stream()
.map(CredentialProviderInfo::getServiceInfo)
.map(ServiceInfo::getComponentName)
.map(ComponentName::flattenToString)
.collect(Collectors.toUnmodifiableSet());
CredentialProviderInfo.getCredentialProviderServices(
mContext,
mUserId,
/* disableSystemAppVerificationForTests= */ false,
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)
.stream()
.map(CredentialProviderInfo::getServiceInfo)
.map(ServiceInfo::getComponentName)
.map(ComponentName::flattenToString)
.collect(Collectors.toUnmodifiableSet());
for (String provider: allProviders) {
if (!enabledProviders.contains(provider)) {