예제 #1
0
        private IAmazonS3 GetAmazonS3Client(AWSS3Labs.Web.Configuration.AmazonS3Config config)
        {
            var credentials = GetAwsCredentials(config);

            RegionEndpoint region = null;

            if (!string.IsNullOrEmpty(config.Region))
            {
                region = RegionEndpoint.GetBySystemName(config.Region);

                if (region.DisplayName == "Unknown")
                {
                    region = FallbackRegionFactory.GetRegionEndpoint();
                }
            }


            if (string.IsNullOrEmpty(_serviceUrl))
            {
                return(new AmazonS3Client(credentials, region));
            }
            else
            {
                var s3Config = new Amazon.S3.AmazonS3Config
                {
                    ServiceURL     = _serviceUrl,
                    RegionEndpoint = region
                };

                return(new AmazonS3Client(credentials, s3Config));
            }
        }
예제 #2
0
        /// <summary>
        /// Default constructor
        /// </summary>
        public AmazonSecurityTokenServiceConfig()
        {
            this.AuthenticationServiceName = "sts";
            var region = FallbackRegionFactory.GetRegionEndpoint(false);

            this.RegionEndpoint = region ?? RegionEndpoint.USEast1;
        }
예제 #3
0
        /// <summary>
        /// Default constructor
        /// </summary>
        public AmazonIdentityManagementServiceConfig()
        {
            this.AuthenticationServiceName = "iam";
            var region = FallbackRegionFactory.GetRegionEndpoint(false);

            this.RegionEndpoint = region ?? RegionEndpoint.USEast1;
        }
예제 #4
0
        public S3FileStorage(S3FileStorageOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            _bucket           = options.Bucket;
            _serializer       = options.Serializer ?? DefaultSerializer.Instance;
            _useChunkEncoding = options.UseChunkEncoding ?? true;
            _cannedAcl        = options.CannedACL;
            _logger           = options.LoggerFactory?.CreateLogger(typeof(S3FileStorage)) ?? NullLogger.Instance;

            var credentials = options.Credentials ?? FallbackCredentialsFactory.GetCredentials();

            if (String.IsNullOrEmpty(options.ServiceUrl))
            {
                var region = options.Region ?? FallbackRegionFactory.GetRegionEndpoint();
                _client = new AmazonS3Client(credentials, region);
            }
            else
            {
                _client = new AmazonS3Client(credentials, new AmazonS3Config {
                    RegionEndpoint    = RegionEndpoint.USEast1,
                    ServiceURL        = options.ServiceUrl,
                    ForcePathStyle    = true,
                    HttpClientFactory = options.HttpClientFactory
                });
            }
        }
        private static void ConfigureSTSRegionalEndpoint(IConfiguration config)
        {
            // Don't set unless the user has specified in the config that they want to use the regional endpoint.
            if (!bool.TryParse(config[ConfigConstants.USE_STS_REGIONAL_ENDPOINTS], out bool useRegionalSTSEndpoint))
            {
                return;
            }
            if (!useRegionalSTSEndpoint)
            {
                return;
            }

            // Don't overwrite an existing value if it has already been set.
            if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(ConfigConstants.STS_REGIONAL_ENDPOINTS_ENV_VARIABLE)))
            {
                return;
            }

            // Don't set if we can't automatically resolve the region (required for using regional endpoints).
            var autoDiscoveredRegion = FallbackRegionFactory.GetRegionEndpoint();

            if (autoDiscoveredRegion == null || autoDiscoveredRegion.DisplayName == "Unknown")
            {
                return;
            }

            // Set the AWS_STS_REGIONAL_ENDPOINTS environment variable to Regional.
            // This will mean that customers don't have to set the system-level variable.
            Environment.SetEnvironmentVariable(ConfigConstants.STS_REGIONAL_ENDPOINTS_ENV_VARIABLE, StsRegionalEndpointsValue.Regional.ToString());
        }
예제 #6
0
        private static (AWSCredentials Creds, RegionEndpoint Region) GetAWSConfig(string profileName = null)
        {
            if (!string.IsNullOrEmpty(profileName))
            {
                var            chain = new CredentialProfileStoreChain();
                AWSCredentials creds;
                RegionEndpoint region;
                if (chain.TryGetProfile(profileName, out var profile))
                {
                    region = profile.Region;
                }
                else
                {
                    throw new ArgumentException($"No region profile with the name '{profileName}' was found.");
                }

                if (chain.TryGetAWSCredentials(profileName, out var credentials))
                {
                    creds = credentials;
                }
                else
                {
                    throw new ArgumentException($"No credential profile with credentials found with the name '{profileName}'.");
                }
            }

            return(FallbackCredentialsFactory.GetCredentials(), FallbackRegionFactory.GetRegionEndpoint());
        }
 public AwsCognitoUser(string _usrId, string _clientId, string _poolId, RegionEndpoint _regionEndpoint = null)
 {
     userId         = _usrId;
     clientId       = _clientId;
     poolId         = _poolId;
     regionEndpoint = _regionEndpoint ?? FallbackRegionFactory.GetRegionEndpoint();
 }
        public RegionEndpoint DetermineAWSRegion()
        {
            // See if a region has been set but don't prompt if not set.
            var regionName = this.GetStringValueOrDefault(this.Region, CommonDefinedCommandOptions.ARGUMENT_AWS_REGION, false);

            if (!string.IsNullOrWhiteSpace(regionName))
            {
                return(RegionEndpoint.GetBySystemName(regionName));
            }

            // See if we can find a region using the region fallback logic.
            if (string.IsNullOrWhiteSpace(regionName))
            {
                var region = FallbackRegionFactory.GetRegionEndpoint(true);
                if (region != null)
                {
                    return(region);
                }
            }

            // If we still don't have a region prompt the user for a region.
            regionName = this.GetStringValueOrDefault(this.Region, CommonDefinedCommandOptions.ARGUMENT_AWS_REGION, true);
            if (!string.IsNullOrWhiteSpace(regionName))
            {
                return(RegionEndpoint.GetBySystemName(regionName));
            }

            throw new ToolsException("Can not determine AWS region. Either configure a default region or use the --region option.", ToolsException.CommonErrorCode.RegionNotConfigured);
        }
예제 #9
0
        /// <summary>
        /// Default constructor
        /// </summary>
        public AmazonSecurityTokenServiceConfig()
            : base(new Amazon.Runtime.Internal.DefaultConfigurationProvider(AmazonSecurityTokenServiceDefaultConfiguration.GetAllConfigurations()))
        {
            this.AuthenticationServiceName = "sts";
            var region = FallbackRegionFactory.GetRegionEndpoint(false);

            this.RegionEndpoint = region ?? RegionEndpoint.USEast1;
        }
예제 #10
0
        public AmazonSecurityTokenServiceConfig()
            : this()
        {
            this.set_AuthenticationServiceName("sts");
            RegionEndpoint regionEndpoint = FallbackRegionFactory.GetRegionEndpoint(false);

            this.set_RegionEndpoint(regionEndpoint ?? RegionEndpoint.USEast1);
        }
        private static RegionEndpoint GetRegionEndpoint(ProgramArgs args)
        {
            if (String.IsNullOrEmpty(args.RegionName))
            {
                return(FallbackRegionFactory.GetRegionEndpoint(includeInstanceMetadata: true));
            }

            return(RegionEndpoint.GetBySystemName(args.RegionName));
        }
예제 #12
0
 public SQSQueue(SQSQueueOptions <T> options) : base(options)
 {
     // TODO: Flow through the options like retries and the like.
     _client = new Lazy <AmazonSQSClient>(() => {
         var credentials = options.Credentials ?? FallbackCredentialsFactory.GetCredentials();
         var region      = options.Region ?? FallbackRegionFactory.GetRegionEndpoint() ?? RegionEndpoint.USEast1;
         return(new AmazonSQSClient(credentials, region));
     });
 }
예제 #13
0
        public void TestOtherProfile()
        {
            using (new FallbackFactoryTestFixture(ProfileText, "other"))
            {
                var creds = FallbackCredentialsFactory.GetCredentials();
                Assert.AreEqual("other_aws_access_key_id", creds.GetCredentials().AccessKey);

                var region = FallbackRegionFactory.GetRegionEndpoint(false);
                Assert.AreEqual(RegionEndpoint.USWest1, region);
            }
        }
예제 #14
0
        public void TestProcessCredentialProfile()
        {
            using (new FallbackFactoryTestFixture(ProfileText, "processCredential"))
            {
                var credentials = FallbackCredentialsFactory.GetCredentials().GetCredentials();
                Assert.AreEqual(ProcessAWSCredentialsTest.ActualAccessKey, credentials.AccessKey);
                Assert.AreEqual(ProcessAWSCredentialsTest.ActualSecretKey, credentials.SecretKey);

                var region = FallbackRegionFactory.GetRegionEndpoint(false);
                Assert.AreEqual(RegionEndpoint.USWest1, region);
            }
        }
        /*
         * Activation of this module requires an app.config file with a MySQL section, this applies to both  .NET Framework and .NET Core applications
         * first add a new section to config sections for MySQL
         * <section name="MySQL" type="MySql.Data.MySqlClient.MySqlConfiguration,MySql.Data"/>
         * then add a MySQL section that looks like this
         *    <MySQL>
         *      <Replication>
         *        <ServerGroups>
         *        </ServerGroups>
         *      </Replication>
         *      <CommandInterceptors/>
         *      <ExceptionInterceptors/>
         *      <AuthenticationPlugins>
         *        <add name="mysql_clear_password" type="ReportingXpress.Common.AWS.RDS.MySQLRoleAuthenticationPlugin, ReportingXpress.Common"></add>
         *      </AuthenticationPlugins>
         *    </MySQL>
         */


        ///// <summary>
        ///// generate a new RDS authentication ticket
        ///// </summary>
        ///// <param name="serverName"></param>
        ///// <param name="portNumber"></param>
        ///// <param name="userId"></param>
        ///// <returns></returns>
        protected override ExpiringRDSTicket GetRDSAuthenticationTicket(string serverName, int portNumber, string userId)
        {
            serverName = VerifyRdsAddress(serverName);
            ExpiringRDSTicket returnValue     = new ExpiringRDSTicket();
            RegionEndpoint    regionEndPoint  = FallbackRegionFactory.GetRegionEndpoint();
            AWSCredentials    roleCredentials = new InstanceProfileAWSCredentials();

            returnValue.AuthorizationTicket = RDSAuthTokenGenerator.GenerateAuthToken(roleCredentials, regionEndPoint, serverName, portNumber, userId);
            //tickets expire in 15 minutes, but Windows time drift is up to a minute in this case, so give it a buffer of 3 minutes
            returnValue.ExpiresUtc = DateTime.UtcNow.AddMinutes(14);
            return(returnValue);
        }
예제 #16
0
        public void TestAwsConfigsAwsProfileNameProfile()
        {
            using (new FallbackFactoryTestFixture(ProfileText, "awsConfigsAwsProfileName", null, true))
            {
                var creds = FallbackCredentialsFactory.GetCredentials();
                Assert.AreEqual("awsprofilename_aws_access_key_id", creds.GetCredentials().AccessKey);
                Assert.AreEqual("awsprofilename_aws_secret_access_key", creds.GetCredentials().SecretKey);

                var region = FallbackRegionFactory.GetRegionEndpoint(false);
                Assert.AreEqual(RegionEndpoint.EUNorth1, region);
            }
        }
예제 #17
0
        public S3FileStorage(S3FileStorageOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            _credentials = options.Credentials ?? FallbackCredentialsFactory.GetCredentials();
            _region      = options.Region ?? FallbackRegionFactory.GetRegionEndpoint();
            _bucket      = options.Bucket;
            _serializer  = options.Serializer ?? DefaultSerializer.Instance;
        }
예제 #18
0
 public CloudWatchMetricsClient(CloudWatchMetricsClientOptions options) : base(options)
 {
     _options    = options;
     _namespace  = options.Namespace;
     _dimensions = options.Dimensions;
     _client     = new Lazy <AmazonCloudWatchClient>(() => new AmazonCloudWatchClient(
                                                         options.Credentials ?? FallbackCredentialsFactory.GetCredentials(),
                                                         new AmazonCloudWatchConfig {
         LogResponse    = false,
         DisableLogging = true,
         RegionEndpoint = options.Region ?? FallbackRegionFactory.GetRegionEndpoint()
     }));
 }
예제 #19
0
        public void TestDefaultProfile()
        {
            using (new FallbackFactoryTestFixture(ProfileText, null))
            {
                var creds = FallbackCredentialsFactory.GetCredentials();
                Assert.AreEqual("default_aws_access_key_id", creds.GetCredentials().AccessKey);

                var region = FallbackRegionFactory.GetRegionEndpoint(false);
                Assert.AreEqual(RegionEndpoint.USWest2, region);

                var enabled = FallbackEndpointDiscoveryEnabledFactory.GetEnabled();
                Assert.IsFalse(enabled.HasValue);
            }
        }
예제 #20
0
        /// <inheritdoc/>
        public virtual TAWSClient GetPrimaryRegionClient()
        {
            // Get Client Credentials and Primary Region
            var(credentials, regionEndpoint)
                = AWSUtilities.GetAWSCredentialsRegion(_context);

            // If RegionEndpoint is null
            if (regionEndpoint is null)
            {
                regionEndpoint = FallbackRegionFactory.GetRegionEndpoint();
            }

            // Setup Client with Primary Region
            // Check Primary Region is available
            return(GetOrCreateRegionClient(credentials, regionEndpoint, true, true));
        }
예제 #21
0
        public void TestOtherProfile()
        {
            using (new FallbackFactoryTestFixture(ProfileText, "other"))
            {
                var creds = FallbackCredentialsFactory.GetCredentials();
                Assert.AreEqual("other_aws_access_key_id", creds.GetCredentials().AccessKey);

                var region = FallbackRegionFactory.GetRegionEndpoint(false);
                Assert.AreEqual(RegionEndpoint.USWest1, region);

                var enabled = FallbackEndpointDiscoveryEnabledFactory.GetEnabled();
                Assert.IsTrue(enabled.HasValue);
                Assert.IsFalse(enabled.Value);

                enabled = FallbackInternalConfigurationFactory.EndpointDiscoveryEnabled;
                Assert.IsTrue(enabled.HasValue);
                Assert.IsFalse(enabled.Value);
            }
        }
예제 #22
0
        public SQSQueue(SQSQueueOptions <T> options) : base(options)
        {
            // TODO: Flow through the options like retries and the like.
            _client = new Lazy <AmazonSQSClient>(() => {
                var credentials = options.Credentials ?? FallbackCredentialsFactory.GetCredentials();

                if (String.IsNullOrEmpty(options.ServiceUrl))
                {
                    var region = options.Region ?? FallbackRegionFactory.GetRegionEndpoint();
                    return(new AmazonSQSClient(credentials, region));
                }

                return(new AmazonSQSClient(
                           credentials,
                           new AmazonSQSConfig {
                    RegionEndpoint = RegionEndpoint.USEast1,
                    ServiceURL = options.ServiceUrl
                }));
            });
        }
        private async Task <TokenValidationParameters> CreateTokenValidationParameters(ILambdaContext context)
        {
            context.Logger.LogLine("Loading user pool configuration from SSM Parameter Store.");
            var configuration = new ConfigurationBuilder()
                                .AddSystemsManager("/ImageRecognition")
                                .Build();

            var region = configuration["AWS:Region"];

            if (string.IsNullOrEmpty(region))
            {
                region = FallbackRegionFactory.GetRegionEndpoint().SystemName;
            }
            var userPoolId       = configuration["AWS:UserPoolId"];
            var userPoolClientId = configuration["AWS:UserPoolClientId"];

            context.Logger.LogLine("Configuring JWT Validation parameters");

            var openIdConfigurationUrl =
                $"https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/openid-configuration";
            var configurationManager = new ConfigurationManager <OpenIdConnectConfiguration>(openIdConfigurationUrl,
                                                                                             new OpenIdConnectConfigurationRetriever());

            context.Logger.LogLine($"Loading open id configuration from {openIdConfigurationUrl}");
            var openIdConfig = await configurationManager.GetConfigurationAsync();


            var validIssuer = $"https://cognito-idp.{region}.amazonaws.com/{userPoolId}";

            context.Logger.LogLine($"Valid Issuer: {validIssuer}");
            context.Logger.LogLine($"Valid Audiences: {userPoolClientId}");

            return(new TokenValidationParameters
            {
                ValidIssuer = validIssuer,
                ValidAudiences = new[] { userPoolClientId },
                IssuerSigningKeys = openIdConfig.SigningKeys
            });
        }
예제 #24
0
        /// <summary>
        /// Try to login to aws using cognito
        /// If user  has not changed the password then he will be redirected to password change
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="newPassword"></param>
        /// <returns></returns>
        private async Task <string> LoginUserAsync(string username, string password, string newPassword = null)
        {
            var a = FallbackRegionFactory.GetRegionEndpoint();

            CognitoInit awsInit = new CognitoInit();

            CognitoUserPool        userPool    = new CognitoUserPool(awsInit.PoolId, awsInit.ClientId, awsInit.Client);
            CognitoUser            user        = new CognitoUser(username, awsInit.ClientId, userPool, awsInit.Client);
            InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
            {
                Password = password
            };

            try
            {
                AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);

                if (authResponse.ChallengeName != null && authResponse.ChallengeName.ToString().Equals(ChallengeNameType.NEW_PASSWORD_REQUIRED, StringComparison.OrdinalIgnoreCase))
                {
                    //This case is when a user is created by admin form portal
                    if (String.IsNullOrWhiteSpace(newPassword))
                    {
                        authResponse = await user.RespondToNewPasswordRequiredAsync(new RespondToNewPasswordRequiredRequest { SessionID = authResponse.SessionID, NewPassword = "******" });
                    }
                    return(ChallengeNameType.NEW_PASSWORD_REQUIRED);
                }
                if (String.IsNullOrWhiteSpace(authResponse.ChallengeName))
                {
                    // GetCredentials(authResponse.AuthenticationResult);
                    return(authResponse.AuthenticationResult.IdToken);
                }
            }
            catch (Exception e)
            {
                return(e.Message);
            }
            return("Login didn't succeded!");
        }
예제 #25
0
        public void TestDefaultProfile()
        {
            using (new FallbackFactoryTestFixture(ProfileText, null))
            {
                var creds = FallbackCredentialsFactory.GetCredentials();
                Assert.AreEqual("default_aws_access_key_id", creds.GetCredentials().AccessKey);

                var region = FallbackRegionFactory.GetRegionEndpoint(false);
                Assert.AreEqual(RegionEndpoint.USWest2, region);

                var enabled = FallbackEndpointDiscoveryEnabledFactory.GetEnabled();
                Assert.IsFalse(enabled.HasValue);

                enabled = FallbackInternalConfigurationFactory.EndpointDiscoveryEnabled;
                Assert.IsFalse(enabled.HasValue);

                var retryMode = FallbackInternalConfigurationFactory.RetryMode;
                Assert.IsFalse(retryMode.HasValue);

                var maxAttempts = FallbackInternalConfigurationFactory.MaxAttempts;
                Assert.IsFalse(maxAttempts.HasValue);
            }
        }
예제 #26
0
        public string ResolveAWSRegion(string region, string lastRegionUsed)
        {
            if (!string.IsNullOrEmpty(region))
            {
                _toolInteractiveService.WriteLine($"Configuring AWS region with specified value {region}.");
                return(region);
            }

            if (!string.IsNullOrEmpty(lastRegionUsed))
            {
                _toolInteractiveService.WriteLine($"Configuring AWS region with previous configured value {lastRegionUsed}.");
                return(lastRegionUsed);
            }

            var fallbackRegion = FallbackRegionFactory.GetRegionEndpoint()?.SystemName;

            if (!string.IsNullOrEmpty(fallbackRegion))
            {
                _toolInteractiveService.WriteLine($"Configuring AWS region using AWS SDK region search to {fallbackRegion}.");
                return(fallbackRegion);
            }

            var availableRegions = new List <string>();

            foreach (var value in Amazon.RegionEndpoint.EnumerableAllRegions.OrderBy(x => x.SystemName))
            {
                availableRegions.Add($"{value.SystemName} ({value.DisplayName})");
            }

            var consoleUtilities = new ConsoleUtilities(_toolInteractiveService);
            var selectedRegion   = consoleUtilities.AskUserToChoose(availableRegions, "Select AWS Region", null);

            // Strip display name
            selectedRegion = selectedRegion.Substring(0, selectedRegion.IndexOf('(') - 1).Trim();

            return(selectedRegion);
        }
예제 #27
0
        /// <summary>
        /// Create a CloudConfig object based on command line args.
        /// </summary>
        /// <param name="args">The command-line args.</param>
        /// <returns>The CloudConfig.</returns>
        /// <exception cref="ArgumentException">If a command-line arg is not given in a valid format.</exception>
        internal static CloudConfig CreateCloudConfig(string[] args)
        {
            string allArgs = string.Join(string.Empty, args);

            if (allArgs == "-i")
            {
                Console.WriteLine("Running in interactive mode...");
                var            chain = new CredentialProfileStoreChain();
                AWSCredentials awsCredentials;
                if (!chain.TryGetAWSCredentials("chessdb-staging", out awsCredentials))
                {
                    throw new ArgumentException($"CloudConfig cannot be initialized. Interactive mode was specified but the " +
                                                "'chessdb-staging' AWS CLI profile cannot be found on this machine.");
                }

                return(new CloudConfig(RegionEndpoint.USEast2, awsCredentials));
            }
            else
            {
                var creds  = FallbackCredentialsFactory.GetCredentials();
                var region = FallbackRegionFactory.GetRegionEndpoint();
                return(new CloudConfig(region, creds));
            }
        }
예제 #28
0
        // This method gets called by the runtime. Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure <AppOptions>(Configuration.GetSection("AppOptions"));

            services.AddAWSService <IAmazonDynamoDB>();
            services.AddAWSService <IAmazonS3>();

            IdentityModelEventSource.ShowPII = true;

            services.AddResponseCompression(options =>
            {
                options.Providers.Add <BrotliCompressionProvider>();
                options.Providers.Add <GzipCompressionProvider>();
                options.EnableForHttps = true;
                options.MimeTypes      = new[]
                { "application/json", "text/tab-separated-values", "application/javascript", "text/csv", "text" };
            });

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                var region = Configuration["AWS:Region"];
                if (string.IsNullOrEmpty(region))
                {
                    region = FallbackRegionFactory.GetRegionEndpoint().SystemName;
                }

                var audience  = Configuration["AWS:UserPoolClientId"];
                var authority = $"https://cognito-idp.{region}.amazonaws.com/" + Configuration["AWS:UserPoolId"];

                Console.WriteLine($"Configure JWT option, Audience: {audience}, Authority: {authority}");

                options.Audience  = audience;
                options.Authority = authority;
            });

            services.AddAuthorization(options =>
            {
                options.AddPolicy("Admin", policy =>
                                  policy.RequireClaim("cognito:groups", "Admin"));
            });

            services.AddControllers();

            // Register the Swagger services
            services.AddSwaggerDocument(document =>
            {
                // Add an authenticate button to Swagger for JWT tokens
                document.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT"));
                document.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT", new OpenApiSecurityScheme
                {
                    Type        = OpenApiSecuritySchemeType.ApiKey,
                    Name        = "Authorization",
                    In          = OpenApiSecurityApiKeyLocation.Header,
                    Description =
                        "Type into the textbox: Bearer {your JWT token}. You can get a JWT token from /Authorization/Authenticate."
                }));

                // Post process the generated document
                document.PostProcess = d =>
                {
                    d.Info.Title       = "ImageRecognition API";
                    d.Info.Description = "API to manage albums and photos.";
                    d.Info.Version     = "1.0.0";
                };
            });
        }
 /// <summary>
 /// Initializes a new instance of the AwsHttpConnection class with credentials from the Instance Profile service
 /// </summary>
 public AwsHttpConnection() : this(
         FallbackCredentialsFactory.GetCredentials(),
         FallbackRegionFactory.GetRegionEndpoint() ?? throw new Exception("Unable to determine the correct AWS region. Please try providing it explicitly."))
 {
 }
        private static ClientConfig CreateAWSClientConfig <TAWSClient>(IPlugInContext context, RegionEndpoint region) where TAWSClient : AmazonServiceClient
        {
            // The previous mechanism for locating the ClientConfig implementation was a switch block
            // containing all of the known cases that the Amazon.KinesisTap.AWS library referenced.
            // However, this meant that any other SDK clients that were instantiated by other libraries
            // were not able to use this code (e.g. if a plugin used Secrets Manager to store an API key).
            // We need to do this more dynamically if we want third party plugins to be able to use this.

            // Get the type of the AWS client being created based on the type parameter,
            // and get the corresponding ClientConfig type from the type cache. If it doesn't
            // exist in the cache, do the discovery. Using a cache eliminates redundant loading of
            // assemblies when multiple instances of the same client are created. Since each client
            // may be configured differently, we can't cache the clients (or the configs) themselves,
            // but we can cache the ClientConfig types, since they are readonly objects.
            var configType = awsClientConfigTypeCache.GetOrAdd(typeof(TAWSClient), (type) =>
            {
                // Identify the "ClientConfig" for the requested SDK client. We can use the SDK's class naming
                // convention to identify this type, replacing the word "Client" with "Config" in the client's
                // full type name. For example:
                // Amazon.SecretsManager.AmazonSecretsManagerClient
                // becomes
                // Amazon.SecretsManager.AmazonSecretsManagerConfig
                var configTypeName = type.FullName.Substring(0, type.FullName.IndexOf("Client")) + "Config";

                // Identify the assembly's name. The only way we can do this in this version of .NET is to
                // use the AssemblyQualifiedName and strip off the type's name from the front. For example:
                // Amazon.SecretsManager.AmazonSecretsManagerClient, AWSSDK.SecretsManager, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604
                // becomes
                // AWSSDK.SecretsManager, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604
                var assemblyName = type.AssemblyQualifiedName.Substring(type.FullName.Length + 1).Trim();

                // Load the Assembly into an object.
                var assembly = Assembly.Load(new AssemblyName(assemblyName));

                // Get the ClientConfig type from the Assembly object.
                return(assembly.GetType(configTypeName));
            });

            // Use Activator to initialize a new instance of the client-specific ClientConfig.
            var clientConfig = (ClientConfig)Activator.CreateInstance(configType);

            // Set the region endpoint property. If the region parameter is null, discover it using
            // the FallbackRegionFactory. This method will return null if it doesn't find anything,
            // so we'll throw an Exception if that's the case (since we won't be able to send any data).
            clientConfig.RegionEndpoint = region ?? FallbackRegionFactory.GetRegionEndpoint();
            if (clientConfig.RegionEndpoint == null)
            {
                context.Logger?.LogError("The 'Region' property was not specified in the configuration, and the agent was unable to discover it automatically.");
                throw new Exception("The 'Region' property was not specified in the configuration, and the agent was unable to discover it automatically.");
            }

            // Check if the configuration contains the ProxyHost property.
            if (!string.IsNullOrWhiteSpace(context.Configuration[ConfigConstants.PROXY_HOST]))
            {
                // Configure the client to use a proxy.
                clientConfig.ProxyHost = context.Configuration[ConfigConstants.PROXY_HOST];

                // If the customer supplied a port number, use that, otherwise use a default of 80.
                clientConfig.ProxyPort = ushort.TryParse(context.Configuration[ConfigConstants.PROXY_PORT], out ushort proxyPort) ? proxyPort : 80;

                context.Logger?.LogDebug("Using proxy host '{0}' with port '{1}'", clientConfig.ProxyHost, clientConfig.ProxyPort);
            }

            // If the configuration contains the ServiceURL property, configure the client to use
            // the supplied service endpoint (this is used for VPC endpoints).
            if (!string.IsNullOrWhiteSpace(context.Configuration[ConfigConstants.SERVICE_URL]))
            {
                // When using alternate service URL's, the AuthenticationRegion property must be set.
                // We'll use the existing region's value for this.
                clientConfig.AuthenticationRegion = clientConfig.RegionEndpoint.SystemName;

                // Try to parse the value into a Uri object. If it doesn't parse correctly, throw an Exception.
                var urlString = context.Configuration[ConfigConstants.SERVICE_URL];
                if (!Uri.TryCreate(urlString, UriKind.Absolute, out Uri uri))
                {
                    var error = string.Format("The 'ServiceURL' property value '{0}' is not in the correct format for a URL.", urlString);
                    context.Logger?.LogError(error);
                    throw new Exception(error);
                }

                clientConfig.ServiceURL = urlString;
                context.Logger?.LogDebug("Using alternate service endpoint '{0}' with AuthenticationRegion '{1}'", clientConfig.ServiceURL, clientConfig.AuthenticationRegion);
            }

            return(clientConfig);
        }