Skip to content

Commit 141e58c

Browse files
committed
WIP JwtVcJson
1 parent 8ef11c9 commit 141e58c

8 files changed

Lines changed: 400 additions & 6 deletions

File tree

src/Codebooks/ClaimsEnum.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ enum ClaimsEnum: string
4646
case CredentialResponseEncryption = 'credential_response_encryption';
4747
// CredentialSigningAlgorithmValuesSupported
4848
case CredentialSigningAlgValuesSupported = 'credential_signing_alg_values_supported';
49-
case CredentialSubject = 'credential_subject';
49+
case Credential_Status = 'credentialStatus';
50+
case Credential_Subject = 'credentialSubject';
5051
case CryptographicBindingMethodsSupported = 'cryptographic_binding_methods_supported';
5152
case DeferredCredentialEndpoint = 'deferred_credential_endpoint';
5253
case Delegation = 'delegation';
@@ -55,6 +56,7 @@ enum ClaimsEnum: string
5556
case EndSessionEndpoint = 'end_session_endpoint';
5657
// ExpirationTime
5758
case Exp = 'exp';
59+
case Expiration_Date = 'expirationDate';
5860
case EncryptionRequired = 'encryption_required';
5961
// EncryptionValuesSupported
6062
case EncValuesSupported = 'enc_values_supported';
@@ -76,6 +78,7 @@ enum ClaimsEnum: string
7678
'introspection_endpoint_auth_signing_alg_values_supported';
7779
// Issuer
7880
case Iss = 'iss';
81+
case Issuance_Date = 'issuanceDate';
7982
case Issuer = 'issuer';
8083
// JWT ID
8184
case Jti = 'jti';
@@ -107,6 +110,7 @@ enum ClaimsEnum: string
107110
case PolicyUri = 'policy_uri';
108111
case PostLogoutRedirectUris = 'post_logout_redirect_uris';
109112
case PreAuthorizedGrantAnonymousAccessSupported = 'pre-authorized_grant_anonymous_access_supported';
113+
case Proof = 'proof';
110114
// ProofSigningAlgorithmValuesSupported
111115
case ProofSigningAlgValuesSupported = 'proof_signing_alg_values_supported';
112116
case ProofTypesSupported = 'proof_types_supported';

src/Helpers.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace SimpleSAML\OpenID;
66

77
use SimpleSAML\OpenID\Helpers\Arr;
8+
use SimpleSAML\OpenID\Helpers\DateTime;
89
use SimpleSAML\OpenID\Helpers\Json;
910
use SimpleSAML\OpenID\Helpers\Type;
1011
use SimpleSAML\OpenID\Helpers\Url;
@@ -19,6 +20,8 @@ class Helpers
1920

2021
protected static ?Type $type = null;
2122

23+
protected static ?DateTime $dateTime = null;
24+
2225
public function url(): Url
2326
{
2427
return self::$url ??= new Url();
@@ -38,4 +41,9 @@ public function type(): Type
3841
{
3942
return self::$type ??= new Type();
4043
}
44+
45+
public function dateTime(): DateTime
46+
{
47+
return self::$dateTime ??= new DateTime();
48+
}
4149
}

src/Helpers/DateTime.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\OpenID\Helpers;
6+
7+
use DateTimeImmutable;
8+
use DateTimeInterface;
9+
use DateTimeZone;
10+
11+
class DateTime
12+
{
13+
/**
14+
* @throws \Exception
15+
*/
16+
public function parseXsDateTime(string $input, ?DateTimeZone $tz = null): DateTimeImmutable
17+
{
18+
// Try extended RFC3339 (with microseconds)
19+
$dt = DateTimeImmutable::createFromFormat(
20+
DateTimeInterface::RFC3339_EXTENDED,
21+
$input,
22+
$tz,
23+
);
24+
if ($dt !== false) {
25+
return $dt;
26+
}
27+
28+
// Fall back to standard atom format (no microseconds)
29+
$dt = DateTimeImmutable::createFromFormat(
30+
DateTimeInterface::ATOM,
31+
$input,
32+
$tz,
33+
);
34+
if ($dt !== false) {
35+
return $dt;
36+
}
37+
38+
// Finally, let the constructor attempt flexible ISO8601 parsing
39+
return new DateTimeImmutable($input, $tz);
40+
}
41+
}

src/VerifiableCredentials/VcDataModel/Claims/VcClaimValue.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims;
66

7+
use DateTimeImmutable;
78
use JsonSerializable;
89

910
class VcClaimValue implements JsonSerializable
@@ -18,8 +19,12 @@ public function __construct(
1819
protected readonly null|string $id,
1920
/** @var non-empty-array<non-empty-string> */
2021
protected readonly array $type,
21-
protected readonly VcCredentialSubjectClaimBag $vcCredentialSubjectClaimBag,
22+
protected readonly VcCredentialSubjectClaimBag $credentialSubjectClaimBag,
2223
protected readonly VcIssuerClaimValue $issuerClaimValue,
24+
protected readonly DateTimeImmutable $issuanceDate,
25+
protected readonly ?VcProofClaimValue $proofClaimValue,
26+
protected readonly ?DateTimeImmutable $expirationDate,
27+
protected readonly ?VcCredentialStatusClaimValue $credentialStatusClaimValue,
2328
) {
2429
}
2530

@@ -55,11 +60,31 @@ public function getType(): array
5560

5661
public function getCredentialSubject(): VcCredentialSubjectClaimBag
5762
{
58-
return $this->vcCredentialSubjectClaimBag;
63+
return $this->credentialSubjectClaimBag;
5964
}
6065

6166
public function getIssuer(): VcIssuerClaimValue
6267
{
6368
return $this->issuerClaimValue;
6469
}
70+
71+
public function getIssuanceDate(): DateTimeImmutable
72+
{
73+
return $this->issuanceDate;
74+
}
75+
76+
public function getProof(): ?VcProofClaimValue
77+
{
78+
return $this->proofClaimValue;
79+
}
80+
81+
public function getExpirationDate(): ?DateTimeImmutable
82+
{
83+
return $this->expirationDate;
84+
}
85+
86+
public function getCredentialStatus(): ?VcCredentialStatusClaimValue
87+
{
88+
return $this->credentialStatusClaimValue;
89+
}
6590
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims;
6+
7+
use SimpleSAML\OpenID\Claims\ClaimInterface;
8+
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
9+
10+
class VcCredentialStatusClaimValue implements ClaimInterface
11+
{
12+
/** @var non-empty-array<mixed> */
13+
protected array $data;
14+
15+
/**
16+
* @param non-empty-string $id,
17+
* @param non-empty-string $type
18+
* @param mixed[] $otherClaims
19+
*/
20+
public function __construct(
21+
protected string $id,
22+
protected string $type,
23+
array $otherClaims = [],
24+
) {
25+
$this->data = array_merge(
26+
$otherClaims,
27+
[ClaimsEnum::Id->value => $this->$id],
28+
[ClaimsEnum::Type->value => $this->type],
29+
);
30+
}
31+
32+
/**
33+
* @return non-empty-string
34+
*/
35+
public function getId(): string
36+
{
37+
return $this->id;
38+
}
39+
40+
/**
41+
* @return non-empty-string
42+
*/
43+
public function getType(): string
44+
{
45+
return $this->type;
46+
}
47+
48+
public function getKey(int|string $key): mixed
49+
{
50+
return $this->data[$key] ?? null;
51+
}
52+
53+
public function getName(): string
54+
{
55+
return ClaimsEnum::Credential_Status->value;
56+
}
57+
58+
/**
59+
* @return non-empty-array<mixed>
60+
*/
61+
public function getValue(): array
62+
{
63+
return $this->data;
64+
}
65+
66+
/**
67+
* @return non-empty-array<mixed>
68+
*/
69+
public function jsonSerialize(): array
70+
{
71+
return $this->getValue();
72+
}
73+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims;
6+
7+
use SimpleSAML\OpenID\Claims\ClaimInterface;
8+
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
9+
10+
class VcProofClaimValue implements ClaimInterface
11+
{
12+
/** @var non-empty-array<mixed> */
13+
protected array $data;
14+
15+
/**
16+
* @param non-empty-string $type
17+
* @param mixed[] $otherClaims
18+
*/
19+
public function __construct(
20+
protected string $type,
21+
array $otherClaims = [],
22+
protected readonly string $name = ClaimsEnum::Proof->value,
23+
) {
24+
$this->data = array_merge(
25+
$otherClaims,
26+
[ClaimsEnum::Type->value => $this->type],
27+
);
28+
}
29+
30+
/**
31+
* @return non-empty-string
32+
*/
33+
public function getType(): string
34+
{
35+
return $this->type;
36+
}
37+
38+
public function getKey(int|string $key): mixed
39+
{
40+
return $this->data[$key] ?? null;
41+
}
42+
43+
public function getName(): string
44+
{
45+
return $this->name;
46+
}
47+
48+
/**
49+
* @return non-empty-array<mixed>
50+
*/
51+
public function getValue(): array
52+
{
53+
return $this->data;
54+
}
55+
56+
/**
57+
* @return non-empty-array<mixed>
58+
*/
59+
public function jsonSerialize(): array
60+
{
61+
return $this->getValue();
62+
}
63+
}

src/VerifiableCredentials/VcDataModel/Factories/VcDataModelClaimFactory.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44

55
namespace SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Factories;
66

7+
use DateTimeImmutable;
78
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
89
use SimpleSAML\OpenID\Exceptions\VcDataModelException;
910
use SimpleSAML\OpenID\Factories\ClaimFactory;
1011
use SimpleSAML\OpenID\Helpers;
1112
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcAtContextClaimValue;
1213
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcClaimValue;
14+
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcCredentialStatusClaimValue;
1315
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcCredentialSubjectClaimBag;
1416
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcCredentialSubjectClaimValue;
1517
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcIssuerClaimValue;
18+
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\VcProofClaimValue;
1619

1720
class VcDataModelClaimFactory
1821
{
@@ -32,13 +35,21 @@ public function buildVcClaimValue(
3235
array $vcType,
3336
VcCredentialSubjectClaimBag $vcCredentialSubjectClaimBag,
3437
VcIssuerClaimValue $vcIssuerClaimValue,
38+
DateTimeImmutable $vcIssuanceDate,
39+
?VcProofClaimValue $vcProofClaimValue,
40+
?DateTimeImmutable $vcExpirationDate,
41+
?VcCredentialStatusClaimValue $vcCredentialStatusClaimValue,
3542
): VcClaimValue {
3643
return new VcClaimValue(
3744
$vcAtContextClaimValue,
3845
$vcId,
3946
$vcType,
4047
$vcCredentialSubjectClaimBag,
4148
$vcIssuerClaimValue,
49+
$vcIssuanceDate,
50+
$vcProofClaimValue,
51+
$vcExpirationDate,
52+
$vcCredentialStatusClaimValue,
4253
);
4354
}
4455

@@ -94,4 +105,40 @@ public function buildVcIssuerClaimValue(array $data): VcIssuerClaimValue
94105

95106
return new VcIssuerClaimValue($id, $data);
96107
}
108+
109+
/**
110+
* @param non-empty-array<mixed> $data
111+
* @throws \SimpleSAML\OpenID\Exceptions\VcDataModelException
112+
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
113+
*/
114+
public function buildVcProofClaimValue(array $data): VcProofClaimValue
115+
{
116+
$type = $data[ClaimsEnum::Type->value] ?? throw new VcDataModelException(
117+
'No Type claim value available.',
118+
);
119+
120+
$type = $this->helpers->type()->ensureNonEmptyString($type);
121+
122+
return new VcProofClaimValue($type, $data);
123+
}
124+
125+
/**
126+
* @param non-empty-array<mixed> $data
127+
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
128+
* @throws \SimpleSAML\OpenID\Exceptions\VcDataModelException
129+
*/
130+
public function buildVcCredentialStatusClaimValue(array $data): VcCredentialStatusClaimValue
131+
{
132+
$id = $data[ClaimsEnum::Id->value] ?? throw new VcDataModelException(
133+
'No Issuer ID claim value available.',
134+
);
135+
$id = $this->helpers->type()->enforceUri($id);
136+
137+
$type = $data[ClaimsEnum::Type->value] ?? throw new VcDataModelException(
138+
'No Type claim value available.',
139+
);
140+
$type = $this->helpers->type()->ensureNonEmptyString($type);
141+
142+
return new VcCredentialStatusClaimValue($id, $type, $data);
143+
}
97144
}

0 commit comments

Comments
 (0)