Skip to content
Merged
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
119 changes: 112 additions & 7 deletions config/module_oidc.php.dist
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ declare(strict_types=1);
*/

use SimpleSAML\Module\oidc\ModuleConfig;
use SimpleSAML\OpenID\Codebooks\AtContextsEnum;
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
use SimpleSAML\OpenID\Codebooks\CredentialFormatIdentifiersEnum;
use SimpleSAML\OpenID\Codebooks\CredentialTypesEnum;
use SimpleSAML\OpenID\Codebooks\LanguageTagsEnum;

$config = [
/**
* (optional) Issuer (OP) identifier which will be used as an issuer (iss)
* (optional) Issuer (OP) identifier that will be used as an issuer (iss)
* claim in tokens. If not set, it will fall back to the current HTTP
* scheme, host and port number if no standard port is used.
* Description of the issuer from OIDC Core specification: "Verifiable
Expand All @@ -55,16 +56,16 @@ $config = [
* example, for key-rollover scenarios. Just add those entries later in
* the list, so they can be published on the OP JWKS discovery endpoint.
*
* The format is array of associative arrays, where each array value
* The format is an array of associative arrays, where each array value
* consists of the following properties (keys):
* - ModuleConfig::KEY_ALGORITHM - \SimpleSAML\OpenID\Algorithms\SignatureAlgorithmEnum case
* representing the algorithm.
* - ModuleConfig::KEY_PRIVATE_KEY_FILENAME - the name of the file
* containing private key inPEM format, which is available in SSP `cert`
* containing a private key in PEM format, which is available in SSP `cert`
* folder.
* - ModuleConfig::KEY_PUBLIC_KEY_FILENAME - the name of the file containing
* corresponding public key in PEM format, which is available in SSP `cert`
* folder.
* the corresponding public key in PEM format, which is available in
* the SSP `cert` folder.
* - ModuleConfig::KEY_PRIVATE_KEY_PASSWORD - private key password, if
* needed.
* - ModuleConfig::KEY_KEY_ID - Optional string representing key identifier.
Expand Down Expand Up @@ -286,7 +287,7 @@ $config = [
/**
* If this OP supports ACRs, indicate which usable auth source supports
* which ACRs. Order of ACRs is important, more important ones being first.
* Syntax: array<string,string[]> (array with an auth source as a key and
* Syntax: array<string, string[]> (array with an auth source as a key and
* value being array of ACR values as strings)
*/

Expand Down Expand Up @@ -339,7 +340,7 @@ $config = [
* Source and destination will have entity IDs corresponding to the OP
* issuer ID and Client ID respectively.
* - ['Source']['entityid'] - contains OpenId Provider issuer ID
* - ['Destination']['entityid'] - contains Relying Party (OIDC Client) ID
* - ['Destination']['entityid'] - contains Relying Party (OIDC Client) ID.
* In addition to that, the following OIDC related data will be available
* in the state array:
* - ['Oidc']['OpenIdProviderMetadata'] - contains information otherwise
Expand Down Expand Up @@ -966,6 +967,101 @@ $config = [
// REQUIRED
ClaimsEnum::Vct->value => 'ResearchAndScholarshipCredentialDcSdJwt',
],

'ResearchAndScholarshipCredentialVcSdJwt' => [
ClaimsEnum::Format->value => CredentialFormatIdentifiersEnum::VcSdJwt->value,
ClaimsEnum::Scope->value => 'ResearchAndScholarshipCredentialVcSdJwt',
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'ResearchAndScholarshipCredentialVcSdJwt',
ClaimsEnum::Locale->value => 'en-US',
ClaimsEnum::Description->value => 'Research and Scholarship Credential',
],
],
ClaimsEnum::Claims->value => [
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'eduPersonPrincipalName'],
ClaimsEnum::Mandatory->value => true,
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Principal Name',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'eduPersonTargetedID'],
ClaimsEnum::Mandatory->value => false,
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Targeted ID',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'displayName'],
ClaimsEnum::Mandatory->value => false,
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Display Name',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'givenName'],
ClaimsEnum::Mandatory->value => false,
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Given Name',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'sn'],
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Last Name',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'mail'],
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Email Address',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
[
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'eduPersonScopedAffiliation'],
ClaimsEnum::Display->value => [
[
ClaimsEnum::Name->value => 'Scoped Affiliation',
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
],
],
],
],

/**
* VCDM 2.0 context is REQUIRED for 'vc+sd-jwt' format.
*/
ClaimsEnum::AtContext->value => [
AtContextsEnum::W3OrgNsCredentialsV2->value,
],

// REQUIRED
/** @see https://www.w3.org/TR/vc-data-model-2.0/#types */
ClaimsEnum::Type->value => [
CredentialTypesEnum::VerifiableCredential->value,
'ResearchAndScholarshipCredentialVcSdJwt',
],
],
],

/**
Expand Down Expand Up @@ -999,6 +1095,15 @@ $config = [
['mail' => ['mail']],
['eduPersonScopedAffiliation' => ['eduPersonScopedAffiliation']],
],
'ResearchAndScholarshipCredentialVcSdJwt' => [
['eduPersonPrincipalName' => [ClaimsEnum::Credential_Subject->value, 'eduPersonPrincipalName']],
['eduPersonTargetedID' => [ClaimsEnum::Credential_Subject->value, 'eduPersonTargetedID']],
['displayName' => [ClaimsEnum::Credential_Subject->value, 'displayName']],
['givenName' => [ClaimsEnum::Credential_Subject->value, 'givenName']],
['sn' => [ClaimsEnum::Credential_Subject->value, 'sn']],
['mail' => [ClaimsEnum::Credential_Subject->value, 'mail']],
['eduPersonScopedAffiliation' => [ClaimsEnum::Credential_Subject->value, 'eduPersonScopedAffiliation']],
],
],

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
use SimpleSAML\OpenID\Codebooks\CredentialFormatIdentifiersEnum;
use SimpleSAML\OpenID\Codebooks\CredentialTypesEnum;
use SimpleSAML\OpenID\Codebooks\HttpMethodsEnum;
use SimpleSAML\OpenID\Codebooks\JwtTypesEnum;
use SimpleSAML\OpenID\Did;
use SimpleSAML\OpenID\Exceptions\OpenId4VciProofException;
use SimpleSAML\OpenID\Exceptions\OpenIdException;
Expand Down Expand Up @@ -612,6 +611,10 @@ public function credential(Request $request): Response
continue;
}

if ($credentialFormatId === CredentialFormatIdentifiersEnum::VcSdJwt->value) {
array_unshift($credentialClaimPath, ClaimsEnum::Credential_Subject->value);
}

/** @psalm-suppress ArgumentTypeCoercion */
$disclosure = $this->verifiableCredentials->disclosureFactory()->build(
value: $attributeValue,
Expand Down Expand Up @@ -688,7 +691,7 @@ public function credential(Request $request): Response
);
}

if (in_array($credentialFormatId, self::SD_JWT_FORMAT_IDS, true)) {
if ($credentialFormatId === CredentialFormatIdentifiersEnum::DcSdJwt->value) {
$sdJwtPayload = [
ClaimsEnum::Iss->value => $issuerDid,
ClaimsEnum::Iat->value => $issuedAt->getTimestamp(),
Expand All @@ -698,9 +701,9 @@ public function credential(Request $request): Response
ClaimsEnum::Vct->value => $resolvedCredentialIdentifier,
];

if ($proof instanceof OpenId4VciProof) {
if ($proof instanceof OpenId4VciProof && is_string($proofKeyId = $proof->getKeyId())) {
$sdJwtPayload[ClaimsEnum::Cnf->value] = [
ClaimsEnum::Kid->value => $proof->getKeyId(),
ClaimsEnum::Kid->value => $proofKeyId,
];
}

Expand All @@ -712,7 +715,43 @@ public function credential(Request $request): Response
ClaimsEnum::Kid->value => $issuerDid . '#0',
],
disclosureBag: $disclosureBag,
jwtTypesEnum: JwtTypesEnum::VcSdJwt,
);
}

if ($credentialFormatId === CredentialFormatIdentifiersEnum::VcSdJwt->value) {
$sdJwtPayload = [
ClaimsEnum::AtContext->value => [
AtContextsEnum::W3OrgNsCredentialsV2->value,
],
ClaimsEnum::Id->value => $vcId,
ClaimsEnum::Type->value => [
CredentialTypesEnum::VerifiableCredential->value,
$resolvedCredentialIdentifier,
],
ClaimsEnum::Issuer->value => $issuerDid,
ClaimsEnum::ValidFrom->value => $issuedAt->format(\DateTimeInterface::RFC3339),
ClaimsEnum::Credential_Subject->value =>
$credentialSubject[ClaimsEnum::Credential_Subject->value] ?? [],
ClaimsEnum::Iss->value => $issuerDid,
ClaimsEnum::Iat->value => $issuedAt->getTimestamp(),
ClaimsEnum::Nbf->value => $issuedAt->getTimestamp(),
ClaimsEnum::Sub->value => $sub,
ClaimsEnum::Jti->value => $vcId,
];

if ($proof instanceof OpenId4VciProof && is_string($proofKeyId = $proof->getKeyId())) {
$sdJwtPayload[ClaimsEnum::Cnf->value] = [
ClaimsEnum::Kid->value => $proofKeyId,
];
}

$verifiableCredential = $this->verifiableCredentials->vcSdJwtFactory()->fromData(
$signingKey,
$signatureAlgorithm,
$sdJwtPayload,
[
ClaimsEnum::Kid->value => $issuerDid . '#0',
],
);
}

Expand Down
Loading