Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/client id scheme #150

Open
wants to merge 3 commits into
base: feature/refactor-issuing
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Release 5.1.0:
- Refactor `issueCredential` of `Issuer` to directly get the credential-to-be-issued
- Replace `buildIssuerCredentialDataProviderOverride` in `CredentialIssuer` with `credentialProvider` to extract user information into a credential
- Remove `dataProvider` from `IssuerAgent`s constructor, as it is not needed with the new issuing interface anyway
- Replace `relyingPartyUrl` with `clientIdScheme` on `OidcSiopVerifier`s constructor, to clarify use of `client_id` in requests
- Rename objects in `OpenIdConstants.ProofType`, `OpenIdConstants.CliendIdScheme` and `OpenIdConstants.ResponseMode`

Release 5.0.1:
- Update JsonPath4K to 2.4.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@ package at.asitplus.openid

import at.asitplus.KmmResult.Companion.wrap
import at.asitplus.dif.PresentationDefinition
import at.asitplus.signum.indispensable.io.ByteArrayBase64Serializer
import at.asitplus.signum.indispensable.io.ByteArrayBase64UrlSerializer
import at.asitplus.signum.indispensable.josef.JsonWebToken
import at.asitplus.signum.indispensable.josef.io.InstantLongSerializer
import kotlinx.datetime.Instant
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encodeToString
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
* Contents of an OIDC Authentication Request.
Expand All @@ -41,7 +33,7 @@ data class AuthenticationRequestParameters(
* OIDC: REQUIRED. OAuth 2.0 Client Identifier valid at the Authorization Server.
*/
@SerialName("client_id")
val clientId: String? = null,
val clientId: String,

/**
* OIDC: REQUIRED. Redirection URI to which the response will be sent. This URI MUST exactly match one of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ object OpenIdConstants {
* Any proof type not natively supported by this library
*/
@Serializable(with = Serializer::class)
class OTHER(stringRepresentation: String) : ProofType(stringRepresentation)
class Other(stringRepresentation: String) : ProofType(stringRepresentation)

object Serializer : KSerializer<ProofType> {
override val descriptor: SerialDescriptor =
Expand All @@ -88,7 +88,7 @@ object OpenIdConstants {
return when (val str = decoder.decodeString()) {
STRING_JWT -> JWT
STRING_CWT -> CWT
else -> OTHER(str)
else -> Other(str)
}
}

Expand Down Expand Up @@ -121,21 +121,22 @@ object OpenIdConstants {
}

/**
* This value represents the RFC6749 default behavior, i.e., the Client Identifier needs to be known to the
* Wallet in advance of the Authorization Request. The Verifier metadata is obtained using RFC7591 or
* through out-of-band mechanisms.
* This value represents the RFC6749 default behavior, i.e., the Client Identifier needs to be known to the
* Wallet in advance of the Authorization Request. The Verifier metadata is obtained using RFC7591 or through
* out-of-band mechanisms.
*/
@Serializable(with = Serializer::class)
object PRE_REGISTERED : ClientIdScheme(STRING_PRE_REGISTERED)
object PreRegistered : ClientIdScheme(STRING_PRE_REGISTERED)

/**
* This value indicates that the Verifier's redirect URI is also the value of the Client Identifier.
* In this case, the Authorization Request MUST NOT be signed, the Verifier MAY omit the `redirect_uri`
* Authorization Request parameter, and all Verifier metadata parameters MUST be passed using the
* `client_metadata` or `client_metadata_uri` parameter.
* This value indicates that the Verifier's Redirect URI (or Response URI when Response Mode `direct_post` is
* used) is also the value of the Client Identifier. The Authorization Request MUST NOT be signed.
* The Verifier MAY omit the `redirect_uri` Authorization Request parameter (or `response_uri` when Response
* Mode `direct_post` is used). All Verifier metadata parameters MUST be passed using the `client_metadata`
* parameter.
*/
@Serializable(with = Serializer::class)
object REDIRECT_URI : ClientIdScheme(STRING_REDIRECT_URI)
object RedirectUri : ClientIdScheme(STRING_REDIRECT_URI)

/**
* When the Client Identifier Scheme is x509_san_dns, the Client Identifier MUST be a DNS name and match a
Expand All @@ -152,24 +153,21 @@ object OpenIdConstants {
* Client Identifier.
*/
@Serializable(with = Serializer::class)
object X509_SAN_DNS : ClientIdScheme(STRING_X509_SAN_DNS)
object X509SanDns : ClientIdScheme(STRING_X509_SAN_DNS)

/**
* When the Client Identifier Scheme is x509_san_uri, the Client Identifier MUST be a URI name and match a
* `uniformResourceIdentifier` Subject Alternative Name (SAN) [RFC5280](https://www.rfc-editor.org/info/rfc5280) entry in the leaf
* certificate passed with the request. The request MUST be signed with the private key corresponding to the
* public key in the leaf X.509 certificate of the certificate chain added to the request in the `x5c` JOSE
* header [RFC7515](https://www.rfc-editor.org/info/rfc7515) of the signed request object.
*
* The Wallet MUST validate the signature and the trust chain of the X.509 certificate.
* All Verifier metadata other than the public key MUST be obtained from the `client_metadata` parameter.
* If the Wallet can establish trust in the Client Identifier authenticated through the certificate, e.g.
* because the Client Identifier is contained in a list of trusted Client Identifiers, it may allow the client
* to freely choose the `redirect_uri` value. If not, the FQDN of the `redirect_uri` value MUST match the
* Client Identifier.
* When the Client Identifier Scheme is `x509_san_uri`, the Client Identifier MUST be a URI and match a
* `uniformResourceIdentifier` Subject Alternative Name (SAN) RFC5280 entry in the leaf certificate passed with
* the request. The request MUST be signed with the private key corresponding to the public key in the leaf
* X.509 certificate of the certificate chain added to the request in the `x5c` JOSE header RFC7515 of the
* signed request object. The Wallet MUST validate the signature and the trust chain of the X.509 certificate.
* All Verifier metadata other than the public key MUST be obtained from the `client_metadata` parameter. If
* the Wallet can establish trust in the Client Identifier authenticated through the certificate, e.g. because
* the Client Identifier is contained in a list of trusted Client Identifiers, it may allow the client to
* freely choose the `redirect_uri` value. If not, the `redirect_uri` value MUST match the Client Identifier.
*/
@Serializable(with = Serializer::class)
object X509_SAN_URI : ClientIdScheme(STRING_X509_SAN_URI)
object X509SanUri : ClientIdScheme(STRING_X509_SAN_URI)

/**
* This value indicates that the Client Identifier is an Entity Identifier defined in OpenID Connect Federation.
Expand All @@ -180,7 +178,7 @@ object OpenIdConstants {
* Identifier scheme is used.
*/
@Serializable(with = Serializer::class)
object ENTITY_ID : ClientIdScheme(STRING_ENTITY_ID)
object EntityId : ClientIdScheme(STRING_ENTITY_ID)

/**
* This value indicates that the Client Identifier is a DID defined in DID-Core. The request MUST be signed
Expand All @@ -192,43 +190,43 @@ object OpenIdConstants {
* or the `client_metadata_uri` parameter.
*/
@Serializable(with = Serializer::class)
object DID : ClientIdScheme(STRING_DID)
object Did : ClientIdScheme(STRING_DID)

/**
* This scheme allows the Verifier to authenticate using a JWT that is bound to a certain public key. When the
* scheme is `verifier_attestation`, the Client Identifier MUST equal the `sub` claim value in the Verifier
* attestation JWT. The request MUST be signed with the private key corresponding to the public key in the `cnf`
* claim in the Verifier attestation JWT. This serves as proof of possession of this key. The Verifier
* attestation JWT MUST be added to the `jwt` JOSE Header of the request object. The Wallet MUST validate the
* signature on the Verifier attestation JWT. The `iss` claim value of the Verifier Attestation JWT MUST
* identify a party the Wallet trusts for issuing Verifier Attestation JWTs. If the Wallet cannot establish
* trust, it MUST refuse the request. If the issuer of the Verifier Attestation JWT adds a `redirect_uris` claim
* to the attestation, the Wallet MUST ensure the `redirect_uri` request parameter value exactly matches one of
* the `redirect_uris` claim entries. All Verifier metadata other than the public key MUST be obtained from the
* `client_metadata` or the `client_metadata_uri parameter`.
* This Client Identifier Scheme allows the Verifier to authenticate using a JWT that is bound to a certain
* public key. When the Client Identifier Scheme is `verifier_attestation`, the Client Identifier MUST equal
* the `sub` claim value in the Verifier attestation JWT. The request MUST be signed with the private key
* corresponding to the public key in the `cnf` claim in the Verifier attestation JWT. This serves as proof of
* possession of this key. The Verifier attestation JWT MUST be added to the `jwt` JOSE Header of the request
* object. The Wallet MUST validate the signature on the Verifier attestation JWT. The `iss` claim value of the
* Verifier Attestation JWT MUST identify a party the Wallet trusts for issuing Verifier Attestation JWTs.
* If the Wallet cannot establish trust, it MUST refuse the request. If the issuer of the Verifier Attestation
* JWT adds a `redirect_uris` claim to the attestation, the Wallet MUST ensure the `redirect_uri` request
* parameter value exactly matches one of the `redirect_uris` claim entries. All Verifier metadata other than
* the public key MUST be obtained from the `client_metadata` parameter.
*/
@Serializable(with = Serializer::class)
object VERIFIER_ATTESTATION : ClientIdScheme(STRING_VERIFIER_ATTESTATION)
object VerifierAttestation : ClientIdScheme(STRING_VERIFIER_ATTESTATION)

/**
* Any not natively supported client id scheme, so it can still be parsed
*/
@Serializable(with = Serializer::class)
class OTHER(stringRepresentation: String) : ClientIdScheme(stringRepresentation)
class Other(stringRepresentation: String) : ClientIdScheme(stringRepresentation)

object Serializer : KSerializer<ClientIdScheme> {
override val descriptor = PrimitiveSerialDescriptor("ClientIdScheme", PrimitiveKind.STRING)

override fun deserialize(decoder: Decoder): ClientIdScheme {
return when (val string = decoder.decodeString()) {
STRING_PRE_REGISTERED -> PRE_REGISTERED
STRING_REDIRECT_URI -> REDIRECT_URI
STRING_X509_SAN_DNS -> X509_SAN_DNS
STRING_X509_SAN_URI -> X509_SAN_URI
STRING_ENTITY_ID -> ENTITY_ID
STRING_DID -> DID
STRING_VERIFIER_ATTESTATION -> VERIFIER_ATTESTATION
else -> OTHER(string)
STRING_PRE_REGISTERED -> PreRegistered
STRING_REDIRECT_URI -> RedirectUri
STRING_X509_SAN_DNS -> X509SanDns
STRING_X509_SAN_URI -> X509SanUri
STRING_ENTITY_ID -> EntityId
STRING_DID -> Did
STRING_VERIFIER_ATTESTATION -> VerifierAttestation
else -> Other(string)
}
}

Expand Down Expand Up @@ -265,7 +263,7 @@ object OpenIdConstants {
* with a redirect URI to the Wallet.
*/
@Serializable(with = Serializer::class)
object DIRECT_POST : ResponseMode(STRING_DIRECT_POST)
object DirectPost : ResponseMode(STRING_DIRECT_POST)

/**
* OID4VP: The Response Mode `direct_post.jwt` causes the Wallet to send the Authorization Response using an
Expand All @@ -274,37 +272,37 @@ object OpenIdConstants {
* using the `application/x-www-form-urlencoded` content type.
*/
@Serializable(with = Serializer::class)
object DIRECT_POST_JWT : ResponseMode(STRING_DIRECT_POST_JWT)
object DirectPostJwt : ResponseMode(STRING_DIRECT_POST_JWT)

/**
* OAuth 2.0: In this mode, Authorization Response parameters are encoded in the query string added to the
* `redirect_uri` when redirecting back to the Client.
*/
@Serializable(with = Serializer::class)
object QUERY : ResponseMode(STRING_QUERY)
object Query : ResponseMode(STRING_QUERY)

/**
* OAuth 2.0: In this mode, Authorization Response parameters are encoded in the fragment added to the
* `redirect_uri` when redirecting back to the Client.
*/
@Serializable(with = Serializer::class)
object FRAGMENT : ResponseMode(STRING_FRAGMENT)
object Fragment : ResponseMode(STRING_FRAGMENT)

/**
* Any not natively supported Client ID Scheme, so it can still be parsed
*/
@Serializable(with = Serializer::class)
class OTHER(stringRepresentation: String) : ResponseMode(stringRepresentation)
class Other(stringRepresentation: String) : ResponseMode(stringRepresentation)

object Serializer : KSerializer<ResponseMode> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ResponseMode", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): ResponseMode {
return when (val string = decoder.decodeString()) {
STRING_DIRECT_POST -> DIRECT_POST
STRING_DIRECT_POST_JWT -> DIRECT_POST_JWT
STRING_QUERY -> QUERY
STRING_FRAGMENT -> FRAGMENT
else -> OTHER(string)
STRING_DIRECT_POST -> DirectPost
STRING_DIRECT_POST_JWT -> DirectPostJwt
STRING_QUERY -> Query
STRING_FRAGMENT -> Fragment
else -> Other(string)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ data class RelyingPartyMetadata(
* If omitted, the default value is `pre-registered`.
*/
@SerialName("client_id_scheme")
val clientIdScheme: OpenIdConstants.ClientIdScheme? = OpenIdConstants.ClientIdScheme.PRE_REGISTERED,
val clientIdScheme: OpenIdConstants.ClientIdScheme? = OpenIdConstants.ClientIdScheme.PreRegistered,
) {

fun serialize() = jsonSerializer.encodeToString(this)
Expand Down
Loading
Loading