33namespace Pdsinterop \Solid \Auth \Utils ;
44
55use DateInterval ;
6- use Lcobucci \JWT \Token \InvalidTokenStructure ;
7- use Pdsinterop \Solid \Auth \JtiStorageInterface ;
6+ use Pdsinterop \Solid \Auth \ReplayDetectorInterface ;
87
98/**
109 * Validates whether a provided JTI (JWT ID) is valid.
1312 */
1413class JtiValidator
1514{
16- ////////////////////////////// CLASS PROPERTIES \\\\\\\\\\\\\\\\\\\\\\\\\\\\
17-
18- /**
19- * Maximum allowed amount of seconds a JTI is valid
20- */
21- private int $ maxIntervalSeconds = 600 ; // @TODO: Time::MINUTES_10
22-
23- //////////////////////////////// PUBLIC API \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
24-
25- /**
26- * @param JtiStorageInterface $jtiStorage
27- * @param DateInterval $interval
28- *
29- * @throw \InvalidArgumentException When the provided Interval is not valid
30- */
31- final public function __construct (private JtiStorageInterface $ jtiStorage , private DateInterval $ interval )
32- {
33- $ intervalSeconds = $ this ->interval ->format ('s ' );
34-
35- // @CHECKME: Is there a maximum validity period? Does the spec say anything about this?
36- // Or do we not need to check and should we just trust the user?
37- // @FIXME: Use DateTime / DateInterval objects rather than math to compare times
38- if ($ intervalSeconds > $ this ->maxIntervalSeconds ) {
39- $ message = vsprintf (
40- 'Given time interval (%s) is larger than the allowed maximum (%s) ' ,
41- [
42- 'interval ' => $ intervalSeconds ,
43- 'maximum ' => $ this ->maxIntervalSeconds ,
44- ]
45- );
46-
47- throw new \InvalidArgumentException ($ message );
48- }
49- }
15+ final public function __construct (private ReplayDetectorInterface $ replayDetector ) {}
5016
5117 public function validate ($ jti , $ targetUri ): bool
5218 {
@@ -58,31 +24,10 @@ public function validate($jti, $targetUri): bool
5824 * The upper limit is chosen based on maximum field length in common database storage types (varchar)
5925 */
6026 if ($ strlen > 12 && $ strlen < 256 ) {
61- $ isValid = $ this ->jtiStorage ->retrieve ($ jti , $ targetUri ) === false ;
62-
63- if ($ isValid === true ) {
64- // @CHECKME: Should we catch exceptions here? Catch them in the DPOP calll? Allow them to bubble up?
65- $ this ->jtiStorage ->store ($ jti , $ targetUri );
66- }
67-
68- // @CHECKME: Should rotation be checked before or after storing the JTI?
69- if ($ this ->shouldRotate ()) {
70- $ this ->jtiStorage ->rotateBuckets ();
71- }
27+ // @CHECKME: Should we fail silently (return false) or loudly (throw InvalidTokeException)?
28+ $ isValid = $ this ->replayDetector ->detect ($ jti , $ targetUri ) === false ;
7229 }
7330
7431 return $ isValid ;
7532 }
76-
77- ////////////////////////////// UTILITY METHODS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\
78-
79- private function shouldRotate (): bool
80- {
81- $ shouldRotate = false ;
82-
83- // @CHECKME: How to round of the interval? Count up from X:00 and add increments?
84- // This would basically be modulo?
85-
86- return $ shouldRotate ;
87- }
8833}
0 commit comments