L'API Credential Manager Holder consente all'app holder (chiamata anche "wallet") per Android di gestire e presentare le credenziali digitali ai verificatori.
Concetti principali
Prima di utilizzare l'API Holder, è importante acquisire familiarità con i seguenti concetti.
Formati delle credenziali
Le credenziali possono essere memorizzate nelle app di archiviazione in diversi formati. Questi formati sono specifiche su come deve essere rappresentata una credenziale e ognuno contiene le seguenti informazioni sulla credenziale:
- Tipo:la categoria, ad esempio una laurea o una patente di guida digitale.
- Proprietà:attributi come nome e cognome.
- Codifica:il modo in cui è strutturata la credenziale, ad esempio SD-JWT o mdoc
- Validità:metodo per verificare crittograficamente l'autenticità della credenziale.
Ogni formato delle credenziali esegue la codifica e la convalida in modo leggermente diverso, ma a livello funzionale sono uguali.
Il registro supporta due formati:
- SD-JWT:è conforme alla specifica IETF SD-JWT-based Verifiable Credentials (SD-JWT VC).
- Documenti mobili o mdocs:sono conformi alla specifica ISO/IEC 18013-5:2021.
Un verificatore può effettuare una richiesta OpenID4VP per SD-JWT e mdoc quando utilizza Credential Manager. La scelta varia in base al caso d'uso e al settore.
Registrazione dei metadati delle credenziali
Gestore delle credenziali non memorizza direttamente le credenziali di un titolare, ma i
metadati delle credenziali. Un'app titolare deve prima registrare i metadati delle credenziali
con Credential Manager utilizzando RegistryManager. Questa procedura di registrazione
crea un record del registro che ha due scopi principali:
- Corrispondenza:i metadati delle credenziali registrate vengono utilizzati per la corrispondenza con le future richieste di verifica.
- Display:gli elementi della UI personalizzati vengono mostrati all'utente nell'interfaccia del selettore delle credenziali.
Utilizzerai la classe OpenId4VpRegistry per registrare le tue credenziali digitali,
in quanto supporta i formati delle credenziali mdoc e SD-JWT. I verificatori invieranno
richieste OpenID4VP per richiedere queste credenziali.
Registrare le credenziali dell'app
Per utilizzare l'API Credential Manager Holder, aggiungi le seguenti dipendenze allo script di build del modulo dell'app:
Groovy
dependencies { // Use to implement credentials registrys implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04" implementation "androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04" implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha04" implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04" }
Kotlin
dependencies { // Use to implement credentials registrys implementation("androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04") implementation("androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04") implementation("androidx.credentials.registry:registry-provider:1.0.0-alpha04") implementation("androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04") }
Crea RegistryManager
Crea un'istanza RegistryManager e registra una richiesta OpenId4VpRegistry.
// Create the registry manager
val registryManager = RegistryManager.create(context)
// The guide covers how to build this out later
val registryRequest = OpenId4VpRegistry(credentialEntries, id)
try {
registryManager.registerCredentials(registryRequest)
} catch (e: Exception) {
// Handle exceptions
}
Crea una richiesta OpenId4VpRegistry
Come accennato in precedenza, dovrai registrare un OpenId4VpRegistry per gestire
una richiesta OpenID4VP da un verificatore. Supporremo che tu abbia caricato alcuni tipi di dati locali con le credenziali del tuo wallet (ad esempio sdJwtsFromStorage). Ora li convertirai negli equivalenti Jetpack DigitalCredentialEntry in base al loro formato: SdJwtEntry o MdocEntry per SD-JWT o mdoc, rispettivamente.
Aggiungere Sd-JWT al registro
Mappa ogni credenziale SD-JWT locale a un SdJwtEntry per il registro:
fun mapToSdJwtEntries(sdJwtsFromStorage: List<StoredSdJwtEntry>): List<SdJwtEntry> {
val list = mutableListOf<SdJwtEntry>()
for (sdJwt in sdJwtsFromStorage) {
list.add(
SdJwtEntry(
verifiableCredentialType = sdJwt.getVCT(),
claims = sdJwt.getClaimsList(),
entryDisplayPropertySet = sdJwt.toDisplayProperties(),
id = sdJwt.getId() // Make sure this cannot be readily guessed
)
)
}
return list
}
Aggiungere mdocs al Registro di sistema
Mappa le tue credenziali mdoc locali nel tipo Jetpack MdocEntry:
fun mapToMdocEntries(mdocsFromStorage: List<StoredMdocEntry>): List<MdocEntry> {
val list = mutableListOf<MdocEntry>()
for (mdoc in mdocsFromStorage) {
list.add(
MdocEntry(
docType = mdoc.retrieveDocType(),
fields = mdoc.getFields(),
entryDisplayPropertySet = mdoc.toDisplayProperties(),
id = mdoc.getId() // Make sure this cannot be readily guessed
)
)
}
return list
}
Punti chiave sul codice
- Un metodo per configurare il campo
idconsiste nel registrare un identificatore delle credenziali criptato, in modo che solo tu possa decriptare il valore. - I campi di visualizzazione dell'interfaccia utente per entrambi i formati devono essere localizzati.
Registrare le credenziali
Combina le voci convertite e registra la richiesta con
RegistryManager:
val credentialEntries = mapToSdJwtEntries(sdJwtsFromStorage) + mapToMdocEntries(mdocsFromStorage)
val openidRegistryRequest = OpenId4VpRegistry(
credentialEntries = credentialEntries,
id = "my-wallet-openid-registry-v1" // A stable, unique ID to identify your registry record.
)
Ora siamo pronti a registrare le tue credenziali in Credential Manager.
try {
val response = registryManager.registerCredentials(openidRegistryRequest)
} catch (e: Exception) {
// Handle failure
}
Ora hai registrato le tue credenziali in Gestore delle credenziali.
Gestione dei metadati delle app
I metadati che l'app titolare registra con Credential Manager hanno le seguenti proprietà:
- Persistenza: le informazioni vengono salvate localmente e persistono tra i riavvii.
- Archiviazione isolata:i record del registro di ogni app vengono archiviati separatamente, il che significa che un'app non può modificare i record del registro di un'altra app.
- Aggiornamenti basati su chiavi:i record del registro di ogni app sono identificati da una
id, che consente di identificare, aggiornare o eliminare i record. - Aggiornamento dei metadati:è buona norma aggiornare i metadati persistenti
ogni volta che l'app cambia o viene caricata per la prima volta. Se un registro viene chiamato più
volte con lo stesso
id, l'ultima chiamata sovrascrive tutti i record precedenti. Per aggiornare, registra di nuovo senza dover prima cancellare il vecchio record.
(Facoltativo) Crea un matcher
Un matcher è un binario Wasm che Credential Manager esegue in una sandbox per filtrare le credenziali registrate in base a una richiesta di verifica in entrata.
- Matcher predefinito: la classe
OpenId4VpRegistryinclude automaticamente il matcherOpenId4VPpredefinito (OpenId4VpDefaults.DEFAULT_MATCHER) quando lo istanzi. Per tutti i casi d'uso standard di OpenID4VP, la libreria gestisce la corrispondenza per te. - Matcher personalizzato: implementa un matcher personalizzato solo se supporti un protocollo non standard che richiede una logica di corrispondenza propria.
Gestire una credenziale selezionata
Quando un utente seleziona una credenziale, l'app titolare deve gestire la richiesta.
Devi definire un'attività che ascolti il filtro
androidx.credentials.registry.provider.action.GET_CREDENTIAL intent.
Il nostro portafoglio di esempio mostra questa procedura.
L'intent avvia l'attività con la richiesta del verificatore e l'origine della chiamata, che estrai con la funzione PendingIntentHandler.retrieveProviderGetCredentialRequest. Questo
restituisce un ProviderGetCredentialRequest contenente tutte le informazioni
associate alla richiesta di verifica. Esistono tre componenti chiave:
- L'app di chiamate:l'app che ha effettuato la richiesta, recuperabile con
getCallingAppInfo. - La credenziale selezionata:informazioni sul candidato scelto dall'utente, recuperate tramite
selectedCredentialSet extension method; corrisponderà all'ID credenziale registrato. - Richieste specifiche: la richiesta specifica effettuata dal verificatore, recuperata
dal metodo
getCredentialOptions. Per un flusso di richiesta di credenziali digitali, puoi aspettarti di trovare un singoloGetDigitalCredentialOptionin questo elenco.
Nella maggior parte dei casi, il verificatore invia una richiesta di presentazione delle credenziali digitali, che puoi elaborare con il seguente codice di esempio:
request.credentialOptions.forEach { option ->
if (option is GetDigitalCredentialOption) {
Log.i(TAG, "Got DC request: ${option.requestJson}")
processRequest(option.requestJson)
}
}
Un esempio è visibile nel portafoglio campione.
Controllare l'identità del verificatore
- Estrai
ProviderGetCredentialRequestdall'intent:
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
- Controlla l'origine privilegiata:le app privilegiate (come i browser web) possono
effettuare chiamate per conto di altri verificatori impostando il parametro origine. Per recuperare questa origine, devi passare un elenco di chiamanti privilegiati e attendibili (una lista consentita in formato JSON) all'API
CallingAppInfodigetOrigin().
val origin = request?.callingAppInfo?.getOrigin(
privilegedAppsJson // Your allow list JSON
)
Se l'origine non è vuota:l'origine viene restituita se packageName e le impronte dei certificati ottenute da signingInfo corrispondono a quelle di un'app trovata nell'allowlist passata all'API getOrigin(). Una volta ottenuto il valore dell'origine, l'app del fornitore deve considerarlo una chiamata privilegiata e impostare questa origine nella risposta OpenID4VP, anziché calcolarla utilizzando la firma dell'app chiamante.
Gestore delle password di Google utilizza un elenco consentito disponibile pubblicamente per le chiamate a
getOrigin(). In qualità di fornitore di credenziali, puoi utilizzare questo elenco o fornire il tuo in formato JSON descritto dall'API. Spetta al fornitore selezionare
l'elenco da utilizzare. Per ottenere l'accesso privilegiato con i fornitori di credenziali di terze parti, consulta la documentazione fornita dalla terza parte.
Se l'origine è vuota,la richiesta di verifica proviene da un'app per Android. L'origine dell'app da inserire nella risposta OpenID4VP deve essere calcolata come
android:apk-key-hash:<encoded SHA 256 fingerprint>.
val appSigningInfo = request?.callingAppInfo?.signingInfoCompat?.signingCertificateHistory[0]?.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val certHash = Base64.encodeToString(md.digest(appSigningInfo), Base64.NO_WRAP or Base64.NO_PADDING)
return "android:apk-key-hash:$certHash"
Eseguire il rendering della UI del supporto
Quando viene selezionata una credenziale, viene richiamata l'app titolare, guidando l'utente nell'interfaccia utente dell'app. Esistono due modi standard per gestire questo flusso di lavoro:
- Se è necessaria un'autenticazione utente aggiuntiva per rilasciare la credenziale, utilizza l'API BiometricPrompt. Ciò è dimostrato nell'esempio.
- In caso contrario, molti wallet optano per un ritorno silenzioso eseguendo il rendering di un'attività vuota che restituisce immediatamente i dati all'app chiamante. In questo modo, si riducono al minimo i clic degli utenti e si offre un'esperienza più fluida.
Restituisce la risposta delle credenziali
Quando l'app titolare è pronta a inviare il risultato, completa l'attività con la risposta della credenziale:
PendingIntentHandler.setGetCredentialResponse(
resultData,
GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()
Se esiste un'eccezione, puoi inviare anche l'eccezione delle credenziali:
PendingIntentHandler.setGetCredentialException(
resultData,
GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()
Fai riferimento all'app di esempio per un esempio completo di restituzione della risposta delle credenziali nel contesto.