Merge "Update the UI jetpack parsing logic."
This commit is contained in:
committed by
Android (Google) Code Review
commit
431d141a2f
@@ -45,7 +45,7 @@ import com.android.credentialmanager.createflow.DisabledProviderInfo
|
||||
import com.android.credentialmanager.createflow.EnabledProviderInfo
|
||||
import com.android.credentialmanager.createflow.RequestDisplayInfo
|
||||
import com.android.credentialmanager.getflow.GetCredentialUiState
|
||||
import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toBundle
|
||||
import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toCredentialDataBundle
|
||||
import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
|
||||
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
|
||||
import com.android.credentialmanager.jetpack.provider.Action
|
||||
@@ -325,7 +325,7 @@ class CredentialManagerRepo(
|
||||
key,
|
||||
subkey,
|
||||
CredentialEntry.toSlice(credentialEntry),
|
||||
null
|
||||
Intent()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ class CredentialManagerRepo(
|
||||
android.service.credentials.CallingAppInfo(
|
||||
context.applicationInfo.packageName, SigningInfo()),
|
||||
TYPE_PASSWORD_CREDENTIAL,
|
||||
toBundle("beckett-bakert@gmail.com", "password123")
|
||||
toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
|
||||
)
|
||||
val fillInIntent = Intent().putExtra(
|
||||
CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
|
||||
@@ -417,7 +417,7 @@ class CredentialManagerRepo(
|
||||
" \"residentKey\": \"required\",\n" +
|
||||
" \"requireResidentKey\": true\n" +
|
||||
" }}")
|
||||
val credentialData = request.data
|
||||
val credentialData = request.credentialData
|
||||
return RequestInfo.newCreateRequestInfo(
|
||||
Binder(),
|
||||
CreateCredentialRequest(
|
||||
@@ -432,7 +432,7 @@ class CredentialManagerRepo(
|
||||
}
|
||||
|
||||
private fun testCreatePasswordRequestInfo(): RequestInfo {
|
||||
val data = toBundle("beckett-bakert@gmail.com", "password123")
|
||||
val data = toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
|
||||
return RequestInfo.newCreateRequestInfo(
|
||||
Binder(),
|
||||
CreateCredentialRequest(
|
||||
|
||||
@@ -242,7 +242,7 @@ class CreateFlowUtils {
|
||||
packageName = it.providerFlattenedComponentName
|
||||
}
|
||||
val pkgInfo = packageManager
|
||||
.getPackageInfo(packageName,
|
||||
.getPackageInfo(packageName!!,
|
||||
PackageManager.PackageInfoFlags.of(0))
|
||||
DisabledProviderInfo(
|
||||
icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
|
||||
@@ -264,7 +264,7 @@ class CreateFlowUtils {
|
||||
val createCredentialRequest = requestInfo.createCredentialRequest
|
||||
val createCredentialRequestJetpack = createCredentialRequest?.let {
|
||||
CreateCredentialRequest.createFrom(
|
||||
it
|
||||
it.type, it.credentialData, it.candidateQueryData, it.requireSystemProvider()
|
||||
)
|
||||
}
|
||||
when (createCredentialRequestJetpack) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.credentialmanager.jetpack.developer
|
||||
|
||||
import android.credentials.Credential
|
||||
import android.os.Bundle
|
||||
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
|
||||
|
||||
/**
|
||||
* Base request class for registering a credential.
|
||||
@@ -28,27 +29,44 @@ import android.os.Bundle
|
||||
* otherwise
|
||||
*/
|
||||
open class CreateCredentialRequest(
|
||||
val type: String,
|
||||
val data: Bundle,
|
||||
val requireSystemProvider: Boolean,
|
||||
open val type: String,
|
||||
open val credentialData: Bundle,
|
||||
open val candidateQueryData: Bundle,
|
||||
open val requireSystemProvider: Boolean
|
||||
) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createFrom(from: android.credentials.CreateCredentialRequest): CreateCredentialRequest {
|
||||
fun createFrom(
|
||||
type: String,
|
||||
credentialData: Bundle,
|
||||
candidateQueryData: Bundle,
|
||||
requireSystemProvider: Boolean
|
||||
): CreateCredentialRequest {
|
||||
return try {
|
||||
when (from.type) {
|
||||
when (type) {
|
||||
Credential.TYPE_PASSWORD_CREDENTIAL ->
|
||||
CreatePasswordRequest.createFrom(from.credentialData)
|
||||
CreatePasswordRequest.createFrom(credentialData)
|
||||
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
|
||||
CreatePublicKeyCredentialBaseRequest.createFrom(from.credentialData)
|
||||
else ->
|
||||
CreateCredentialRequest(
|
||||
from.type, from.credentialData, from.requireSystemProvider()
|
||||
)
|
||||
when (credentialData.getString(BUNDLE_KEY_SUBTYPE)) {
|
||||
CreatePublicKeyCredentialRequest
|
||||
.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST ->
|
||||
CreatePublicKeyCredentialRequest.createFrom(credentialData)
|
||||
CreatePublicKeyCredentialRequestPrivileged
|
||||
.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV ->
|
||||
CreatePublicKeyCredentialRequestPrivileged
|
||||
.createFrom(credentialData)
|
||||
else -> throw FrameworkClassParsingException()
|
||||
}
|
||||
else -> throw FrameworkClassParsingException()
|
||||
}
|
||||
} catch (e: FrameworkClassParsingException) {
|
||||
CreateCredentialRequest(
|
||||
from.type, from.credentialData, from.requireSystemProvider()
|
||||
// Parsing failed but don't crash the process. Instead just output a request with
|
||||
// the raw framework values.
|
||||
CreateCustomCredentialRequest(
|
||||
type,
|
||||
credentialData,
|
||||
candidateQueryData,
|
||||
requireSystemProvider
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 custom create request class for registering a credential.
|
||||
*
|
||||
* An application can construct a subtype custom request and call
|
||||
* [CredentialManager.executeCreateCredential] to launch framework UI flows to collect consent and
|
||||
* any other metadata needed from the user to register a new user credential.
|
||||
*
|
||||
* @property type the credential type determined by the credential-type-specific subclass for custom
|
||||
* use cases
|
||||
* @property credentialData the full credential creation request data in the [Bundle] format for
|
||||
* custom use cases
|
||||
* @property candidateQueryData the partial request data in the [Bundle] format that will be sent to
|
||||
* the provider during the initial candidate query stage, which should not contain sensitive user
|
||||
* credential information
|
||||
* @property requireSystemProvider true if must only be fulfilled by a system provider and false
|
||||
* otherwise
|
||||
* @throws IllegalArgumentException If [type] is empty
|
||||
* @throws NullPointerException If [type] or [credentialData] are null
|
||||
*/
|
||||
open class CreateCustomCredentialRequest(
|
||||
final override val type: String,
|
||||
final override val credentialData: Bundle,
|
||||
final override val candidateQueryData: Bundle,
|
||||
@get:JvmName("requireSystemProvider")
|
||||
final override val requireSystemProvider: Boolean
|
||||
) : CreateCredentialRequest(type, credentialData, candidateQueryData, requireSystemProvider) {
|
||||
init {
|
||||
require(type.isNotEmpty()) { "type should not be empty" }
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,11 @@ class CreatePasswordRequest constructor(
|
||||
val id: String,
|
||||
val password: String,
|
||||
) : CreateCredentialRequest(
|
||||
Credential.TYPE_PASSWORD_CREDENTIAL,
|
||||
toBundle(id, password),
|
||||
false,
|
||||
type = Credential.TYPE_PASSWORD_CREDENTIAL,
|
||||
credentialData = toCredentialDataBundle(id, password),
|
||||
// No credential data should be sent during the query phase.
|
||||
candidateQueryData = Bundle(),
|
||||
requireSystemProvider = false,
|
||||
) {
|
||||
|
||||
init {
|
||||
@@ -46,7 +48,7 @@ class CreatePasswordRequest constructor(
|
||||
const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
|
||||
|
||||
@JvmStatic
|
||||
internal fun toBundle(id: String, password: String): Bundle {
|
||||
internal fun toCredentialDataBundle(id: String, password: String): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(BUNDLE_KEY_ID, id)
|
||||
bundle.putString(BUNDLE_KEY_PASSWORD, password)
|
||||
@@ -54,7 +56,14 @@ class CreatePasswordRequest constructor(
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createFrom(data: Bundle): CreatePasswordRequest {
|
||||
internal fun toCandidateDataBundle(id: String): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(BUNDLE_KEY_ID, id)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
internal fun createFrom(data: Bundle): CreatePasswordRequest {
|
||||
try {
|
||||
val id = data.getString(BUNDLE_KEY_ID)
|
||||
val password = data.getString(BUNDLE_KEY_PASSWORD)
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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 ->
|
||||
CreatePublicKeyCredentialRequest.createFrom(data)
|
||||
CreatePublicKeyCredentialRequestPrivileged
|
||||
.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED ->
|
||||
CreatePublicKeyCredentialRequestPrivileged.createFrom(data)
|
||||
else -> throw FrameworkClassParsingException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,50 +17,81 @@
|
||||
package com.android.credentialmanager.jetpack.developer
|
||||
|
||||
import android.os.Bundle
|
||||
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
* A request to register a passkey from the user's public key credential provider.
|
||||
*
|
||||
* @property requestJson the privileged request in JSON format in the standard webauthn web json
|
||||
* shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
|
||||
* @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
|
||||
* immediately when there is no available passkey registration offering instead of falling back to
|
||||
* discovering remote options, and false (default) otherwise
|
||||
* @throws NullPointerException If [requestJson] is null
|
||||
* @throws IllegalArgumentException If [requestJson] is empty
|
||||
*/
|
||||
class CreatePublicKeyCredentialRequest @JvmOverloads constructor(
|
||||
requestJson: String,
|
||||
@get:JvmName("allowHybrid")
|
||||
val allowHybrid: Boolean = true
|
||||
) : CreatePublicKeyCredentialBaseRequest(
|
||||
requestJson,
|
||||
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
toBundle(requestJson, allowHybrid),
|
||||
false,
|
||||
val requestJson: String,
|
||||
@get:JvmName("preferImmediatelyAvailableCredentials")
|
||||
val preferImmediatelyAvailableCredentials: Boolean = false
|
||||
) : CreateCredentialRequest(
|
||||
type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
credentialData = toCredentialDataBundle(requestJson, preferImmediatelyAvailableCredentials),
|
||||
// The whole request data should be passed during the query phase.
|
||||
candidateQueryData = toCredentialDataBundle(requestJson, preferImmediatelyAvailableCredentials),
|
||||
requireSystemProvider = false,
|
||||
) {
|
||||
|
||||
init {
|
||||
require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
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"
|
||||
const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
|
||||
"androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
|
||||
internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
|
||||
internal 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 {
|
||||
internal fun toCredentialDataBundle(
|
||||
requestJson: String,
|
||||
preferImmediatelyAvailableCredentials: Boolean
|
||||
): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(BUNDLE_KEY_SUBTYPE,
|
||||
BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST)
|
||||
BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST)
|
||||
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
|
||||
bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
|
||||
bundle.putBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
|
||||
preferImmediatelyAvailableCredentials)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createFrom(data: Bundle): CreatePublicKeyCredentialRequest {
|
||||
internal fun toCandidateDataBundle(
|
||||
requestJson: String,
|
||||
preferImmediatelyAvailableCredentials: 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_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
|
||||
preferImmediatelyAvailableCredentials)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Suppress("deprecation") // bundle.get() used for boolean value to prevent default
|
||||
// boolean value from being returned.
|
||||
@JvmStatic
|
||||
internal 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)
|
||||
val preferImmediatelyAvailableCredentials =
|
||||
data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
|
||||
return CreatePublicKeyCredentialRequest(requestJson!!,
|
||||
(preferImmediatelyAvailableCredentials!!) as Boolean)
|
||||
} catch (e: Exception) {
|
||||
throw FrameworkClassParsingException()
|
||||
}
|
||||
|
||||
@@ -17,45 +17,62 @@
|
||||
package com.android.credentialmanager.jetpack.developer
|
||||
|
||||
import android.os.Bundle
|
||||
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* brower, caBLE, can use this. These permissions will be introduced in an upcoming release.
|
||||
* TODO("Add specific permission info/annotation")
|
||||
*
|
||||
* @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
|
||||
* @property requestJson the privileged request in JSON format in the standard webauthn web json
|
||||
* shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
|
||||
* @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
|
||||
* immediately when there is no available passkey registration offering instead of falling back to
|
||||
* discovering remote options, and false (default) otherwise
|
||||
* @property relyingParty the expected true RP ID which will override the one in the [requestJson],
|
||||
* where rp is defined [here](https://w3c.github.io/webauthn/#rp-id)
|
||||
* @property clientDataHash a hash that is used to verify the [relyingParty] Identity
|
||||
* @throws NullPointerException If any of [requestJson], [relyingParty], or [clientDataHash] is
|
||||
* null
|
||||
* @throws IllegalArgumentException If any of [requestJson], [relyingParty], or [clientDataHash] is
|
||||
* empty
|
||||
*/
|
||||
class CreatePublicKeyCredentialRequestPrivileged @JvmOverloads constructor(
|
||||
requestJson: String,
|
||||
val rp: String,
|
||||
val clientDataHash: String,
|
||||
@get:JvmName("allowHybrid")
|
||||
val allowHybrid: Boolean = true
|
||||
) : CreatePublicKeyCredentialBaseRequest(
|
||||
val requestJson: String,
|
||||
val relyingParty: String,
|
||||
val clientDataHash: String,
|
||||
@get:JvmName("preferImmediatelyAvailableCredentials")
|
||||
val preferImmediatelyAvailableCredentials: Boolean = false
|
||||
) : CreateCredentialRequest(
|
||||
type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
credentialData = toCredentialDataBundle(
|
||||
requestJson,
|
||||
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
toBundle(requestJson, rp, clientDataHash, allowHybrid),
|
||||
false,
|
||||
relyingParty,
|
||||
clientDataHash,
|
||||
preferImmediatelyAvailableCredentials
|
||||
),
|
||||
// The whole request data should be passed during the query phase.
|
||||
candidateQueryData = toCredentialDataBundle(
|
||||
requestJson, relyingParty, clientDataHash, preferImmediatelyAvailableCredentials
|
||||
),
|
||||
requireSystemProvider = false,
|
||||
) {
|
||||
|
||||
init {
|
||||
require(rp.isNotEmpty()) { "rp must not be empty" }
|
||||
require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
|
||||
require(relyingParty.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) {
|
||||
class Builder(
|
||||
private var requestJson: String,
|
||||
private var relyingParty: String,
|
||||
private var clientDataHash: String
|
||||
) {
|
||||
|
||||
private var allowHybrid: Boolean = true
|
||||
private var preferImmediatelyAvailableCredentials: Boolean = false
|
||||
|
||||
/**
|
||||
* Sets the privileged request in JSON format.
|
||||
@@ -66,23 +83,30 @@ class CreatePublicKeyCredentialRequestPrivileged @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether hybrid credentials are allowed to fulfill this request, true by default.
|
||||
* Sets to true if you prefer the operation to return immediately when there is no available
|
||||
* passkey registration offering instead of falling back to discovering remote options, and
|
||||
* false otherwise.
|
||||
*
|
||||
* The default value is false.
|
||||
*/
|
||||
fun setAllowHybrid(allowHybrid: Boolean): Builder {
|
||||
this.allowHybrid = allowHybrid
|
||||
@Suppress("MissingGetterMatchingBuilder")
|
||||
fun setPreferImmediatelyAvailableCredentials(
|
||||
preferImmediatelyAvailableCredentials: Boolean
|
||||
): Builder {
|
||||
this.preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected true RP ID which will override the one in the [requestJson].
|
||||
*/
|
||||
fun setRp(rp: String): Builder {
|
||||
this.rp = rp
|
||||
fun setRelyingParty(relyingParty: String): Builder {
|
||||
this.relyingParty = relyingParty
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a hash that is used to verify the [rp] Identity.
|
||||
* Sets a hash that is used to verify the [relyingParty] Identity.
|
||||
*/
|
||||
fun setClientDataHash(clientDataHash: String): Builder {
|
||||
this.clientDataHash = clientDataHash
|
||||
@@ -91,49 +115,65 @@ class CreatePublicKeyCredentialRequestPrivileged @JvmOverloads constructor(
|
||||
|
||||
/** Builds a [CreatePublicKeyCredentialRequestPrivileged]. */
|
||||
fun build(): CreatePublicKeyCredentialRequestPrivileged {
|
||||
return CreatePublicKeyCredentialRequestPrivileged(this.requestJson,
|
||||
this.rp, this.clientDataHash, this.allowHybrid)
|
||||
return CreatePublicKeyCredentialRequestPrivileged(
|
||||
this.requestJson,
|
||||
this.relyingParty, this.clientDataHash, this.preferImmediatelyAvailableCredentials
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
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"
|
||||
internal const val BUNDLE_KEY_RELYING_PARTY =
|
||||
"androidx.credentials.BUNDLE_KEY_RELYING_PARTY"
|
||||
internal const val BUNDLE_KEY_CLIENT_DATA_HASH =
|
||||
"androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
|
||||
internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
|
||||
"androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
|
||||
|
||||
internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
|
||||
|
||||
internal const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV =
|
||||
"androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_" +
|
||||
"PRIVILEGED"
|
||||
|
||||
@JvmStatic
|
||||
internal fun toBundle(
|
||||
requestJson: String,
|
||||
rp: String,
|
||||
clientDataHash: String,
|
||||
allowHybrid: Boolean
|
||||
internal fun toCredentialDataBundle(
|
||||
requestJson: String,
|
||||
relyingParty: String,
|
||||
clientDataHash: String,
|
||||
preferImmediatelyAvailableCredentials: Boolean
|
||||
): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(BUNDLE_KEY_SUBTYPE,
|
||||
BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED)
|
||||
bundle.putString(
|
||||
PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
|
||||
BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV
|
||||
)
|
||||
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
|
||||
bundle.putString(BUNDLE_KEY_RP, rp)
|
||||
bundle.putString(BUNDLE_KEY_RELYING_PARTY, relyingParty)
|
||||
bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash)
|
||||
bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
|
||||
bundle.putBoolean(
|
||||
BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
|
||||
preferImmediatelyAvailableCredentials
|
||||
)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Suppress("deprecation") // bundle.get() used for boolean value to prevent default
|
||||
// boolean value from being returned.
|
||||
@JvmStatic
|
||||
fun createFrom(data: Bundle): CreatePublicKeyCredentialRequestPrivileged {
|
||||
internal fun createFrom(data: Bundle): CreatePublicKeyCredentialRequestPrivileged {
|
||||
try {
|
||||
val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
|
||||
val rp = data.getString(BUNDLE_KEY_RP)
|
||||
val rp = data.getString(BUNDLE_KEY_RELYING_PARTY)
|
||||
val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
|
||||
val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
|
||||
val preferImmediatelyAvailableCredentials =
|
||||
data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
|
||||
return CreatePublicKeyCredentialRequestPrivileged(
|
||||
requestJson!!,
|
||||
rp!!,
|
||||
clientDataHash!!,
|
||||
(allowHybrid!!) as Boolean,
|
||||
requestJson!!,
|
||||
rp!!,
|
||||
clientDataHash!!,
|
||||
(preferImmediatelyAvailableCredentials!!) as Boolean,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw FrameworkClassParsingException()
|
||||
|
||||
@@ -28,30 +28,40 @@ import android.os.Bundle
|
||||
* otherwise
|
||||
*/
|
||||
open class GetCredentialOption(
|
||||
val type: String,
|
||||
val data: Bundle,
|
||||
val requireSystemProvider: Boolean,
|
||||
open val type: String,
|
||||
open val requestData: Bundle,
|
||||
open val candidateQueryData: Bundle,
|
||||
open val requireSystemProvider: Boolean,
|
||||
) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createFrom(from: android.credentials.GetCredentialOption): GetCredentialOption {
|
||||
fun createFrom(
|
||||
type: String,
|
||||
requestData: Bundle,
|
||||
candidateQueryData: Bundle,
|
||||
requireSystemProvider: Boolean
|
||||
): GetCredentialOption {
|
||||
return try {
|
||||
when (from.type) {
|
||||
when (type) {
|
||||
Credential.TYPE_PASSWORD_CREDENTIAL ->
|
||||
GetPasswordOption.createFrom(from.credentialRetrievalData)
|
||||
GetPasswordOption.createFrom(requestData)
|
||||
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
|
||||
GetPublicKeyCredentialBaseOption.createFrom(from.credentialRetrievalData)
|
||||
else ->
|
||||
GetCredentialOption(
|
||||
from.type, from.credentialRetrievalData, from.requireSystemProvider()
|
||||
)
|
||||
when (requestData.getString(PublicKeyCredential.BUNDLE_KEY_SUBTYPE)) {
|
||||
GetPublicKeyCredentialOption
|
||||
.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION ->
|
||||
GetPublicKeyCredentialOption.createFrom(requestData)
|
||||
GetPublicKeyCredentialOptionPrivileged
|
||||
.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED ->
|
||||
GetPublicKeyCredentialOptionPrivileged.createFrom(requestData)
|
||||
else -> throw FrameworkClassParsingException()
|
||||
}
|
||||
else -> throw FrameworkClassParsingException()
|
||||
}
|
||||
} catch (e: FrameworkClassParsingException) {
|
||||
GetCredentialOption(
|
||||
from.type,
|
||||
from.credentialRetrievalData,
|
||||
from.requireSystemProvider()
|
||||
)
|
||||
// Parsing failed but don't crash the process. Instead just output a request with
|
||||
// the raw framework values.
|
||||
GetCustomCredentialOption(
|
||||
type, requestData, candidateQueryData, requireSystemProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ package com.android.credentialmanager.jetpack.developer
|
||||
* @throws IllegalArgumentException If [getCredentialOptions] is empty
|
||||
*/
|
||||
class GetCredentialRequest constructor(
|
||||
val getCredentialOptions: List<GetCredentialOption>,
|
||||
val getCredentialOptions: List<GetCredentialOption>,
|
||||
) {
|
||||
|
||||
init {
|
||||
@@ -61,7 +61,14 @@ class GetCredentialRequest constructor(
|
||||
@JvmStatic
|
||||
fun createFrom(from: android.credentials.GetCredentialRequest): GetCredentialRequest {
|
||||
return GetCredentialRequest(
|
||||
from.getCredentialOptions.map {GetCredentialOption.createFrom(it)}
|
||||
from.getCredentialOptions.map {
|
||||
GetCredentialOption.createFrom(
|
||||
it.type,
|
||||
it.credentialRetrievalData,
|
||||
it.candidateQueryData,
|
||||
it.requireSystemProvider()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
/**
|
||||
* Allows extending custom versions of GetCredentialOptions for unique use cases.
|
||||
*
|
||||
* @property type the credential type determined by the credential-type-specific subclass
|
||||
* generated for custom use cases
|
||||
* @property requestData the request data in the [Bundle] format, generated for custom use cases
|
||||
* @property candidateQueryData the partial request data in the [Bundle] format that will be sent to
|
||||
* the provider during the initial candidate query stage, which should not contain sensitive user
|
||||
* information
|
||||
* @property requireSystemProvider true if must only be fulfilled by a system provider and false
|
||||
* otherwise
|
||||
* @throws IllegalArgumentException If [type] is empty
|
||||
* @throws NullPointerException If [requestData] or [type] is null
|
||||
*/
|
||||
open class GetCustomCredentialOption(
|
||||
final override val type: String,
|
||||
final override val requestData: Bundle,
|
||||
final override val candidateQueryData: Bundle,
|
||||
@get:JvmName("requireSystemProvider")
|
||||
final override val requireSystemProvider: Boolean
|
||||
) : GetCredentialOption(
|
||||
type,
|
||||
requestData,
|
||||
candidateQueryData,
|
||||
requireSystemProvider
|
||||
) {
|
||||
init {
|
||||
require(type.isNotEmpty()) { "type should not be empty" }
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import android.os.Bundle
|
||||
class GetPasswordOption : GetCredentialOption(
|
||||
Credential.TYPE_PASSWORD_CREDENTIAL,
|
||||
Bundle(),
|
||||
Bundle(),
|
||||
false,
|
||||
) {
|
||||
companion object {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,44 +21,62 @@ 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
|
||||
* @property requestJson the privileged request in JSON format in the standard webauthn web json
|
||||
* shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
|
||||
* @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
|
||||
* immediately when there is no available credential instead of falling back to discovering remote
|
||||
* credentials, and false (default) otherwise
|
||||
* @throws NullPointerException If [requestJson] is null
|
||||
* @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
|
||||
val requestJson: String,
|
||||
@get:JvmName("preferImmediatelyAvailableCredentials")
|
||||
val preferImmediatelyAvailableCredentials: Boolean = false,
|
||||
) : GetCredentialOption(
|
||||
type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
requestData = toRequestDataBundle(requestJson, preferImmediatelyAvailableCredentials),
|
||||
candidateQueryData = toRequestDataBundle(requestJson, preferImmediatelyAvailableCredentials),
|
||||
requireSystemProvider = false
|
||||
) {
|
||||
init {
|
||||
require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
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"
|
||||
internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
|
||||
"androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
|
||||
internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
|
||||
internal 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 {
|
||||
internal fun toRequestDataBundle(
|
||||
requestJson: String,
|
||||
preferImmediatelyAvailableCredentials: Boolean
|
||||
): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(
|
||||
PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
|
||||
BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION
|
||||
)
|
||||
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
|
||||
bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
|
||||
bundle.putBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
|
||||
preferImmediatelyAvailableCredentials)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Suppress("deprecation") // bundle.get() used for boolean value to prevent default
|
||||
// boolean value from being returned.
|
||||
@JvmStatic
|
||||
fun createFrom(data: Bundle): GetPublicKeyCredentialOption {
|
||||
internal 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)
|
||||
val preferImmediatelyAvailableCredentials =
|
||||
data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
|
||||
return GetPublicKeyCredentialOption(requestJson!!,
|
||||
(preferImmediatelyAvailableCredentials!!) as Boolean)
|
||||
} catch (e: Exception) {
|
||||
throw FrameworkClassParsingException()
|
||||
}
|
||||
|
||||
@@ -21,41 +21,59 @@ 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.
|
||||
* can use this. These permissions will be introduced in an upcoming release.
|
||||
* TODO("Add specific permission info/annotation")
|
||||
*
|
||||
* @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
|
||||
* @property requestJson the privileged request in JSON format in the standard webauthn web json
|
||||
* shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
|
||||
* @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
|
||||
* immediately when there is no available credential instead of falling back to discovering remote
|
||||
* credentials, and false (default) otherwise
|
||||
* @property relyingParty the expected true RP ID which will override the one in the [requestJson],
|
||||
* where relyingParty is defined [here](https://w3c.github.io/webauthn/#rp-id) in more detail
|
||||
* @property clientDataHash a hash that is used to verify the [relyingParty] Identity
|
||||
* @throws NullPointerException If any of [requestJson], [relyingParty], or [clientDataHash]
|
||||
* is null
|
||||
* @throws IllegalArgumentException If any of [requestJson], [relyingParty], or [clientDataHash] is
|
||||
* empty
|
||||
*/
|
||||
class GetPublicKeyCredentialOptionPrivileged @JvmOverloads constructor(
|
||||
requestJson: String,
|
||||
val rp: String,
|
||||
val clientDataHash: String,
|
||||
@get:JvmName("allowHybrid")
|
||||
val allowHybrid: Boolean = true
|
||||
) : GetPublicKeyCredentialBaseOption(
|
||||
val requestJson: String,
|
||||
val relyingParty: String,
|
||||
val clientDataHash: String,
|
||||
@get:JvmName("preferImmediatelyAvailableCredentials")
|
||||
val preferImmediatelyAvailableCredentials: Boolean = false
|
||||
) : GetCredentialOption(
|
||||
type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
requestData = toBundle(
|
||||
requestJson,
|
||||
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
|
||||
toBundle(requestJson, rp, clientDataHash, allowHybrid),
|
||||
false,
|
||||
relyingParty,
|
||||
clientDataHash,
|
||||
preferImmediatelyAvailableCredentials
|
||||
),
|
||||
candidateQueryData = toBundle(
|
||||
requestJson,
|
||||
relyingParty,
|
||||
clientDataHash,
|
||||
preferImmediatelyAvailableCredentials
|
||||
),
|
||||
requireSystemProvider = false,
|
||||
) {
|
||||
|
||||
init {
|
||||
require(rp.isNotEmpty()) { "rp must not be empty" }
|
||||
require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
|
||||
require(relyingParty.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) {
|
||||
class Builder(
|
||||
private var requestJson: String,
|
||||
private var relyingParty: String,
|
||||
private var clientDataHash: String
|
||||
) {
|
||||
|
||||
private var allowHybrid: Boolean = true
|
||||
private var preferImmediatelyAvailableCredentials: Boolean = false
|
||||
|
||||
/**
|
||||
* Sets the privileged request in JSON format.
|
||||
@@ -66,23 +84,30 @@ class GetPublicKeyCredentialOptionPrivileged @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether hybrid credentials are allowed to fulfill this request, true by default.
|
||||
* Sets to true if you prefer the operation to return immediately when there is no available
|
||||
* credential instead of falling back to discovering remote credentials, and false
|
||||
* otherwise.
|
||||
*
|
||||
* The default value is false.
|
||||
*/
|
||||
fun setAllowHybrid(allowHybrid: Boolean): Builder {
|
||||
this.allowHybrid = allowHybrid
|
||||
@Suppress("MissingGetterMatchingBuilder")
|
||||
fun setPreferImmediatelyAvailableCredentials(
|
||||
preferImmediatelyAvailableCredentials: Boolean
|
||||
): Builder {
|
||||
this.preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected true RP ID which will override the one in the [requestJson].
|
||||
*/
|
||||
fun setRp(rp: String): Builder {
|
||||
this.rp = rp
|
||||
fun setRelyingParty(relyingParty: String): Builder {
|
||||
this.relyingParty = relyingParty
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a hash that is used to verify the [rp] Identity.
|
||||
* Sets a hash that is used to verify the [relyingParty] Identity.
|
||||
*/
|
||||
fun setClientDataHash(clientDataHash: String): Builder {
|
||||
this.clientDataHash = clientDataHash
|
||||
@@ -91,47 +116,63 @@ class GetPublicKeyCredentialOptionPrivileged @JvmOverloads constructor(
|
||||
|
||||
/** Builds a [GetPublicKeyCredentialOptionPrivileged]. */
|
||||
fun build(): GetPublicKeyCredentialOptionPrivileged {
|
||||
return GetPublicKeyCredentialOptionPrivileged(this.requestJson,
|
||||
this.rp, this.clientDataHash, this.allowHybrid)
|
||||
return GetPublicKeyCredentialOptionPrivileged(
|
||||
this.requestJson,
|
||||
this.relyingParty, this.clientDataHash, this.preferImmediatelyAvailableCredentials
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
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"
|
||||
internal const val BUNDLE_KEY_RELYING_PARTY =
|
||||
"androidx.credentials.BUNDLE_KEY_RELYING_PARTY"
|
||||
internal const val BUNDLE_KEY_CLIENT_DATA_HASH =
|
||||
"androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
|
||||
internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
|
||||
"androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
|
||||
internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
|
||||
internal 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
|
||||
requestJson: String,
|
||||
relyingParty: String,
|
||||
clientDataHash: String,
|
||||
preferImmediatelyAvailableCredentials: Boolean
|
||||
): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(
|
||||
PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
|
||||
BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED
|
||||
)
|
||||
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
|
||||
bundle.putString(BUNDLE_KEY_RP, rp)
|
||||
bundle.putString(BUNDLE_KEY_RELYING_PARTY, relyingParty)
|
||||
bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash)
|
||||
bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
|
||||
bundle.putBoolean(
|
||||
BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
|
||||
preferImmediatelyAvailableCredentials
|
||||
)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Suppress("deprecation") // bundle.get() used for boolean value to prevent default
|
||||
// boolean value from being returned.
|
||||
@JvmStatic
|
||||
fun createFrom(data: Bundle): GetPublicKeyCredentialOptionPrivileged {
|
||||
internal fun createFrom(data: Bundle): GetPublicKeyCredentialOptionPrivileged {
|
||||
try {
|
||||
val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
|
||||
val rp = data.getString(BUNDLE_KEY_RP)
|
||||
val rp = data.getString(BUNDLE_KEY_RELYING_PARTY)
|
||||
val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
|
||||
val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
|
||||
val preferImmediatelyAvailableCredentials =
|
||||
data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
|
||||
return GetPublicKeyCredentialOptionPrivileged(
|
||||
requestJson!!,
|
||||
rp!!,
|
||||
clientDataHash!!,
|
||||
(allowHybrid!!) as Boolean,
|
||||
requestJson!!,
|
||||
rp!!,
|
||||
clientDataHash!!,
|
||||
(preferImmediatelyAvailableCredentials!!) as Boolean,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw FrameworkClassParsingException()
|
||||
|
||||
@@ -45,6 +45,8 @@ class PublicKeyCredential constructor(
|
||||
/** The type value for public key credential related operations. */
|
||||
const val TYPE_PUBLIC_KEY_CREDENTIAL: String =
|
||||
"androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL"
|
||||
/** The Bundle key value for the public key credential subtype (privileged or regular). */
|
||||
internal const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
|
||||
const val BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON =
|
||||
"androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user