From 4c15b904f5c5664b406013cd7d72c469567a2115 Mon Sep 17 00:00:00 2001 From: Reema Bajwa Date: Thu, 23 Mar 2023 01:28:40 +0000 Subject: [PATCH] Pass set allowed providers permission to UI Test: local build & deploy + CTS tests Bug: 274667625 Change-Id: Id152608626287269959b66666d83a157e1f2c982 --- .../android/credentials/ui/RequestInfo.java | 38 ++++++++++++-- .../CredentialProviderInfoFactory.java | 26 ++-------- .../service/credentials/PermissionUtils.java | 50 +++++++++++++++++++ .../credentials/CreateRequestSession.java | 6 ++- .../credentials/PrepareGetRequestSession.java | 4 +- .../credentials/ProviderGetSession.java | 21 ++++++-- 6 files changed, 114 insertions(+), 31 deletions(-) create mode 100644 core/java/android/service/credentials/PermissionUtils.java diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java index 49ae9e97b840f..09d2db89a043e 100644 --- a/core/java/android/credentials/ui/RequestInfo.java +++ b/core/java/android/credentials/ui/RequestInfo.java @@ -74,13 +74,30 @@ public final class RequestInfo implements Parcelable { @NonNull private final String mAppPackageName; + private final boolean mHasPermissionToOverrideDefault; + /** Creates new {@code RequestInfo} for a create-credential flow. */ @NonNull public static RequestInfo newCreateRequestInfo( @NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest, @NonNull String appPackageName) { return new RequestInfo( - token, TYPE_CREATE, appPackageName, createCredentialRequest, null); + token, TYPE_CREATE, appPackageName, createCredentialRequest, null, + /*hasPermissionToOverrideDefault=*/ false); + } + + /** + * Creates new {@code RequestInfo} for a create-credential flow. + * + * @hide + */ + @NonNull + public static RequestInfo newCreateRequestInfo( + @NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest, + @NonNull String appPackageName, boolean hasPermissionToOverrideDefault) { + return new RequestInfo( + token, TYPE_CREATE, appPackageName, createCredentialRequest, null, + hasPermissionToOverrideDefault); } /** Creates new {@code RequestInfo} for a get-credential flow. */ @@ -89,7 +106,18 @@ public final class RequestInfo implements Parcelable { @NonNull IBinder token, @NonNull GetCredentialRequest getCredentialRequest, @NonNull String appPackageName) { return new RequestInfo( - token, TYPE_GET, appPackageName, null, getCredentialRequest); + token, TYPE_GET, appPackageName, null, getCredentialRequest, + /*hasPermissionToOverrideDefault=*/ false); + } + + + /** + * Returns whether the calling package has the permission + * + * @hide + */ + public boolean hasPermissionToOverrideDefault() { + return mHasPermissionToOverrideDefault; } /** Returns the request token matching the user request. */ @@ -132,12 +160,14 @@ public final class RequestInfo implements Parcelable { private RequestInfo(@NonNull IBinder token, @NonNull @RequestType String type, @NonNull String appPackageName, @Nullable CreateCredentialRequest createCredentialRequest, - @Nullable GetCredentialRequest getCredentialRequest) { + @Nullable GetCredentialRequest getCredentialRequest, + boolean hasPermissionToOverrideDefault) { mToken = token; mType = type; mAppPackageName = appPackageName; mCreateCredentialRequest = createCredentialRequest; mGetCredentialRequest = getCredentialRequest; + mHasPermissionToOverrideDefault = hasPermissionToOverrideDefault; } private RequestInfo(@NonNull Parcel in) { @@ -157,6 +187,7 @@ public final class RequestInfo implements Parcelable { AnnotationValidations.validate(NonNull.class, null, mAppPackageName); mCreateCredentialRequest = createCredentialRequest; mGetCredentialRequest = getCredentialRequest; + mHasPermissionToOverrideDefault = in.readBoolean(); } @Override @@ -166,6 +197,7 @@ public final class RequestInfo implements Parcelable { dest.writeString8(mAppPackageName); dest.writeTypedObject(mCreateCredentialRequest, flags); dest.writeTypedObject(mGetCredentialRequest, flags); + dest.writeBoolean(mHasPermissionToOverrideDefault); } @Override diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java index 8069414c3e6e7..47b75d1358135 100644 --- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java +++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java @@ -163,28 +163,12 @@ public final class CredentialProviderInfoFactory { private static boolean isSystemProviderWithValidPermission( ServiceInfo serviceInfo, Context context) { - requireNonNull(context, "context must not be null"); - - 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); + if (context == null) { + Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission"); + return false; } - return false; + return PermissionUtils.hasPermission(context, serviceInfo.packageName, + Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE); } private static boolean isValidSystemProvider( diff --git a/core/java/android/service/credentials/PermissionUtils.java b/core/java/android/service/credentials/PermissionUtils.java new file mode 100644 index 0000000000000..c8bb202c35f78 --- /dev/null +++ b/core/java/android/service/credentials/PermissionUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.credentials; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; + +/** + * Utils for checking permissions, or any other permission related function + * + * @hide + */ +public class PermissionUtils { + //TODO(274838409): Move all CredentialManagerService permission checks here + + /** Checks whether the given package name hold the given permission **/ + public static boolean hasPermission(Context context, String packageName, String permission) { + try { + ApplicationInfo appInfo = + context.getPackageManager() + .getApplicationInfo( + packageName, + PackageManager.ApplicationInfoFlags.of( + PackageManager.MATCH_SYSTEM_ONLY)); + if (appInfo != null + && context.checkPermission(permission, /* pid= */ -1, appInfo.uid) + == PackageManager.PERMISSION_GRANTED) { + return true; + } + } catch (PackageManager.NameNotFoundException e) { + } + return false; + } +} + diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 06fe4f0b874b2..687c86190fbdd 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -16,6 +16,7 @@ package com.android.server.credentials; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; @@ -31,6 +32,7 @@ import android.credentials.ui.RequestInfo; import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; +import android.service.credentials.PermissionUtils; import android.util.Log; import com.android.server.credentials.metrics.ApiName; @@ -88,7 +90,9 @@ public final class CreateRequestSession extends RequestSession beginGetOptionToCredentialOptionMap = new HashMap<>(); @@ -120,7 +120,8 @@ public final class ProviderGetSession extends ProviderSession beginGetOptionToCredentialOptionMap = new HashMap<>(); @@ -178,12 +179,13 @@ public final class ProviderGetSession extends ProviderSession providerCapabilities, android.credentials.GetCredentialRequest clientRequest, - ComponentName componentName + CredentialProviderInfo info ) { List filteredOptions = new ArrayList<>(); for (CredentialOption option : clientRequest.getCredentialOptions()) { if (providerCapabilities.contains(option.getType()) - && isProviderAllowed(option, componentName)) { + && isProviderAllowed(option, info.getComponentName()) + && checkSystemProviderRequirement(option, info.isSystemProvider())) { Log.i(TAG, "In createProviderRequest - capability found : " + option.getType()); filteredOptions.add(option); @@ -212,6 +214,15 @@ public final class ProviderGetSession extends ProviderSession callbacks,