Merge "Refactor origin to request object for the credential manager privilege APIs" into udc-dev am: eda0bf7f8a
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21487335 Change-Id: Ib6119589bdd965a34a8c3f2e9a3b8c376be2d039 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -13577,17 +13577,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();
|
||||
@@ -13619,9 +13628,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);
|
||||
@@ -13656,6 +13663,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;
|
||||
}
|
||||
@@ -13666,6 +13674,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 {
|
||||
@@ -40564,7 +40573,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);
|
||||
|
||||
@@ -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;
|
||||
@@ -68,6 +73,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.
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -162,62 +166,15 @@ 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
|
||||
@@ -258,58 +215,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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
@@ -48,6 +52,14 @@ public final class GetCredentialRequest implements Parcelable {
|
||||
@NonNull
|
||||
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.
|
||||
@@ -75,6 +87,14 @@ public final class GetCredentialRequest implements Parcelable {
|
||||
return mData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -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
|
||||
*/
|
||||
@@ -208,6 +234,20 @@ public final class GetCredentialRequest implements Parcelable {
|
||||
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 Builder setOrigin(@NonNull String origin) {
|
||||
mOrigin = origin;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link GetCredentialRequest}.
|
||||
*
|
||||
@@ -222,7 +262,7 @@ public final class GetCredentialRequest implements Parcelable {
|
||||
mCredentialOptions,
|
||||
/*valueName=*/ "credentialOptions");
|
||||
return new GetCredentialRequest(mCredentialOptions, mData,
|
||||
mAlwaysSendAppInfoToProvider);
|
||||
mAlwaysSendAppInfoToProvider, mOrigin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -101,8 +101,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",
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -360,21 +360,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 {
|
||||
@@ -386,9 +387,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(
|
||||
@@ -397,43 +404,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,
|
||||
@@ -519,6 +496,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);
|
||||
@@ -531,43 +513,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,
|
||||
|
||||
Reference in New Issue
Block a user