From c79a4aaae580f3f89920953c487516bfb799e676 Mon Sep 17 00:00:00 2001 From: Reema Bajwa Date: Thu, 15 Dec 2022 00:24:59 +0000 Subject: [PATCH] Add the clear credential provider API Test: Built locally Bug: 253155222 API-Coverage-Bug: 247549381 Change-Id: I0b3fef5e7be861f546475e397ccb2afc0b0a3216 --- core/api/current.txt | 10 ++ .../ClearCredentialStateRequest.aidl | 3 + .../ClearCredentialStateRequest.java | 100 ++++++++++++++++++ .../CredentialProviderService.java | 57 ++++++++++ .../IClearCredentialStateCallback.aidl | 27 +++++ .../ICredentialProviderService.aidl | 3 + 6 files changed, 200 insertions(+) create mode 100644 core/java/android/service/credentials/ClearCredentialStateRequest.aidl create mode 100644 core/java/android/service/credentials/ClearCredentialStateRequest.java create mode 100644 core/java/android/service/credentials/IClearCredentialStateCallback.aidl diff --git a/core/api/current.txt b/core/api/current.txt index 9ef88c4b963b9..5d94bb60c002c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39598,6 +39598,15 @@ package android.service.credentials { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public final class ClearCredentialStateRequest implements android.os.Parcelable { + ctor public ClearCredentialStateRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull android.os.Bundle); + method public int describeContents(); + method @NonNull public android.service.credentials.CallingAppInfo getCallingAppInfo(); + method @NonNull public android.os.Bundle getData(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + public final class CreateCredentialRequest implements android.os.Parcelable { ctor public CreateCredentialRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull String, @NonNull android.os.Bundle); method public int describeContents(); @@ -39638,6 +39647,7 @@ package android.service.credentials { method public abstract void onBeginCreateCredential(@NonNull android.service.credentials.BeginCreateCredentialRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); method public abstract void onBeginGetCredential(@NonNull android.service.credentials.BeginGetCredentialRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public abstract void onClearCredentialState(@NonNull android.service.credentials.ClearCredentialStateRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); field public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities"; field public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION"; field public static final String EXTRA_CREATE_CREDENTIAL_REQUEST = "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST"; diff --git a/core/java/android/service/credentials/ClearCredentialStateRequest.aidl b/core/java/android/service/credentials/ClearCredentialStateRequest.aidl new file mode 100644 index 0000000000000..f4b45c2e43373 --- /dev/null +++ b/core/java/android/service/credentials/ClearCredentialStateRequest.aidl @@ -0,0 +1,3 @@ +package android.service.credentials; + +parcelable ClearCredentialStateRequest; \ No newline at end of file diff --git a/core/java/android/service/credentials/ClearCredentialStateRequest.java b/core/java/android/service/credentials/ClearCredentialStateRequest.java new file mode 100644 index 0000000000000..57189bbe9fc7b --- /dev/null +++ b/core/java/android/service/credentials/ClearCredentialStateRequest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.credentials; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; +/** + * A request class for clearing a user's credential state. + * Providers must clear the credential state when they receive this request. + */ +public final class ClearCredentialStateRequest implements Parcelable { + /** The request data. */ + @NonNull + private final CallingAppInfo mCallingAppInfo; + + /** The request data. */ + @NonNull + private final Bundle mData; + + /** Returns the request data. */ + @NonNull + public Bundle getData() { + return mData; + } + + /** Returns the calling app info containing information pertaining to the calling app. */ + @NonNull + public CallingAppInfo getCallingAppInfo() { + return mCallingAppInfo; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mCallingAppInfo, flags); + dest.writeBundle(mData); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "ClearCredentialStateRequest {callingAppInfo=" + + mCallingAppInfo.toString() + " }, {data= " + mData + "}"; + } + + /** + * Constructs a {@link ClearCredentialStateRequest}. + * + * @param data the request data + */ + public ClearCredentialStateRequest(@NonNull CallingAppInfo callingAppInfo, + @NonNull Bundle data) { + mCallingAppInfo = requireNonNull( + callingAppInfo, "callingAppInfo must not be null"); + mData = requireNonNull(data, "data must not be null"); + } + + private ClearCredentialStateRequest(@NonNull Parcel in) { + mCallingAppInfo = in.readTypedObject(CallingAppInfo.CREATOR); + Bundle data = in.readBundle(); + mData = data; + AnnotationValidations.validate(NonNull.class, null, mData); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public ClearCredentialStateRequest[] newArray(int size) { + return new ClearCredentialStateRequest[size]; + } + + @Override + public ClearCredentialStateRequest createFromParcel(@NonNull Parcel in) { + return new ClearCredentialStateRequest(in); + } + }; +} diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index 7735e4cdb394e..41d20f26b3816 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; +import android.credentials.ClearCredentialStateException; import android.credentials.CreateCredentialException; import android.credentials.GetCredentialException; import android.os.CancellationSignal; @@ -224,6 +225,40 @@ public abstract class CredentialProviderService extends Service { )); return transport; } + + @Override + public ICancellationSignal onClearCredentialState(ClearCredentialStateRequest request, + IClearCredentialStateCallback callback) { + Objects.requireNonNull(request); + Objects.requireNonNull(callback); + + ICancellationSignal transport = CancellationSignal.createTransport(); + + mHandler.sendMessage(obtainMessage( + CredentialProviderService::onClearCredentialState, + CredentialProviderService.this, request, + CancellationSignal.fromTransport(transport), + new OutcomeReceiver() { + @Override + public void onResult(Void result) { + try { + callback.onSuccess(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + @Override + public void onError(ClearCredentialStateException e) { + try { + callback.onFailure(e.errorType, e.getMessage()); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + } + } + )); + return transport; + } }; /** @@ -262,4 +297,26 @@ public abstract class CredentialProviderService extends Service { @NonNull CancellationSignal cancellationSignal, @NonNull OutcomeReceiver callback); + + /** + * Called by the android system to clear the credential state. + * + * This api isinvoked by developers after users sign out of an app, with an intention to + * clear any stored credential session that providers have retained. + * + * As a provider, you must clear any credential state, if maintained. For e.g. a provider may + * have stored an active credential session that is used to limit or rank sign-in options for + * future credential retrieval flows. When a user signs out of the app, such state should be + * cleared and an exhaustive list of credentials must be presented to the user on subsequent + * credential retrieval flows. + * + * @param request The clear credential request for the provider to handle. + * @param cancellationSignal Signal for providers to listen to any cancellation requests from + * the android system. + * @param callback Object used to relay the result of the request. + */ + public abstract void onClearCredentialState(@NonNull ClearCredentialStateRequest request, + @NonNull CancellationSignal cancellationSignal, + @NonNull OutcomeReceiver callback); } diff --git a/core/java/android/service/credentials/IClearCredentialStateCallback.aidl b/core/java/android/service/credentials/IClearCredentialStateCallback.aidl new file mode 100644 index 0000000000000..ec805d0a1799b --- /dev/null +++ b/core/java/android/service/credentials/IClearCredentialStateCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.credentials; + +/** + * Callback for onClearCredentialState request. + * + * @hide + */ +interface IClearCredentialStateCallback { + oneway void onSuccess(); + oneway void onFailure(String errorType, CharSequence message); +} \ No newline at end of file diff --git a/core/java/android/service/credentials/ICredentialProviderService.aidl b/core/java/android/service/credentials/ICredentialProviderService.aidl index 24d253fa61efb..626dd78586264 100644 --- a/core/java/android/service/credentials/ICredentialProviderService.aidl +++ b/core/java/android/service/credentials/ICredentialProviderService.aidl @@ -20,7 +20,9 @@ import android.os.ICancellationSignal; import android.service.credentials.BeginGetCredentialRequest; import android.service.credentials.BeginCreateCredentialRequest; import android.service.credentials.IBeginGetCredentialCallback; +import android.service.credentials.ClearCredentialStateRequest; import android.service.credentials.IBeginCreateCredentialCallback; +import android.service.credentials.IClearCredentialStateCallback; import android.os.ICancellationSignal; /** @@ -31,4 +33,5 @@ import android.os.ICancellationSignal; interface ICredentialProviderService { ICancellationSignal onBeginGetCredential(in BeginGetCredentialRequest request, in IBeginGetCredentialCallback callback); ICancellationSignal onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback); + ICancellationSignal onClearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback); }