@@ -219,17 +219,19 @@ class FidoMetadataDownloaderSpec
219219 private def makeHttpServer (
220220 path : String ,
221221 response : String ,
222+ inspectRequest : HttpServletRequest => Any = _ => {},
222223 ): (Server , String , X509Certificate ) =
223- makeHttpServer(
224- Map (path -> (200 , response.getBytes(StandardCharsets .UTF_8 )))
225- )
224+ makeHttpServer(Map (path -> (request => {
225+ inspectRequest(request)
226+ (200 , response.getBytes(StandardCharsets .UTF_8 ))
227+ })))
226228 private def makeHttpServer (
227229 path : String ,
228230 response : Array [Byte ],
229231 ): (Server , String , X509Certificate ) =
230- makeHttpServer(Map (path -> (200 , response)))
232+ makeHttpServer(Map (path -> (_ => ( 200 , response) )))
231233 private def makeHttpServer (
232- responses : Map [String , (Int , Array [Byte ])]
234+ responses : Map [String , HttpServletRequest => (Int , Array [Byte ])]
233235 ): (Server , String , X509Certificate ) = {
234236 val tlsKey = TestAuthenticator .generateEcKeypair()
235237 val tlsCert = TestAuthenticator .buildCertificate(
@@ -271,8 +273,10 @@ class FidoMetadataDownloaderSpec
271273 request : HttpServletRequest ,
272274 response : HttpServletResponse ,
273275 ): Unit = {
276+
274277 responses.get(target) match {
275- case Some ((status, responseBody)) => {
278+ case Some (processRequest) => {
279+ val (status, responseBody) = processRequest(request)
276280 response.getOutputStream.write(responseBody)
277281 response.setStatus(status)
278282 }
@@ -1119,8 +1123,13 @@ class FidoMetadataDownloaderSpec
11191123 val (server, serverUrl, httpsCert) =
11201124 makeHttpServer(
11211125 Map (
1122- " /blob.jwt" -> (HttpStatus .TOO_MANY_REQUESTS_429 , newBlobJwt
1123- .getBytes(StandardCharsets .UTF_8 ))
1126+ " /blob.jwt" -> (_ =>
1127+ (
1128+ HttpStatus .TOO_MANY_REQUESTS_429 ,
1129+ newBlobJwt
1130+ .getBytes(StandardCharsets .UTF_8 ),
1131+ )
1132+ )
11241133 )
11251134 )
11261135 startServer(server)
@@ -1181,10 +1190,17 @@ class FidoMetadataDownloaderSpec
11811190 val (server, _, httpsCert) =
11821191 makeHttpServer(
11831192 Map (
1184- " /chain.pem" -> (200 , certChainPem.getBytes(
1185- StandardCharsets .UTF_8
1186- )),
1187- " /blob.jwt" -> (200 , blobJwt.getBytes(StandardCharsets .UTF_8 )),
1193+ " /chain.pem" -> (_ =>
1194+ (
1195+ 200 ,
1196+ certChainPem.getBytes(
1197+ StandardCharsets .UTF_8
1198+ ),
1199+ )
1200+ ),
1201+ " /blob.jwt" -> (_ =>
1202+ (200 , blobJwt.getBytes(StandardCharsets .UTF_8 ))
1203+ ),
11881204 )
11891205 )
11901206 startServer(server)
@@ -2289,6 +2305,123 @@ class FidoMetadataDownloaderSpec
22892305 blob should not be null
22902306 blob.getNo should equal(newBlobNo)
22912307 }
2308+
2309+ withEachLoadMethod(load => {
2310+ describe(
2311+ """ The download request sends the If-None-Match header set to the "no" value of the cached BLOB"""
2312+ ) {
2313+ val oldBlobExpires = CertValidFrom .plus(10 , ChronoUnit .DAYS )
2314+ val newBlobExpires = oldBlobExpires.plus(5 , ChronoUnit .DAYS )
2315+
2316+ val oldBlobJwt =
2317+ makeBlob(
2318+ List (blobCert),
2319+ blobKeypair,
2320+ oldBlobExpires.atOffset(ZoneOffset .UTC ).toLocalDate,
2321+ no = oldBlobNo,
2322+ )
2323+ val newBlobJwt =
2324+ makeBlob(
2325+ List (blobCert),
2326+ blobKeypair,
2327+ newBlobExpires.atOffset(ZoneOffset .UTC ).toLocalDate,
2328+ no = newBlobNo,
2329+ )
2330+
2331+ def downloader (
2332+ currentTime : Instant ,
2333+ serverUrl : String ,
2334+ serverCert : X509Certificate ,
2335+ ): FidoMetadataDownloader = {
2336+ FidoMetadataDownloader
2337+ .builder()
2338+ .expectLegalHeader(
2339+ " Kom ihåg att du aldrig får snyta dig i mattan!"
2340+ )
2341+ .useTrustRoot(trustRootCert)
2342+ .downloadBlob(new URL (s " ${serverUrl}/blob.jwt " ))
2343+ .useBlobCache(
2344+ () =>
2345+ Optional .of(
2346+ new ByteArray (oldBlobJwt.getBytes(StandardCharsets .UTF_8 ))
2347+ ),
2348+ _ => {},
2349+ )
2350+ .clock(Clock .fixed(currentTime, ZoneOffset .UTC ))
2351+ .useCrls(crls.asJava)
2352+ .trustHttpsCerts(serverCert)
2353+ .build()
2354+ }
2355+
2356+ /** Needed to work around some strange scalafmt issues */
2357+ def toQuoted (i : Int ): String = String .join(" " , " \" " , i.toString, " \" " )
2358+
2359+ it(" when the cached BLOB is up to date." ) {
2360+ var requestRan = false
2361+ var requestSucceeded = false
2362+ val (server, serverUrl, serverCert) =
2363+ makeHttpServer(
2364+ " /blob.jwt" ,
2365+ newBlobJwt,
2366+ request => {
2367+ requestRan = true
2368+ request.getHeader(" If-None-Match" ) should equal(
2369+ toQuoted(oldBlobNo)
2370+ )
2371+ // The above assertion won't directly cause the test to fail, since it runs in the server context.
2372+ requestSucceeded = true
2373+ },
2374+ )
2375+ startServer(server)
2376+
2377+ val blob =
2378+ load(
2379+ downloader(
2380+ oldBlobExpires.minus(1 , ChronoUnit .DAYS ),
2381+ serverUrl,
2382+ serverCert,
2383+ )
2384+ ).getPayload
2385+ blob should not be null
2386+ if (requestRan) {
2387+ blob.getNo should equal(newBlobNo)
2388+ requestSucceeded should be(true )
2389+ } else {
2390+ blob.getNo should equal(oldBlobNo)
2391+ }
2392+ }
2393+
2394+ it(" when the cached BLOB is expired." ) {
2395+ var requestSucceeded = false
2396+ val (server, serverUrl, serverCert) =
2397+ makeHttpServer(
2398+ " /blob.jwt" ,
2399+ newBlobJwt,
2400+ request => {
2401+ request.getHeader(" If-None-Match" ) should equal(
2402+ toQuoted(oldBlobNo)
2403+ )
2404+ // The above assertion won't directly cause the test to fail, since it runs in the server context.
2405+ requestSucceeded = true
2406+ },
2407+ )
2408+ startServer(server)
2409+
2410+ val blob =
2411+ load(
2412+ downloader(
2413+ oldBlobExpires.plus(1 , ChronoUnit .DAYS ),
2414+ serverUrl,
2415+ serverCert,
2416+ )
2417+ ).getPayload
2418+ blob should not be null
2419+ blob.getNo should equal(newBlobNo)
2420+ requestSucceeded should be(true )
2421+ }
2422+
2423+ }
2424+ })
22922425 }
22932426
22942427}
0 commit comments