Skip to content

Commit 30343b7

Browse files
committed
Add redirect tests, fix test issues, refactor code
1 parent e423bd0 commit 30343b7

File tree

3 files changed

+227
-49
lines changed

3 files changed

+227
-49
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- Min. PHP version to 8.1 #488
1818
- `fetchURL` response type to `Response` class #488
1919
- `Nonce` claim must be present, Partially reverts #280
20-
- `verifySignatures` method signature, accepting `JWS` object instead of string
20+
- `verifySignatures` method signature, accepting `JWS` object instead of string #488
2121

2222
### Fixed
2323
- Check existence of `sub` claim when verifying JWT #474
@@ -33,7 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333
- `getResponseContentType()`, replaced with new response method `getContentType()` #488
3434
- `verifyJWTClaims()`, replaced with individual checks #488
3535
- `validateIssuer()`, replaced with `IssuerChecker` #488
36-
- `verifyJWTSignature()`, replaced with `verifyJWS()` #488
36+
- `verifyJWTSignature()`, replaced with `verifyJWSSignature()` #488
3737

3838
## [1.0.1] - 2024-09-13
3939

src/OpenIDConnectClient.php

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
use Jose\Component\Signature\Serializer\CompactSerializer;
5858
use Jose\Component\Signature\Serializer\JWSSerializerManager;
5959
use Symfony\Component\Clock\Clock;
60+
use Throwable;
6061

6162
use function bin2hex;
6263
use function is_object;
@@ -426,10 +427,10 @@ public function authenticate(): bool
426427
$id_token = $this->handleJweResponse($id_token);
427428
}
428429

429-
$jws = $this->jwsSerializerManager->unserialize($id_token);
430+
$jws = $this->unserializeJWS($id_token);
430431

431432
// Verify header
432-
$this->headerCheckerManager->check($jws, 0, ['alg']);
433+
$this->verifyJWSHeader($jws);
433434

434435
// Verify the signature
435436
$this->verifySignatures($jws);
@@ -449,7 +450,7 @@ public function authenticate(): bool
449450
$this->tokenResponse = $token_json;
450451

451452
// Get claims from JWT
452-
$claims = json_decode($jws->getPayload());
453+
$claims = $this->getJWSClaims($jws);
453454

454455
if (!$this->verifyIdTokenClaims($claims)) {
455456
throw new OpenIDConnectClientException('Unable to verify JWT claims');
@@ -486,10 +487,10 @@ public function authenticate(): bool
486487
$id_token = $this->handleJweResponse($id_token);
487488
}
488489

489-
$jws = $this->jwsSerializerManager->unserialize($id_token);
490+
$jws = $this->unserializeJWS($id_token);
490491

491492
// Verify header
492-
$this->headerCheckerManager->check($jws, 0, ['alg']);
493+
$this->verifyJWSHeader($jws);
493494

494495
// Verify the signature
495496
$this->verifySignatures($jws);
@@ -503,7 +504,7 @@ public function authenticate(): bool
503504
}
504505

505506
// Get claims from JWT
506-
$claims = json_decode($jws->getPayload());
507+
$claims = $this->getJWSClaims($jws);
507508

508509
if (!$this->verifyIdTokenClaims($claims)) {
509510
throw new OpenIDConnectClientException('Unable to verify JWT claims');
@@ -607,16 +608,16 @@ public function verifyLogoutToken(): bool
607608
$logout_token = $this->handleJweResponse($logout_token);
608609
}
609610

610-
$jws = $this->jwsSerializerManager->unserialize($logout_token);
611+
$jws = $this->unserializeJWS($logout_token);
611612

612613
// Verify header
613-
$this->headerCheckerManager->check($jws, 0, ['alg']);
614+
$this->verifyJWSHeader($jws);
614615

615616
// Verify the signature
616617
$this->verifySignatures($jws);
617618

618619
// Get claims from JWT
619-
$claims = json_decode($jws->getPayload());
620+
$claims = $this->getJWSClaims($jws);
620621

621622
// Verify Logout Token Claims
622623
if (!$this->verifyLogoutTokenClaims($claims)) {
@@ -1194,12 +1195,23 @@ private function getJWK(string $alg, string $key): JWK
11941195
);
11951196
}
11961197

1198+
/**
1199+
* Returns the claims from a JWS object
1200+
*
1201+
* @param JWS $jws
1202+
* @return object
1203+
*/
1204+
public function getJWSClaims(JWS $jws): object
1205+
{
1206+
return json_decode($jws->getPayload());
1207+
}
1208+
11971209
/**
11981210
* @param JWS $jws
11991211
* @return bool
12001212
* @throws OpenIDConnectClientException
12011213
*/
1202-
public function verifyJWS(JWS $jws): bool
1214+
public function verifyJWSSignature(JWS $jws): bool
12031215
{
12041216
$signature = $jws->getSignature(0);
12051217
$alg = $signature->getProtectedHeaderParameter('alg');
@@ -1259,13 +1271,31 @@ public function verifyJWS(JWS $jws): bool
12591271
}
12601272

12611273
/**
1262-
* @param string $jwt encoded JWT
1274+
* Verifies the JWS header of a JWS object
1275+
*
1276+
* @param JWS $jws
1277+
* @param int $index
1278+
* @param array $mandatoryHeaderParameters
12631279
* @return void
12641280
* @throws OpenIDConnectClientException
12651281
*/
1266-
public function verifySignatures(JWS $jws)
1282+
public function verifyJWSHeader(JWS $jws, int $index = 0, array $mandatoryHeaderParameters = ['alg']): void
12671283
{
1268-
if (!$this->verifyJWS($jws)) {
1284+
try {
1285+
$this->headerCheckerManager->check($jws, $index, $mandatoryHeaderParameters);
1286+
} catch (Throwable) {
1287+
throw new OpenIDConnectClientException('Unable to verify JWS header');
1288+
}
1289+
}
1290+
1291+
/**
1292+
* @param JWS $jws
1293+
* @return void
1294+
* @throws OpenIDConnectClientException
1295+
*/
1296+
public function verifySignatures(JWS $jws): void
1297+
{
1298+
if (!$this->verifyJWSSignature($jws)) {
12691299
throw new OpenIDConnectClientException('Unable to verify signature');
12701300
}
12711301
}
@@ -1277,6 +1307,17 @@ public function urlEncode(string $str): string
12771307
return strtr($enc, '+/', '-_');
12781308
}
12791309

1310+
/**
1311+
* Unserializes a JWS string into a JWS object
1312+
*
1313+
* @param string $jws
1314+
* @return JWS
1315+
*/
1316+
public function unserializeJWS(string $jws): JWS
1317+
{
1318+
return $this->jwsSerializerManager->unserialize($jws);
1319+
}
1320+
12801321
/**
12811322
* @param string $jwt encoded JWT
12821323
* @param int $section the section we would like to decode
@@ -1381,7 +1422,7 @@ private function getClaimsFromUserInfoResponse(Response $response)
13811422
}
13821423
}
13831424

1384-
$jws = $this->jwsSerializerManager->unserialize($jwt);
1425+
$jws = $this->unserializeJWS($jwt);
13851426

13861427
return $this->getClaimsFromSignedUserInfoResponse($jws);
13871428

@@ -1412,13 +1453,13 @@ private function getClaimsFromUnsignedUserInfoResponse($content)
14121453
private function getClaimsFromSignedUserInfoResponse(JWS $jws)
14131454
{
14141455
// Verify header
1415-
$this->headerCheckerManager->check($jws, 0, ['alg']);
1456+
$this->verifyJWSHeader($jws);
14161457

14171458
// Verify the signature
14181459
$this->verifySignatures($jws);
14191460

14201461
// Get claims from JWT
1421-
$claims = json_decode($jws->getPayload());
1462+
$claims = $this->getJWSClaims($jws);
14221463

14231464
/*
14241465
* The sub (subject) Claim MUST always be returned in the UserInfo Response.

0 commit comments

Comments
 (0)