diff options
| author | 2023-02-18 00:36:31 +0000 | |
|---|---|---|
| committer | 2023-02-22 17:20:07 +0000 | |
| commit | 9eb577e6cf16fea86e17959834e070f280a230ff (patch) | |
| tree | fbabefc9ccc3652c12acb76c638295a05367bf5f | |
| parent | 79d1135cb8913dbbb4e87e2d324394e830fc8165 (diff) | |
Refactor origin to request object for the credential manager privilege APIs
Bug: 268534702
DetailedCoverageBugs: 255429881, 255429478
Test: local-deployment
Change-Id: Id40024989f19d3bd806201b0007b301185064b76
9 files changed, 277 insertions, 209 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 2968b59e16c9..b03c1cdca7ca 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -13576,17 +13576,26 @@ 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); method public boolean alwaysSendAppInfoToProvider(); method public int describeContents(); method @NonNull public android.os.Bundle getCandidateQueryData(); method @NonNull public android.os.Bundle getCredentialData(); + method @Nullable public String getOrigin(); method @NonNull public String getType(); method public boolean isSystemProviderRequired(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CreateCredentialRequest> CREATOR; } + public static final class CreateCredentialRequest.Builder { + ctor public CreateCredentialRequest.Builder(@NonNull android.os.Bundle, @NonNull android.os.Bundle); + method @NonNull public android.credentials.CreateCredentialRequest build(); + method @NonNull public android.credentials.CreateCredentialRequest.Builder setAlwaysSendAppInfoToProvider(boolean); + method @NonNull public android.credentials.CreateCredentialRequest.Builder setIsSystemProviderRequired(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN) public android.credentials.CreateCredentialRequest.Builder setOrigin(@NonNull String); + method @NonNull public android.credentials.CreateCredentialRequest.Builder setType(@NonNull String); + } + public final class CreateCredentialResponse implements android.os.Parcelable { ctor public CreateCredentialResponse(@NonNull android.os.Bundle); method public int describeContents(); @@ -13618,9 +13627,7 @@ package android.credentials { public final class CredentialManager { method public void clearCredentialState(@NonNull android.credentials.ClearCredentialStateRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException>); method public void createCredential(@NonNull android.credentials.CreateCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CreateCredentialException>); - method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN) public void createCredentialWithOrigin(@NonNull android.credentials.CreateCredentialRequest, @Nullable String, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CreateCredentialException>); method public void getCredential(@NonNull android.credentials.GetCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>); - method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN) public void getCredentialWithOrigin(@NonNull android.credentials.GetCredentialRequest, @Nullable String, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>); method public boolean isEnabledCredentialProviderService(@NonNull android.content.ComponentName); method public void registerCredentialDescription(@NonNull android.credentials.RegisterCredentialDescriptionRequest); method public void unregisterCredentialDescription(@NonNull android.credentials.UnregisterCredentialDescriptionRequest); @@ -13655,6 +13662,7 @@ package android.credentials { method public int describeContents(); method @NonNull public java.util.List<android.credentials.CredentialOption> getCredentialOptions(); method @NonNull public android.os.Bundle getData(); + method @Nullable public String getOrigin(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.credentials.GetCredentialRequest> CREATOR; } @@ -13665,6 +13673,7 @@ package android.credentials { 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<android.credentials.CredentialOption>); + method @NonNull @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN) public android.credentials.GetCredentialRequest.Builder setOrigin(@NonNull String); } public final class GetCredentialResponse implements android.os.Parcelable { @@ -40560,7 +40569,9 @@ package android.service.credentials { public final class CallingAppInfo implements android.os.Parcelable { ctor public CallingAppInfo(@NonNull String, @NonNull android.content.pm.SigningInfo); + ctor public CallingAppInfo(@NonNull String, @NonNull android.content.pm.SigningInfo, @Nullable String); method public int describeContents(); + method @Nullable public String getOrigin(); method @NonNull public String getPackageName(); method @NonNull public android.content.pm.SigningInfo getSigningInfo(); method public void writeToParcel(@NonNull android.os.Parcel, int); diff --git a/core/java/android/credentials/CreateCredentialRequest.java b/core/java/android/credentials/CreateCredentialRequest.java index 1e2a86f2ed11..b756a4323842 100644 --- a/core/java/android/credentials/CreateCredentialRequest.java +++ b/core/java/android/credentials/CreateCredentialRequest.java @@ -16,9 +16,14 @@ package android.credentials; +import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN; + import static java.util.Objects.requireNonNull; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -69,6 +74,14 @@ public final class CreateCredentialRequest implements Parcelable { private final boolean mIsSystemProviderRequired; /** + * The origin of the calling app. Callers of this special API (e.g. browsers) + * can set this origin for an app different from their own, to be able to get credentials + * on behalf of that app. + */ + @Nullable + private final String mOrigin; + + /** * Returns the requested credential type. */ @NonNull @@ -123,6 +136,14 @@ public final class CreateCredentialRequest implements Parcelable { return mAlwaysSendAppInfoToProvider; } + /** + * Returns the origin of the calling app if set otherwise returns null. + */ + @Nullable + public String getOrigin() { + return mOrigin; + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); @@ -130,6 +151,7 @@ public final class CreateCredentialRequest implements Parcelable { dest.writeBundle(mCandidateQueryData); dest.writeBoolean(mIsSystemProviderRequired); dest.writeBoolean(mAlwaysSendAppInfoToProvider); + dest.writeString8(mOrigin); } @Override @@ -146,6 +168,7 @@ public final class CreateCredentialRequest implements Parcelable { + ", isSystemProviderRequired=" + mIsSystemProviderRequired + ", alwaysSendAppInfoToProvider=" + mAlwaysSendAppInfoToProvider + + ", origin=" + mOrigin + "}"; } @@ -165,21 +188,26 @@ public final class CreateCredentialRequest implements Parcelable { * the query phase, and will only be sent along * with the final request, after the user has selected * an entry on the UI. + * @param origin the origin of the calling app. Callers of this special setter (e.g. browsers) + * can set this origin for an app different from their own, to be able to get + * credentials on behalf of that app. * * @throws IllegalArgumentException If type is empty. */ - public CreateCredentialRequest( + private CreateCredentialRequest( @NonNull String type, @NonNull Bundle credentialData, @NonNull Bundle candidateQueryData, boolean isSystemProviderRequired, - boolean alwaysSendAppInfoToProvider) { + boolean alwaysSendAppInfoToProvider, + @NonNull String origin) { 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; + mOrigin = origin; } private CreateCredentialRequest(@NonNull Parcel in) { @@ -188,6 +216,7 @@ public final class CreateCredentialRequest implements Parcelable { Bundle candidateQueryData = in.readBundle(); boolean isSystemProviderRequired = in.readBoolean(); boolean alwaysSendAppInfoToProvider = in.readBoolean(); + mOrigin = in.readString8(); mType = type; AnnotationValidations.validate(NonNull.class, null, mType); @@ -211,4 +240,104 @@ public final class CreateCredentialRequest implements Parcelable { return new CreateCredentialRequest(in); } }; + + /** A builder for {@link CreateCredentialRequest}. */ + public static final class Builder { + + private boolean mAlwaysSendAppInfoToProvider; + + @NonNull + private String mType; + + @NonNull + private final Bundle mCredentialData; + + @NonNull + private final Bundle mCandidateQueryData; + + private boolean mIsSystemProviderRequired; + + private String mOrigin; + + /** + * @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 + */ + public Builder(@NonNull Bundle credentialData, @NonNull Bundle candidateQueryData) { + mCredentialData = requireNonNull(credentialData, + "credentialData must not be null"); + mCandidateQueryData = requireNonNull(candidateQueryData, + "candidateQueryData must not be null"); + } + + /** + * 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 CreateCredentialRequest.Builder setAlwaysSendAppInfoToProvider(boolean value) { + mAlwaysSendAppInfoToProvider = value; + return this; + } + + /** + * Sets the requested credential type. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public CreateCredentialRequest.Builder setType(@NonNull String type) { + mType = type; + return this; + } + + /** + * Sets whether the request must only be fulfilled by a system provider. + * This defaults to false + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public CreateCredentialRequest.Builder setIsSystemProviderRequired(boolean value) { + mIsSystemProviderRequired = value; + return this; + } + + /** + * Sets the origin of the calling app. Callers of this special setter (e.g. browsers) + * can set this origin for an app different from their own, to be able to get + * credentials on behalf of that app. The permission check only happens later when this + * instance is passed and processed by the Credential Manager. + */ + @SuppressLint({"MissingGetterMatchingBuilder", "AndroidFrameworkRequiresPermission"}) + @RequiresPermission(CREDENTIAL_MANAGER_SET_ORIGIN) + @NonNull + public CreateCredentialRequest.Builder setOrigin(@NonNull String origin) { + mOrigin = origin; + return this; + } + + /** + * Builds a {@link GetCredentialRequest}. + * + * @throws IllegalArgumentException If credentialOptions is empty. + */ + @NonNull + public CreateCredentialRequest build() { + Preconditions.checkStringNotEmpty( + mType, + "type must not be empty"); + + return new CreateCredentialRequest(mType, mCredentialData, mCandidateQueryData, + mIsSystemProviderRequired, mAlwaysSendAppInfoToProvider, mOrigin); + } + } } diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index ff7fc36e355d..f99994f9b85b 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -123,6 +123,10 @@ public final class CredentialManager { * * <p>The execution can potentially launch UI flows to collect user consent to using a * credential, display a picker when multiple credentials exist, etc. + * Callers (e.g. browsers) may optionally set origin in {@link GetCredentialRequest} for an + * app different from their own, to be able to get credentials on behalf of that app. They would + * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN} + * to use this functionality * * @param request the request specifying type(s) of credentials to get from the user * @param activity the activity used to launch any UI needed @@ -163,61 +167,14 @@ public final class CredentialManager { } /** - * Launches the necessary flows to retrieve an app credential from the user, for the given - * origin. - * - * <p>The execution can potentially launch UI flows to collect user consent to using a - * credential, display a picker when multiple credentials exist, etc. - * - * @param request the request specifying type(s) of credentials to get from the user - * @param origin the origin of the calling app. Callers of this special API (e.g. browsers) - * can set this origin for an app different from their own, to be able to get credentials - * on behalf of that app. - * @param activity the activity used to launch any UI needed - * @param cancellationSignal an optional signal that allows for cancelling this call - * @param executor the callback will take place on this {@link Executor} - * @param callback the callback invoked when the request succeeds or fails - */ - @RequiresPermission(CREDENTIAL_MANAGER_SET_ORIGIN) - public void getCredentialWithOrigin( - @NonNull GetCredentialRequest request, - @Nullable String origin, - @NonNull Activity activity, - @Nullable CancellationSignal cancellationSignal, - @CallbackExecutor @NonNull Executor executor, - @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { - requireNonNull(request, "request must not be null"); - requireNonNull(activity, "activity must not be null"); - requireNonNull(executor, "executor must not be null"); - requireNonNull(callback, "callback must not be null"); - - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - Log.w(TAG, "getCredential already canceled"); - return; - } - - ICancellationSignal cancelRemote = null; - try { - cancelRemote = - mService.executeGetCredentialWithOrigin( - request, - new GetCredentialTransport(activity, executor, callback), - mContext.getOpPackageName(), - origin); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - - if (cancellationSignal != null && cancelRemote != null) { - cancellationSignal.setRemote(cancelRemote); - } - } - - /** * Launches the necessary flows to register an app credential for the user. * * <p>The execution can potentially launch UI flows to collect user consent to creating or * storing the new credential, etc. + * Callers (e.g. browsers) may optionally set origin in {@link CreateCredentialRequest} for an + * app different from their own, to be able to get credentials on behalf of that app. They would + * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN} + * to use this functionality * * @param request the request specifying type(s) of credentials to get from the user * @param activity the activity used to launch any UI needed @@ -259,58 +216,6 @@ public final class CredentialManager { } /** - * Launches the necessary flows to register an app credential for the user. - * - * <p>The execution can potentially launch UI flows to collect user consent to creating or - * storing the new credential, etc. - * - * @param request the request specifying type(s) of credentials to get from the user, for the - * given origin - * @param origin the origin of the calling app. Callers of this special API (e.g. browsers) - * can set this origin for an app different from their own, to be able to get credentials - * on behalf of that app. - * @param activity the activity used to launch any UI needed - * @param cancellationSignal an optional signal that allows for cancelling this call - * @param executor the callback will take place on this {@link Executor} - * @param callback the callback invoked when the request succeeds or fails - */ - @RequiresPermission(CREDENTIAL_MANAGER_SET_ORIGIN) - public void createCredentialWithOrigin( - @NonNull CreateCredentialRequest request, - @Nullable String origin, - @NonNull Activity activity, - @Nullable CancellationSignal cancellationSignal, - @CallbackExecutor @NonNull Executor executor, - @NonNull - OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) { - requireNonNull(request, "request must not be null"); - requireNonNull(activity, "activity must not be null"); - requireNonNull(executor, "executor must not be null"); - requireNonNull(callback, "callback must not be null"); - - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - Log.w(TAG, "createCredential already canceled"); - return; - } - - ICancellationSignal cancelRemote = null; - try { - cancelRemote = - mService.executeCreateCredentialWithOrigin( - request, - new CreateCredentialTransport(activity, executor, callback), - mContext.getOpPackageName(), - origin); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - - if (cancellationSignal != null && cancelRemote != null) { - cancellationSignal.setRemote(cancelRemote); - } - } - - /** * Clears the current user credential state from all credential providers. * * <p>You should invoked this api after your user signs out of your app to notify all credential diff --git a/core/java/android/credentials/GetCredentialRequest.java b/core/java/android/credentials/GetCredentialRequest.java index bc92c7cb148a..951cbe4e58c0 100644 --- a/core/java/android/credentials/GetCredentialRequest.java +++ b/core/java/android/credentials/GetCredentialRequest.java @@ -16,9 +16,13 @@ package android.credentials; +import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN; + import static java.util.Objects.requireNonNull; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Parcel; @@ -49,6 +53,14 @@ public final class GetCredentialRequest implements Parcelable { private final Bundle mData; /** + * The origin of the calling app. Callers of this special API (e.g. browsers) + * can set this origin for an app different from their own, to be able to get credentials + * on behalf of that app. + */ + @Nullable + private String mOrigin; + + /** * 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 @@ -76,6 +88,14 @@ public final class GetCredentialRequest implements Parcelable { } /** + * Returns the origin of the calling app if set otherwise returns null. + */ + @Nullable + public String getOrigin() { + return mOrigin; + } + + /** * 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, @@ -90,6 +110,7 @@ public final class GetCredentialRequest implements Parcelable { dest.writeTypedList(mCredentialOptions, flags); dest.writeBundle(mData); dest.writeBoolean(mAlwaysSendAppInfoToProvider); + dest.writeString8(mOrigin); } @Override @@ -103,11 +124,12 @@ public final class GetCredentialRequest implements Parcelable { + ", data=" + mData + ", alwaysSendAppInfoToProvider=" + mAlwaysSendAppInfoToProvider + + ", origin=" + mOrigin + "}"; } private GetCredentialRequest(@NonNull List<CredentialOption> credentialOptions, - @NonNull Bundle data, @NonNull boolean alwaysSendAppInfoToProvider) { + @NonNull Bundle data, @NonNull boolean alwaysSendAppInfoToProvider, String origin) { Preconditions.checkCollectionNotEmpty( credentialOptions, /*valueName=*/ "credentialOptions"); @@ -118,6 +140,7 @@ public final class GetCredentialRequest implements Parcelable { mData = requireNonNull(data, "data must not be null"); mAlwaysSendAppInfoToProvider = alwaysSendAppInfoToProvider; + mOrigin = origin; } private GetCredentialRequest(@NonNull Parcel in) { @@ -132,6 +155,7 @@ public final class GetCredentialRequest implements Parcelable { AnnotationValidations.validate(NonNull.class, null, mData); mAlwaysSendAppInfoToProvider = in.readBoolean(); + mOrigin = in.readString8(); } @NonNull public static final Parcelable.Creator<GetCredentialRequest> CREATOR = @@ -159,6 +183,8 @@ public final class GetCredentialRequest implements Parcelable { @NonNull private boolean mAlwaysSendAppInfoToProvider = true; + private String mOrigin; + /** * @param data the top request level data */ @@ -209,6 +235,20 @@ public final class GetCredentialRequest implements Parcelable { } /** + * Sets the origin of the calling app. Callers of this special setter (e.g. browsers) + * can set this origin for an app different from their own, to be able to get + * credentials on behalf of that app. The permission check only happens later when this + * instance is passed and processed by the Credential Manager. + */ + @SuppressLint({"MissingGetterMatchingBuilder", "AndroidFrameworkRequiresPermission"}) + @RequiresPermission(CREDENTIAL_MANAGER_SET_ORIGIN) + @NonNull + public Builder setOrigin(@NonNull String origin) { + mOrigin = origin; + return this; + } + + /** * Builds a {@link GetCredentialRequest}. * * @throws IllegalArgumentException If credentialOptions is empty. @@ -222,7 +262,7 @@ public final class GetCredentialRequest implements Parcelable { mCredentialOptions, /*valueName=*/ "credentialOptions"); return new GetCredentialRequest(mCredentialOptions, mData, - mAlwaysSendAppInfoToProvider); + mAlwaysSendAppInfoToProvider, mOrigin); } } } diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl index 6d81d80d249c..625fc8ab5dad 100644 --- a/core/java/android/credentials/ICredentialManager.aidl +++ b/core/java/android/credentials/ICredentialManager.aidl @@ -41,12 +41,8 @@ interface ICredentialManager { @nullable ICancellationSignal executeGetCredential(in GetCredentialRequest request, in IGetCredentialCallback callback, String callingPackage); - @nullable ICancellationSignal executeGetCredentialWithOrigin(in GetCredentialRequest request, in IGetCredentialCallback callback, String callingPackage, String origin); - @nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage); - @nullable ICancellationSignal executeCreateCredentialWithOrigin(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage, String origin); - @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage); @nullable ICancellationSignal listEnabledProviders(in IListEnabledProvidersCallback callback); diff --git a/core/java/android/service/credentials/CallingAppInfo.java b/core/java/android/service/credentials/CallingAppInfo.java index fba91d457236..e755581638f5 100644 --- a/core/java/android/service/credentials/CallingAppInfo.java +++ b/core/java/android/service/credentials/CallingAppInfo.java @@ -17,6 +17,7 @@ package android.service.credentials; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.pm.SigningInfo; import android.os.Parcel; import android.os.Parcelable; @@ -32,6 +33,8 @@ import java.util.Objects; public final class CallingAppInfo implements Parcelable { @NonNull private final String mPackageName; @NonNull private final SigningInfo mSigningInfo; + @Nullable + private final String mOrigin; /** * Constructs a new instance. @@ -41,14 +44,31 @@ public final class CallingAppInfo implements Parcelable { */ public CallingAppInfo(@NonNull String packageName, @NonNull SigningInfo signingInfo) { + this(packageName, signingInfo, /*origin=*/ null); + } + + /** + * Constructs a new instance. + * + * @param packageName - the package name of the calling app + * @param signingInfo - the signing info on the calling app + * @param origin - the origin that the calling app wants to use when making request on behalf of + * other + * @throws IllegalArgumentException If {@code packageName} is null or empty. + * @throws NullPointerException If {@code signingInfo} is null. + */ + public CallingAppInfo(@NonNull String packageName, + @NonNull SigningInfo signingInfo, @Nullable String origin) { mPackageName = Preconditions.checkStringNotEmpty(packageName, "package name" + "must not be null or empty"); mSigningInfo = Objects.requireNonNull(signingInfo); + mOrigin = origin; } private CallingAppInfo(@NonNull Parcel in) { mPackageName = in.readString8(); mSigningInfo = in.readTypedObject(SigningInfo.CREATOR); + mOrigin = in.readString8(); } public static final @NonNull Creator<CallingAppInfo> CREATOR = new Creator<CallingAppInfo>() { @@ -76,6 +96,22 @@ public final class CallingAppInfo implements Parcelable { return mSigningInfo; } + /** + * Returns the origin of the calling app if set otherwise returns null. + * This value is set only if the origin is different than that of the calling app, + * and should be expected from privileged callers(browsers) only when making request on behalf + * of other applications. + * + * Android system makes sure that only applications that poses the permission + * {@link android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN} can set the origin on + * the incoming {@link android.credentials.GetCredentialRequest} or + * {@link android.credentials.CreateCredentialRequest}. + */ + @Nullable + public String getOrigin() { + return mOrigin; + } + @Override public int describeContents() { return 0; @@ -85,6 +121,7 @@ public final class CallingAppInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mPackageName); dest.writeTypedObject(mSigningInfo, flags); + dest.writeString8(mOrigin); } @Override @@ -97,6 +134,7 @@ public final class CallingAppInfo implements Parcelable { } else { builder.append(", mSigningInfo: null"); } + builder.append(",mOrigin: " + mOrigin); builder.append(" }"); return builder.toString(); } diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java index 444e9f222ddc..102320a0f4c0 100644 --- a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java +++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java @@ -102,8 +102,11 @@ public class CredentialManagerTest { mGetRequest = new GetCredentialRequest.Builder(Bundle.EMPTY).addCredentialOption( new CredentialOption(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY, Bundle.EMPTY, false)).build(); - mCreateRequest = new CreateCredentialRequest(Credential.TYPE_PASSWORD_CREDENTIAL, - Bundle.EMPTY, Bundle.EMPTY, false, false); + mCreateRequest = new CreateCredentialRequest.Builder(Bundle.EMPTY, Bundle.EMPTY) + .setType(Credential.TYPE_PASSWORD_CREDENTIAL) + .setIsSystemProviderRequired(false) + .setAlwaysSendAppInfoToProvider(false) + .build(); mClearRequest = new ClearCredentialStateRequest(Bundle.EMPTY); final Slice slice = new Slice.Builder(Uri.parse("foo://bar"), null).addText("some text", diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index 0d25bece62a6..e3236b38b0f7 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -402,30 +402,26 @@ class CredentialManagerRepo( ) val credentialData = request.credentialData return RequestInfo.newCreateRequestInfo( - Binder(), - CreateCredentialRequest( - "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL", - credentialData, - /*candidateQueryData=*/ Bundle(), - /*isSystemProviderRequired=*/ false, - /*alwaysSendAppInfoToProvider=*/ true - ), - "com.google.android.youtube" + Binder(), + CreateCredentialRequest.Builder(credentialData, Bundle()) + .setType("androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL") + .setIsSystemProviderRequired(false) + .setAlwaysSendAppInfoToProvider(true) + .build(), + "com.google.android.youtube" ) } private fun testCreatePasswordRequestInfo(): RequestInfo { val request = CreatePasswordRequest("beckett-bakert@gmail.com", "password123") return RequestInfo.newCreateRequestInfo( - Binder(), - CreateCredentialRequest( - TYPE_PASSWORD_CREDENTIAL, - request.credentialData, - request.candidateQueryData, - /*isSystemProviderRequired=*/ false, - /*alwaysSendAppInfoToProvider=*/ true - ), - "com.google.android.youtube" + Binder(), + CreateCredentialRequest.Builder(request.credentialData, request.candidateQueryData) + .setType(TYPE_PASSWORD_CREDENTIAL) + .setIsSystemProviderRequired(false) + .setAlwaysSendAppInfoToProvider(true) + .build(), + "com.google.android.youtube" ) } @@ -437,15 +433,13 @@ class CredentialManagerRepo( displayInfo.toBundle() ) return RequestInfo.newCreateRequestInfo( - Binder(), - CreateCredentialRequest( - "other-sign-ins", - data, - /*candidateQueryData=*/ Bundle(), - /*isSystemProviderRequired=*/ false, - /*alwaysSendAppInfoToProvider=*/ true - ), - "com.google.android.youtube" + Binder(), + CreateCredentialRequest.Builder(data, Bundle()) + .setType("other-sign-ins") + .setIsSystemProviderRequired(false) + .setAlwaysSendAppInfoToProvider(true) + .build(), + "com.google.android.youtube" ) } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index cce12a252e78..bf070ca2f0a6 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -342,21 +342,22 @@ public final class CredentialManagerService int userId, @Nullable String origin) { final PackageInfo packageInfo; - String actualPackageName = origin == null ? realPackageName : origin; + CallingAppInfo callingAppInfo; try { packageInfo = getContext() .getPackageManager() .getPackageInfoAsUser( - actualPackageName, + realPackageName, PackageManager.PackageInfoFlags.of( PackageManager.GET_SIGNING_CERTIFICATES), userId); + callingAppInfo = new CallingAppInfo(realPackageName, packageInfo.signingInfo, origin); } catch (PackageManager.NameNotFoundException e) { Log.i(TAG, "Issue while retrieving signatureInfo : " + e.getMessage()); - return new CallingAppInfo(actualPackageName, null); + callingAppInfo = new CallingAppInfo(realPackageName, null, origin); } - return new CallingAppInfo(actualPackageName, packageInfo.signingInfo); + return callingAppInfo; } final class CredentialManagerServiceStub extends ICredentialManager.Stub { @@ -368,9 +369,15 @@ public final class CredentialManagerService Log.i(TAG, "starting executeGetCredential with callingPackage: " + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); + if (request.getOrigin() != null) { + // Check privileged permissions + mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); + } + final int userId = UserHandle.getCallingUserId(); final int callingUid = Binder.getCallingUid(); enforceCallingPackage(callingPackage, callingUid); + // New request session, scoped for this request only. final GetRequestSession session = new GetRequestSession( @@ -379,43 +386,13 @@ public final class CredentialManagerService callingUid, callback, request, - constructCallingAppInfo(callingPackage, userId, null), + constructCallingAppInfo(callingPackage, userId, request.getOrigin()), CancellationSignal.fromTransport(cancelTransport)); processGetCredential(request, callback, session); return cancelTransport; } - public ICancellationSignal executeGetCredentialWithOrigin( - GetCredentialRequest request, - IGetCredentialCallback callback, - final String callingPackage, - final String origin) { - Log.i(TAG, "starting executeGetCredential with callingPackage: " + callingPackage); - ICancellationSignal cancelTransport = CancellationSignal.createTransport(); - - // Check privileged permissions - mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); - - final int userId = UserHandle.getCallingUserId(); - final int callingUid = Binder.getCallingUid(); - enforceCallingPackage(callingPackage, callingUid); - - // New request session, scoped for this request only. - final GetRequestSession session = - new GetRequestSession( - getContext(), - userId, - callingUid, - callback, - request, - constructCallingAppInfo(callingPackage, userId, origin), - CancellationSignal.fromTransport(cancelTransport)); - - processGetCredential(request, callback, session); - return cancelTransport; - } - private void processGetCredential( GetCredentialRequest request, IGetCredentialCallback callback, @@ -511,6 +488,11 @@ public final class CredentialManagerService + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); + if (request.getOrigin() != null) { + // Check privileged permissions + mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); + } + final int userId = UserHandle.getCallingUserId(); final int callingUid = Binder.getCallingUid(); enforceCallingPackage(callingPackage, callingUid); @@ -523,43 +505,13 @@ public final class CredentialManagerService callingUid, request, callback, - constructCallingAppInfo(callingPackage, userId, null), + constructCallingAppInfo(callingPackage, userId, request.getOrigin()), CancellationSignal.fromTransport(cancelTransport)); processCreateCredential(request, callback, session); return cancelTransport; } - public ICancellationSignal executeCreateCredentialWithOrigin( - CreateCredentialRequest request, - ICreateCredentialCallback callback, - String callingPackage, - String origin) { - Log.i(TAG, "starting executeCreateCredential with callingPackage: " + callingPackage); - ICancellationSignal cancelTransport = CancellationSignal.createTransport(); - - // Check privileged permissions - mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); - - final int userId = UserHandle.getCallingUserId(); - final int callingUid = Binder.getCallingUid(); - enforceCallingPackage(callingPackage, callingUid); - - // New request session, scoped for this request only. - final CreateRequestSession session = - new CreateRequestSession( - getContext(), - userId, - callingUid, - request, - callback, - constructCallingAppInfo(callingPackage, userId, origin), - CancellationSignal.fromTransport(cancelTransport)); - - processCreateCredential(request, callback, session); - return cancelTransport; - } - private void processCreateCredential( CreateCredentialRequest request, ICreateCredentialCallback callback, |