2626import org .elasticsearch .action .update .UpdateAction ;
2727import org .elasticsearch .action .update .UpdateRequestBuilder ;
2828import org .elasticsearch .client .Client ;
29+ import org .elasticsearch .cluster .ClusterState ;
30+ import org .elasticsearch .cluster .node .DiscoveryNode ;
31+ import org .elasticsearch .cluster .node .DiscoveryNodes ;
2932import org .elasticsearch .cluster .service .ClusterService ;
3033import org .elasticsearch .common .settings .MockSecureSettings ;
3134import org .elasticsearch .common .Strings ;
4447import org .elasticsearch .test .ClusterServiceUtils ;
4548import org .elasticsearch .test .ESTestCase ;
4649import org .elasticsearch .test .EqualsHashCodeTestUtils ;
50+ import org .elasticsearch .test .VersionUtils ;
4751import org .elasticsearch .threadpool .FixedExecutorBuilder ;
4852import org .elasticsearch .threadpool .ThreadPool ;
4953import org .elasticsearch .xpack .core .XPackSettings ;
5357import org .elasticsearch .xpack .core .security .user .User ;
5458import org .elasticsearch .xpack .core .watcher .watch .ClockMock ;
5559import org .elasticsearch .xpack .security .support .SecurityIndexManager ;
60+ import org .junit .After ;
5661import org .junit .AfterClass ;
5762import org .junit .Before ;
5863import org .junit .BeforeClass ;
6671import java .time .temporal .ChronoUnit ;
6772import java .util .Base64 ;
6873import java .util .Collections ;
74+ import java .util .EnumSet ;
6975import java .util .HashMap ;
7076import java .util .Map ;
7177import java .util .concurrent .ExecutionException ;
@@ -91,6 +97,7 @@ public class TokenServiceTests extends ESTestCase {
9197 private Client client ;
9298 private SecurityIndexManager securityIndex ;
9399 private ClusterService clusterService ;
100+ private boolean mixedCluster ;
94101 private Settings tokenServiceEnabledSettings = Settings .builder ()
95102 .put (XPackSettings .TOKEN_SERVICE_ENABLED_SETTING .getKey (), true ).build ();
96103
@@ -141,6 +148,25 @@ public void setupClient() {
141148 return null ;
142149 }).when (securityIndex ).prepareIndexIfNeededThenExecute (any (Consumer .class ), any (Runnable .class ));
143150 this .clusterService = ClusterServiceUtils .createClusterService (threadPool );
151+ this .mixedCluster = randomBoolean ();
152+ if (mixedCluster ) {
153+ Version version = VersionUtils .randomVersionBetween (random (), Version .V_5_6_0 , Version .V_5_6_10 );
154+ logger .info ("adding a node with version [{}] to the cluster service" , version );
155+ ClusterState updatedState = ClusterState .builder (clusterService .state ())
156+ .nodes (DiscoveryNodes .builder (clusterService .state ().nodes ())
157+ .add (new DiscoveryNode ("56node" , ESTestCase .buildNewFakeTransportAddress (), Collections .emptyMap (),
158+ EnumSet .allOf (DiscoveryNode .Role .class ), version ))
159+ .build ())
160+ .build ();
161+ ClusterServiceUtils .setState (clusterService , updatedState );
162+ }
163+ }
164+
165+ @ After
166+ public void stopClusterService () {
167+ if (clusterService != null ) {
168+ clusterService .close ();
169+ }
144170 }
145171
146172 @ BeforeClass
@@ -172,7 +198,7 @@ public void testAttachAndGetToken() throws Exception {
172198 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
173199 tokenService .getAndValidateToken (requestContext , future );
174200 UserToken serialized = future .get ();
175- assertEquals (authentication , serialized .getAuthentication ());
201+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
176202 }
177203
178204 try (ThreadContext .StoredContext ignore = requestContext .newStoredContext (true )) {
@@ -183,11 +209,12 @@ public void testAttachAndGetToken() throws Exception {
183209 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
184210 anotherService .getAndValidateToken (requestContext , future );
185211 UserToken fromOtherService = future .get ();
186- assertEquals (authentication , fromOtherService .getAuthentication ());
212+ assertAuthenticationEquals (authentication , fromOtherService .getAuthentication ());
187213 }
188214 }
189215
190216 public void testRotateKey () throws Exception {
217+ assumeFalse ("internally managed keys do not work in a mixed cluster" , mixedCluster );
191218 TokenService tokenService = new TokenService (tokenServiceEnabledSettings , systemUTC (), client , securityIndex , clusterService );
192219 Authentication authentication = new Authentication (new User ("joe" , "admin" ), new RealmRef ("native_realm" , "native" , "node1" ), null );
193220 PlainActionFuture <Tuple <UserToken , String >> tokenFuture = new PlainActionFuture <>();
@@ -203,15 +230,15 @@ public void testRotateKey() throws Exception {
203230 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
204231 tokenService .getAndValidateToken (requestContext , future );
205232 UserToken serialized = future .get ();
206- assertEquals (authentication , serialized .getAuthentication ());
233+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
207234 }
208235 rotateKeys (tokenService );
209236
210237 try (ThreadContext .StoredContext ignore = requestContext .newStoredContext (true )) {
211238 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
212239 tokenService .getAndValidateToken (requestContext , future );
213240 UserToken serialized = future .get ();
214- assertEquals (authentication , serialized .getAuthentication ());
241+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
215242 }
216243
217244 PlainActionFuture <Tuple <UserToken , String >> newTokenFuture = new PlainActionFuture <>();
@@ -240,6 +267,7 @@ private void rotateKeys(TokenService tokenService) {
240267 }
241268
242269 public void testKeyExchange () throws Exception {
270+ assumeFalse ("internally managed keys do not work in a mixed cluster" , mixedCluster );
243271 TokenService tokenService = new TokenService (tokenServiceEnabledSettings , systemUTC (), client , securityIndex , clusterService );
244272 int numRotations = 0 ;randomIntBetween (1 , 5 );
245273 for (int i = 0 ; i < numRotations ; i ++) {
@@ -261,7 +289,7 @@ public void testKeyExchange() throws Exception {
261289 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
262290 otherTokenService .getAndValidateToken (requestContext , future );
263291 UserToken serialized = future .get ();
264- assertEquals (authentication , serialized .getAuthentication ());
292+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
265293 }
266294
267295 rotateKeys (tokenService );
@@ -272,11 +300,12 @@ public void testKeyExchange() throws Exception {
272300 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
273301 otherTokenService .getAndValidateToken (requestContext , future );
274302 UserToken serialized = future .get ();
275- assertEquals (authentication , serialized .getAuthentication ());
303+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
276304 }
277305 }
278306
279307 public void testPruneKeys () throws Exception {
308+ assumeFalse ("internally managed keys do not work in a mixed cluster" , mixedCluster );
280309 TokenService tokenService = new TokenService (tokenServiceEnabledSettings , systemUTC (), client , securityIndex , clusterService );
281310 Authentication authentication = new Authentication (new User ("joe" , "admin" ), new RealmRef ("native_realm" , "native" , "node1" ), null );
282311 PlainActionFuture <Tuple <UserToken , String >> tokenFuture = new PlainActionFuture <>();
@@ -292,7 +321,7 @@ public void testPruneKeys() throws Exception {
292321 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
293322 tokenService .getAndValidateToken (requestContext , future );
294323 UserToken serialized = future .get ();
295- assertEquals (authentication , serialized .getAuthentication ());
324+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
296325 }
297326 TokenMetaData metaData = tokenService .pruneKeys (randomIntBetween (0 , 100 ));
298327 tokenService .refreshMetaData (metaData );
@@ -306,7 +335,7 @@ public void testPruneKeys() throws Exception {
306335 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
307336 tokenService .getAndValidateToken (requestContext , future );
308337 UserToken serialized = future .get ();
309- assertEquals (authentication , serialized .getAuthentication ());
338+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
310339 }
311340
312341 PlainActionFuture <Tuple <UserToken , String >> newTokenFuture = new PlainActionFuture <>();
@@ -332,7 +361,7 @@ public void testPruneKeys() throws Exception {
332361 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
333362 tokenService .getAndValidateToken (requestContext , future );
334363 UserToken serialized = future .get ();
335- assertEquals (authentication , serialized .getAuthentication ());
364+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
336365 }
337366
338367 }
@@ -353,7 +382,7 @@ public void testPassphraseWorks() throws Exception {
353382 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
354383 tokenService .getAndValidateToken (requestContext , future );
355384 UserToken serialized = future .get ();
356- assertEquals (authentication , serialized .getAuthentication ());
385+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
357386 }
358387
359388 try (ThreadContext .StoredContext ignore = requestContext .newStoredContext (true )) {
@@ -454,7 +483,7 @@ public void testTokenExpiry() throws Exception {
454483 // the clock is still frozen, so the cookie should be valid
455484 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
456485 tokenService .getAndValidateToken (requestContext , future );
457- assertEquals (authentication , future .get ().getAuthentication ());
486+ assertAuthenticationEquals (authentication , future .get ().getAuthentication ());
458487 }
459488
460489 final TimeValue defaultExpiration = TokenService .TOKEN_EXPIRATION .get (Settings .EMPTY );
@@ -464,7 +493,7 @@ public void testTokenExpiry() throws Exception {
464493 clock .fastForwardSeconds (fastForwardAmount );
465494 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
466495 tokenService .getAndValidateToken (requestContext , future );
467- assertEquals (authentication , future .get ().getAuthentication ());
496+ assertAuthenticationEquals (authentication , future .get ().getAuthentication ());
468497 }
469498
470499 try (ThreadContext .StoredContext ignore = requestContext .newStoredContext (true )) {
@@ -473,7 +502,7 @@ public void testTokenExpiry() throws Exception {
473502 clock .rewind (TimeValue .timeValueNanos (clock .instant ().getNano ())); // trim off nanoseconds since don't store them in the index
474503 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
475504 tokenService .getAndValidateToken (requestContext , future );
476- assertEquals (authentication , future .get ().getAuthentication ());
505+ assertAuthenticationEquals (authentication , future .get ().getAuthentication ());
477506 }
478507
479508 try (ThreadContext .StoredContext ignore = requestContext .newStoredContext (true )) {
@@ -569,7 +598,7 @@ public void testIndexNotAvailable() throws Exception {
569598 PlainActionFuture <UserToken > future = new PlainActionFuture <>();
570599 tokenService .getAndValidateToken (requestContext , future );
571600 UserToken serialized = future .get ();
572- assertEquals (authentication , serialized .getAuthentication ());
601+ assertAuthenticationEquals (authentication , serialized .getAuthentication ());
573602
574603 when (securityIndex .isAvailable ()).thenReturn (false );
575604 when (securityIndex .indexExists ()).thenReturn (true );
@@ -601,6 +630,7 @@ public void testDecodePre6xToken() throws GeneralSecurityException, ExecutionExc
601630 assertWarnings ("[xpack.security.authc.token.passphrase] setting was deprecated in Elasticsearch and will be removed in a future" +
602631 " release! See the breaking changes documentation for the next major version." );
603632 }
633+
604634 public void testGetAuthenticationWorksWithExpiredToken () throws Exception {
605635 TokenService tokenService =
606636 new TokenService (tokenServiceEnabledSettings , Clock .systemUTC (), client , securityIndex , clusterService );
@@ -611,7 +641,7 @@ public void testGetAuthenticationWorksWithExpiredToken() throws Exception {
611641 PlainActionFuture <Tuple <Authentication , Map <String , Object >>> authFuture = new PlainActionFuture <>();
612642 tokenService .getAuthenticationAndMetaData (userTokenString , authFuture );
613643 Authentication retrievedAuth = authFuture .actionGet ().v1 ();
614- assertEquals (authentication , retrievedAuth );
644+ assertAuthenticationEquals (authentication , retrievedAuth );
615645 }
616646
617647 private void mockGetTokenFromId (UserToken userToken ) {
@@ -638,4 +668,16 @@ public static void mockGetTokenFromId(UserToken userToken, Client client) {
638668 return Void .TYPE ;
639669 }).when (client ).get (any (GetRequest .class ), any (ActionListener .class ));
640670 }
671+
672+ private void assertAuthenticationEquals (Authentication expected , Authentication actual ) {
673+ if (mixedCluster ) {
674+ assertNotNull (expected );
675+ assertNotNull (actual );
676+ assertEquals (expected .getUser (), actual .getUser ());
677+ assertEquals (expected .getAuthenticatedBy (), actual .getAuthenticatedBy ());
678+ assertEquals (expected .getLookedUpBy (), actual .getLookedUpBy ());
679+ } else {
680+ assertEquals (expected , actual );
681+ }
682+ }
641683}
0 commit comments