Skip to content
14 changes: 1 addition & 13 deletions extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* permissions and limitations under the License.
*/
using Amazon.Runtime;

using AWSSDK.Extensions.NETCore.Setup;
using Microsoft.Extensions.Logging;

namespace Amazon.Extensions.NETCore.Setup
Expand Down Expand Up @@ -92,18 +92,6 @@ internal set
/// </summary>
public LoggingSetting Logging { get; set; }

/// <summary>
/// Create a service client for the specified service interface using the options set in this instance.
/// For example if T is set to IAmazonS3 then the AmazonS3ServiceClient which implements IAmazonS3 is created
/// and returned.
/// </summary>
/// <typeparam name="T">The service interface that a service client will be created for.</typeparam>
/// <returns>The service client that implements the service interface.</returns>
public T CreateServiceClient<T>() where T : class, IAmazonService
{
return new ClientFactory<T>(this).CreateServiceClient((ILogger)null, this) as T;
}

/// <summary>
/// Container for logging settings of the SDK
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Amazon.Extensions.NETCore.Setup;
using Amazon.Runtime;

namespace AWSSDK.Extensions.NETCore.Setup
{
/// <summary>
///
/// </summary>
public static class AWSOptionsExtensions
{
/// <summary>
/// Create a service client for the specified service interface using the options set in this instance.
/// For example if T is set to IAmazonS3 then the AmazonS3ServiceClient which implements IAmazonS3 is created
/// and returned.
/// </summary>
/// <typeparam name="T">The service interface that a service client will be created for.</typeparam>
/// <returns>The service client that implements the service interface.</returns>
public static T CreateServiceClient<T>(this AWSOptions options)
where T : class, IAmazonService
{
var credentials = new DefaultAWSCredentials(options, null);
var clientFactory = new ClientFactory<T>(options, credentials, null);

return clientFactory.CreateServiceClient() as T;
}
}
}
106 changes: 19 additions & 87 deletions extensions/src/AWSSDK.Extensions.NETCore.Setup/ClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
using Amazon.Runtime.Credentials.Internal;
using AWSSDK.Extensions.NETCore.Setup;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand All @@ -36,68 +37,45 @@ internal class ClientFactory<T>
private static readonly Type[] EMPTY_TYPES = Array.Empty<Type>();
private static readonly object[] EMPTY_PARAMETERS = Array.Empty<object>();

private AWSOptions _awsOptions;
private readonly AWSOptions _options;
private readonly AWSCredentials _credentials;
private readonly ILogger _logger;

/// <summary>
/// Constructs an instance of the ClientFactory
/// </summary>
/// <param name="awsOptions">The AWS options used for creating service clients.</param>
internal ClientFactory(AWSOptions awsOptions)
{
_awsOptions = awsOptions;
}

/// <summary>
/// Creates the AWS service client that implements the service client interface. The AWSOptions object
/// will be searched for in the IServiceProvider.
/// </summary>
/// <param name="provider">The dependency injection provider.</param>
/// <returns>The AWS service client</returns>
internal object CreateServiceClient(IServiceProvider provider)
/// <param name="credentials"></param>
/// <param name="logger"></param>
internal ClientFactory(AWSOptions awsOptions, AWSCredentials credentials, ILogger logger)
{
var loggerFactory = provider.GetService<Microsoft.Extensions.Logging.ILoggerFactory>();
var logger = loggerFactory?.CreateLogger("AWSSDK");

var options = _awsOptions ?? provider.GetService<AWSOptions>();
if(options == null)
{
var configuration = provider.GetService<IConfiguration>();
if(configuration != null)
{
options = configuration.GetAWSOptions();
if (options != null)
logger?.LogInformation("Found AWS options in IConfiguration");
}
}

return CreateServiceClient(logger, options);
_options = awsOptions ?? throw new ArgumentNullException(nameof(awsOptions));
_credentials = credentials ?? throw new ArgumentNullException(nameof(credentials));
_logger = logger;
}

/// <summary>
/// Creates the AWS service client that implements the service client interface. The AWSOptions object
/// will be searched for in the IServiceProvider.
/// Creates the AWS service client that implements the service client interface.
/// </summary>
/// <param name="logger">Logger instance for writing diagnostic logs.</param>
/// <param name="options">The AWS options used for creating the service client.</param>
/// <returns>The AWS service client</returns>
internal IAmazonService CreateServiceClient(ILogger logger, AWSOptions options)
internal IAmazonService CreateServiceClient()
{
PerformGlobalConfig(logger, options);
var credentials = CreateCredentials(logger, options);
PerformGlobalConfig(_logger, _options);
var credentials = _credentials;

if (!string.IsNullOrEmpty(options?.SessionRoleArn))
if (!string.IsNullOrEmpty(_options?.SessionRoleArn))
{
if (string.IsNullOrEmpty(options?.ExternalId))
if (string.IsNullOrEmpty(_options?.ExternalId))
{
credentials = new AssumeRoleAWSCredentials(credentials, options.SessionRoleArn, options.SessionName);
credentials = new AssumeRoleAWSCredentials(credentials, _options.SessionRoleArn, _options.SessionName);
}
else
{
credentials = new AssumeRoleAWSCredentials(credentials, options.SessionRoleArn, options.SessionName, new AssumeRoleAWSCredentialsOptions() { ExternalId = options.ExternalId });
credentials = new AssumeRoleAWSCredentials(credentials, _options.SessionRoleArn, _options.SessionName, new AssumeRoleAWSCredentialsOptions() { ExternalId = _options.ExternalId });
}
}

var config = CreateConfig(options);
var config = CreateConfig(_options);
var client = CreateClient(credentials, config);
return client as IAmazonService;
}
Expand Down Expand Up @@ -165,52 +143,6 @@ private static AmazonServiceClient CreateClient(AWSCredentials credentials, Clie
#endif
}

/// <summary>
/// Creates the AWSCredentials using either the profile indicated from the AWSOptions object
/// of the SDK fallback credentials search.
/// </summary>
/// <param name="logger"></param>
/// <param name="options"></param>
/// <returns></returns>
private static AWSCredentials CreateCredentials(ILogger logger, AWSOptions options)
{
if (options != null)
{
if (options.Credentials != null)
{
logger?.LogInformation("Using AWS credentials specified with the AWSOptions.Credentials property");
return options.Credentials;
}
if (!string.IsNullOrEmpty(options.Profile))
{
var chain = new CredentialProfileStoreChain(options.ProfilesLocation);
AWSCredentials result;
if (chain.TryGetAWSCredentials(options.Profile, out result))
{
logger?.LogInformation($"Found AWS credentials for the profile {options.Profile}");
return result;
}
else
{
logger?.LogInformation($"Failed to find AWS credentials for the profile {options.Profile}");
}
}
}

var credentials = DefaultIdentityResolverConfiguration.ResolveDefaultIdentity<AWSCredentials>();
if (credentials == null)
{
logger?.LogError("Last effort to find AWS Credentials with AWS SDK's default credential search failed");
throw new AmazonClientException("Failed to find AWS Credentials for constructing AWS service client");
}
else
{
logger?.LogInformation("Found credentials using the AWS SDK's default credential search");
}

return credentials;
}

/// <summary>
/// Creates the ClientConfig object for the service client.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Amazon.Extensions.NETCore.Setup;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
using Amazon.Runtime.Credentials.Internal;
using Microsoft.Extensions.Logging;

namespace AWSSDK.Extensions.NETCore.Setup
{
/// <summary>
///
/// </summary>
public class DefaultAWSCredentials : AWSCredentials
{
private readonly AWSOptions _options;
private readonly ILogger _logger;

/// <summary>
///
/// </summary>
/// <param name="awsOptions"></param>
/// <param name="logger"></param>
public DefaultAWSCredentials(AWSOptions awsOptions, ILogger logger)
{
_options = awsOptions;
_logger = logger;
}

/// <summary>
///
/// </summary>
/// <returns></returns>
public override ImmutableCredentials GetCredentials()
{
if (_options != null)
{
if (_options.Credentials != null)
{
_logger?.LogInformation("Using AWS credentials specified with the AWSOptions.Credentials property");
return _options.Credentials.GetCredentials();
}
if (!string.IsNullOrEmpty(_options.Profile))
{
var chain = new CredentialProfileStoreChain(_options.ProfilesLocation);
AWSCredentials result;
if (chain.TryGetAWSCredentials(_options.Profile, out result))
{
_logger?.LogInformation($"Found AWS credentials for the profile {_options.Profile}");
return result.GetCredentials();
}
else
{
_logger?.LogInformation($"Failed to find AWS credentials for the profile {_options.Profile}");
}
}
}

var credentials = DefaultIdentityResolverConfiguration.ResolveDefaultIdentity<AWSCredentials>();
if (credentials == null)
{
_logger?.LogError("Last effort to find AWS Credentials with AWS SDK's default credential search failed");
throw new AmazonClientException("Failed to find AWS Credentials for constructing AWS service client");
}
else
{
_logger?.LogInformation("Found credentials using the AWS SDK's default credential search");
}

return credentials.GetCredentials();
}
}
}
Loading