diff options
| author | 2022-10-28 06:00:43 +0000 | |
|---|---|---|
| committer | 2022-10-28 06:04:50 +0000 | |
| commit | 0ff65e14f19b9ac4094e5a1c51710ad7e63c10a3 (patch) | |
| tree | 3a8c74a431321cf93fba51dd622cb0cfdb17ea43 | |
| parent | 66a14232f8f897f523e1fe8f9393d571bdfff19d (diff) | |
Define converter methods to parse the app requests.
Provides conversion between the framework requests and the jetpack
requests. Note that these classes technically should be defined in the
jetpack library but are temporarily left util we are able to ship the
jetpack code into the framework.
Bug: 255688485
Test: local deployment
Change-Id: I31ae459bb1578ee41492de1a2b0523f9ed72cee2
22 files changed, 930 insertions, 9 deletions
diff --git a/core/java/android/credentials/Credential.java b/core/java/android/credentials/Credential.java index fed259254239..db89170b0cd7 100644 --- a/core/java/android/credentials/Credential.java +++ b/core/java/android/credentials/Credential.java @@ -36,7 +36,8 @@ public final class Credential implements Parcelable { * * @hide */ - @NonNull public static final String TYPE_PASSWORD = "android.credentials.TYPE_PASSWORD"; + @NonNull public static final String TYPE_PASSWORD_CREDENTIAL = + "android.credentials.TYPE_PASSWORD_CREDENTIAL"; /** * The credential type. diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index 56fb1a91aa90..0988cba2f424 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -36,7 +36,7 @@ import com.android.credentialmanager.createflow.CreateScreenState import com.android.credentialmanager.createflow.RequestDisplayInfo import com.android.credentialmanager.getflow.GetCredentialUiState import com.android.credentialmanager.getflow.GetScreenState -import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL +import com.android.credentialmanager.jetpack.provider.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL // Consider repo per screen, similar to view model? class CredentialManagerRepo( diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt index 8e30208e75d9..aeea46a85caf 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt @@ -39,8 +39,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.graphics.drawable.toBitmap import com.android.credentialmanager.R -import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PASSWORD_CREDENTIAL -import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL +import com.android.credentialmanager.jetpack.provider.CredentialEntryUi.Companion.TYPE_PASSWORD_CREDENTIAL +import com.android.credentialmanager.jetpack.provider.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL import com.android.credentialmanager.ui.theme.Grey100 import com.android.credentialmanager.ui.theme.Shapes import com.android.credentialmanager.ui.theme.Typography diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt new file mode 100644 index 000000000000..7e7dbde8655a --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.credentials.Credential +import android.os.Bundle + +/** + * Base request class for registering a credential. + * + * @property type the credential type + * @property data the request data in the [Bundle] format + * @property requireSystemProvider true if must only be fulfilled by a system provider and false + * otherwise + */ +open class CreateCredentialRequest( + val type: String, + val data: Bundle, + val requireSystemProvider: Boolean, +) { + companion object { + @JvmStatic + fun createFrom(from: android.credentials.CreateCredentialRequest): CreateCredentialRequest { + return try { + when (from.type) { + Credential.TYPE_PASSWORD_CREDENTIAL -> + CreatePasswordRequest.createFrom(from.data) + PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> + CreatePublicKeyCredentialBaseRequest.createFrom(from.data) + else -> + CreateCredentialRequest(from.type, from.data, from.requireSystemProvider()) + } + } catch (e: FrameworkClassParsingException) { + CreateCredentialRequest(from.type, from.data, from.requireSystemProvider()) + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt new file mode 100644 index 000000000000..f0da9f9d1866 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.credentials.Credential +import android.os.Bundle + +/** + * A request to save the user password credential with their password provider. + * + * @property id the user id associated with the password + * @property password the password + * @throws NullPointerException If [id] is null + * @throws NullPointerException If [password] is null + * @throws IllegalArgumentException If [password] is empty + */ +class CreatePasswordRequest constructor( + val id: String, + val password: String, +) : CreateCredentialRequest( + Credential.TYPE_PASSWORD_CREDENTIAL, + toBundle(id, password), + false, +) { + + init { + require(password.isNotEmpty()) { "password should not be empty" } + } + + companion object { + const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID" + const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD" + + @JvmStatic + internal fun toBundle(id: String, password: String): Bundle { + val bundle = Bundle() + bundle.putString(BUNDLE_KEY_ID, id) + bundle.putString(BUNDLE_KEY_PASSWORD, password) + return bundle + } + + @JvmStatic + fun createFrom(data: Bundle): CreatePasswordRequest { + try { + val id = data.getString(BUNDLE_KEY_ID) + val password = data.getString(BUNDLE_KEY_PASSWORD) + return CreatePasswordRequest(id!!, password!!) + } catch (e: Exception) { + throw FrameworkClassParsingException() + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt new file mode 100644 index 000000000000..26d61f9eb7a9 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * Base request class for registering a public key credential. + * + * @property requestJson The request in JSON format + * @throws NullPointerException If [requestJson] is null. This is handled by the Kotlin runtime + * @throws IllegalArgumentException If [requestJson] is empty + * + * @hide + */ +abstract class CreatePublicKeyCredentialBaseRequest constructor( + val requestJson: String, + type: String, + data: Bundle, + requireSystemProvider: Boolean, +) : CreateCredentialRequest(type, data, requireSystemProvider) { + + init { + require(requestJson.isNotEmpty()) { "request json must not be empty" } + } + + companion object { + const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON" + const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE" + + @JvmStatic + fun createFrom(data: Bundle): CreatePublicKeyCredentialBaseRequest { + return when (data.getString(BUNDLE_KEY_SUBTYPE)) { + CreatePublicKeyCredentialRequest + .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST -> + CreatePublicKeyCredentialRequestPrivileged.createFrom(data) + CreatePublicKeyCredentialRequestPrivileged + .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED -> + CreatePublicKeyCredentialRequestPrivileged.createFrom(data) + else -> throw FrameworkClassParsingException() + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt new file mode 100644 index 000000000000..2eda90b827dc --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * A request to register a passkey from the user's public key credential provider. + * + * @property requestJson the request in JSON format + * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request, + * true by default + * @throws NullPointerException If [requestJson] or [allowHybrid] is null. This is handled by the + * Kotlin runtime + * @throws IllegalArgumentException If [requestJson] is empty + * + * @hide + */ +class CreatePublicKeyCredentialRequest @JvmOverloads constructor( + requestJson: String, + @get:JvmName("allowHybrid") + val allowHybrid: Boolean = true +) : CreatePublicKeyCredentialBaseRequest( + requestJson, + PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL, + toBundle(requestJson, allowHybrid), + false, +) { + companion object { + const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID" + const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST = + "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST" + + @JvmStatic + internal fun toBundle(requestJson: String, allowHybrid: Boolean): Bundle { + val bundle = Bundle() + bundle.putString(BUNDLE_KEY_SUBTYPE, + BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST) + bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson) + bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid) + return bundle + } + + @JvmStatic + fun createFrom(data: Bundle): CreatePublicKeyCredentialRequest { + try { + val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON) + val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID) + return CreatePublicKeyCredentialRequest(requestJson!!, (allowHybrid!!) as Boolean) + } catch (e: Exception) { + throw FrameworkClassParsingException() + } + } + } +}
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt new file mode 100644 index 000000000000..36324f83a7e5 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt @@ -0,0 +1,143 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * A privileged request to register a passkey from the user’s public key credential provider, where + * the caller can modify the rp. Only callers with privileged permission, e.g. user’s default + * brower, caBLE, can use this. + * + * @property requestJson the privileged request in JSON format + * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request, + * true by default + * @property rp the expected true RP ID which will override the one in the [requestJson] + * @property clientDataHash a hash that is used to verify the [rp] Identity + * @throws NullPointerException If any of [allowHybrid], [requestJson], [rp], or [clientDataHash] is + * null. This is handled by the Kotlin runtime + * @throws IllegalArgumentException If any of [requestJson], [rp], or [clientDataHash] is empty + * + * @hide + */ +class CreatePublicKeyCredentialRequestPrivileged @JvmOverloads constructor( + requestJson: String, + val rp: String, + val clientDataHash: String, + @get:JvmName("allowHybrid") + val allowHybrid: Boolean = true +) : CreatePublicKeyCredentialBaseRequest( + requestJson, + PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL, + toBundle(requestJson, rp, clientDataHash, allowHybrid), + false, +) { + + init { + require(rp.isNotEmpty()) { "rp must not be empty" } + require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" } + } + + /** A builder for [CreatePublicKeyCredentialRequestPrivileged]. */ + class Builder(var requestJson: String, var rp: String, var clientDataHash: String) { + + private var allowHybrid: Boolean = true + + /** + * Sets the privileged request in JSON format. + */ + fun setRequestJson(requestJson: String): Builder { + this.requestJson = requestJson + return this + } + + /** + * Sets whether hybrid credentials are allowed to fulfill this request, true by default. + */ + fun setAllowHybrid(allowHybrid: Boolean): Builder { + this.allowHybrid = allowHybrid + return this + } + + /** + * Sets the expected true RP ID which will override the one in the [requestJson]. + */ + fun setRp(rp: String): Builder { + this.rp = rp + return this + } + + /** + * Sets a hash that is used to verify the [rp] Identity. + */ + fun setClientDataHash(clientDataHash: String): Builder { + this.clientDataHash = clientDataHash + return this + } + + /** Builds a [CreatePublicKeyCredentialRequestPrivileged]. */ + fun build(): CreatePublicKeyCredentialRequestPrivileged { + return CreatePublicKeyCredentialRequestPrivileged(this.requestJson, + this.rp, this.clientDataHash, this.allowHybrid) + } + } + + companion object { + const val BUNDLE_KEY_RP = "androidx.credentials.BUNDLE_KEY_RP" + const val BUNDLE_KEY_CLIENT_DATA_HASH = + "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH" + const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID" + const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED = + "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_" + + "PRIVILEGED" + + @JvmStatic + internal fun toBundle( + requestJson: String, + rp: String, + clientDataHash: String, + allowHybrid: Boolean + ): Bundle { + val bundle = Bundle() + bundle.putString(BUNDLE_KEY_SUBTYPE, + BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED) + bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson) + bundle.putString(BUNDLE_KEY_RP, rp) + bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash) + bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid) + return bundle + } + + @JvmStatic + fun createFrom(data: Bundle): CreatePublicKeyCredentialRequestPrivileged { + try { + val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON) + val rp = data.getString(BUNDLE_KEY_RP) + val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH) + val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID) + return CreatePublicKeyCredentialRequestPrivileged( + requestJson!!, + rp!!, + clientDataHash!!, + (allowHybrid!!) as Boolean, + ) + } catch (e: Exception) { + throw FrameworkClassParsingException() + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/Credential.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/Credential.kt new file mode 100644 index 000000000000..ee08e9e30649 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/Credential.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * Base class for a credential with which the user consented to authenticate to the app. + * + * @property type the credential type + * @property data the credential data in the [Bundle] format. + */ +open class Credential(val type: String, val data: Bundle) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/FrameworkClassParsingException.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/FrameworkClassParsingException.kt new file mode 100644 index 000000000000..497c272750ac --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/FrameworkClassParsingException.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +/** + * Internal exception used to indicate a parsing error while converting from a framework type to + * a jetpack type. + * + * @hide + */ +internal class FrameworkClassParsingException : Exception()
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt new file mode 100644 index 000000000000..eb65241ed4df --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.credentials.Credential +import android.os.Bundle + +/** + * Base request class for getting a registered credential. + * + * @property type the credential type + * @property data the request data in the [Bundle] format + * @property requireSystemProvider true if must only be fulfilled by a system provider and false + * otherwise + */ +open class GetCredentialOption( + val type: String, + val data: Bundle, + val requireSystemProvider: Boolean, +) { + companion object { + @JvmStatic + fun createFrom(from: android.credentials.GetCredentialOption): GetCredentialOption { + return try { + when (from.type) { + Credential.TYPE_PASSWORD_CREDENTIAL -> + GetPasswordOption.createFrom(from.data) + PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> + GetPublicKeyCredentialBaseOption.createFrom(from.data) + else -> + GetCredentialOption(from.type, from.data, from.requireSystemProvider()) + } + } catch (e: FrameworkClassParsingException) { + GetCredentialOption(from.type, from.data, from.requireSystemProvider()) + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt new file mode 100644 index 000000000000..7f9256ed6c75 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +/** + * Encapsulates a request to get a user credential. + * + * @property getCredentialOptions the list of [GetCredentialOption] from which the user can choose + * one to authenticate to the app + * @throws IllegalArgumentException If [getCredentialOptions] is empty + */ +class GetCredentialRequest constructor( + val getCredentialOptions: List<GetCredentialOption>, +) { + + init { + require(getCredentialOptions.isNotEmpty()) { "credentialRequests should not be empty" } + } + + /** A builder for [GetCredentialRequest]. */ + class Builder { + private var getCredentialOptions: MutableList<GetCredentialOption> = mutableListOf() + + /** Adds a specific type of [GetCredentialOption]. */ + fun addGetCredentialOption(getCredentialOption: GetCredentialOption): Builder { + getCredentialOptions.add(getCredentialOption) + return this + } + + /** Sets the list of [GetCredentialOption]. */ + fun setGetCredentialOptions(getCredentialOptions: List<GetCredentialOption>): Builder { + this.getCredentialOptions = getCredentialOptions.toMutableList() + return this + } + + /** + * Builds a [GetCredentialRequest]. + * + * @throws IllegalArgumentException If [getCredentialOptions] is empty + */ + fun build(): GetCredentialRequest { + return GetCredentialRequest(getCredentialOptions.toList()) + } + } + + companion object { + @JvmStatic + fun createFrom(from: android.credentials.GetCredentialRequest): GetCredentialRequest { + return GetCredentialRequest( + from.getCredentialOptions.map {GetCredentialOption.createFrom(it)} + ) + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt new file mode 100644 index 000000000000..2facad17b04e --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.credentials.Credential +import android.os.Bundle + +/** A request to retrieve the user's saved application password from their password provider. */ +class GetPasswordOption : GetCredentialOption( + Credential.TYPE_PASSWORD_CREDENTIAL, + Bundle(), + false, +) { + companion object { + @JvmStatic + fun createFrom(data: Bundle): GetPasswordOption { + return GetPasswordOption() + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt new file mode 100644 index 000000000000..9b51b306dd6b --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * Base request class for getting a registered public key credential. + * + * @property requestJson the request in JSON format + * @throws NullPointerException If [requestJson] is null - auto handled by the + * Kotlin runtime + * @throws IllegalArgumentException If [requestJson] is empty + * + * @hide + */ +abstract class GetPublicKeyCredentialBaseOption constructor( + val requestJson: String, + type: String, + data: Bundle, + requireSystemProvider: Boolean, +) : GetCredentialOption(type, data, requireSystemProvider) { + + init { + require(requestJson.isNotEmpty()) { "request json must not be empty" } + } + + companion object { + const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON" + const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE" + + @JvmStatic + fun createFrom(data: Bundle): GetPublicKeyCredentialBaseOption { + return when (data.getString(BUNDLE_KEY_SUBTYPE)) { + GetPublicKeyCredentialOption + .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION -> + GetPublicKeyCredentialOption.createFrom(data) + GetPublicKeyCredentialOptionPrivileged + .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED -> + GetPublicKeyCredentialOptionPrivileged.createFrom(data) + else -> throw FrameworkClassParsingException() + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt new file mode 100644 index 000000000000..6f13c17f9b6e --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * A request to get passkeys from the user's public key credential provider. + * + * @property requestJson the request in JSON format + * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request, + * true by default + * @throws NullPointerException If [requestJson] or [allowHybrid] is null. It is handled by the + * Kotlin runtime + * @throws IllegalArgumentException If [requestJson] is empty + * + * @hide + */ +class GetPublicKeyCredentialOption @JvmOverloads constructor( + requestJson: String, + @get:JvmName("allowHybrid") + val allowHybrid: Boolean = true, +) : GetPublicKeyCredentialBaseOption( + requestJson, + PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL, + toBundle(requestJson, allowHybrid), + false +) { + companion object { + const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID" + const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION = + "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION" + + @JvmStatic + internal fun toBundle(requestJson: String, allowHybrid: Boolean): Bundle { + val bundle = Bundle() + bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson) + bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid) + return bundle + } + + @JvmStatic + fun createFrom(data: Bundle): GetPublicKeyCredentialOption { + try { + val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON) + val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID) + return GetPublicKeyCredentialOption(requestJson!!, (allowHybrid!!) as Boolean) + } catch (e: Exception) { + throw FrameworkClassParsingException() + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt new file mode 100644 index 000000000000..79c62a1cdfbe --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt @@ -0,0 +1,141 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * A privileged request to get passkeys from the user's public key credential provider. The caller + * can modify the RP. Only callers with privileged permission (e.g. user's public browser or caBLE) + * can use this. + * + * @property requestJson the privileged request in JSON format + * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request, + * true by default + * @property rp the expected true RP ID which will override the one in the [requestJson] + * @property clientDataHash a hash that is used to verify the [rp] Identity + * @throws NullPointerException If any of [allowHybrid], [requestJson], [rp], or [clientDataHash] + * is null. This is handled by the Kotlin runtime + * @throws IllegalArgumentException If any of [requestJson], [rp], or [clientDataHash] is empty + * + * @hide + */ +class GetPublicKeyCredentialOptionPrivileged @JvmOverloads constructor( + requestJson: String, + val rp: String, + val clientDataHash: String, + @get:JvmName("allowHybrid") + val allowHybrid: Boolean = true +) : GetPublicKeyCredentialBaseOption( + requestJson, + PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL, + toBundle(requestJson, rp, clientDataHash, allowHybrid), + false, +) { + + init { + require(rp.isNotEmpty()) { "rp must not be empty" } + require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" } + } + + /** A builder for [GetPublicKeyCredentialOptionPrivileged]. */ + class Builder(var requestJson: String, var rp: String, var clientDataHash: String) { + + private var allowHybrid: Boolean = true + + /** + * Sets the privileged request in JSON format. + */ + fun setRequestJson(requestJson: String): Builder { + this.requestJson = requestJson + return this + } + + /** + * Sets whether hybrid credentials are allowed to fulfill this request, true by default. + */ + fun setAllowHybrid(allowHybrid: Boolean): Builder { + this.allowHybrid = allowHybrid + return this + } + + /** + * Sets the expected true RP ID which will override the one in the [requestJson]. + */ + fun setRp(rp: String): Builder { + this.rp = rp + return this + } + + /** + * Sets a hash that is used to verify the [rp] Identity. + */ + fun setClientDataHash(clientDataHash: String): Builder { + this.clientDataHash = clientDataHash + return this + } + + /** Builds a [GetPublicKeyCredentialOptionPrivileged]. */ + fun build(): GetPublicKeyCredentialOptionPrivileged { + return GetPublicKeyCredentialOptionPrivileged(this.requestJson, + this.rp, this.clientDataHash, this.allowHybrid) + } + } + + companion object { + const val BUNDLE_KEY_RP = "androidx.credentials.BUNDLE_KEY_RP" + const val BUNDLE_KEY_CLIENT_DATA_HASH = + "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH" + const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID" + const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED = + "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION" + + "_PRIVILEGED" + + @JvmStatic + internal fun toBundle( + requestJson: String, + rp: String, + clientDataHash: String, + allowHybrid: Boolean + ): Bundle { + val bundle = Bundle() + bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson) + bundle.putString(BUNDLE_KEY_RP, rp) + bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash) + bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid) + return bundle + } + + @JvmStatic + fun createFrom(data: Bundle): GetPublicKeyCredentialOptionPrivileged { + try { + val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON) + val rp = data.getString(BUNDLE_KEY_RP) + val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH) + val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID) + return GetPublicKeyCredentialOptionPrivileged( + requestJson!!, + rp!!, + clientDataHash!!, + (allowHybrid!!) as Boolean, + ) + } catch (e: Exception) { + throw FrameworkClassParsingException() + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt new file mode 100644 index 000000000000..b45a63bcf4ec --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 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 com.android.credentialmanager.jetpack.developer + +import android.os.Bundle + +/** + * Represents the user's passkey credential granted by the user for app sign-in. + * + * @property authenticationResponseJson the public key credential authentication response in + * JSON format that follows the standard webauthn json format shown at + * [this w3c link](https://w3c.github.io/webauthn/#dictdef-authenticationresponsejson) + * @throws NullPointerException If [authenticationResponseJson] is null. This is handled by the + * kotlin runtime + * @throws IllegalArgumentException If [authenticationResponseJson] is empty + * + * @hide + */ +class PublicKeyCredential constructor( + val authenticationResponseJson: String +) : Credential( + TYPE_PUBLIC_KEY_CREDENTIAL, + toBundle(authenticationResponseJson) +) { + + init { + require(authenticationResponseJson.isNotEmpty()) { + "authentication response JSON must not be empty" } + } + companion object { + /** The type value for public key credential related operations. */ + const val TYPE_PUBLIC_KEY_CREDENTIAL: String = + "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL" + const val BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON = + "androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON" + + @JvmStatic + internal fun toBundle(authenticationResponseJson: String): Bundle { + val bundle = Bundle() + bundle.putString(BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON, authenticationResponseJson) + return bundle + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/ActionUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt index d4341b498fe0..1e639fe6bd55 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/ActionUi.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.credentialmanager.jetpack +package com.android.credentialmanager.jetpack.provider import android.app.slice.Slice import android.credentials.ui.Entry diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/CredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt index d6f1b5f5c8e9..12ab436e1507 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/CredentialEntryUi.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.credentialmanager.jetpack +package com.android.credentialmanager.jetpack.provider import android.app.slice.Slice import android.graphics.drawable.Icon diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasskeyCredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasskeyCredentialEntryUi.kt index bb3b206500b4..c5dbe66e8dbb 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasskeyCredentialEntryUi.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasskeyCredentialEntryUi.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.credentialmanager.jetpack +package com.android.credentialmanager.jetpack.provider import android.app.slice.Slice import android.credentials.ui.Entry diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasswordCredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasswordCredentialEntryUi.kt index 7311b7081343..5049503b32c1 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasswordCredentialEntryUi.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasswordCredentialEntryUi.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.credentialmanager.jetpack +package com.android.credentialmanager.jetpack.provider import android.app.slice.Slice import android.credentials.ui.Entry diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/SaveEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt index fad3309fb86f..b260cf63587c 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/SaveEntryUi.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.credentialmanager.jetpack +package com.android.credentialmanager.jetpack.provider import android.app.slice.Slice import android.credentials.ui.Entry |