Skip to content

Commit fccdbe1

Browse files
committed
WIP
1 parent 6d4245b commit fccdbe1

15 files changed

+587
-4
lines changed

routing/routes/routes.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
use SimpleSAML\Module\oidc\Controllers\AccessTokenController;
1111
use SimpleSAML\Module\oidc\Controllers\Admin\ClientController;
1212
use SimpleSAML\Module\oidc\Controllers\Admin\ConfigController;
13-
use SimpleSAML\Module\oidc\Controllers\Admin\TestController;
13+
use SimpleSAML\Module\oidc\Controllers\Admin\FederationTestController;
14+
use SimpleSAML\Module\oidc\Controllers\Admin\VerifiableCredentailsTestController;
1415
use SimpleSAML\Module\oidc\Controllers\AuthorizationController;
1516
use SimpleSAML\Module\oidc\Controllers\ConfigurationDiscoveryController;
1617
use SimpleSAML\Module\oidc\Controllers\EndSessionController;
@@ -66,11 +67,16 @@
6667
// Testing
6768

6869
$routes->add(RoutesEnum::AdminTestTrustChainResolution->name, RoutesEnum::AdminTestTrustChainResolution->value)
69-
->controller([TestController::class, 'trustChainResolution'])
70+
->controller([FederationTestController::class, 'trustChainResolution'])
7071
->methods([HttpMethodsEnum::GET->value, HttpMethodsEnum::POST->value]);
7172
$routes->add(RoutesEnum::AdminTestTrustMarkValidation->name, RoutesEnum::AdminTestTrustMarkValidation->value)
72-
->controller([TestController::class, 'trustMarkValidation'])
73+
->controller([FederationTestController::class, 'trustMarkValidation'])
7374
->methods([HttpMethodsEnum::GET->value, HttpMethodsEnum::POST->value]);
75+
$routes->add(
76+
RoutesEnum::AdminTestVerifiableCredentialIssuance->name,
77+
RoutesEnum::AdminTestVerifiableCredentialIssuance->value,
78+
)->controller([VerifiableCredentailsTestController::class, 'verifiableCredentialIssuance'])
79+
->methods([HttpMethodsEnum::GET->value, HttpMethodsEnum::POST->value]);
7480

7581
/*****************************************************************************************************************
7682
* OpenID Connect

routing/services/services.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ services:
6060
factory: ['@SimpleSAML\Module\oidc\Factories\Grant\ImplicitGrantFactory', 'build']
6161
SimpleSAML\Module\oidc\Server\Grants\RefreshTokenGrant:
6262
factory: ['@SimpleSAML\Module\oidc\Factories\Grant\RefreshTokenGrantFactory', 'build']
63+
SimpleSAML\Module\oidc\Server\Grants\PreAuthCodeGrant:
64+
factory: ['@SimpleSAML\Module\oidc\Factories\Grant\PreAuthCodeGrantFactory', 'build']
65+
6366
# Responses
6467
SimpleSAML\Module\oidc\Server\ResponseTypes\IdTokenResponse:
6568
factory: ['@SimpleSAML\Module\oidc\Factories\IdTokenResponseFactory', 'build']
@@ -125,6 +128,8 @@ services:
125128
factory: [ '@SimpleSAML\Module\oidc\Factories\CoreFactory', 'build' ]
126129
SimpleSAML\OpenID\Federation:
127130
factory: [ '@SimpleSAML\Module\oidc\Factories\FederationFactory', 'build' ]
131+
SimpleSAML\OpenID\VerifiableCredentials:
132+
factory: [ '@SimpleSAML\Module\oidc\Factories\VerifiableCredentialsFactory', 'build' ]
128133
SimpleSAML\OpenID\Jwks:
129134
factory: [ '@SimpleSAML\Module\oidc\Factories\JwksFactory', 'build' ]
130135
SimpleSAML\OpenID\Jwk: ~

src/Codebooks/ParametersEnum.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77
enum ParametersEnum: string
88
{
99
case ClientId = 'client_id';
10+
case CredentialOffer = 'credential_offer';
11+
case CredentialOfferUri = 'credential_offer_uri';
1012
}

src/Codebooks/RoutesEnum.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum RoutesEnum: string
2828
// Testing
2929
case AdminTestTrustChainResolution = 'admin/test/trust-chain-resolution';
3030
case AdminTestTrustMarkValidation = 'admin/test/trust-mark-validation';
31+
case AdminTestVerifiableCredentialIssuance = 'admin/test/verifiable-credential-issuance';
3132

3233

3334
/*****************************************************************************************************************

src/Controllers/Admin/TestController.php renamed to src/Controllers/Admin/FederationTestController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use Symfony\Component\HttpFoundation\Request;
1818
use Symfony\Component\HttpFoundation\Response;
1919

20-
class TestController
20+
class FederationTestController
2121
{
2222
protected readonly Federation $federationWithArrayLogger;
2323

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Module\oidc\Controllers\Admin;
6+
7+
use SimpleSAML\Module\oidc\Admin\Authorization;
8+
use SimpleSAML\Module\oidc\Codebooks\ParametersEnum;
9+
use SimpleSAML\Module\oidc\Codebooks\RoutesEnum;
10+
use SimpleSAML\Module\oidc\Entities\ScopeEntity;
11+
use SimpleSAML\Module\oidc\Factories\Entities\AuthCodeEntityFactory;
12+
use SimpleSAML\Module\oidc\Factories\Entities\ClientEntityFactory;
13+
use SimpleSAML\Module\oidc\Factories\TemplateFactory;
14+
use SimpleSAML\Module\oidc\Helpers;
15+
use SimpleSAML\Module\oidc\ModuleConfig;
16+
use SimpleSAML\Module\oidc\Repositories\AuthCodeRepository;
17+
use SimpleSAML\Module\oidc\Repositories\ClientRepository;
18+
use SimpleSAML\Module\oidc\Services\LoggerService;
19+
use SimpleSAML\Module\oidc\Utils\Debug\ArrayLogger;
20+
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
21+
use SimpleSAML\OpenID\Codebooks\GrantTypesEnum;
22+
use SimpleSAML\OpenID\Federation;
23+
use SimpleSAML\OpenID\VerifiableCredentials;
24+
use Symfony\Component\HttpFoundation\Request;
25+
use Symfony\Component\HttpFoundation\Response;
26+
27+
class VerifiableCredentailsTestController
28+
{
29+
public function __construct(
30+
protected readonly ModuleConfig $moduleConfig,
31+
protected readonly TemplateFactory $templateFactory,
32+
protected readonly Authorization $authorization,
33+
protected readonly VerifiableCredentials $verifiableCredentials,
34+
protected readonly AuthCodeRepository $authCodeRepository,
35+
protected readonly AuthCodeEntityFactory $authCodeEntityFactory,
36+
protected readonly ClientRepository $clientRepository,
37+
protected readonly ClientEntityFactory $clientEntityFactory,
38+
protected readonly Federation $federation,
39+
protected readonly Helpers $helpers,
40+
protected readonly LoggerService $loggerService,
41+
) {
42+
$this->authorization->requireAdmin(true);
43+
}
44+
45+
/**
46+
* @throws \SimpleSAML\Error\ConfigurationError
47+
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
48+
* @throws \SimpleSAML\OpenID\Exceptions\CredentialOfferException
49+
*/
50+
public function verifiableCredentialIssuance(Request $request): Response
51+
{
52+
$sampleData = [
53+
'eduPersonPrincipalName' => '[email protected]',
54+
'eduPersonTargetedID' => 'abc123',
55+
'displayName' => 'Test User',
56+
'givenName' => 'Test',
57+
'sn' => 'User',
58+
'mail' => '[email protected]',
59+
'eduPersonScopedAffiliation' => '[email protected]',
60+
];
61+
62+
$this->loggerService->info('test', $sampleData);;
63+
64+
// TODO mivanci Wallet (client) credential_offer_endpoint metadata
65+
// https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#client-metadata
66+
67+
$clientId = '1234567890';
68+
$clientSecret = '1234567890';
69+
70+
if (($client = $this->clientRepository->findById($clientId)) === null) {
71+
$client = $this->clientEntityFactory->fromData(
72+
id: $clientId,
73+
secret: $clientSecret,
74+
name: 'VCI Test Client',
75+
description: 'Test client for VCI',
76+
redirectUri: ['https://example.com/oidc/callback'],
77+
scopes: ['openid', 'ResearchAndScholarshipCredentialJwtVcJson'],
78+
isEnabled: true,
79+
);
80+
81+
$this->clientRepository->add($client);
82+
;
83+
}
84+
85+
$authCodeId = '1234567890';
86+
87+
// TODO mivanci Add indication of preauthz code to the auth code table.
88+
89+
if (($authCode = $this->authCodeRepository->findById($authCodeId)) === null) {
90+
$authCode = $this->authCodeEntityFactory->fromData(
91+
id: $authCodeId,
92+
client: $client,
93+
scopes: [
94+
new ScopeEntity('openid'),
95+
new ScopeEntity('ResearchAndScholarshipCredentialJwtVcJson'),
96+
],
97+
expiryDateTime: new \DateTimeImmutable('+1 month'),
98+
userIdentifier: 'testuid',
99+
redirectUri: 'https://example.com/oidc/callback',
100+
nonce: '1234567890',
101+
);
102+
103+
$this->authCodeRepository->persistNewAuthCode($authCode);
104+
}
105+
106+
107+
$credentialOffer = $this->verifiableCredentials->credentialOfferFactory()->from(
108+
parameters: [
109+
ClaimsEnum::CredentialIssuer->value => $this->moduleConfig->getIssuer(),
110+
ClaimsEnum::CredentialConfigurationIds->value => [
111+
'ResearchAndScholarshipCredentialJwtVcJson',
112+
],
113+
ClaimsEnum::Grants->value => [
114+
GrantTypesEnum::PreAuthorizedCode->value => [
115+
ClaimsEnum::PreAuthorizedCode->value => $authCode->getIdentifier(),
116+
// TODO mivanci support for TxCode
117+
// ClaimsEnum::TxCode->value => [
118+
// ClaimsEnum::InputMode->value => 'numeric',
119+
// ClaimsEnum::Length->value => 6,
120+
// ClaimsEnum::Description->value => 'Sent to user mail',
121+
// ],
122+
],
123+
],
124+
],
125+
);
126+
127+
$credentialOfferValue = $credentialOffer->jsonSerialize();
128+
$parameterName = ParametersEnum::CredentialOfferUri->value;
129+
if (is_array($credentialOfferValue)) {
130+
$parameterName = ParametersEnum::CredentialOffer->value;
131+
$credentialOfferValue = json_encode($credentialOfferValue);
132+
}
133+
134+
$credentialOfferUri = "openid-credential-offer://?$parameterName=$credentialOfferValue";
135+
136+
// https://quickchart.io/documentation/qr-codes/
137+
$qrUri = 'https://quickchart.io/qr?size=200&margin=1&text=' . urlencode($credentialOfferUri);
138+
139+
return $this->templateFactory->build(
140+
'oidc:tests/verifiable-credential-issuance.twig',
141+
compact('qrUri', 'sampleData', 'credentialOfferUri'),
142+
RoutesEnum::AdminTestVerifiableCredentialIssuance->value,
143+
);
144+
}
145+
}

src/Factories/AuthorizationServerFactory.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use SimpleSAML\Module\oidc\Server\AuthorizationServer;
2525
use SimpleSAML\Module\oidc\Server\Grants\AuthCodeGrant;
2626
use SimpleSAML\Module\oidc\Server\Grants\ImplicitGrant;
27+
use SimpleSAML\Module\oidc\Server\Grants\PreAuthCodeGrant;
2728
use SimpleSAML\Module\oidc\Server\Grants\RefreshTokenGrant;
2829
use SimpleSAML\Module\oidc\Server\RequestRules\RequestRulesManager;
2930
use SimpleSAML\Module\oidc\Server\ResponseTypes\IdTokenResponse;
@@ -41,6 +42,7 @@ public function __construct(
4142
private readonly IdTokenResponse $idTokenResponse,
4243
private readonly RequestRulesManager $requestRulesManager,
4344
private readonly CryptKey $privateKey,
45+
private readonly PreAuthCodeGrant $preAuthCodeGrant,
4446
) {
4547
}
4648

@@ -71,6 +73,12 @@ public function build(): AuthorizationServer
7173
$this->moduleConfig->getAccessTokenDuration(),
7274
);
7375

76+
// TODO mivanci Only enable if VCI is enabled.
77+
$authorizationServer->enableGrantType(
78+
$this->preAuthCodeGrant,
79+
$this->moduleConfig->getAccessTokenDuration(),
80+
);
81+
7482
return $authorizationServer;
7583
}
7684
}

src/Factories/Grant/AuthCodeGrantFactory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use SimpleSAML\Module\oidc\Server\Grants\AuthCodeGrant;
2727
use SimpleSAML\Module\oidc\Server\RequestRules\RequestRulesManager;
2828
use SimpleSAML\Module\oidc\Server\TokenIssuers\RefreshTokenIssuer;
29+
use SimpleSAML\Module\oidc\Services\LoggerService;
2930
use SimpleSAML\Module\oidc\Utils\RequestParamsResolver;
3031

3132
class AuthCodeGrantFactory
@@ -41,6 +42,7 @@ public function __construct(
4142
private readonly AuthCodeEntityFactory $authCodeEntityFactory,
4243
private readonly RefreshTokenIssuer $refreshTokenIssuer,
4344
private readonly Helpers $helpers,
45+
private readonly LoggerService $loggerService,
4446
) {
4547
}
4648

@@ -60,6 +62,7 @@ public function build(): AuthCodeGrant
6062
$this->authCodeEntityFactory,
6163
$this->refreshTokenIssuer,
6264
$this->helpers,
65+
$this->loggerService
6366
);
6467
$authCodeGrant->setRefreshTokenTTL($this->moduleConfig->getRefreshTokenDuration());
6568

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the simplesamlphp-module-oidc.
7+
*
8+
* Copyright (C) 2018 by the Spanish Research and Academic Network.
9+
*
10+
* This code was developed by Universidad de Córdoba (UCO https://www.uco.es)
11+
* for the RedIRIS SIR service (SIR: http://www.rediris.es/sir)
12+
*
13+
* For the full copyright and license information, please view the LICENSE
14+
* file that was distributed with this source code.
15+
*/
16+
17+
namespace SimpleSAML\Module\oidc\Factories\Grant;
18+
19+
use SimpleSAML\Module\oidc\Factories\Entities\AccessTokenEntityFactory;
20+
use SimpleSAML\Module\oidc\Factories\Entities\AuthCodeEntityFactory;
21+
use SimpleSAML\Module\oidc\Helpers;
22+
use SimpleSAML\Module\oidc\ModuleConfig;
23+
use SimpleSAML\Module\oidc\Repositories\AccessTokenRepository;
24+
use SimpleSAML\Module\oidc\Repositories\AuthCodeRepository;
25+
use SimpleSAML\Module\oidc\Repositories\RefreshTokenRepository;
26+
use SimpleSAML\Module\oidc\Server\Grants\AuthCodeGrant;
27+
use SimpleSAML\Module\oidc\Server\Grants\PreAuthCodeGrant;
28+
use SimpleSAML\Module\oidc\Server\RequestRules\RequestRulesManager;
29+
use SimpleSAML\Module\oidc\Server\TokenIssuers\RefreshTokenIssuer;
30+
use SimpleSAML\Module\oidc\Services\LoggerService;
31+
use SimpleSAML\Module\oidc\Utils\RequestParamsResolver;
32+
33+
class PreAuthCodeGrantFactory
34+
{
35+
public function __construct(
36+
private readonly ModuleConfig $moduleConfig,
37+
private readonly AuthCodeRepository $authCodeRepository,
38+
private readonly AccessTokenRepository $accessTokenRepository,
39+
private readonly RefreshTokenRepository $refreshTokenRepository,
40+
private readonly RequestRulesManager $requestRulesManager,
41+
private readonly RequestParamsResolver $requestParamsResolver,
42+
private readonly AccessTokenEntityFactory $accessTokenEntityFactory,
43+
private readonly AuthCodeEntityFactory $authCodeEntityFactory,
44+
private readonly RefreshTokenIssuer $refreshTokenIssuer,
45+
private readonly Helpers $helpers,
46+
private readonly LoggerService $loggerService,
47+
) {
48+
}
49+
50+
/**
51+
* @throws \Exception
52+
*/
53+
public function build(): PreAuthCodeGrant
54+
{
55+
$preAuthCodeGrant = new PreAuthCodeGrant(
56+
$this->authCodeRepository,
57+
$this->accessTokenRepository,
58+
$this->refreshTokenRepository,
59+
$this->moduleConfig->getAuthCodeDuration(),
60+
$this->requestRulesManager,
61+
$this->requestParamsResolver,
62+
$this->accessTokenEntityFactory,
63+
$this->authCodeEntityFactory,
64+
$this->refreshTokenIssuer,
65+
$this->helpers,
66+
$this->loggerService
67+
);
68+
$preAuthCodeGrant->setRefreshTokenTTL($this->moduleConfig->getRefreshTokenDuration());
69+
70+
return $preAuthCodeGrant;
71+
}
72+
}

src/Factories/TemplateFactory.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ protected function includeDefaultMenuItems(): void
148148
Translate::noop('Verifiable Credential Settings'),
149149
),
150150
);
151+
152+
$this->oidcMenu->addItem(
153+
$this->oidcMenu->buildItem(
154+
$this->moduleConfig->getModuleUrl(RoutesEnum::AdminTestVerifiableCredentialIssuance->value),
155+
Translate::noop('Test Verifiable Credential Issuance'),
156+
),
157+
);
151158
}
152159

153160
public function setShowMenu(bool $showMenu): TemplateFactory

0 commit comments

Comments
 (0)