22
33namespace Pdsinterop \Solid \Auth ;
44
5- use Pdsinterop \Solid \Auth \Utils \Jwks ;
5+ use Pdsinterop \Solid \Auth \Exception \InvalidTokenException ;
6+ use Pdsinterop \Solid \Auth \Utils \DPop ;
67use Pdsinterop \Solid \Auth \Enum \OpenId \OpenIdConnectMetadata as OidcMeta ;
7- use Laminas \Diactoros \Response \JsonResponse as JsonResponse ;
8+ use Laminas \Diactoros \Response \JsonResponse ;
89use League \OAuth2 \Server \CryptTrait ;
910
1011use DateTimeImmutable ;
@@ -21,14 +22,17 @@ class TokenGenerator
2122 public Config $ config ;
2223
2324 private \DateInterval $ validFor ;
25+ private DPop $ dpopUtil ;
2426
2527 //////////////////////////////// PUBLIC API \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
2628
2729 final public function __construct (
2830 Config $ config ,
29- \DateInterval $ validFor
31+ \DateInterval $ validFor ,
32+ DPop $ dpopUtil ,
3033 ) {
3134 $ this ->config = $ config ;
35+ $ this ->dpopUtil = $ dpopUtil ;
3236 $ this ->validFor = $ validFor ;
3337
3438 $ this ->setEncryptionKey ($ this ->config ->getKeys ()->getEncryptionKey ());
@@ -48,10 +52,9 @@ public function generateRegistrationAccessToken($clientId, $privateKey) {
4852 return $ token ->toString ();
4953 }
5054
51- public function generateIdToken ($ accessToken , $ clientId , $ subject , $ nonce , $ privateKey , $ dpopKey , $ now =null ) {
55+ public function generateIdToken ($ accessToken , $ clientId , $ subject , $ nonce , $ privateKey , $ dpop , $ now =null ) {
5256 $ issuer = $ this ->config ->getServer ()->get (OidcMeta::ISSUER );
5357
54- $ jwks = $ this ->getJwks ();
5558 $ tokenHash = $ this ->generateTokenHash ($ accessToken );
5659
5760 // Create JWT
@@ -61,6 +64,8 @@ public function generateIdToken($accessToken, $clientId, $subject, $nonce, $priv
6164
6265 $ expire = $ now ->add ($ this ->validFor );
6366
67+ $ jkt = $ this ->makeJwkThumbprint ($ dpop );
68+
6469 $ token = $ jwtConfig ->builder ()
6570 ->issuedBy ($ issuer )
6671 ->permittedFor ($ clientId )
@@ -74,10 +79,8 @@ public function generateIdToken($accessToken, $clientId, $subject, $nonce, $priv
7479 ->withClaim ("at_hash " , $ tokenHash ) //FIXME: at_hash should only be added if the response_type is a token
7580 ->withClaim ("c_hash " , $ tokenHash ) // FIXME: c_hash should only be added if the response_type is a code
7681 ->withClaim ("cnf " , array (
77- "jkt " => $ dpopKey ,
78- // "jwk" => $jwks['keys'][0]
82+ "jkt " => $ jkt ,
7983 ))
80- ->withHeader ('kid ' , $ jwks ['keys ' ][0 ]['kid ' ])
8184 ->getToken ($ jwtConfig ->signer (), $ jwtConfig ->signingKey ());
8285 return $ token ->toString ();
8386 }
@@ -104,7 +107,7 @@ public function respondToRegistration($registration, $privateKey) {
104107 return array_merge ($ registrationBase , $ registration );
105108 }
106109
107- public function addIdTokenToResponse ($ response , $ clientId , $ subject , $ nonce , $ privateKey , $ dpopKey =null ) {
110+ public function addIdTokenToResponse ($ response , $ clientId , $ subject , $ nonce , $ privateKey , $ dpop =null ) {
108111 if ($ response ->hasHeader ("Location " )) {
109112 $ value = $ response ->getHeaderLine ("Location " );
110113
@@ -115,7 +118,7 @@ public function addIdTokenToResponse($response, $clientId, $subject, $nonce, $pr
115118 $ subject ,
116119 $ nonce ,
117120 $ privateKey ,
118- $ dpopKey
121+ $ dpop
119122 );
120123 $ value = preg_replace ("/#access_token=(.*?)&/ " , "#access_token= \$1&id_token= $ idToken& " , $ value );
121124 $ response = $ response ->withHeader ("Location " , $ value );
@@ -126,7 +129,7 @@ public function addIdTokenToResponse($response, $clientId, $subject, $nonce, $pr
126129 $ subject ,
127130 $ nonce ,
128131 $ privateKey ,
129- $ dpopKey
132+ $ dpop
130133 );
131134 $ value = preg_replace ("/code=(.*?)&/ " , "code= \$1&id_token= $ idToken& " , $ value );
132135 $ response = $ response ->withHeader ("Location " , $ value );
@@ -143,7 +146,7 @@ public function addIdTokenToResponse($response, $clientId, $subject, $nonce, $pr
143146 $ subject ,
144147 $ nonce ,
145148 $ privateKey ,
146- $ dpopKey
149+ $ dpop
147150 );
148151
149152 $ body ['access_token ' ] = $ body ['id_token ' ];
@@ -178,9 +181,16 @@ private function generateTokenHash($accessToken) {
178181 return $ atHash ;
179182 }
180183
181- private function getJwks () {
182- $ key = $ this ->config ->getKeys ()->getPublicKey ();
183- $ jwks = new Jwks ($ key );
184- return json_decode ($ jwks ->__toString (), true );
184+ private function makeJwkThumbprint ($ dpop ): string
185+ {
186+ $ dpopConfig = Configuration::forUnsecuredSigner ();
187+ $ parsedDpop = $ dpopConfig ->parser ()->parse ($ dpop );
188+ $ jwk = $ parsedDpop ->headers ()->get ("jwk " );
189+
190+ if (empty ($ jwk )) {
191+ throw new InvalidTokenException ('Required JWK header missing in DPOP ' );
192+ }
193+
194+ return $ this ->dpopUtil ->makeJwkThumbprint ($ jwk );
185195 }
186196}
0 commit comments