@@ -52,16 +52,13 @@ public void testImdsV1() throws IOException {
5252        assertTrue (Strings .hasText (profileName ));
5353
5454        final  var  credentialsResponse  = handleRequest (handler , "GET" , SECURITY_CREDENTIALS_URI  + profileName );
55-         assertEquals (RestStatus .OK , credentialsResponse .status ());
5655
5756        assertThat (generatedCredentials , aMapWithSize (1 ));
58-         final  var  accessKey  = generatedCredentials .keySet ().iterator ().next ();
59-         final  var  sessionToken  = generatedCredentials .values ().iterator ().next ();
60- 
61-         final  var  responseMap  = XContentHelper .convertToMap (XContentType .JSON .xContent (), credentialsResponse .body ().streamInput (), false );
62-         assertEquals (Set .of ("AccessKeyId" , "Expiration" , "RoleArn" , "SecretAccessKey" , "Token" ), responseMap .keySet ());
63-         assertEquals (accessKey , responseMap .get ("AccessKeyId" ));
64-         assertEquals (sessionToken , responseMap .get ("Token" ));
57+         assertValidCredentialsResponse (
58+             credentialsResponse ,
59+             generatedCredentials .keySet ().iterator ().next (),
60+             generatedCredentials .values ().iterator ().next ()
61+         );
6562    }
6663
6764    public  void  testImdsV2Disabled () {
@@ -78,6 +75,7 @@ public void testImdsV2() throws IOException {
7875
7976        final  var  tokenResponse  = handleRequest (handler , "PUT" , "/latest/api/token" );
8077        assertEquals (RestStatus .OK , tokenResponse .status ());
78+         assertEquals (List .of ("86400"  /* seconds in a day */ ), tokenResponse .responseHeaders ().get ("x-aws-ec2-metadata-token-ttl-seconds" ));
8179        final  var  token  = tokenResponse .body ().utf8ToString ();
8280
8381        final  var  roleResponse  = checkImdsV2GetRequest (handler , SECURITY_CREDENTIALS_URI , token );
@@ -86,16 +84,13 @@ public void testImdsV2() throws IOException {
8684        assertTrue (Strings .hasText (profileName ));
8785
8886        final  var  credentialsResponse  = checkImdsV2GetRequest (handler , SECURITY_CREDENTIALS_URI  + profileName , token );
89-         assertEquals (RestStatus .OK , credentialsResponse .status ());
9087
9188        assertThat (generatedCredentials , aMapWithSize (1 ));
92-         final  var  accessKey  = generatedCredentials .keySet ().iterator ().next ();
93-         final  var  sessionToken  = generatedCredentials .values ().iterator ().next ();
94- 
95-         final  var  responseMap  = XContentHelper .convertToMap (XContentType .JSON .xContent (), credentialsResponse .body ().streamInput (), false );
96-         assertEquals (Set .of ("AccessKeyId" , "Expiration" , "RoleArn" , "SecretAccessKey" , "Token" ), responseMap .keySet ());
97-         assertEquals (accessKey , responseMap .get ("AccessKeyId" ));
98-         assertEquals (sessionToken , responseMap .get ("Token" ));
89+         assertValidCredentialsResponse (
90+             credentialsResponse ,
91+             generatedCredentials .keySet ().iterator ().next (),
92+             generatedCredentials .values ().iterator ().next ()
93+         );
9994    }
10095
10196    public  void  testAvailabilityZone () {
@@ -113,7 +108,54 @@ public void testAvailabilityZone() {
113108        assertEquals (generatedAvailabilityZones , Set .of (availabilityZone ));
114109    }
115110
116-     private  record  TestHttpResponse (RestStatus  status , BytesReference  body ) {}
111+     public  void  testAlternativeCredentialsEndpoint () throws  IOException  {
112+         expectThrows (
113+             IllegalArgumentException .class ,
114+             new  Ec2ImdsServiceBuilder (Ec2ImdsVersion .V2 ).alternativeCredentialsEndpoints (Set .of ("/should-not-work" ))::buildHandler 
115+         );
116+ 
117+         final  var  alternativePaths  = randomList (1 , 5 , () -> "/"  + randomIdentifier ());
118+         final  Map <String , String > generatedCredentials  = new  HashMap <>();
119+ 
120+         final  var  handler  = new  Ec2ImdsServiceBuilder (Ec2ImdsVersion .V1 ).alternativeCredentialsEndpoints (alternativePaths )
121+             .newCredentialsConsumer (generatedCredentials ::put )
122+             .buildHandler ();
123+ 
124+         final  var  credentialsResponse  = handleRequest (handler , "GET" , randomFrom (alternativePaths ));
125+ 
126+         assertThat (generatedCredentials , aMapWithSize (1 ));
127+         assertValidCredentialsResponse (
128+             credentialsResponse ,
129+             generatedCredentials .keySet ().iterator ().next (),
130+             generatedCredentials .values ().iterator ().next ()
131+         );
132+     }
133+ 
134+     private  static  void  assertValidCredentialsResponse (TestHttpResponse  credentialsResponse , String  accessKey , String  sessionToken )
135+         throws  IOException  {
136+         assertEquals (RestStatus .OK , credentialsResponse .status ());
137+         final  var  responseMap  = XContentHelper .convertToMap (XContentType .JSON .xContent (), credentialsResponse .body ().streamInput (), false );
138+         assertEquals (Set .of ("AccessKeyId" , "Expiration" , "RoleArn" , "SecretAccessKey" , "Token" ), responseMap .keySet ());
139+         assertEquals (accessKey , responseMap .get ("AccessKeyId" ));
140+         assertEquals (sessionToken , responseMap .get ("Token" ));
141+     }
142+ 
143+     public  void  testInstanceIdentityDocument () {
144+         final  Set <String > generatedRegions  = new  HashSet <>();
145+         final  var  handler  = new  Ec2ImdsServiceBuilder (Ec2ImdsVersion .V1 ).instanceIdentityDocument ((builder , params ) -> {
146+             final  var  newRegion  = randomIdentifier ();
147+             generatedRegions .add (newRegion );
148+             return  builder .field ("region" , newRegion );
149+         }).buildHandler ();
150+ 
151+         final  var  instanceIdentityResponse  = handleRequest (handler , "GET" , "/latest/dynamic/instance-identity/document" );
152+         assertEquals (RestStatus .OK , instanceIdentityResponse .status ());
153+         final  var  instanceIdentityString  = instanceIdentityResponse .body ().utf8ToString ();
154+ 
155+         assertEquals (Strings .format ("{\" region\" :\" %s\" }" , generatedRegions .iterator ().next ()), instanceIdentityString );
156+     }
157+ 
158+     private  record  TestHttpResponse (RestStatus  status , Headers  responseHeaders , BytesReference  body ) {}
117159
118160    private  static  TestHttpResponse  checkImdsV2GetRequest (Ec2ImdsHttpHandler  handler , String  uri , String  token ) {
119161        final  var  unauthorizedResponse  = handleRequest (handler , "GET" , uri , null );
@@ -145,7 +187,11 @@ private static TestHttpResponse handleRequest(Ec2ImdsHttpHandler handler, String
145187            fail (e );
146188        }
147189        assertNotEquals (0 , httpExchange .getResponseCode ());
148-         return  new  TestHttpResponse (RestStatus .fromCode (httpExchange .getResponseCode ()), httpExchange .getResponseBodyContents ());
190+         return  new  TestHttpResponse (
191+             RestStatus .fromCode (httpExchange .getResponseCode ()),
192+             httpExchange .getResponseHeaders (),
193+             httpExchange .getResponseBodyContents ()
194+         );
149195    }
150196
151197    private  static  class  TestHttpExchange  extends  HttpExchange  {
0 commit comments