Update CreateCredentialRequest and GetCredentialOption with recent changes.
Specifically: 1. for the create request, add the api for prefetch data that's the partial request data used during the initial ping to each provider. This is needed for security reason, so that we don't send sensitive request data to providers until the user explicitly consents. 2. for both requests, add(unhide) the requireSystemProvider api, which when true indicates this request can only be fulfilled by system providers. Bug: 246564035 Bug: 253153445 CTS-Coverage-Bug: 246637346 Test: Local Build & Deployment Change-Id: I9f4a96dc28e87f92924abda8412b15010ee431b7
This commit is contained in:
@@ -13025,10 +13025,12 @@ package android.credentials {
|
||||
}
|
||||
|
||||
public final class CreateCredentialRequest implements android.os.Parcelable {
|
||||
ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle);
|
||||
ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle, boolean);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.os.Bundle getData();
|
||||
method @NonNull public android.os.Bundle getCandidateQueryData();
|
||||
method @NonNull public android.os.Bundle getCredentialData();
|
||||
method @NonNull public String getType();
|
||||
method public boolean requireSystemProvider();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CreateCredentialRequest> CREATOR;
|
||||
}
|
||||
@@ -13066,10 +13068,11 @@ package android.credentials {
|
||||
}
|
||||
|
||||
public final class GetCredentialOption implements android.os.Parcelable {
|
||||
ctor public GetCredentialOption(@NonNull String, @NonNull android.os.Bundle);
|
||||
ctor public GetCredentialOption(@NonNull String, @NonNull android.os.Bundle, boolean);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.os.Bundle getData();
|
||||
method @NonNull public String getType();
|
||||
method public boolean requireSystemProvider();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.GetCredentialOption> CREATOR;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,17 @@ public final class CreateCredentialRequest implements Parcelable {
|
||||
private final String mType;
|
||||
|
||||
/**
|
||||
* The request data.
|
||||
* The full credential creation request data.
|
||||
*/
|
||||
@NonNull
|
||||
private final Bundle mData;
|
||||
private final Bundle mCredentialData;
|
||||
|
||||
/**
|
||||
* The partial request data that will be sent to the provider during the initial creation
|
||||
* candidate query stage.
|
||||
*/
|
||||
@NonNull
|
||||
private final Bundle mCandidateQueryData;
|
||||
|
||||
/**
|
||||
* Determines whether or not the request must only be fulfilled by a system provider.
|
||||
@@ -58,18 +65,39 @@ public final class CreateCredentialRequest implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request data.
|
||||
* Returns the full credential creation request data.
|
||||
*
|
||||
* For security reason, a provider will receive the request data in two stages. First it gets
|
||||
* a partial request, {@link #getCandidateQueryData()} that do not contain sensitive user
|
||||
* information; it uses this information to provide credential creation candidates that the
|
||||
* [@code CredentialManager] will show to the user. Next, this full request data will be sent to
|
||||
* a provider only if the user further grants the consent by choosing a candidate from the
|
||||
* provider.
|
||||
*/
|
||||
@NonNull
|
||||
public Bundle getData() {
|
||||
return mData;
|
||||
public Bundle getCredentialData() {
|
||||
return mCredentialData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the partial request data that will be sent to the provider during the initial
|
||||
* creation candidate query stage.
|
||||
*
|
||||
* For security reason, a provider will receive the request data in two stages. First it gets
|
||||
* this partial request that do not contain sensitive user information; it uses this information
|
||||
* to provide credential creation candidates that the [@code CredentialManager] will show to
|
||||
* the user. Next, the full request data, {@link #getCredentialData()}, will be sent to a
|
||||
* provider only if the user further grants the consent by choosing a candidate from the
|
||||
* provider.
|
||||
*/
|
||||
@NonNull
|
||||
public Bundle getCandidateQueryData() {
|
||||
return mCandidateQueryData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the request must only be fulfilled by a system provider, and false
|
||||
* otherwise.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean requireSystemProvider() {
|
||||
return mRequireSystemProvider;
|
||||
@@ -78,7 +106,8 @@ public final class CreateCredentialRequest implements Parcelable {
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString8(mType);
|
||||
dest.writeBundle(mData);
|
||||
dest.writeBundle(mCredentialData);
|
||||
dest.writeBundle(mCandidateQueryData);
|
||||
dest.writeBoolean(mRequireSystemProvider);
|
||||
}
|
||||
|
||||
@@ -91,7 +120,8 @@ public final class CreateCredentialRequest implements Parcelable {
|
||||
public String toString() {
|
||||
return "CreateCredentialRequest {"
|
||||
+ "type=" + mType
|
||||
+ ", data=" + mData
|
||||
+ ", credentialData=" + mCredentialData
|
||||
+ ", candidateQueryData=" + mCandidateQueryData
|
||||
+ ", requireSystemProvider=" + mRequireSystemProvider
|
||||
+ "}";
|
||||
}
|
||||
@@ -100,44 +130,37 @@ public final class CreateCredentialRequest implements Parcelable {
|
||||
* Constructs a {@link CreateCredentialRequest}.
|
||||
*
|
||||
* @param type the requested credential type
|
||||
* @param data the request data
|
||||
*
|
||||
* @throws IllegalArgumentException If type is empty
|
||||
*/
|
||||
public CreateCredentialRequest(@NonNull String type, @NonNull Bundle data) {
|
||||
this(type, data, /*requireSystemProvider=*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link CreateCredentialRequest}.
|
||||
*
|
||||
* @param type the requested credential type
|
||||
* @param data the request data
|
||||
* @param requireSystemProvider whether or not the request must only be fulfilled by a system
|
||||
* provider
|
||||
* @param credentialData the full credential creation request data
|
||||
* @param candidateQueryData the partial request data that will be sent to the provider
|
||||
* during the initial creation candidate query stage
|
||||
* @param requireSystemProvider whether the request must only be fulfilled by a system provider
|
||||
*
|
||||
* @throws IllegalArgumentException If type is empty.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public CreateCredentialRequest(
|
||||
@NonNull String type,
|
||||
@NonNull Bundle data,
|
||||
@NonNull Bundle credentialData,
|
||||
@NonNull Bundle candidateQueryData,
|
||||
boolean requireSystemProvider) {
|
||||
mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
|
||||
mData = requireNonNull(data, "data must not be null");
|
||||
mCredentialData = requireNonNull(credentialData, "credentialData must not be null");
|
||||
mCandidateQueryData = requireNonNull(candidateQueryData,
|
||||
"candidateQueryData must not be null");
|
||||
mRequireSystemProvider = requireSystemProvider;
|
||||
}
|
||||
|
||||
private CreateCredentialRequest(@NonNull Parcel in) {
|
||||
String type = in.readString8();
|
||||
Bundle data = in.readBundle();
|
||||
Bundle credentialData = in.readBundle();
|
||||
Bundle candidateQueryData = in.readBundle();
|
||||
boolean requireSystemProvider = in.readBoolean();
|
||||
|
||||
mType = type;
|
||||
AnnotationValidations.validate(NonNull.class, null, mType);
|
||||
mData = data;
|
||||
AnnotationValidations.validate(NonNull.class, null, mData);
|
||||
mCredentialData = credentialData;
|
||||
AnnotationValidations.validate(NonNull.class, null, mCredentialData);
|
||||
mCandidateQueryData = candidateQueryData;
|
||||
AnnotationValidations.validate(NonNull.class, null, mCandidateQueryData);
|
||||
mRequireSystemProvider = requireSystemProvider;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +67,6 @@ public final class GetCredentialOption implements Parcelable {
|
||||
/**
|
||||
* Returns true if the request must only be fulfilled by a system provider, and false
|
||||
* otherwise.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean requireSystemProvider() {
|
||||
return mRequireSystemProvider;
|
||||
@@ -95,18 +93,6 @@ public final class GetCredentialOption implements Parcelable {
|
||||
+ "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link GetCredentialOption}.
|
||||
*
|
||||
* @param type the requested credential type
|
||||
* @param data the request data
|
||||
*
|
||||
* @throws IllegalArgumentException If type is empty
|
||||
*/
|
||||
public GetCredentialOption(@NonNull String type, @NonNull Bundle data) {
|
||||
this(type, data, /*requireSystemProvider=*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link GetCredentialOption}.
|
||||
*
|
||||
@@ -116,8 +102,6 @@ public final class GetCredentialOption implements Parcelable {
|
||||
* provider
|
||||
*
|
||||
* @throws IllegalArgumentException If type is empty.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public GetCredentialOption(
|
||||
@NonNull String type,
|
||||
|
||||
@@ -458,12 +458,15 @@ class CredentialManagerRepo(
|
||||
" \"residentKey\": \"required\",\n" +
|
||||
" \"requireResidentKey\": true\n" +
|
||||
" }}")
|
||||
val data = request.data
|
||||
val credentialData = request.data
|
||||
return RequestInfo.newCreateRequestInfo(
|
||||
Binder(),
|
||||
CreateCredentialRequest(
|
||||
TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
data
|
||||
credentialData,
|
||||
// TODO: populate with actual data
|
||||
/*candidateQueryData=*/ Bundle(),
|
||||
/*requireSystemProvider=*/ false
|
||||
),
|
||||
/*isFirstUsage=*/false,
|
||||
"tribank"
|
||||
@@ -476,7 +479,10 @@ class CredentialManagerRepo(
|
||||
Binder(),
|
||||
CreateCredentialRequest(
|
||||
TYPE_PASSWORD_CREDENTIAL,
|
||||
data
|
||||
data,
|
||||
// TODO: populate with actual data
|
||||
/*candidateQueryData=*/ Bundle(),
|
||||
/*requireSystemProvider=*/ false
|
||||
),
|
||||
/*isFirstUsage=*/false,
|
||||
"tribank"
|
||||
@@ -489,7 +495,9 @@ class CredentialManagerRepo(
|
||||
Binder(),
|
||||
CreateCredentialRequest(
|
||||
"other-sign-ins",
|
||||
data
|
||||
data,
|
||||
/*candidateQueryData=*/ Bundle(),
|
||||
/*requireSystemProvider=*/ false
|
||||
),
|
||||
/*isFirstUsage=*/false,
|
||||
"tribank"
|
||||
@@ -501,7 +509,8 @@ class CredentialManagerRepo(
|
||||
Binder(),
|
||||
GetCredentialRequest.Builder()
|
||||
.addGetCredentialOption(
|
||||
GetCredentialOption(TYPE_PUBLIC_KEY_CREDENTIAL, Bundle())
|
||||
GetCredentialOption(
|
||||
TYPE_PUBLIC_KEY_CREDENTIAL, Bundle(), /*requireSystemProvider=*/ false)
|
||||
)
|
||||
.build(),
|
||||
/*isFirstUsage=*/false,
|
||||
|
||||
@@ -38,14 +38,18 @@ open class CreateCredentialRequest(
|
||||
return try {
|
||||
when (from.type) {
|
||||
Credential.TYPE_PASSWORD_CREDENTIAL ->
|
||||
CreatePasswordRequest.createFrom(from.data)
|
||||
CreatePasswordRequest.createFrom(from.credentialData)
|
||||
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
|
||||
CreatePublicKeyCredentialBaseRequest.createFrom(from.data)
|
||||
CreatePublicKeyCredentialBaseRequest.createFrom(from.credentialData)
|
||||
else ->
|
||||
CreateCredentialRequest(from.type, from.data, from.requireSystemProvider())
|
||||
CreateCredentialRequest(
|
||||
from.type, from.credentialData, from.requireSystemProvider()
|
||||
)
|
||||
}
|
||||
} catch (e: FrameworkClassParsingException) {
|
||||
CreateCredentialRequest(from.type, from.data, from.requireSystemProvider())
|
||||
CreateCredentialRequest(
|
||||
from.type, from.credentialData, from.requireSystemProvider()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.content.Intent;
|
||||
import android.credentials.ui.CreateCredentialProviderData;
|
||||
import android.credentials.ui.Entry;
|
||||
import android.credentials.ui.ProviderPendingIntentResponse;
|
||||
import android.os.Bundle;
|
||||
import android.service.credentials.BeginCreateCredentialRequest;
|
||||
import android.service.credentials.BeginCreateCredentialResponse;
|
||||
import android.service.credentials.CreateCredentialRequest;
|
||||
@@ -68,12 +67,11 @@ public final class ProviderCreateSession extends ProviderSession<
|
||||
createRequestSession.mClientRequest,
|
||||
createRequestSession.mClientCallingPackage);
|
||||
if (providerCreateRequest != null) {
|
||||
// TODO : Replace with proper splitting of request
|
||||
BeginCreateCredentialRequest providerBeginCreateRequest =
|
||||
new BeginCreateCredentialRequest(
|
||||
providerCreateRequest.getCallingPackage(),
|
||||
providerCreateRequest.getType(),
|
||||
new Bundle());
|
||||
createRequestSession.mClientRequest.getCandidateQueryData());
|
||||
return new ProviderCreateSession(context, providerInfo, createRequestSession, userId,
|
||||
remoteCredentialService, providerBeginCreateRequest, providerCreateRequest);
|
||||
}
|
||||
@@ -88,7 +86,7 @@ public final class ProviderCreateSession extends ProviderSession<
|
||||
String capability = clientRequest.getType();
|
||||
if (providerCapabilities.contains(capability)) {
|
||||
return new CreateCredentialRequest(clientCallingPackage, capability,
|
||||
clientRequest.getData());
|
||||
clientRequest.getCredentialData());
|
||||
}
|
||||
Log.i(TAG, "Unable to create provider request - capabilities do not match");
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user