blob: c75b5618ec29d5453e70b89b8b6e89177538ff05 [file] [log] [blame]
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.credentials
import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.credentials.internal.FrameworkClassParsingException
/**
* 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
* @param id the user id associated with the password
* @param password the password
* @param origin the origin of a different application if the request is being made on behalf of
* that application (Note: for API level >=34, setting a non-null value for this parameter will
* throw a SecurityException if android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present)
* @param preferImmediatelyAvailableCredentials true if you prefer the operation to return
* immediately when there is no available credential creation offering instead of falling back to
* discovering remote options, and false (default) otherwise
*/
class CreatePasswordRequest private constructor(
val id: String,
val password: String,
isAutoSelectAllowed: Boolean,
displayInfo: DisplayInfo,
origin: String? = null,
preferImmediatelyAvailableCredentials: Boolean,
credentialData: Bundle = toCredentialDataBundle(id, password),
candidateQueryData: Bundle = toCandidateDataBundle(),
) : CreateCredentialRequest(
type = PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
credentialData = credentialData,
candidateQueryData = candidateQueryData,
isSystemProviderRequired = false,
isAutoSelectAllowed,
displayInfo,
origin,
preferImmediatelyAvailableCredentials,
) {
/**
* Constructs a [CreatePasswordRequest] to save the user password credential with their
* password provider.
*
* @param id the user id associated with the password
* @param password the password
* @param origin the origin of a different application if the request is being made on behalf of
* that application (Note: for API level >=34, setting a non-null value for this parameter will
* throw a SecurityException if android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present)
* @param preferImmediatelyAvailableCredentials true if you prefer the operation to return
* immediately when there is no available password saving option instead of falling back
* to discovering remote options, and false (default) otherwise
* @param isAutoSelectAllowed whether a create option will be automatically chosen if it is
* the only one available to the user (note that there is a chance that the credential provider
* does not support auto-select even if you turn this bit on); not recommended to be true for
* password request type to ensure that the user will always get a confirmation dialog even if
* the password saving provider does not offer any UI
* @throws NullPointerException If [id] is null
* @throws NullPointerException If [password] is null
* @throws IllegalArgumentException If [password] is empty
* @throws SecurityException if [origin] is set but
* android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present
*/
@JvmOverloads constructor(
id: String,
password: String,
origin: String? = null,
preferImmediatelyAvailableCredentials: Boolean = false,
isAutoSelectAllowed: Boolean = false,
) : this(
id = id,
password = password,
isAutoSelectAllowed = isAutoSelectAllowed,
displayInfo = DisplayInfo(id, null),
origin = origin,
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials)
/**
* Constructs a [CreatePasswordRequest] to save the user password credential with their
* password provider.
*
* @param id the user id associated with the password
* @param password the password
* @param origin the origin of a different application if the request is being made on behalf of
* that application (Note: for API level >=34, setting a non-null value for this parameter will
* throw a SecurityException if android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present)
* @param preferDefaultProvider the preferred default provider component name to prioritize in
* the selection UI flows (Note: your app must have the permission
* android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS to specify this, or it
* would not take effect; also this bit may not take effect for Android API level 33 and below,
* depending on the pre-34 provider(s) you have chosen)
* @param 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 (preferably) otherwise
* @param isAutoSelectAllowed whether a create option will be automatically chosen if it is
* the only one available to the user (note that there is a chance that the credential provider
* does not support auto-select even if you turn this bit on); not recommended to be true for
* password request type to ensure that the user will always get a confirmation dialog even if
* the password saving provider does not offer any UI
* @throws NullPointerException If [id] is null
* @throws NullPointerException If [password] is null
* @throws IllegalArgumentException If [password] is empty
* @throws SecurityException if [origin] is set but
* android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present
*/
constructor(
id: String,
password: String,
origin: String?,
preferDefaultProvider: String?,
preferImmediatelyAvailableCredentials: Boolean,
isAutoSelectAllowed: Boolean
) : this(
id = id,
password = password,
isAutoSelectAllowed = isAutoSelectAllowed,
displayInfo = DisplayInfo(
userId = id,
userDisplayName = null,
preferDefaultProvider = preferDefaultProvider,
),
origin = origin,
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
)
init {
require(password.isNotEmpty()) { "password should not be empty" }
}
internal companion object {
@RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID"
@RestrictTo(RestrictTo.Scope.LIBRARY) // used from java tests
const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
@JvmStatic
internal fun toCredentialDataBundle(id: String, password: String): Bundle {
val bundle = Bundle()
bundle.putString(BUNDLE_KEY_ID, id)
bundle.putString(BUNDLE_KEY_PASSWORD, password)
return bundle
}
// No credential data should be sent during the query phase.
@JvmStatic
internal fun toCandidateDataBundle(): Bundle {
return Bundle()
}
@JvmStatic
@RequiresApi(23)
internal fun createFrom(
data: Bundle,
origin: String?,
candidateQueryData: Bundle,
): CreatePasswordRequest {
try {
val id = data.getString(BUNDLE_KEY_ID)!!
val password = data.getString(BUNDLE_KEY_PASSWORD)!!
val displayInfo = try {
DisplayInfo.parseFromCredentialDataBundle(data)
} catch (e: IllegalArgumentException) {
DisplayInfo(id, null)
}
val preferImmediatelyAvailableCredentials =
data.getBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS, false)
val isAutoSelectAllowed =
data.getBoolean(BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED, false)
return CreatePasswordRequest(
id = id,
password = password,
displayInfo = displayInfo,
origin = origin,
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
credentialData = data,
candidateQueryData = candidateQueryData,
isAutoSelectAllowed = isAutoSelectAllowed,
)
} catch (e: Exception) {
throw FrameworkClassParsingException()
}
}
}
}