summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Reema Bajwa <reemabajwa@google.com> 2023-02-18 00:36:31 +0000
committer Reema Bajwa <reemabajwa@google.com> 2023-02-22 17:20:07 +0000
commit9eb577e6cf16fea86e17959834e070f280a230ff (patch)
treefbabefc9ccc3652c12acb76c638295a05367bf5f
parent79d1135cb8913dbbb4e87e2d324394e830fc8165 (diff)
Refactor origin to request object for the credential manager privilege APIs
Bug: 268534702 DetailedCoverageBugs: 255429881, 255429478 Test: local-deployment Change-Id: Id40024989f19d3bd806201b0007b301185064b76
-rw-r--r--core/api/current.txt17
-rw-r--r--core/java/android/credentials/CreateCredentialRequest.java133
-rw-r--r--core/java/android/credentials/CredentialManager.java111
-rw-r--r--core/java/android/credentials/GetCredentialRequest.java44
-rw-r--r--core/java/android/credentials/ICredentialManager.aidl4
-rw-r--r--core/java/android/service/credentials/CallingAppInfo.java38
-rw-r--r--core/tests/coretests/src/android/credentials/CredentialManagerTest.java7
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt48
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java84
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,