Skip to content

Commit

Permalink
Fixes multi-session bug preventing users from having simultaneous AWS…
Browse files Browse the repository at this point in the history
… sessions active (#23)

Fixes Multi Session bug preventing users from having simultaneous AWS
sessions active
  • Loading branch information
vgmello authored Dec 8, 2023
1 parent 705d7a6 commit 07b383d
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.14.0.81108" developmentDependency="true">
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.*" developmentDependency="true">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ namespace Ellosoft.AwsCredentialsManager.Commands.Credentials;
[Examples("new prod")]
public class CreateCredentialsProfile : AsyncCommand<CreateCredentialsProfile.Settings>
{
private const string DEFAULT_AWS_PROFILE_VALUE = "[credential name]";

public class Settings : AwsSettings
{
[CommandArgument(0, "<CREDENTIAL_NAME>")]
Expand All @@ -27,9 +29,9 @@ public class Settings : AwsSettings
[Description("AWS role ARN")]
public string? AwsRoleArn { get; set; }

[CommandOption("-p|--aws-profile")]
[CommandOption("--aws-profile")]
[Description("AWS profile to use (profile used in AWS CLI)")]
[DefaultValue("default")]
[DefaultValue(DEFAULT_AWS_PROFILE_VALUE)]
public string? AwsProfile { get; set; }

[CommandOption("--okta-app-url")]
Expand Down Expand Up @@ -63,10 +65,11 @@ public override async Task<int> ExecuteAsync(CommandContext context, Settings se
{
var oktaAppUrl = settings.OktaAppUrl ?? await GetAwsAppUrl(settings.OktaUserProfile);
var awsRole = settings.AwsRoleArn ?? await GetAwsRoleArn(settings.OktaUserProfile, oktaAppUrl);
var awsProfile = settings.AwsProfile is null or DEFAULT_AWS_PROFILE_VALUE ? null : settings.AwsProfile;

_credentialsManager.CreateCredential(
name: settings.Name,
awsProfile: settings.AwsProfile!,
awsProfile: awsProfile,
awsRole: awsRole,
oktaAppUrl: oktaAppUrl,
oktaProfile: settings.OktaUserProfile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ namespace Ellosoft.AwsCredentialsManager.Commands.Credentials;
[Examples(
"get prod",
"get prod --aws-profile default")]
public class GetCredentials : AsyncCommand<GetCredentials.Settings>
public class GetCredentials(
CredentialsManager credentialsManager,
AwsOktaSessionManager sessionManager
) : AsyncCommand<GetCredentials.Settings>
{
public class Settings : AwsSettings
{
Expand All @@ -25,23 +28,11 @@ public class Settings : AwsSettings
public string? AwsProfile { get; set; }
}

private readonly CredentialsManager _credentialsManager;
private readonly AwsOktaSessionManager _sessionManager;

public GetCredentials(
CredentialsManager credentialsManager,
AwsOktaSessionManager sessionManager
)
{
_credentialsManager = credentialsManager;
_sessionManager = sessionManager;
}

public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
{
var credential = settings.Credential ?? _credentialsManager.GetCredential();
var credential = settings.Credential ?? credentialsManager.GetCredentialNameFromUser();

var awsCredentials = await _sessionManager.CreateOrResumeSessionAsync(credential, settings.AwsProfile);
var awsCredentials = await sessionManager.CreateOrResumeSessionAsync(credential, settings.AwsProfile);

if (awsCredentials is null)
return 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Ellosoft.AwsCredentialsManager.Commands.Credentials;
[Name("list"), Alias("ls")]
[Description("List saved credential profiles")]
[Examples("ls")]
public class ListCredentialsProfiles : Command<ListCredentialsProfiles.Settings>
public class ListCredentialsProfiles(IConfigManager configManager) : Command<ListCredentialsProfiles.Settings>
{
public class Settings : AwsSettings
{
Expand All @@ -20,13 +20,9 @@ public class Settings : AwsSettings
public string OktaUserProfile { get; set; } = OktaConfiguration.DefaultProfileName;
}

private readonly IConfigManager _configManager;

public ListCredentialsProfiles(IConfigManager configManager) => _configManager = configManager;

public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
{
var credentials = _configManager.AppConfig.Credentials;
var credentials = configManager.AppConfig.Credentials;

var table = new Table()
.Title("[green]Saved credentials[/]")
Expand All @@ -36,8 +32,8 @@ public override int Execute([NotNull] CommandContext context, [NotNull] Settings

var filteredCredentials = credentials.Where(kv => kv.Value.OktaProfile == settings.OktaUserProfile);

foreach (var credential in filteredCredentials)
table.AddRow(credential.Key, credential.Value.RoleArn, credential.Value.AwsProfile);
foreach (var (credentialName, credentialConfig) in filteredCredentials)
table.AddRow(credentialName, credentialConfig.RoleArn, credentialConfig.GetAwsProfileSafe(credentialName));

AnsiConsole.Write(table);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ await GenerateDbPassword(

private async Task<int> HandleAdHocRequest(Settings settings)
{
var credentialName = _credentialsManager.GetCredential();
var credentialName = _credentialsManager.GetCredentialNameFromUser();

AnsiConsole.MarkupLine($"Getting RDS password using [green i]{credentialName}[/] credential profile");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@

<ItemGroup>
<PackageReference Include="AngleSharp" Version="1.0.7" />
<PackageReference Include="AWSSDK.RDS" Version="3.7.300.2" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.300.1" />
<PackageReference Include="AWSSDK.RDS" Version="3.7.301.10" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.300.16" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ public class AwsOktaSessionManager(
private readonly AwsCredentialsService _awsCredentialsService = new();
private readonly AwsSamlService _awsSamlService = new();

public async Task<AWSCredentials?> CreateOrResumeSessionAsync(string credentialProfile, string? awsProfile)
public async Task<AWSCredentials?> CreateOrResumeSessionAsync(string credentialProfile, string? outputAwsProfile)
{
if (!credentialsManager.TryGetCredential(credentialProfile, out var credentialsConfig))
return null;

var awsProfileName = awsProfile ?? credentialsConfig.AwsProfile;
var awsProfile = credentialsConfig.GetAwsProfileSafe(credentialProfile);

if (TryResumeSession(awsProfileName, credentialsConfig.RoleArn, out var awsCredentialsData))
return CreateAwsCredentials(awsCredentialsData);
if (TryResumeSession(awsProfile, credentialsConfig.RoleArn, out var awsCredentialsData))
return CreateAwsCredentials(awsCredentialsData, awsProfile, outputAwsProfile);

var newCredential = await CreateSessionAsync(credentialProfile, awsProfileName, credentialsConfig);
var newCredential = await CreateSessionAsync(credentialProfile, awsProfile, credentialsConfig);

return newCredential is not null ? CreateAwsCredentials(newCredential) : null;
return newCredential is not null ? CreateAwsCredentials(newCredential, awsProfile, outputAwsProfile) : null;
}

private bool TryResumeSession(string awsProfile, string roleArn, [NotNullWhen(true)] out AwsCredentialsData? credentialsData)
Expand Down Expand Up @@ -58,7 +58,7 @@ Do you want renew the credentials now ?[/]
return true;
}

private async Task<AwsCredentialsData?> CreateSessionAsync(string credentialProfile, string awsProfileName, CredentialsConfiguration credentialsConfig)
private async Task<AwsCredentialsData?> CreateSessionAsync(string credentialProfile, string awsProfile, CredentialsConfiguration credentialsConfig)
{
var authResult = await loginService.InteractiveLogin(credentialsConfig.OktaProfile!);

Expand All @@ -74,7 +74,7 @@ Do you want renew the credentials now ?[/]

var awsCredentialsData = await _awsCredentialsService.GetAwsCredentials(samlData.SamlAssertion, credentialsConfig.RoleArn, idp);

_awsCredentialsService.StoreCredentials(awsProfileName, awsCredentialsData);
_awsCredentialsService.StoreCredentials(awsProfile, awsCredentialsData);

return awsCredentialsData;
}
Expand All @@ -99,6 +99,13 @@ [bold yellow]The AWS role ARN specified in the credential [b]'{credentialProfile
return null;
}

private static SessionAWSCredentials CreateAwsCredentials(AwsCredentialsData credentialsData) =>
new(credentialsData.AccessKeyId, credentialsData.SecretAccessKey, credentialsData.SessionToken);
private SessionAWSCredentials CreateAwsCredentials(AwsCredentialsData credentialsData, string credentialProfile, string? outputAwsProfile)
{
if (outputAwsProfile is not null && outputAwsProfile != credentialProfile)
{
_awsCredentialsService.StoreCredentials(outputAwsProfile, credentialsData);
}

return new SessionAWSCredentials(credentialsData.AccessKeyId, credentialsData.SecretAccessKey, credentialsData.SessionToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Ellosoft.AwsCredentialsManager.Services.Configuration.Interactive;

public class CredentialsManager(IConfigManager configManager)
{
public string GetCredential()
public string GetCredentialNameFromUser()
{
var appConfig = configManager.AppConfig;

Expand Down Expand Up @@ -43,7 +43,7 @@ public bool TryGetCredential(string credentialProfile, [NotNullWhen(true)] out C
return false;
}

public void CreateCredential(string name, string awsProfile, string awsRole, string oktaAppUrl, string oktaProfile)
public void CreateCredential(string name, string? awsProfile, string awsRole, string oktaAppUrl, string oktaProfile)
{
var credential = new CredentialsConfiguration
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private EnvironmentConfiguration CreateNewEnvironment(string? environment = null

AnsiConsole.MarkupLine($"Creating environment [green i]{environmentName}[/]");

var credentialName = _credentialsManager.GetCredential();
var credentialName = _credentialsManager.GetCredentialNameFromUser();
var environmentConfig = new EnvironmentConfiguration { Credential = credentialName };

while (!_configManager.AppConfig.Environments.TryAdd(environmentName, environmentConfig))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ public class CredentialsConfiguration : ResourceConfiguration
{
public required string RoleArn { get; set; }

public required string AwsProfile { get; set; } = "default";
public string? AwsProfile { get; set; }

public string? OktaAppUrl { get; set; }

public string? OktaProfile { get; set; }

/// <summary>
/// If the AwsProfile is populated then return its value otherwise returns the credential name
/// </summary>
internal string GetAwsProfileSafe(string credentialName) => AwsProfile ?? credentialName;
}

0 comments on commit 07b383d

Please sign in to comment.