diff --git a/src/D2L.Bmx/ConsolePrompter.cs b/src/D2L.Bmx/ConsolePrompter.cs index eae26f91..019b1862 100644 --- a/src/D2L.Bmx/ConsolePrompter.cs +++ b/src/D2L.Bmx/ConsolePrompter.cs @@ -8,7 +8,7 @@ internal interface IConsolePrompter { string PromptOrg( bool allowEmptyInput ); string PromptProfile(); string PromptUser( bool allowEmptyInput ); - string PromptPassword(); + string PromptPassword( string user, string org ); int? PromptDuration(); string PromptAccount( string[] accounts ); string PromptRole( string[] roles ); @@ -63,7 +63,7 @@ string IConsolePrompter.PromptUser( bool allowEmptyInput ) { return user; } - string IConsolePrompter.PromptPassword() { + string IConsolePrompter.PromptPassword( string user, string org ) { Func readKey; if( IS_WINDOWS ) { // On Windows, Console.ReadKey calls native console API, and will fail without a console attached @@ -84,6 +84,8 @@ Input to BMX is redirected. Password input may be displayed on screen! readKey = () => (char)_stdinReader.Read(); } + Console.Error.WriteLine( $"{ParameterDescriptions.Org}: {org}" ); + Console.Error.WriteLine( $"{ParameterDescriptions.User}: {user}" ); Console.Error.Write( $"{ParameterDescriptions.Password}: " ); string? originalTerminalSettings = null; diff --git a/src/D2L.Bmx/Okta/OktaApi.cs b/src/D2L.Bmx/Okta/OktaApi.cs index b21fcc6c..7a4f09f7 100644 --- a/src/D2L.Bmx/Okta/OktaApi.cs +++ b/src/D2L.Bmx/Okta/OktaApi.cs @@ -23,15 +23,18 @@ Task VerifyMfaChallengeResponseAsync( internal class OktaApi : IOktaApi { private readonly CookieContainer _cookieContainer; private readonly HttpClient _httpClient; + private string? _organization; public OktaApi() { _cookieContainer = new CookieContainer(); - _httpClient = new HttpClient( new HttpClientHandler { CookieContainer = _cookieContainer } ); - _httpClient.Timeout = TimeSpan.FromSeconds( 30 ); + _httpClient = new HttpClient( new HttpClientHandler { CookieContainer = _cookieContainer } ) { + Timeout = TimeSpan.FromSeconds( 30 ) + }; _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue( "application/json" ) ); } void IOktaApi.SetOrganization( string organization ) { + _organization = organization; if( !organization.Contains( '.' ) ) { _httpClient.BaseAddress = new Uri( $"https://{organization}.okta.com/api/v1/" ); } else { @@ -83,7 +86,11 @@ await resp.Content.ReadAsStreamAsync(), authnResponse.Embedded.Factors ); } - throw new BmxException( "Okta authentication failed. Check if org, user and password is correct" ); + + string org = _organization ?? "unknown"; + throw new BmxException( + $"Okta authentication for user '{username}' in org '{org}'" + + "failed. Check if org, user, and password is correct" ); } async Task IOktaApi.IssueMfaChallengeAsync( string stateToken, string factorId ) { @@ -168,7 +175,6 @@ async Task IOktaApi.GetAwsAccountAppsAsync() { return apps?.Where( app => app.AppName == "amazon_aws" ).ToArray() ?? throw new BmxException( "Error retrieving AWS accounts from Okta." ); - } async Task IOktaApi.GetPageAsync( string samlLoginUrl ) { diff --git a/src/D2L.Bmx/OktaAuthenticator.cs b/src/D2L.Bmx/OktaAuthenticator.cs index 79741457..0abd199c 100644 --- a/src/D2L.Bmx/OktaAuthenticator.cs +++ b/src/D2L.Bmx/OktaAuthenticator.cs @@ -50,7 +50,7 @@ bool ignoreCache throw new BmxException( "Okta authentication failed. Please run `bmx login` first." ); } - string password = consolePrompter.PromptPassword(); + string password = consolePrompter.PromptPassword( user, org ); var authnResponse = await oktaApi.AuthenticateAsync( user, password );