@@ -12,6 +12,7 @@ import at.asitplus.openid.OidcUserInfoExtended
1212import at.asitplus.openid.OpenIdConstants
1313import at.asitplus.signum.indispensable.SignatureAlgorithm
1414import at.asitplus.signum.indispensable.josef.JsonWebKeySet
15+ import at.asitplus.signum.indispensable.josef.JweEncrypted
1516import at.asitplus.signum.indispensable.josef.JwsSigned
1617import at.asitplus.wallet.lib.agent.EphemeralKeyWithoutCert
1718import at.asitplus.wallet.lib.agent.Issuer
@@ -70,6 +71,20 @@ class CredentialIssuer(
7071 private val encryptionService : IssuerEncryptionService = IssuerEncryptionService (),
7172) {
7273
74+ sealed interface CredentialResponse {
75+ /* *
76+ * Send [response] as JSON-serialized content to the client with media
77+ * type `application/json` (see [at.asitplus.wallet.lib.data.MediaTypes.Application.JSON]).
78+ */
79+ data class Plain (val response : CredentialResponseParameters ) : CredentialResponse
80+
81+ /* *
82+ * Send [response] as JWE-serialized content to the client with media
83+ * type `application/jwt` (see [at.asitplus.wallet.lib.data.MediaTypes.Application.JWT]).
84+ */
85+ data class Encrypted (val response : JweEncrypted ) : CredentialResponse
86+ }
87+
7388 private val supportedCredentialConfigurations = credentialSchemes
7489 .flatMap { it.toSupportedCredentialFormat().entries }
7590 .associate {
@@ -165,12 +180,12 @@ class CredentialIssuer(
165180 input : String ,
166181 credentialDataProvider : CredentialDataProviderFun ,
167182 request : RequestInfo ? = null,
168- ): KmmResult <CredentialResponseParameters > = catching {
183+ ): KmmResult <CredentialResponse > = catching {
169184 credentialInternal(
170185 authorizationHeader = authorizationHeader,
171- params = encryptionService.decrypt(input).getOrThrow(),
186+ request = encryptionService.decrypt(input).getOrThrow(),
172187 credentialDataProvider = credentialDataProvider,
173- request = request,
188+ requestInfo = request,
174189 hasBeenEncrypted = true ,
175190 ).getOrThrow()
176191 }
@@ -196,11 +211,11 @@ class CredentialIssuer(
196211 params : CredentialRequestParameters ,
197212 credentialDataProvider : CredentialDataProviderFun ,
198213 request : RequestInfo ? = null,
199- ): KmmResult <CredentialResponseParameters > = credentialInternal(
214+ ): KmmResult <CredentialResponse > = credentialInternal(
200215 authorizationHeader = authorizationHeader,
201- params = params,
216+ request = params,
202217 credentialDataProvider = credentialDataProvider,
203- request = request,
218+ requestInfo = request,
204219 hasBeenEncrypted = false ,
205220 )
206221
@@ -225,12 +240,12 @@ class CredentialIssuer(
225240 params : WalletService .CredentialRequest ,
226241 credentialDataProvider : CredentialDataProviderFun ,
227242 request : RequestInfo ? = null,
228- ): KmmResult <CredentialResponseParameters > = catching {
243+ ): KmmResult <CredentialResponse > = catching {
229244 credentialInternal(
230245 authorizationHeader = authorizationHeader,
231- params = params.decryptIfNeeded(),
246+ request = params.decryptIfNeeded(),
232247 credentialDataProvider = credentialDataProvider,
233- request = request,
248+ requestInfo = request,
234249 hasBeenEncrypted = false ,
235250 ).getOrThrow()
236251 }
@@ -242,19 +257,19 @@ class CredentialIssuer(
242257
243258 private suspend fun credentialInternal (
244259 authorizationHeader : String ,
245- params : CredentialRequestParameters ,
260+ request : CredentialRequestParameters ,
246261 credentialDataProvider : CredentialDataProviderFun ,
247- request : RequestInfo ? = null,
262+ requestInfo : RequestInfo ? = null,
248263 hasBeenEncrypted : Boolean = false,
249- ): KmmResult <CredentialResponseParameters > = catching {
264+ ): KmmResult <CredentialResponse > = catching {
250265 Napier .i(" credential called" )
251- Napier .d(" credential called with $authorizationHeader , $params " )
266+ Napier .d(" credential called with $authorizationHeader , $request " )
252267 if (! hasBeenEncrypted && encryptionService.requireRequestEncryption)
253268 throw InvalidEncryptionParameters (" Credential request has not been encrypted" )
254- authorizationService.validateAccessToken(authorizationHeader, request ).getOrThrow()
255- val userInfo = params .introspectTokenLoadUserInfo(authorizationHeader, request )
256- val (scheme, representation) = params .extractCredentialRepresentation()
257- proofValidator.validateProofExtractSubjectPublicKeys(params ).map { subjectPublicKey ->
269+ authorizationService.validateAccessToken(authorizationHeader, requestInfo ).getOrThrow()
270+ val userInfo = request .introspectTokenLoadUserInfo(authorizationHeader, requestInfo )
271+ val (scheme, representation) = request .extractCredentialRepresentation()
272+ val responseParameters = proofValidator.validateProofExtractSubjectPublicKeys(request ).map { subjectPublicKey ->
258273 issuer.issueCredential(
259274 credentialDataProvider(
260275 CredentialDataProviderInput (
@@ -269,7 +284,8 @@ class CredentialIssuer(
269284 ).getOrElse {
270285 throw CredentialRequestDenied (" No credential from issuer" , it)
271286 }
272- }.toCredentialResponseParameters(encryptionService.encryptResponseIfNecessary(params))
287+ }.toCredentialResponseParameters()
288+ encryptionService.encryptResponse(responseParameters, request)
273289 .also { Napier .i(" credential returns" ); Napier .d(" credential returns $it " ) }
274290 }
275291
@@ -299,10 +315,16 @@ class CredentialIssuer(
299315 if (! it.validCredentialIdentifiers.contains(credentialIdentifier))
300316 throw InvalidToken (" credential_identifier $credentialIdentifier expected to be in $it " )
301317 } ? : credentialConfigurationId?.let { credentialConfigurationId ->
302- if (it.scope == null )
303- throw InvalidToken (" no scope stored for access token $authorizationHeader " )
304- if (! it.scope.contains(credentialConfigurationId))
305- throw InvalidToken (" credential_configuration_id $credentialConfigurationId expected to be $it " )
318+ // TODO Test this
319+ if (it.scope != null ) {
320+ if (! it.scope.contains(credentialConfigurationId))
321+ throw InvalidToken (" credential_configuration_id $credentialConfigurationId expected to be $it " )
322+ } else if (it.authorizationDetails != null ) {
323+ if (! it.validCredentialConfigurationIds.contains(credentialConfigurationId))
324+ throw InvalidToken (" credential_configuration_id $credentialConfigurationId expected to be in $it " )
325+ } else {
326+ throw InvalidToken (" neither scope nor authorization details stored $authorizationHeader " )
327+ }
306328 } ? : authorizationHeader.run {
307329 throw InvalidToken (" neither credential_identifier nor credential_configuration_id set" )
308330 }
0 commit comments