From 78959c1313cf76a3f6daa6a7ed1a4e09955c4484 Mon Sep 17 00:00:00 2001 From: Reema Bajwa Date: Wed, 25 Jan 2023 04:11:27 +0000 Subject: [PATCH] Optionally remove calling app info from query phase Test: Built locally Bug: 267948031 API-Coverage-Bug: 247549381 Change-Id: I8272fca0aec600ef46628bd5bee9acc3186680c7 --- core/api/current.txt | 14 ++-- .../credentials/CreateCredentialRequest.java | 65 +++++++++++++++++-- .../credentials/GetCredentialRequest.java | 55 +++++++++++++++- .../BeginCreateCredentialRequest.java | 23 +++++-- .../BeginGetCredentialRequest.java | 21 +++--- .../credentials/ProviderCreateSession.java | 25 +++++-- .../credentials/ProviderGetSession.java | 35 ++++++---- 7 files changed, 192 insertions(+), 46 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index d07ba5449a102..999444e004efd 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -13467,7 +13467,9 @@ package android.credentials { } public final class CreateCredentialRequest implements android.os.Parcelable { + ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle, boolean, boolean); ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle, boolean); + method public boolean alwaysSendAppInfoToProvider(); method public int describeContents(); method @NonNull public android.os.Bundle getCandidateQueryData(); method @NonNull public android.os.Bundle getCredentialData(); @@ -13539,6 +13541,7 @@ package android.credentials { } public final class GetCredentialRequest implements android.os.Parcelable { + method public boolean alwaysSendAppInfoToProvider(); method public int describeContents(); method @NonNull public java.util.List getCredentialOptions(); method @NonNull public android.os.Bundle getData(); @@ -13550,6 +13553,7 @@ package android.credentials { ctor public GetCredentialRequest.Builder(@NonNull android.os.Bundle); method @NonNull public android.credentials.GetCredentialRequest.Builder addCredentialOption(@NonNull android.credentials.CredentialOption); method @NonNull public android.credentials.GetCredentialRequest build(); + method @NonNull public android.credentials.GetCredentialRequest.Builder setAlwaysSendAppInfoToProvider(boolean); method @NonNull public android.credentials.GetCredentialRequest.Builder setCredentialOptions(@NonNull java.util.List); } @@ -40211,9 +40215,10 @@ package android.service.credentials { } public class BeginCreateCredentialRequest implements android.os.Parcelable { - ctor public BeginCreateCredentialRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull String, @NonNull android.os.Bundle); + ctor public BeginCreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle, @Nullable android.service.credentials.CallingAppInfo); + ctor public BeginCreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle); method public int describeContents(); - method @NonNull public android.service.credentials.CallingAppInfo getCallingAppInfo(); + method @Nullable public android.service.credentials.CallingAppInfo getCallingAppInfo(); method @NonNull public android.os.Bundle getData(); method @NonNull public String getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -40248,16 +40253,17 @@ package android.service.credentials { public final class BeginGetCredentialRequest implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List getBeginGetCredentialOptions(); - method @NonNull public android.service.credentials.CallingAppInfo getCallingAppInfo(); + method @Nullable public android.service.credentials.CallingAppInfo getCallingAppInfo(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } public static final class BeginGetCredentialRequest.Builder { - ctor public BeginGetCredentialRequest.Builder(@NonNull android.service.credentials.CallingAppInfo); + ctor public BeginGetCredentialRequest.Builder(); method @NonNull public android.service.credentials.BeginGetCredentialRequest.Builder addBeginGetCredentialOption(@NonNull android.service.credentials.BeginGetCredentialOption); method @NonNull public android.service.credentials.BeginGetCredentialRequest build(); method @NonNull public android.service.credentials.BeginGetCredentialRequest.Builder setBeginGetCredentialOptions(@NonNull java.util.List); + method @NonNull public android.service.credentials.BeginGetCredentialRequest.Builder setCallingAppInfo(@Nullable android.service.credentials.CallingAppInfo); } public final class BeginGetCredentialResponse implements android.os.Parcelable { diff --git a/core/java/android/credentials/CreateCredentialRequest.java b/core/java/android/credentials/CreateCredentialRequest.java index 26f8831003cd8..aec88b9c6f6b3 100644 --- a/core/java/android/credentials/CreateCredentialRequest.java +++ b/core/java/android/credentials/CreateCredentialRequest.java @@ -32,6 +32,18 @@ import com.android.internal.util.Preconditions; */ public final class CreateCredentialRequest implements Parcelable { + /** + * True/false value to determine if the calling app info should be + * sent to the provider at every stage. + * + * Developers must set this to false if they wish to remove the + * {@link android.service.credentials.CallingAppInfo} from the query phase request + * that providers receive. Note, that providers will still receive the app info in + * the final phase after the user has selected the entry. + */ + private final boolean mAlwaysSendAppInfoToProvider; + + /** * The requested credential type. */ @@ -103,12 +115,21 @@ public final class CreateCredentialRequest implements Parcelable { return mIsSystemProviderRequired; } + /** + * Return true/false value to determine if the calling app info should always be sent + * to providers (if true), or removed from the query phase (if false). + */ + public boolean alwaysSendAppInfoToProvider() { + return mAlwaysSendAppInfoToProvider; + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); dest.writeBundle(mCredentialData); dest.writeBundle(mCandidateQueryData); dest.writeBoolean(mIsSystemProviderRequired); + dest.writeBoolean(mAlwaysSendAppInfoToProvider); } @Override @@ -123,9 +144,44 @@ public final class CreateCredentialRequest implements Parcelable { + ", credentialData=" + mCredentialData + ", candidateQueryData=" + mCandidateQueryData + ", isSystemProviderRequired=" + mIsSystemProviderRequired + + ", alwaysSendAppInfoToProvider=" + + mAlwaysSendAppInfoToProvider + "}"; } + /** + * Constructs a {@link CreateCredentialRequest}. + * + * @param type the requested credential type + * @param credentialData the full credential creation request data + * @param candidateQueryData the partial request data that will be sent to the provider + * during the initial creation candidate query stage + * @param isSystemProviderRequired whether the request must only be fulfilled by a system + * provider + * @param alwaysSendAppInfoToProvider whether the + * {@link android.service.credentials.CallingAppInfo} should be propagated to the provider + * at every stage of the request. If set to false, + * the calling app info will be removed from + * the query phase, and will only be sent along + * with the final request, after the user has selected + * an entry on the UI. + * + * @throws IllegalArgumentException If type is empty. + */ + public CreateCredentialRequest( + @NonNull String type, + @NonNull Bundle credentialData, + @NonNull Bundle candidateQueryData, + boolean isSystemProviderRequired, + boolean alwaysSendAppInfoToProvider) { + mType = Preconditions.checkStringNotEmpty(type, "type must not be empty"); + mCredentialData = requireNonNull(credentialData, "credentialData must not be null"); + mCandidateQueryData = requireNonNull(candidateQueryData, + "candidateQueryData must not be null"); + mIsSystemProviderRequired = isSystemProviderRequired; + mAlwaysSendAppInfoToProvider = alwaysSendAppInfoToProvider; + } + /** * Constructs a {@link CreateCredentialRequest}. * @@ -143,11 +199,8 @@ public final class CreateCredentialRequest implements Parcelable { @NonNull Bundle credentialData, @NonNull Bundle candidateQueryData, boolean isSystemProviderRequired) { - mType = Preconditions.checkStringNotEmpty(type, "type must not be empty"); - mCredentialData = requireNonNull(credentialData, "credentialData must not be null"); - mCandidateQueryData = requireNonNull(candidateQueryData, - "candidateQueryData must not be null"); - mIsSystemProviderRequired = isSystemProviderRequired; + this(type, credentialData, candidateQueryData, isSystemProviderRequired, + /*mAlwaysSendAppInfoToProvider=*/true); } private CreateCredentialRequest(@NonNull Parcel in) { @@ -155,6 +208,7 @@ public final class CreateCredentialRequest implements Parcelable { Bundle credentialData = in.readBundle(); Bundle candidateQueryData = in.readBundle(); boolean isSystemProviderRequired = in.readBoolean(); + boolean alwaysSendAppInfoToProvider = in.readBoolean(); mType = type; AnnotationValidations.validate(NonNull.class, null, mType); @@ -163,6 +217,7 @@ public final class CreateCredentialRequest implements Parcelable { mCandidateQueryData = candidateQueryData; AnnotationValidations.validate(NonNull.class, null, mCandidateQueryData); mIsSystemProviderRequired = isSystemProviderRequired; + mAlwaysSendAppInfoToProvider = alwaysSendAppInfoToProvider; } public static final @NonNull Parcelable.Creator CREATOR = diff --git a/core/java/android/credentials/GetCredentialRequest.java b/core/java/android/credentials/GetCredentialRequest.java index a869c5b489061..bc92c7cb148a9 100644 --- a/core/java/android/credentials/GetCredentialRequest.java +++ b/core/java/android/credentials/GetCredentialRequest.java @@ -19,6 +19,7 @@ package android.credentials; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; +import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -47,6 +48,17 @@ public final class GetCredentialRequest implements Parcelable { @NonNull private final Bundle mData; + /** + * True/False value to determine if the calling app info should be + * removed from the request that is sent to the providers. + * Developers must set this to false if they wish to remove the + * {@link android.service.credentials.CallingAppInfo} from the query phases requests that + * providers receive. + * If not set, the default value will be true and the calling app info will be + * propagated to the providers. + */ + private final boolean mAlwaysSendAppInfoToProvider; + /** * Returns the list of credential options to be requested. */ @@ -63,10 +75,21 @@ public final class GetCredentialRequest implements Parcelable { return mData; } + /** + * Returns a value to determine if the calling app info should be always + * sent to the provider in every phase (if true), or should be removed + * from the query phase, and only sent as part of the request in the final phase, + * after the user has made a selection on the UI (if false). + */ + public boolean alwaysSendAppInfoToProvider() { + return mAlwaysSendAppInfoToProvider; + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeTypedList(mCredentialOptions, flags); dest.writeBundle(mData); + dest.writeBoolean(mAlwaysSendAppInfoToProvider); } @Override @@ -78,11 +101,13 @@ public final class GetCredentialRequest implements Parcelable { public String toString() { return "GetCredentialRequest {credentialOption=" + mCredentialOptions + ", data=" + mData + + ", alwaysSendAppInfoToProvider=" + + mAlwaysSendAppInfoToProvider + "}"; } private GetCredentialRequest(@NonNull List credentialOptions, - @NonNull Bundle data) { + @NonNull Bundle data, @NonNull boolean alwaysSendAppInfoToProvider) { Preconditions.checkCollectionNotEmpty( credentialOptions, /*valueName=*/ "credentialOptions"); @@ -92,6 +117,7 @@ public final class GetCredentialRequest implements Parcelable { mCredentialOptions = credentialOptions; mData = requireNonNull(data, "data must not be null"); + mAlwaysSendAppInfoToProvider = alwaysSendAppInfoToProvider; } private GetCredentialRequest(@NonNull Parcel in) { @@ -104,6 +130,8 @@ public final class GetCredentialRequest implements Parcelable { Bundle data = in.readBundle(); mData = data; AnnotationValidations.validate(NonNull.class, null, mData); + + mAlwaysSendAppInfoToProvider = in.readBoolean(); } @NonNull public static final Parcelable.Creator CREATOR = @@ -128,6 +156,9 @@ public final class GetCredentialRequest implements Parcelable { @NonNull private final Bundle mData; + @NonNull + private boolean mAlwaysSendAppInfoToProvider = true; + /** * @param data the top request level data */ @@ -145,6 +176,25 @@ public final class GetCredentialRequest implements Parcelable { return this; } + /** + * Sets a true/false value to determine if the calling app info should be + * removed from the request that is sent to the providers. + * + * Developers must set this to false if they wish to remove the + * {@link android.service.credentials.CallingAppInfo} from the query phases requests that + * providers receive. Note that the calling app info will still be sent in the + * final phase after the user has made a selection on the UI. + * + * If not set, the default value will be true and the calling app info will be + * propagated to the providers in every phase. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setAlwaysSendAppInfoToProvider(boolean value) { + mAlwaysSendAppInfoToProvider = value; + return this; + } + /** * Sets the list of {@link CredentialOption}. */ @@ -171,7 +221,8 @@ public final class GetCredentialRequest implements Parcelable { Preconditions.checkCollectionElementsNotNull( mCredentialOptions, /*valueName=*/ "credentialOptions"); - return new GetCredentialRequest(mCredentialOptions, mData); + return new GetCredentialRequest(mCredentialOptions, mData, + mAlwaysSendAppInfoToProvider); } } } diff --git a/core/java/android/service/credentials/BeginCreateCredentialRequest.java b/core/java/android/service/credentials/BeginCreateCredentialRequest.java index 348bb2b810d7e..e9f7c8a639e40 100644 --- a/core/java/android/service/credentials/BeginCreateCredentialRequest.java +++ b/core/java/android/service/credentials/BeginCreateCredentialRequest.java @@ -17,6 +17,7 @@ package android.service.credentials; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Parcel; @@ -38,7 +39,7 @@ import java.util.Objects; */ @SuppressLint("ParcelNotFinal") public class BeginCreateCredentialRequest implements Parcelable { - private final @NonNull CallingAppInfo mCallingAppInfo; + private final @Nullable CallingAppInfo mCallingAppInfo; private final @NonNull String mType; private final @NonNull Bundle mData; @@ -49,13 +50,23 @@ public class BeginCreateCredentialRequest implements Parcelable { * null or empty. * @throws NullPointerException If {@code data} is null. */ - public BeginCreateCredentialRequest(@NonNull CallingAppInfo callingAppInfo, - @NonNull String type, @NonNull Bundle data) { - mCallingAppInfo = Objects.requireNonNull(callingAppInfo, - "callingAppInfo must not be null"); + public BeginCreateCredentialRequest(@NonNull String type, @NonNull Bundle data, + @Nullable CallingAppInfo callingAppInfo) { mType = Preconditions.checkStringNotEmpty(type, "type must not be null or empty"); mData = Objects.requireNonNull(data, "data must not be null"); + mCallingAppInfo = callingAppInfo; + } + + /** + * Constructs a new instance without {@link CallingAppInfo}. + * + * @throws IllegalArgumentException If {{@code type} string is + * null or empty. + * @throws NullPointerException If {@code data} is null. + */ + public BeginCreateCredentialRequest(@NonNull String type, @NonNull Bundle data) { + this(type, data, /*callingAppInfo=*/null); } private BeginCreateCredentialRequest(@NonNull Parcel in) { @@ -90,7 +101,7 @@ public class BeginCreateCredentialRequest implements Parcelable { } /** Returns the info pertaining to the calling app. */ - @NonNull + @Nullable public CallingAppInfo getCallingAppInfo() { return mCallingAppInfo; } diff --git a/core/java/android/service/credentials/BeginGetCredentialRequest.java b/core/java/android/service/credentials/BeginGetCredentialRequest.java index 1e04739068326..48b2b0593f1da 100644 --- a/core/java/android/service/credentials/BeginGetCredentialRequest.java +++ b/core/java/android/service/credentials/BeginGetCredentialRequest.java @@ -17,6 +17,7 @@ package android.service.credentials; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Intent; import android.os.Parcel; @@ -43,7 +44,7 @@ import java.util.Objects; */ public final class BeginGetCredentialRequest implements Parcelable { /** Info pertaining to the app requesting for credentials. */ - @NonNull private final CallingAppInfo mCallingAppInfo; + @Nullable private final CallingAppInfo mCallingAppInfo; /** * List of credential options. Each {@link BeginGetCredentialOption} object holds parameters to @@ -56,7 +57,7 @@ public final class BeginGetCredentialRequest implements Parcelable { */ @NonNull private final List mBeginGetCredentialOptions; - private BeginGetCredentialRequest(@NonNull CallingAppInfo callingAppInfo, + private BeginGetCredentialRequest(@Nullable CallingAppInfo callingAppInfo, @NonNull List getBeginCredentialOptions) { this.mCallingAppInfo = callingAppInfo; this.mBeginGetCredentialOptions = getBeginCredentialOptions; @@ -98,7 +99,7 @@ public final class BeginGetCredentialRequest implements Parcelable { /** * Returns info pertaining to the app requesting credentials. */ - public @NonNull CallingAppInfo getCallingAppInfo() { + public @Nullable CallingAppInfo getCallingAppInfo() { return mCallingAppInfo; } @@ -114,17 +115,16 @@ public final class BeginGetCredentialRequest implements Parcelable { * Builder for {@link BeginGetCredentialRequest}. */ public static final class Builder { - private CallingAppInfo mCallingAppInfo; + private CallingAppInfo mCallingAppInfo = null; private List mBeginGetCredentialOptions = new ArrayList<>(); /** - * Creates a new builder. - * @param callingAppInfo info pertaining to the app requesting credentials - * - * @throws IllegalArgumentException If {@code callingAppInfo} is null or empty. + * Sets information pertaining to the calling app. + * @param callingAppInfo the info object containing the package name, and app signatures */ - public Builder(@NonNull CallingAppInfo callingAppInfo) { - mCallingAppInfo = Objects.requireNonNull(callingAppInfo); + public @NonNull Builder setCallingAppInfo(@Nullable CallingAppInfo callingAppInfo) { + mCallingAppInfo = callingAppInfo; + return this; } /** @@ -165,7 +165,6 @@ public final class BeginGetCredentialRequest implements Parcelable { * {@code callingAppInfo} is null or empty. */ public @NonNull BeginGetCredentialRequest build() { - Objects.requireNonNull(mCallingAppInfo, "callingAppInfo"); Preconditions.checkCollectionNotEmpty(mBeginGetCredentialOptions, "beginGetCredentialOptions"); return new BeginGetCredentialRequest(mCallingAppInfo, mBeginGetCredentialOptions); diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java index ade40ad064ee0..ec983df8836b0 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java @@ -26,6 +26,7 @@ import android.credentials.CreateCredentialResponse; import android.credentials.ui.CreateCredentialProviderData; import android.credentials.ui.Entry; import android.credentials.ui.ProviderPendingIntentResponse; +import android.os.Bundle; import android.service.credentials.BeginCreateCredentialRequest; import android.service.credentials.BeginCreateCredentialResponse; import android.service.credentials.CallingAppInfo; @@ -74,10 +75,11 @@ public final class ProviderCreateSession extends ProviderSession< createRequestSession.mClientAppInfo); if (providerCreateRequest != null) { BeginCreateCredentialRequest providerBeginCreateRequest = - new BeginCreateCredentialRequest( - providerCreateRequest.getCallingAppInfo(), - providerCreateRequest.getType(), - createRequestSession.mClientRequest.getCandidateQueryData()); + constructQueryPhaseRequest(createRequestSession.mClientRequest.getType(), + createRequestSession.mClientRequest.getCandidateQueryData(), + createRequestSession.mClientAppInfo, + createRequestSession + .mClientRequest.alwaysSendAppInfoToProvider()); return new ProviderCreateSession(context, providerInfo, createRequestSession, userId, remoteCredentialService, providerBeginCreateRequest, providerCreateRequest); } @@ -85,6 +87,21 @@ public final class ProviderCreateSession extends ProviderSession< return null; } + private static BeginCreateCredentialRequest constructQueryPhaseRequest( + String type, Bundle candidateQueryData, CallingAppInfo callingAppInfo, + boolean propagateToProvider) { + if (propagateToProvider) { + return new BeginCreateCredentialRequest( + type, + candidateQueryData + ); + } + return new BeginCreateCredentialRequest( + type, + candidateQueryData, + callingAppInfo); + } + @Nullable private static CreateCredentialRequest createProviderRequest(List providerCapabilities, android.credentials.CreateCredentialRequest clientRequest, diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index ead2acbd933ba..1583b83c5b2ff 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -92,9 +92,11 @@ public final class ProviderGetSession extends ProviderSession new BeginGetCredentialOption( - option.getType(), - option.getCandidateQueryData())).collect(Collectors - .toList())) - .build(); + CallingAppInfo callingAppInfo, + boolean propagateToProvider) { + BeginGetCredentialRequest.Builder builder = new BeginGetCredentialRequest.Builder(); + builder.setBeginGetCredentialOptions( + filteredRequest.getCredentialOptions().stream().map( + option -> { + return new BeginGetCredentialOption( + option.getType(), + option.getCandidateQueryData()); + }).collect(Collectors.toList())); + if (propagateToProvider) { + builder.setCallingAppInfo(callingAppInfo); + } + return builder.build(); } @Nullable @@ -145,10 +151,11 @@ public final class ProviderGetSession extends ProviderSession callbacks, int userId, RemoteCredentialService remoteCredentialService, BeginGetCredentialRequest beginGetRequest, - android.credentials.GetCredentialRequest completeGetRequest) { + android.credentials.GetCredentialRequest completeGetRequest, + CallingAppInfo callingAppInfo) { super(context, info, beginGetRequest, callbacks, userId, remoteCredentialService); mCompleteRequest = completeGetRequest; - mCallingAppInfo = beginGetRequest.getCallingAppInfo(); + mCallingAppInfo = callingAppInfo; setStatus(Status.PENDING); }