public void TestAccessingEC2InstanceMetadataProperties()
        {
            using (var servlet = new EC2InstanceMetadataServlet())
            {
                var allMembers = typeof(EC2InstanceMetadata).GetMembers(BindingFlags.Public | BindingFlags.Static);
                foreach (var member in allMembers)
                {
                    servlet.AddMetadataGenericResponse(string.Empty, string.Empty, HttpStatusCode.NotFound);

                    var fi = member as FieldInfo;
                    var pi = member as PropertyInfo;

                    object value;

                    // make and exception for IsIMDSEnabled property or the IMDS endpoint and URI helpers
                    if (pi != null && !pi.Name.Equals("IsIMDSEnabled") && !pi.Name.Equals("ServiceEndpoint") && !pi.Name.StartsWith("EC2"))
                    {
                        value = pi.GetValue(null);
                        // all properties should return null on non-EC2 instances
                        Assert.IsNull(value, "Property {0} should be null", pi.Name);
                    }
                    else if (fi != null)
                    {
                        value = fi.GetValue(null);
                        // all fields should return non-null on non-EC2 instances
                        Assert.IsNotNull(value, "Field {0} should not be null", fi.Name);
                    }
                }
            }
        }
        public void TestEC2InstanceMetadataInsecureCredentialsFallbackToken()
        {
            var failFastStatusCodes = new HttpStatusCode[]
            {
                HttpStatusCode.NotFound,
                HttpStatusCode.Forbidden,
                HttpStatusCode.MethodNotAllowed
            };

            foreach (var failFastStatusCode in failFastStatusCodes)
            {
                var token = string.Empty;

                using (var servlet = new EC2InstanceMetadataServlet())
                {
                    servlet.AddTokenFetchResponse(token, failFastStatusCode);
                    servlet.AddMetadataGenericResponse("Item1", token, HttpStatusCode.OK);
                    servlet.AddMetadataGetSecurityCredentialsResponse(_fakeValidIamSecurityCredentialMetadata, token);

                    var metadata = EC2InstanceMetadata.IAMSecurityCredentials;

                    Assert.IsNotNull(metadata);
                    Assert.AreEqual(1, metadata.Count);
                    Assert.IsTrue(metadata.ContainsKey("Item1"));
                    var creds = metadata["Item1"];
                    Assert.AreEqual("value1", creds.AccessKeyId);
                    Assert.AreEqual("value2", creds.SecretAccessKey);
                    Assert.AreEqual("value3", creds.Token);
                }
            }
        }
        public void TestEC2InstanceMetadataInsecureCredentialsFallbackNotFound()
        {
            var token = string.Empty;

            using (var servlet = new EC2InstanceMetadataServlet())
            {
                servlet.AddTokenFetchResponse(token, HttpStatusCode.NotFound);
                servlet.AddMetadataGenericResponse("Item1", token, HttpStatusCode.NotFound);

                var metadata = EC2InstanceMetadata.IAMSecurityCredentials;

                Assert.IsNull(metadata);
            }
        }
 public void TestEC2InstanceMetadataAPIToken400BadRequest()
 {
     using (var servlet = new EC2InstanceMetadataServlet())
     {
         //DEFAULT_RETRIES of 3 for the metadata call for getting a token when BadRequest is used.
         servlet.AddTokenFetchResponse(string.Empty, HttpStatusCode.BadRequest);
         servlet.AddTokenFetchResponse(string.Empty, HttpStatusCode.BadRequest);
         servlet.AddTokenFetchResponse(string.Empty, HttpStatusCode.BadRequest);
         try
         {
             var metadata = EC2InstanceMetadata.IAMSecurityCredentials;
         }
         catch (WebException wex)
         {
             var response = wex.Response as HttpWebResponse;
             Assert.IsNotNull(response);
             Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
             throw;
         }
     }
 }
        public void TestEC2InstanceMetadata401Unauthorized()
        {
            var token = "ValidToken";

            using (var servlet = new EC2InstanceMetadataServlet())
            {
                servlet.AddTokenFetchResponse(token);
                servlet.AddMetadataGetSecurityCredentialsResponse(new IAMSecurityCredentialMetadata(), token, HttpStatusCode.Unauthorized);
                try
                {
                    var metadata = EC2InstanceMetadata.IAMSecurityCredentials;
                }
                catch (WebException wex)
                {
                    var response = wex.Response as HttpWebResponse;
                    Assert.IsNotNull(response);
                    Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                    throw;
                }
            }
        }
        public void TestEC2InstanceMetadataInsecureCredentialsRetry()
        {
            var token = string.Empty;

            using (var servlet = new EC2InstanceMetadataServlet())
            {
                servlet.AddTokenFetchResponse(token, HttpStatusCode.NotFound);
                servlet.AddMetadataGenericResponse("Item1", token, HttpStatusCode.ServiceUnavailable);
                servlet.AddMetadataGenericResponse("Item1", token, HttpStatusCode.OK);
                servlet.AddMetadataGetSecurityCredentialsResponse(_fakeValidIamSecurityCredentialMetadata, token);

                var metadata = EC2InstanceMetadata.IAMSecurityCredentials;

                Assert.IsNotNull(metadata);
                Assert.AreEqual(1, metadata.Count);
                Assert.IsTrue(metadata.ContainsKey("Item1"));
                var creds = metadata["Item1"];
                Assert.AreEqual("value1", creds.AccessKeyId);
                Assert.AreEqual("value2", creds.SecretAccessKey);
                Assert.AreEqual("value3", creds.Token);
            }
        }
        public void StaticStabilityWhenIMDSExperiencesAnOutageScenarioTest()
        {
            var currentTime = new DateTime(1997, 8, 29, 16, 20, 0);

            var token = "ValidToken";

            var profileMetadata = new IAMInstanceProfileMetadata
            {
                InstanceProfileArn = "profile_arn",
                InstanceProfileId  = "profile_id"
            };

            var validCredentialMetadata = new IAMSecurityCredentialMetadata
            {
                AccessKeyId     = "value1",
                SecretAccessKey = "secret1",
                Expiration      = currentTime.AddMinutes(75)
            };

            var expiredCredentialMetadata = new IAMSecurityCredentialMetadata
            {
                AccessKeyId     = "expired",
                SecretAccessKey = "expired",
                Expiration      = currentTime.Subtract(TimeSpan.FromMinutes(5))
            };

            var validCredentialMetadata2 = new IAMSecurityCredentialMetadata
            {
                AccessKeyId     = "value2",
                SecretAccessKey = "secret2",
                Expiration      = currentTime.AddHours(6)
            };

            using (new AWSConfigsDateFaker(() => currentTime.ToUniversalTime()))
                using (var imdsServlet = new EC2InstanceMetadataServlet())
                {
                    var instanceProfileAwsCredentials =
                        new InstanceProfileAWSCredentials(
                            // use a dummy role so InstanceProfileAWSCredentials doesn't try and call imds server to resolve role
                            role: "dummyRole",
                            proxy: null);

                    // EXPIRED TEST 1 & 2 - can use IMDS provider if first IMDS call returns expired creds
                    // Given IMDS service immediately returns an expired credential
                    imdsServlet.AddTokenFetchResponse(token);
                    imdsServlet.AddMetadataSecurityInfoResponse(profileMetadata, token);
                    imdsServlet.AddMetadataGetSecurityCredentialsResponse(expiredCredentialMetadata, token);
                    // When InstanceProfileAWSCredentials returns a Credential
                    var expiredInitialCreds = instanceProfileAwsCredentials.GetCredentials();
                    // Then the Credential is valid and be used to call a Service
                    AssertAreEqual(expiredCredentialMetadata, expiredInitialCreds);

                    // REFRESH TEST 2/LOGGING TEST - Can send a request after receiving a 500
                    // Given 20 minutes has passed (expired credential cache time is up to 15 minutes)
                    currentTime += TimeSpan.FromMinutes(20);
                    // Given the IMDS service is running normally
                    imdsServlet.AddTokenFetchResponse(token);
                    imdsServlet.AddMetadataSecurityInfoResponse(profileMetadata, token);
                    imdsServlet.AddMetadataGetSecurityCredentialsResponse(validCredentialMetadata, token);
                    // When InstanceProfileAWSCredentials returns a Credential
                    var initialCreds = instanceProfileAwsCredentials.GetCredentials();
                    // Then the Credential is valid and be used to call a Service
                    AssertAreEqual(validCredentialMetadata, initialCreds);

                    // Given 1 hour has passed (default credential cache time is 1 hour)
                    currentTime += TimeSpan.FromMinutes(65);
                    // And the IMDS service returns 5xx error
                    imdsServlet.AddTokenFetchResponse(token);
                    imdsServlet.AddMetadataSecurityInfoResponse(profileMetadata, token);
                    imdsServlet.AddMetadataGenericResponse(contents: "", token: token, HttpStatusCode.ServiceUnavailable);

                    // When InstanceProfileAWSCredentials returns the previously valid Credential
                    var badCreds = instanceProfileAwsCredentials.GetCredentials();
                    // Then the Credential is the previously valid Credential and can be used to call a Service
                    AssertAreEqual(validCredentialMetadata, badCreds);
                    // And there is a log message that an expired credential is being used

                    // Given 90 minutes has passed (credential cache time is up to 60 minutes)
                    currentTime += TimeSpan.FromMinutes(90);
                    // And the IMDS service is running normally (again)
                    imdsServlet.AddTokenFetchResponse(token);
                    imdsServlet.AddMetadataSecurityInfoResponse(profileMetadata, token);
                    imdsServlet.AddMetadataGetSecurityCredentialsResponse(validCredentialMetadata2, token);
                    // When InstanceProfileAWSCredentials returns a Credential
                    var goodCreds2 = instanceProfileAwsCredentials.GetCredentials();
                    // Then the Credential is valid and be used to call a Service
                    AssertAreEqual(validCredentialMetadata2, goodCreds2);

                    // EXPIRED TEST 3 - Can perform 3 successive requests with expired credentials. IMDS must only be called once.

                    // Given IMDS service immediately returns an expired credential
                    imdsServlet.AddTokenFetchResponse(token);
                    imdsServlet.AddMetadataSecurityInfoResponse(profileMetadata, token);
                    imdsServlet.AddMetadataGetSecurityCredentialsResponse(expiredCredentialMetadata, token);
                    // When InstanceProfileAWSCredentials returns a Credential
                    var creds1 = instanceProfileAwsCredentials.GetCredentials();
                    // And InstanceProfileAWSCredentials returns a Credential
                    var creds2 = instanceProfileAwsCredentials.GetCredentials();
                    // And InstanceProfileAWSCredentials returns a Credential
                    var creds3 = instanceProfileAwsCredentials.GetCredentials();
                    // Then IMDS is only called once
                    // (imdsServlet would have thrown an exception if an additional call was made)
                }
        }