77package org .elasticsearch .xpack .security .authc ;
88
99import com .google .common .collect .Sets ;
10+
1011import org .elasticsearch .ElasticsearchSecurityException ;
1112import org .elasticsearch .action .DocWriteResponse ;
1213import org .elasticsearch .action .admin .cluster .health .ClusterHealthResponse ;
@@ -287,9 +288,26 @@ public void testInvalidatedApiKeysDeletedByRemover() throws Exception {
287288 assertThat (invalidateResponse .getPreviouslyInvalidatedApiKeys ().size (), equalTo (0 ));
288289 assertThat (invalidateResponse .getErrors ().size (), equalTo (0 ));
289290
291+ awaitApiKeysRemoverCompletion ();
292+ refreshSecurityIndex ();
293+
290294 PlainActionFuture <GetApiKeyResponse > getApiKeyResponseListener = new PlainActionFuture <>();
291295 client .execute (GetApiKeyAction .INSTANCE , GetApiKeyRequest .usingRealmName ("file" ), getApiKeyResponseListener );
292- assertThat (getApiKeyResponseListener .get ().getApiKeyInfos ().length , is (2 ));
296+ Set <String > expectedKeyIds = Sets .newHashSet (createdApiKeys .get (0 ).getId (), createdApiKeys .get (1 ).getId ());
297+ boolean apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover = false ;
298+ for (ApiKey apiKey : getApiKeyResponseListener .get ().getApiKeyInfos ()) {
299+ assertThat (apiKey .getId (), isIn (expectedKeyIds ));
300+ if (apiKey .getId ().equals (createdApiKeys .get (0 ).getId ())) {
301+ // has been invalidated but not yet deleted by ExpiredApiKeysRemover
302+ assertThat (apiKey .isInvalidated (), is (true ));
303+ apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover = true ;
304+ } else if (apiKey .getId ().equals (createdApiKeys .get (1 ).getId ())) {
305+ // active api key
306+ assertThat (apiKey .isInvalidated (), is (false ));
307+ }
308+ }
309+ assertThat (getApiKeyResponseListener .get ().getApiKeyInfos ().length ,
310+ is ((apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover ) ? 2 : 1 ));
293311
294312 client = waitForExpiredApiKeysRemoverTriggerReadyAndGetClient ().filterWithHeader (
295313 Collections .singletonMap ("Authorization" , UsernamePasswordToken .basicAuthHeaderValue (SecuritySettingsSource .TEST_SUPERUSER ,
@@ -302,16 +320,24 @@ public void testInvalidatedApiKeysDeletedByRemover() throws Exception {
302320 assertThat (listener .get ().getInvalidatedApiKeys ().size (), is (1 ));
303321
304322 awaitApiKeysRemoverCompletion ();
305-
306323 refreshSecurityIndex ();
307324
308- // Verify that 1st invalidated API key is deleted whereas the next one is not
325+ // Verify that 1st invalidated API key is deleted whereas the next one may be or may not be as it depends on whether update was
326+ // indexed before ExpiredApiKeysRemover ran
309327 getApiKeyResponseListener = new PlainActionFuture <>();
310328 client .execute (GetApiKeyAction .INSTANCE , GetApiKeyRequest .usingRealmName ("file" ), getApiKeyResponseListener );
311- assertThat (getApiKeyResponseListener .get ().getApiKeyInfos ().length , is (1 ));
312- ApiKey apiKey = getApiKeyResponseListener .get ().getApiKeyInfos ()[0 ];
313- assertThat (apiKey .getId (), is (createdApiKeys .get (1 ).getId ()));
314- assertThat (apiKey .isInvalidated (), is (true ));
329+ expectedKeyIds = Sets .newHashSet (createdApiKeys .get (1 ).getId ());
330+ apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover = false ;
331+ for (ApiKey apiKey : getApiKeyResponseListener .get ().getApiKeyInfos ()) {
332+ assertThat (apiKey .getId (), isIn (expectedKeyIds ));
333+ if (apiKey .getId ().equals (createdApiKeys .get (1 ).getId ())) {
334+ // has been invalidated but not yet deleted by ExpiredApiKeysRemover
335+ assertThat (apiKey .isInvalidated (), is (true ));
336+ apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover = true ;
337+ }
338+ }
339+ assertThat (getApiKeyResponseListener .get ().getApiKeyInfos ().length ,
340+ is ((apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover ) ? 1 : 0 ));
315341 }
316342
317343 private Client waitForExpiredApiKeysRemoverTriggerReadyAndGetClient () throws Exception {
@@ -334,7 +360,6 @@ private Client waitForExpiredApiKeysRemoverTriggerReadyAndGetClient() throws Exc
334360 return internalCluster ().client (nodeWithMostRecentRun );
335361 }
336362
337- @ AwaitsFix ( bugUrl = "https://github.com/elastic/elasticsearch/issues/41747" )
338363 public void testExpiredApiKeysBehaviorWhenKeysExpired1WeekBeforeAnd1DayBefore () throws Exception {
339364 Client client = waitForExpiredApiKeysRemoverTriggerReadyAndGetClient ().filterWithHeader (
340365 Collections .singletonMap ("Authorization" , UsernamePasswordToken .basicAuthHeaderValue (SecuritySettingsSource .TEST_SUPERUSER ,
@@ -359,7 +384,7 @@ public void testExpiredApiKeysBehaviorWhenKeysExpired1WeekBeforeAnd1DayBefore()
359384 .get ();
360385 assertThat (expirationDateUpdatedResponse .getResult (), is (DocWriteResponse .Result .UPDATED ));
361386
362- // Expire the 2nd key such that it cannot be deleted by the remover
387+ // Expire the 2nd key such that it can be deleted by the remover
363388 // hack doc to modify the expiration time to the week before
364389 Instant weekBefore = created .minus (8L , ChronoUnit .DAYS );
365390 assertTrue (Instant .now ().isAfter (weekBefore ));
@@ -379,23 +404,24 @@ public void testExpiredApiKeysBehaviorWhenKeysExpired1WeekBeforeAnd1DayBefore()
379404
380405 refreshSecurityIndex ();
381406
382- // Verify get API keys does not return expired and deleted key
407+ // Verify get API keys does not return api keys deleted by ExpiredApiKeysRemover
383408 getApiKeyResponseListener = new PlainActionFuture <>();
384409 client .execute (GetApiKeyAction .INSTANCE , GetApiKeyRequest .usingRealmName ("file" ), getApiKeyResponseListener );
385- assertThat (getApiKeyResponseListener .get ().getApiKeyInfos ().length , is (3 ));
386410
387411 Set <String > expectedKeyIds = Sets .newHashSet (createdApiKeys .get (0 ).getId (), createdApiKeys .get (2 ).getId (),
388412 createdApiKeys .get (3 ).getId ());
413+ boolean apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover = false ;
389414 for (ApiKey apiKey : getApiKeyResponseListener .get ().getApiKeyInfos ()) {
390415 assertThat (apiKey .getId (), isIn (expectedKeyIds ));
391416 if (apiKey .getId ().equals (createdApiKeys .get (0 ).getId ())) {
392417 // has been expired, not invalidated
393418 assertTrue (apiKey .getExpiration ().isBefore (Instant .now ()));
394419 assertThat (apiKey .isInvalidated (), is (false ));
395420 } else if (apiKey .getId ().equals (createdApiKeys .get (2 ).getId ())) {
396- // has not been expired as no expiration, but invalidated
421+ // has not been expired as no expiration, is invalidated but not yet deleted by ExpiredApiKeysRemover
397422 assertThat (apiKey .getExpiration (), is (nullValue ()));
398423 assertThat (apiKey .isInvalidated (), is (true ));
424+ apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover = true ;
399425 } else if (apiKey .getId ().equals (createdApiKeys .get (3 ).getId ())) {
400426 // has not been expired as no expiration, not invalidated
401427 assertThat (apiKey .getExpiration (), is (nullValue ()));
@@ -404,6 +430,8 @@ public void testExpiredApiKeysBehaviorWhenKeysExpired1WeekBeforeAnd1DayBefore()
404430 fail ("unexpected API key " + apiKey );
405431 }
406432 }
433+ assertThat (getApiKeyResponseListener .get ().getApiKeyInfos ().length ,
434+ is ((apiKeyInvalidatedButNotYetDeletedByExpiredApiKeysRemover ) ? 3 : 2 ));
407435 }
408436
409437 private void refreshSecurityIndex () throws Exception {
0 commit comments