134
134
*/
135
135
public class AuthenticationServiceTests extends ESTestCase {
136
136
137
+ private static final String SECOND_REALM_NAME = "second_realm" ;
138
+ private static final String SECOND_REALM_TYPE = "second" ;
139
+ private static final String FIRST_REALM_NAME = "file_realm" ;
140
+ private static final String FIRST_REALM_TYPE = "file" ;
137
141
private AuthenticationService service ;
138
142
private TransportMessage message ;
139
143
private RestRequest restRequest ;
@@ -167,11 +171,11 @@ public void init() throws Exception {
167
171
threadContext = new ThreadContext (Settings .EMPTY );
168
172
169
173
firstRealm = mock (Realm .class );
170
- when (firstRealm .type ()).thenReturn ("file" );
171
- when (firstRealm .name ()).thenReturn ("file_realm" );
174
+ when (firstRealm .type ()).thenReturn (FIRST_REALM_TYPE );
175
+ when (firstRealm .name ()).thenReturn (FIRST_REALM_NAME );
172
176
secondRealm = mock (Realm .class );
173
- when (secondRealm .type ()).thenReturn ("second" );
174
- when (secondRealm .name ()).thenReturn ("second_realm" );
177
+ when (secondRealm .type ()).thenReturn (SECOND_REALM_TYPE );
178
+ when (secondRealm .name ()).thenReturn (SECOND_REALM_NAME );
175
179
Settings settings = Settings .builder ()
176
180
.put ("path.home" , createTempDir ())
177
181
.put ("node.name" , "authc_test" )
@@ -305,26 +309,35 @@ public void testAuthenticateSmartRealmOrdering() {
305
309
when (secondRealm .token (threadContext )).thenReturn (token );
306
310
final String reqId = AuditUtil .getOrGenerateRequestId (threadContext );
307
311
312
+ // Authenticate against the normal chain. 1st Realm will be checked (and not pass) then 2nd realm will successfully authc
308
313
final AtomicBoolean completed = new AtomicBoolean (false );
309
314
service .authenticate ("_action" , message , (User )null , ActionListener .wrap (result -> {
310
315
assertThat (result , notNullValue ());
311
316
assertThat (result .getUser (), is (user ));
312
317
assertThat (result .getLookedUpBy (), is (nullValue ()));
313
318
assertThat (result .getAuthenticatedBy (), is (notNullValue ())); // TODO implement equals
319
+ assertThat (result .getAuthenticatedBy ().getName (), is (SECOND_REALM_NAME ));
320
+ assertThat (result .getAuthenticatedBy ().getType (), is (SECOND_REALM_TYPE ));
314
321
assertThreadContextContainsAuthentication (result );
315
322
setCompletedToTrue (completed );
316
323
}, this ::logAndFail ));
317
324
assertTrue (completed .get ());
318
325
319
326
completed .set (false );
327
+ // Authenticate against the smart chain.
328
+ // "SecondRealm" will be at the top of the list and will successfully authc.
329
+ // "FirstRealm" will not be used
320
330
service .authenticate ("_action" , message , (User )null , ActionListener .wrap (result -> {
321
331
assertThat (result , notNullValue ());
322
332
assertThat (result .getUser (), is (user ));
323
333
assertThat (result .getLookedUpBy (), is (nullValue ()));
324
334
assertThat (result .getAuthenticatedBy (), is (notNullValue ())); // TODO implement equals
335
+ assertThat (result .getAuthenticatedBy ().getName (), is (SECOND_REALM_NAME ));
336
+ assertThat (result .getAuthenticatedBy ().getType (), is (SECOND_REALM_TYPE ));
325
337
assertThreadContextContainsAuthentication (result );
326
338
setCompletedToTrue (completed );
327
339
}, this ::logAndFail ));
340
+
328
341
verify (auditTrail ).authenticationFailed (reqId , firstRealm .name (), token , "_action" , message );
329
342
verify (auditTrail , times (2 )).authenticationSuccess (reqId , secondRealm .name (), user , "_action" , message );
330
343
verify (firstRealm , times (2 )).name (); // used above one time
@@ -337,6 +350,30 @@ public void testAuthenticateSmartRealmOrdering() {
337
350
verify (firstRealm ).authenticate (eq (token ), any (ActionListener .class ));
338
351
verify (secondRealm , times (2 )).authenticate (eq (token ), any (ActionListener .class ));
339
352
verifyNoMoreInteractions (auditTrail , firstRealm , secondRealm );
353
+
354
+ // Now assume some change in the backend system so that 2nd realm no longer has the user, but the 1st realm does.
355
+ mockAuthenticate (secondRealm , token , null );
356
+ mockAuthenticate (firstRealm , token , user );
357
+
358
+ completed .set (false );
359
+ // This will authenticate against the smart chain.
360
+ // "SecondRealm" will be at the top of the list but will no longer authenticate the user.
361
+ // Then "FirstRealm" will be checked.
362
+ service .authenticate ("_action" , message , (User )null , ActionListener .wrap (result -> {
363
+ assertThat (result , notNullValue ());
364
+ assertThat (result .getUser (), is (user ));
365
+ assertThat (result .getLookedUpBy (), is (nullValue ()));
366
+ assertThat (result .getAuthenticatedBy (), is (notNullValue ()));
367
+ assertThat (result .getAuthenticatedBy ().getName (), is (FIRST_REALM_NAME ));
368
+ assertThat (result .getAuthenticatedBy ().getType (), is (FIRST_REALM_TYPE ));
369
+ assertThreadContextContainsAuthentication (result );
370
+ setCompletedToTrue (completed );
371
+ }, this ::logAndFail ));
372
+
373
+ verify (auditTrail , times (1 )).authenticationFailed (reqId , SECOND_REALM_NAME , token , "_action" , message );
374
+ verify (auditTrail , times (1 )).authenticationSuccess (reqId , FIRST_REALM_NAME , user , "_action" , message );
375
+ verify (secondRealm , times (3 )).authenticate (eq (token ), any (ActionListener .class )); // 2 from above + 1 more
376
+ verify (firstRealm , times (2 )).authenticate (eq (token ), any (ActionListener .class )); // 1 from above + 1 more
340
377
}
341
378
342
379
public void testCacheClearOnSecurityIndexChange () {
0 commit comments