View Javadoc
1   package de.dlr.shepard.common.filters;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.mockito.ArgumentMatchers.any;
5   import static org.mockito.Mockito.never;
6   import static org.mockito.Mockito.verify;
7   import static org.mockito.Mockito.when;
8   
9   import de.dlr.shepard.BaseTestCase;
10  import de.dlr.shepard.auth.apikey.entities.ApiKey;
11  import de.dlr.shepard.auth.apikey.services.ApiKeyService;
12  import de.dlr.shepard.auth.security.ApiKeyLastSeenCache;
13  import de.dlr.shepard.auth.security.JWTPrincipal;
14  import de.dlr.shepard.auth.security.JWTSecurityContext;
15  import de.dlr.shepard.auth.security.RolesList;
16  import de.dlr.shepard.auth.users.entities.User;
17  import de.dlr.shepard.common.util.PKIHelper;
18  import io.jsonwebtoken.Jwts;
19  import io.quarkus.test.InjectMock;
20  import io.quarkus.test.component.QuarkusComponentTest;
21  import io.quarkus.test.component.TestConfigProperty;
22  import jakarta.inject.Inject;
23  import jakarta.ws.rs.container.ContainerRequestContext;
24  import jakarta.ws.rs.core.Response;
25  import jakarta.ws.rs.core.SecurityContext;
26  import jakarta.ws.rs.core.UriInfo;
27  import java.net.URI;
28  import java.net.URISyntaxException;
29  import java.security.KeyFactory;
30  import java.security.NoSuchAlgorithmException;
31  import java.security.PrivateKey;
32  import java.security.PublicKey;
33  import java.security.spec.InvalidKeySpecException;
34  import java.security.spec.PKCS8EncodedKeySpec;
35  import java.security.spec.X509EncodedKeySpec;
36  import java.util.Base64;
37  import java.util.Date;
38  import java.util.UUID;
39  import org.apache.commons.lang3.time.DateUtils;
40  import org.junit.jupiter.api.BeforeAll;
41  import org.junit.jupiter.api.BeforeEach;
42  import org.junit.jupiter.api.Test;
43  import org.mockito.ArgumentCaptor;
44  import org.mockito.Captor;
45  
46  @QuarkusComponentTest
47  @TestConfigProperty(
48    key = "oidc.public",
49    value = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiAxFyffvM0oiga3h2E7XpHtJvu1vTodrn9Y426FOv80YJcMwPkaI5tXY5hnLjgOwsVNSBv9wAhLL4bUfP+TVhdg4dijD2H/3FamheQaPmduimytzQjlHIIfFuZidH12ZyUrOWfDxiHiRFQ3Dd8dlS7MbIsWt/qBIg16ZZazTJTiaSyP/qH305x9iRjrtGRmvE2VMOdc5EhujFMJnQWWgwOnv2C9U9KIchkPCz+TAL4kKJ79BUi4b0+jxL5Cbgyt0bMo27Zx0zQjU7f0ynFIllqZ6new3Q8HYbr4AIkca4pMjfKWrTHkrQBL2cEXHLIHt86C17goKteToqDjphkwImwIDAQAB"
50  )
51  @TestConfigProperty(key = "oidc.role", value = "test_role")
52  public class JWTFilterTest extends BaseTestCase {
53  
54    private static PrivateKey privateKey;
55    private static PublicKey publicKey;
56  
57    @InjectMock
58    ContainerRequestContext context;
59  
60    @InjectMock
61    UriInfo uriInfo;
62  
63    @InjectMock
64    PKIHelper pkiHelper;
65  
66    @InjectMock
67    ApiKeyService apiKeyService;
68  
69    @InjectMock
70    ApiKeyLastSeenCache apiKeyLastSeenCache;
71  
72    @Inject
73    JWTFilter filter;
74  
75    @Captor
76    ArgumentCaptor<Response> responseCaptor;
77  
78    @Captor
79    ArgumentCaptor<SecurityContext> scCaptor;
80  
81    @BeforeAll
82    public static void createKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
83      var privateString =
84        "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCIDEXJ9+8zSiKBreHYTteke0m+7W9Oh2uf1jjboU6/zRglwzA+Rojm1djmGcuOA7CxU1IG/3ACEsvhtR8/5NWF2Dh2KMPYf/cVqaF5Bo+Z26KbK3NCOUcgh8W5mJ0fXZnJSs5Z8PGIeJEVDcN3x2VLsxsixa3+oEiDXpllrNMlOJpLI/+offTnH2JGOu0ZGa8TZUw51zkSG6MUwmdBZaDA6e/YL1T0ohyGQ8LP5MAviQonv0FSLhvT6PEvkJuDK3RsyjbtnHTNCNTt/TKcUiWWpnqd7DdDwdhuvgAiRxrikyN8patMeStAEvZwRccsge3zoLXuCgq15OioOOmGTAibAgMBAAECggEABBqirFIPZDOzUMgnDPhr5ulVMy5EclEBfSPgOTfngT+1n8YAmZBVJumCjoZuro0L8n159v4TqexZPCjTlYDYtB3urhnStqA9muiwF0+MW27Vu+qWooPJ0oBmBZBGBSE0t27LRMlQ7/X7InB02hMoyhzQD7943TqGlXfwFrIc+H1uXN8MrB4boRX71/yEPT8hv8nWB0FLcgfwtl1l+81otJFveMO/RLStHUH3Auomb/Hh4u96H6S6lUZ8TJ6+8jh2LXmg/RpsqHIWhDbZaNQJE1YdySe3bijov3s/PISaE8pRec6l6KaYkUuFUa6RoGP1RnopsFuN+EeLRMXTRtxgEQKBgQDDB1YRjE7YAYUqeuohhMgx9Ms39zsJGrs6KHE4uWtJFR/Jo3Kq093ykGA+IO+DK/IhBXGzy53SIQ9J7WEONpMmaahY6/Bkhn2nRI9biNaPCovHeO+nIpwtIdTUQLg/d+om+jC2My0YLGk71A5TRkIBPBE9NirbITxibo6jwWWOwwKBgQCylI1fx6f1gdEAP0qM7/LVLrZU3Qx+Q9rPcGG2FI1gWYu69o3JBGpSXqKcAc9hxtFVBaOGpaj9sB8+fPfMXWAvM7c808eL0zOmDC6RlQs0N4XmpV/vUeurgkLQfgB4sfUXbVWHQNsAkvB64BVbbmWFEcHzaBMytb2whvU9hcExSQKBgQCDuSjAoWt/KUev8WTBTtWIKDY5jpopBA0AsuAF1/ZGXiYiImsIRiDZ+/mE/OnIRp46/1pUfWoSypFw9Qtgdivc/e/eXzz2KIAlwYCx6jJAWnceOuhiklW5heghk7Td6TgVK1ZLOTVz5ksNRaSHSiS6gL+EAFnhtwj50oI0yCK30QKBgF7k028HADhUYEQaXbogs1AW/2p+/+mEkxxR4opHx4xgaQDTjSo5P2o/wXbW+2VAqfHdCjU9iFwuH5wr+d1N7ROIDqGzA8FIXJSquoA/y/FWY7/ZNu5MAMhlcq2plwSLw+pL/fveOcHHUyRoONEaC7Y3ZnG6ZyE2M/M+88hab/uJAoGARSSJgG3rRz8hcfQEfopo3rzdeAMY0ws+fXlHp6u51PP+238rB0Y+/b/NeHzwwuqeIxqVTcbd5E8Va7KESPuuzfIQtKbGuVwFpZzWHmROt312AoxeSwRDpOQibpfBAF59D40+SCl6N64whiVoEgJvOQGYB6BIcunIhSpLSD2YId4=";
85      var publicString =
86        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiAxFyffvM0oiga3h2E7XpHtJvu1vTodrn9Y426FOv80YJcMwPkaI5tXY5hnLjgOwsVNSBv9wAhLL4bUfP+TVhdg4dijD2H/3FamheQaPmduimytzQjlHIIfFuZidH12ZyUrOWfDxiHiRFQ3Dd8dlS7MbIsWt/qBIg16ZZazTJTiaSyP/qH305x9iRjrtGRmvE2VMOdc5EhujFMJnQWWgwOnv2C9U9KIchkPCz+TAL4kKJ79BUi4b0+jxL5Cbgyt0bMo27Zx0zQjU7f0ynFIllqZ6new3Q8HYbr4AIkca4pMjfKWrTHkrQBL2cEXHLIHt86C17goKteToqDjphkwImwIDAQAB";
87      var keyFactory = KeyFactory.getInstance("RSA");
88  
89      byte[] privateDecoded = Base64.getDecoder().decode(privateString);
90      PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateDecoded);
91      privateKey = keyFactory.generatePrivate(privateSpec);
92  
93      byte[] publicDecoded = Base64.getDecoder().decode(publicString);
94      X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(publicDecoded);
95      publicKey = keyFactory.generatePublic(publicSpec);
96    }
97  
98    @BeforeEach
99    public void setUpKeys() throws IllegalAccessException {
100     when(pkiHelper.getPublicKey()).thenReturn(publicKey);
101   }
102 
103   @BeforeEach
104   public void setUpUriInfo() throws URISyntaxException {
105     URI uri = new URI("http://localhost:8080/shepard/api/projects");
106     URI baseUri = new URI("http://localhost:8080/shepard/api");
107     String relativePath = "/projects";
108     when(uriInfo.getPath()).thenReturn(relativePath);
109     when(uriInfo.getAbsolutePath()).thenReturn(uri);
110     when(uriInfo.getBaseUri()).thenReturn(baseUri);
111     when(context.getUriInfo()).thenReturn(uriInfo);
112     when(context.getMethod()).thenReturn("GET");
113   }
114 
115   @Test
116   public void testFilterCORS() throws URISyntaxException {
117     when(context.getMethod()).thenReturn("OPTIONS");
118     filter.filter(context);
119     verify(context, never()).abortWith(any());
120   }
121 
122   @Test
123   public void testFilterPublic_publicRoute() throws URISyntaxException {
124     when(uriInfo.getPath()).thenReturn("/versionz");
125     filter.filter(context);
126     verify(context, never()).abortWith(any());
127   }
128 
129   @Test
130   public void testFilterPublic_privateRoute() throws URISyntaxException {
131     when(uriInfo.getPath()).thenReturn("/versionsz");
132     filter.filter(context);
133     verify(context).abortWith(any());
134   }
135 
136   @Test
137   public void testFilterNoHeader() throws URISyntaxException {
138     when(context.getHeaderString("Authorization")).thenReturn(null);
139     filter.filter(context);
140     verify(context).abortWith(responseCaptor.capture());
141     assertEquals(401, responseCaptor.getValue().getStatus());
142   }
143 
144   @Test
145   public void testFilterWrongHeader() {
146     when(context.getHeaderString("Authorization")).thenReturn("sehr falsch");
147     filter.filter(context);
148     verify(context).abortWith(responseCaptor.capture());
149     assertEquals(401, responseCaptor.getValue().getStatus());
150   }
151 
152   @Test
153   public void testFilterTokenExpired() throws InvalidKeySpecException, NoSuchAlgorithmException {
154     Date now = DateUtils.addMinutes(new Date(), -10);
155     Date future = DateUtils.addMinutes(new Date(), -5);
156 
157     String jws = Jwts.builder()
158       .setSubject("Bob")
159       .setAudience("account")
160       .setExpiration(future)
161       .setNotBefore(now)
162       .setIssuedAt(new Date())
163       .setId(UUID.randomUUID().toString())
164       .claim("azp", "testcase")
165       .claim("name", "MyName")
166       .claim("preferred_username", "MyUserName")
167       .claim("given_name", "MyFirstName")
168       .claim("family_name", "MyLastName")
169       .claim("email", "MyEMail")
170       .claim("realm_access", new RolesList(new String[] { "test_role" }))
171       .signWith(privateKey)
172       .compact();
173 
174     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
175     filter.filter(context);
176     verify(context).abortWith(responseCaptor.capture());
177     assertEquals(401, responseCaptor.getValue().getStatus());
178   }
179 
180   @Test
181   public void testFilterMissingSubject() throws InvalidKeySpecException, NoSuchAlgorithmException {
182     Date now = new Date();
183     Date future = DateUtils.addMinutes(now, 5);
184     UUID keyId = UUID.randomUUID();
185 
186     String jws = Jwts.builder()
187       .setAudience("account")
188       .setExpiration(future)
189       .setNotBefore(now)
190       .setIssuedAt(new Date())
191       .setId(keyId.toString())
192       .claim("azp", "testcase")
193       .claim("name", "MyName")
194       .claim("preferred_username", "MyUserName")
195       .claim("given_name", "MyFirstName")
196       .claim("family_name", "MyLastName")
197       .claim("email", "MyEMail")
198       .claim("realm_access", new RolesList(new String[] { "test_role" }))
199       .signWith(privateKey)
200       .compact();
201 
202     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
203     filter.filter(context);
204     verify(context).abortWith(responseCaptor.capture());
205     assertEquals(401, responseCaptor.getValue().getStatus());
206   }
207 
208   @Test
209   public void testFilterEmptySubject() throws InvalidKeySpecException, NoSuchAlgorithmException {
210     Date now = new Date();
211     Date future = DateUtils.addMinutes(now, 5);
212     UUID keyId = UUID.randomUUID();
213 
214     String jws = Jwts.builder()
215       .setAudience("account")
216       .setExpiration(future)
217       .setNotBefore(now)
218       .setIssuedAt(new Date())
219       .setId(keyId.toString())
220       .claim("azp", "testcase")
221       .claim("name", "MyName")
222       .claim("preferred_username", "MyUserName")
223       .claim("given_name", "MyFirstName")
224       .claim("family_name", "MyLastName")
225       .claim("email", "MyEMail")
226       .claim("realm_access", new RolesList(new String[] { "test_role" }))
227       .claim("sub", "")
228       .signWith(privateKey)
229       .compact();
230 
231     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
232     filter.filter(context);
233     verify(context).abortWith(responseCaptor.capture());
234     assertEquals(401, responseCaptor.getValue().getStatus());
235   }
236 
237   @Test
238   public void testFilterMissingRole() throws InvalidKeySpecException, NoSuchAlgorithmException {
239     Date now = new Date();
240     Date future = DateUtils.addMinutes(now, 5);
241     UUID keyId = UUID.randomUUID();
242 
243     String jws = Jwts.builder()
244       .setSubject("Bob")
245       .setAudience("account")
246       .setExpiration(future)
247       .setNotBefore(now)
248       .setIssuedAt(new Date())
249       .setId(keyId.toString())
250       .claim("azp", "testcase")
251       .claim("name", "MyName")
252       .claim("preferred_username", "MyUserName")
253       .claim("given_name", "MyFirstName")
254       .claim("family_name", "MyLastName")
255       .claim("email", "MyEMail")
256       .signWith(privateKey)
257       .compact();
258 
259     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
260     filter.filter(context);
261     verify(context).abortWith(responseCaptor.capture());
262     assertEquals(401, responseCaptor.getValue().getStatus());
263   }
264 
265   @Test
266   public void testFilterWrongRole() throws InvalidKeySpecException, NoSuchAlgorithmException {
267     Date now = new Date();
268     Date future = DateUtils.addMinutes(now, 5);
269     UUID keyId = UUID.randomUUID();
270 
271     String jws = Jwts.builder()
272       .setSubject("Bob")
273       .setAudience("account")
274       .setExpiration(future)
275       .setNotBefore(now)
276       .setIssuedAt(new Date())
277       .setId(keyId.toString())
278       .claim("azp", "testcase")
279       .claim("name", "MyName")
280       .claim("preferred_username", "MyUserName")
281       .claim("given_name", "MyFirstName")
282       .claim("family_name", "MyLastName")
283       .claim("email", "MyEMail")
284       .claim("realm_access", new RolesList(new String[] { "wrong_role" }))
285       .signWith(privateKey)
286       .compact();
287 
288     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
289     filter.filter(context);
290     verify(context).abortWith(responseCaptor.capture());
291     assertEquals(401, responseCaptor.getValue().getStatus());
292   }
293 
294   @Test
295   @TestConfigProperty(key = "oidc.role", value = "")
296   public void testFilterNoRoleConfigured()
297     throws InvalidKeySpecException, NoSuchAlgorithmException, IllegalAccessException {
298     Date now = new Date();
299     Date future = DateUtils.addMinutes(now, 5);
300     UUID keyId = UUID.randomUUID();
301 
302     String jws = Jwts.builder()
303       .setSubject("Bob")
304       .setAudience("account")
305       .setExpiration(future)
306       .setNotBefore(now)
307       .setIssuedAt(new Date())
308       .setId(keyId.toString())
309       .claim("azp", "testcase")
310       .claim("name", "MyName")
311       .claim("preferred_username", "MyUserName")
312       .claim("given_name", "MyFirstName")
313       .claim("family_name", "MyLastName")
314       .claim("email", "MyEMail")
315       .claim("realm_access", new RolesList(new String[] { "another_role" }))
316       .signWith(privateKey)
317       .compact();
318 
319     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
320     filter.filter(context);
321     verify(context, never()).abortWith(any());
322   }
323 
324   @Test
325   public void testFilterSucessful() throws InvalidKeySpecException, NoSuchAlgorithmException {
326     Date now = new Date();
327     Date future = DateUtils.addMinutes(now, 5);
328     UUID keyId = UUID.randomUUID();
329 
330     String jws = Jwts.builder()
331       .setSubject("Bob")
332       .setAudience("account")
333       .setExpiration(future)
334       .setNotBefore(now)
335       .setIssuedAt(new Date())
336       .setId(keyId.toString())
337       .claim("azp", "testcase")
338       .claim("name", "MyName")
339       .claim("preferred_username", "MyUserName")
340       .claim("given_name", "MyFirstName")
341       .claim("family_name", "MyLastName")
342       .claim("email", "MyEMail")
343       .claim("realm_access", new RolesList(new String[] { "test_role" }))
344       .signWith(privateKey)
345       .compact();
346 
347     JWTPrincipal principal = new JWTPrincipal("account", "testcase", "Bob", keyId.toString(), new String[0]);
348     JWTSecurityContext securityContext = new JWTSecurityContext(context.getSecurityContext(), principal);
349 
350     when(context.getHeaderString("Authorization")).thenReturn("Bearer " + jws);
351     filter.filter(context);
352     verify(context, never()).abortWith(any());
353     verify(context).setSecurityContext(scCaptor.capture());
354     assertEquals(securityContext.getUserPrincipal(), scCaptor.getValue().getUserPrincipal());
355   }
356 
357   @Test
358   public void testFilterSucessfulApiKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
359     Date now = new Date();
360     UUID uid = UUID.randomUUID();
361 
362     String jws = Jwts.builder()
363       .setSubject("MyUserName")
364       .setNotBefore(now)
365       .setIssuedAt(new Date())
366       .setId(uid.toString())
367       .signWith(privateKey)
368       .compact();
369 
370     User user = new User("MyUserName");
371 
372     ApiKey apiKey = new ApiKey(uid);
373     apiKey.setName("MyApiKey");
374     apiKey.setJws(jws);
375     apiKey.setBelongsTo(user);
376 
377     JWTPrincipal principal = new JWTPrincipal("MyUserName", uid.toString());
378     JWTSecurityContext securityContext = new JWTSecurityContext(context.getSecurityContext(), principal);
379 
380     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
381     when(apiKeyService.getApiKey(uid)).thenReturn(apiKey);
382 
383     filter.filter(context);
384     verify(context, never()).abortWith(any());
385     verify(context).setSecurityContext(scCaptor.capture());
386     verify(apiKeyLastSeenCache).cacheKey(uid.toString());
387     assertEquals(securityContext.getUserPrincipal(), scCaptor.getValue().getUserPrincipal());
388   }
389 
390   @Test
391   public void testFilterMissingSubjectApiKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
392     Date now = new Date();
393     UUID uid = UUID.randomUUID();
394 
395     String jws = Jwts.builder()
396       .setNotBefore(now)
397       .setIssuedAt(new Date())
398       .setId(uid.toString())
399       .signWith(privateKey)
400       .compact();
401 
402     User user = new User("MyUserName");
403 
404     ApiKey apiKey = new ApiKey(uid);
405     apiKey.setName("MyApiKey");
406     apiKey.setJws(jws);
407     apiKey.setBelongsTo(user);
408 
409     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
410     when(apiKeyService.getApiKey(user.getUsername(), uid)).thenReturn(apiKey);
411 
412     filter.filter(context);
413     verify(context).abortWith(responseCaptor.capture());
414     assertEquals(401, responseCaptor.getValue().getStatus());
415   }
416 
417   @Test
418   public void testFilterEmptySubjectApiKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
419     Date now = new Date();
420     UUID uid = UUID.randomUUID();
421 
422     String jws = Jwts.builder()
423       .setNotBefore(now)
424       .setIssuedAt(new Date())
425       .setId(uid.toString())
426       .claim("sub", "")
427       .signWith(privateKey)
428       .compact();
429 
430     User user = new User("MyUserName");
431 
432     ApiKey apiKey = new ApiKey(uid);
433     apiKey.setName("MyApiKey");
434     apiKey.setJws(jws);
435     apiKey.setBelongsTo(user);
436 
437     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
438     when(apiKeyService.getApiKey(user.getUsername(), uid)).thenReturn(apiKey);
439 
440     filter.filter(context);
441     verify(context).abortWith(responseCaptor.capture());
442     assertEquals(401, responseCaptor.getValue().getStatus());
443   }
444 
445   @Test
446   public void testFilterNotYetValidApiKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
447     Date future = DateUtils.addMinutes(new Date(), 5);
448     UUID uid = UUID.randomUUID();
449 
450     String jws = Jwts.builder()
451       .setSubject("MyUserName")
452       .setNotBefore(future)
453       .setIssuedAt(new Date())
454       .setId(uid.toString())
455       .signWith(privateKey)
456       .compact();
457 
458     User user = new User("MyUserName");
459 
460     ApiKey apiKey = new ApiKey(uid);
461     apiKey.setName("MyApiKey");
462     apiKey.setJws(jws);
463     apiKey.setBelongsTo(user);
464 
465     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
466     when(apiKeyService.getApiKey(user.getUsername(), uid)).thenReturn(apiKey);
467 
468     filter.filter(context);
469     verify(context).abortWith(responseCaptor.capture());
470     assertEquals(401, responseCaptor.getValue().getStatus());
471   }
472 
473   @Test
474   public void testFilterNotFoundInDBApiKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
475     Date now = new Date();
476     UUID uid = UUID.randomUUID();
477 
478     String jws = Jwts.builder()
479       .setSubject("MyUserName")
480       .setNotBefore(now)
481       .setIssuedAt(new Date())
482       .setId(uid.toString())
483       .signWith(privateKey)
484       .compact();
485 
486     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
487     when(apiKeyService.getApiKey("MyUserName", uid)).thenReturn(null);
488 
489     filter.filter(context);
490     verify(context).abortWith(responseCaptor.capture());
491     assertEquals(401, responseCaptor.getValue().getStatus());
492   }
493 
494   @Test
495   public void testFilterWrongFoundInDBApiKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
496     Date now = new Date();
497     UUID uid = UUID.randomUUID();
498 
499     String jws = Jwts.builder()
500       .setSubject("MyUserName")
501       .setNotBefore(now)
502       .setIssuedAt(new Date())
503       .setId(uid.toString())
504       .signWith(privateKey)
505       .compact();
506 
507     User user = new User("MyUserName");
508 
509     ApiKey apiKey = new ApiKey(uid);
510     apiKey.setName("MyApiKey");
511     apiKey.setJws("Wrong");
512     apiKey.setBelongsTo(user);
513 
514     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
515     when(apiKeyService.getApiKey(user.getUsername(), uid)).thenReturn(apiKey);
516 
517     filter.filter(context);
518     verify(context).abortWith(responseCaptor.capture());
519     assertEquals(401, responseCaptor.getValue().getStatus());
520   }
521 
522   @Test
523   public void testFilterGracePeriod() throws InvalidKeySpecException, NoSuchAlgorithmException {
524     Date now = new Date();
525     UUID uid = UUID.randomUUID();
526 
527     String jws = Jwts.builder()
528       .setSubject("MyUserName")
529       .setNotBefore(now)
530       .setIssuedAt(new Date())
531       .setId(uid.toString())
532       .signWith(privateKey)
533       .compact();
534 
535     JWTPrincipal principal = new JWTPrincipal("MyUserName", uid.toString());
536     JWTSecurityContext securityContext = new JWTSecurityContext(context.getSecurityContext(), principal);
537 
538     when(context.getHeaderString("X-API-KEY")).thenReturn(jws);
539     when(apiKeyLastSeenCache.isKeyCached(uid.toString())).thenReturn(true);
540 
541     filter.filter(context);
542     verify(context, never()).abortWith(any());
543     verify(context).setSecurityContext(scCaptor.capture());
544     verify(apiKeyService, never()).getApiKey("MyUserName", uid);
545     assertEquals(securityContext.getUserPrincipal(), scCaptor.getValue().getUserPrincipal());
546   }
547 }