From 7173109d055f9120d64489fc7a708eee06630290 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 30 Jan 2019 14:43:41 +0100 Subject: [PATCH] SEBWIN-220: Corrected configuration algorithm to also verify the current administrator password when reconfiguring during application startup. --- .../Communication/ClientHostTests.cs | 2 +- SafeExamBrowser.Client/ClientController.cs | 23 +- .../DataFormats/XmlParser.cs | 2 +- .../Data/PasswordRequestPurpose.cs | 9 +- SafeExamBrowser.Contracts/I18n/TextKey.cs | 6 +- SafeExamBrowser.I18n/Text.xml | 20 +- .../Operations/ClientOperation.cs | 2 +- .../Operations/ConfigurationOperation.cs | 380 +++++++++++------- .../Operations/SessionActivationOperation.cs | 14 + SafeExamBrowser.Runtime/RuntimeController.cs | 22 +- 10 files changed, 304 insertions(+), 176 deletions(-) diff --git a/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs b/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs index 939b2b39..a2cfe768 100644 --- a/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Communication/ClientHostTests.cs @@ -129,7 +129,7 @@ namespace SafeExamBrowser.Client.UnitTests.Communication public void MustHandlePasswordRequestCorrectly() { var passwordRequested = false; - var purpose = PasswordRequestPurpose.Administrator; + var purpose = PasswordRequestPurpose.LocalAdministrator; var requestId = Guid.NewGuid(); var resetEvent = new AutoResetEvent(false); diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index 624c2c37..161b95a2 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -285,13 +285,28 @@ namespace SafeExamBrowser.Client private void ClientHost_PasswordRequested(PasswordRequestEventArgs args) { - var isAdmin = args.Purpose == PasswordRequestPurpose.Administrator; - var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired; - var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle; - var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title)); + var message = default(TextKey); + var title = default(TextKey); logger.Info($"Received input request with id '{args.RequestId}' for the {args.Purpose.ToString().ToLower()} password."); + switch (args.Purpose) + { + case PasswordRequestPurpose.LocalAdministrator: + message = TextKey.PasswordDialog_LocalAdminPasswordRequired; + title = TextKey.PasswordDialog_LocalAdminPasswordRequiredTitle; + break; + case PasswordRequestPurpose.LocalSettings: + message = TextKey.PasswordDialog_LocalSettingsPasswordRequired; + title = TextKey.PasswordDialog_LocalSettingsPasswordRequiredTitle; + break; + case PasswordRequestPurpose.Settings: + message = TextKey.PasswordDialog_SettingsPasswordRequired; + title = TextKey.PasswordDialog_SettingsPasswordRequiredTitle; + break; + } + + var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title)); var result = dialog.Show(); runtime.SubmitPassword(args.RequestId, result.Success, result.Password); diff --git a/SafeExamBrowser.Configuration/DataFormats/XmlParser.cs b/SafeExamBrowser.Configuration/DataFormats/XmlParser.cs index eaa567e3..434c96c5 100644 --- a/SafeExamBrowser.Configuration/DataFormats/XmlParser.cs +++ b/SafeExamBrowser.Configuration/DataFormats/XmlParser.cs @@ -252,7 +252,7 @@ namespace SafeExamBrowser.Configuration.DataFormats if (status != LoadStatus.Success) { - logger.Error($"Element '{element}' is not supported!"); + logger.Error($"Element '{element}' is not a supported value type!"); } return status; diff --git a/SafeExamBrowser.Contracts/Communication/Data/PasswordRequestPurpose.cs b/SafeExamBrowser.Contracts/Communication/Data/PasswordRequestPurpose.cs index 20a79136..d4a98763 100644 --- a/SafeExamBrowser.Contracts/Communication/Data/PasswordRequestPurpose.cs +++ b/SafeExamBrowser.Contracts/Communication/Data/PasswordRequestPurpose.cs @@ -14,9 +14,14 @@ namespace SafeExamBrowser.Contracts.Communication.Data public enum PasswordRequestPurpose { /// - /// The password is to be used as administrator password for an application configuration. + /// The password is to be used as administrator password for the local client configuration. /// - Administrator, + LocalAdministrator, + + /// + /// The password is to be used as settings password for the local client configuration. + /// + LocalSettings, /// /// The password is to be used as settings password for an application configuration. diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs index 0fbf4262..2e2bd662 100644 --- a/SafeExamBrowser.Contracts/I18n/TextKey.cs +++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs @@ -85,10 +85,12 @@ namespace SafeExamBrowser.Contracts.I18n OperationStatus_WaitExplorerStartup, OperationStatus_WaitExplorerTermination, OperationStatus_WaitRuntimeDisconnection, - PasswordDialog_AdminPasswordRequired, - PasswordDialog_AdminPasswordRequiredTitle, PasswordDialog_Cancel, PasswordDialog_Confirm, + PasswordDialog_LocalAdminPasswordRequired, + PasswordDialog_LocalAdminPasswordRequiredTitle, + PasswordDialog_LocalSettingsPasswordRequired, + PasswordDialog_LocalSettingsPasswordRequiredTitle, PasswordDialog_QuitPasswordRequired, PasswordDialog_QuitPasswordRequiredTitle, PasswordDialog_SettingsPasswordRequired, diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index 9d10002c..adf381fe 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -213,18 +213,24 @@ Waiting for the runtime to disconnect - - Please enter the administrator password for the application configuration: - - - Administrator Password Required - Cancel Confirm + + Please enter the administrator password for the local client configuration: + + + Administrator Password Required + + + Please enter the settings password for the local client configuration: + + + Settings Password Required + Please enter the quit password in order to terminate the application: @@ -232,7 +238,7 @@ Quit Password Required - Please enter the settings password for the application configuration: + Please enter the settings password for the selected application configuration: Settings Password Required diff --git a/SafeExamBrowser.Runtime/Operations/ClientOperation.cs b/SafeExamBrowser.Runtime/Operations/ClientOperation.cs index c140e5ea..ff46d4d0 100644 --- a/SafeExamBrowser.Runtime/Operations/ClientOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ClientOperation.cs @@ -102,7 +102,7 @@ namespace SafeExamBrowser.Runtime.Operations var clientExecutable = Context.Next.AppConfig.ClientExecutablePath; var clientLogFile = $"{'"' + Context.Next.AppConfig.ClientLogFile + '"'}"; - var clientLogLevel = logger.LogLevel.ToString(); + var clientLogLevel = Context.Next.Settings.LogLevel.ToString(); var runtimeHostUri = Context.Next.AppConfig.RuntimeAddress; var startupToken = Context.Next.StartupToken.ToString("D"); diff --git a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs index 14b8cebd..07a75cb9 100644 --- a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs @@ -59,11 +59,11 @@ namespace SafeExamBrowser.Runtime.Operations StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration); var result = OperationResult.Failed; - var isValidUri = TryInitializeSettingsUri(out Uri uri); + var isValidUri = TryInitializeSettingsUri(out var uri, out var source); if (isValidUri) { - result = LoadSettings(uri); + result = LoadSettingsForStartup(uri, source); } else { @@ -81,11 +81,11 @@ namespace SafeExamBrowser.Runtime.Operations StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration); var result = OperationResult.Failed; - var isValidUri = TryValidateSettingsUri(Context.ReconfigurationFilePath, out Uri uri); + var isValidUri = TryValidateSettingsUri(Context.ReconfigurationFilePath, out var uri); if (isValidUri) { - result = LoadSettings(uri); + result = LoadSettingsForReconfiguration(uri); } else { @@ -104,66 +104,88 @@ namespace SafeExamBrowser.Runtime.Operations private OperationResult LoadDefaultSettings() { - logger.Info("No valid configuration resource specified nor found in PROGRAMDATA or APPDATA - loading default settings..."); + logger.Info("No valid configuration resource specified and no local client configuration found - loading default settings..."); Context.Next.Settings = configuration.LoadDefaultSettings(); return OperationResult.Success; } - private OperationResult LoadSettings(Uri uri) + private OperationResult LoadSettingsForStartup(Uri uri, UriSource source) { - var passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true }; - var status = configuration.TryLoadSettings(uri, out var settings, passwordParams); + var currentPassword = default(string); + var passwordParams = default(PasswordParameters); + var settings = default(Settings); + var status = default(LoadStatus?); - if (status == LoadStatus.PasswordNeeded && Context.Current?.Settings.AdminPasswordHash != null) + if (source == UriSource.CommandLine) { - passwordParams.Password = Context.Current.Settings.AdminPasswordHash; - passwordParams.IsHash = true; + var hasAppDataFile = File.Exists(AppDataFile); + var hasProgramDataFile = File.Exists(ProgramDataFile); - status = configuration.TryLoadSettings(uri, out settings, passwordParams); - } - - for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++) - { - var success = TryGetPassword(PasswordRequestPurpose.Settings, out var password); - - if (success) + if (hasProgramDataFile) { - passwordParams.Password = password; - passwordParams.IsHash = false; + status = TryLoadSettings(new Uri(ProgramDataFile, UriKind.Absolute), UriSource.ProgramData, out _, out settings); } - else + else if (hasAppDataFile) { - return OperationResult.Aborted; + status = TryLoadSettings(new Uri(AppDataFile, UriKind.Absolute), UriSource.AppData, out _, out settings); } - status = configuration.TryLoadSettings(uri, out settings, passwordParams); + if ((!hasProgramDataFile && !hasAppDataFile) || status == LoadStatus.Success) + { + currentPassword = settings?.AdminPasswordHash; + status = TryLoadSettings(uri, source, out passwordParams, out settings, currentPassword); + } } - - Context.Next.Settings = settings; - - if (settings != null) + else { - logger.LogLevel = settings.LogLevel; + status = TryLoadSettings(uri, source, out passwordParams, out settings); } - return HandleLoadResult(uri, settings, status, passwordParams); + if (status.HasValue) + { + return DetermineLoadResult(uri, source, settings, status.Value, passwordParams, currentPassword); + } + else + { + return OperationResult.Aborted; + } } - private OperationResult HandleLoadResult(Uri uri, Settings settings, LoadStatus status, PasswordParameters password) + private OperationResult LoadSettingsForReconfiguration(Uri uri) { - if (status == LoadStatus.LoadWithBrowser) - { - return HandleBrowserResource(uri); - } + var currentPassword = Context.Current.Settings.AdminPasswordHash; + var source = UriSource.Reconfiguration; + var status = TryLoadSettings(uri, source, out var passwordParams, out var settings, currentPassword); - if (status == LoadStatus.Success && settings.ConfigurationMode == ConfigurationMode.ConfigureClient) + if (status.HasValue) { - return HandleClientConfiguration(uri, password); + return DetermineLoadResult(uri, source, settings, status.Value, passwordParams, currentPassword); } - - if (status == LoadStatus.Success) + else { + return OperationResult.Aborted; + } + } + + private OperationResult DetermineLoadResult(Uri uri, UriSource source, Settings settings, LoadStatus status, PasswordParameters passwordParams, string currentPassword = default(string)) + { + if (status == LoadStatus.LoadWithBrowser || status == LoadStatus.Success) + { + var isNewConfiguration = source == UriSource.CommandLine || source == UriSource.Reconfiguration; + + Context.Next.Settings = settings; + + if (status == LoadStatus.LoadWithBrowser) + { + return HandleBrowserResource(uri); + } + + if (isNewConfiguration && settings.ConfigurationMode == ConfigurationMode.ConfigureClient) + { + return HandleClientConfiguration(uri, passwordParams, currentPassword); + } + return OperationResult.Success; } @@ -180,132 +202,171 @@ namespace SafeExamBrowser.Runtime.Operations return OperationResult.Success; } - private OperationResult HandleClientConfiguration(Uri resource, PasswordParameters password) + private OperationResult HandleClientConfiguration(Uri uri, PasswordParameters passwordParams, string currentPassword = default(string)) { - var isAppDataFile = Path.GetFullPath(resource.AbsolutePath).Equals(AppDataFile, StringComparison.OrdinalIgnoreCase); - var isProgramDataFile = Path.GetFullPath(resource.AbsolutePath).Equals(ProgramDataFile, StringComparison.OrdinalIgnoreCase); var isFirstSession = Context.Current == null; + var success = TryConfigureClient(uri, passwordParams, currentPassword); - if (!isAppDataFile && !isProgramDataFile) + if (success == true) { - var requiresAuthentication = IsAuthenticationRequiredForClientConfiguration(password); - - logger.Info("Starting client configuration..."); - - if (requiresAuthentication) + if (isFirstSession && AbortAfterClientConfiguration()) { - var result = HandleClientConfigurationAuthentication(); - - if (result != OperationResult.Success) - { - return result; - } - } - else - { - logger.Info("Authentication is not required."); - } - - var status = configuration.ConfigureClientWith(resource, password); - - if (status == SaveStatus.Success) - { - logger.Info("Client configuration was successful."); - } - else - { - logger.Error($"Client configuration failed with status '{status}'!"); - ActionRequired?.Invoke(new ClientConfigurationErrorMessageArgs()); - - return OperationResult.Failed; - } - - if (isFirstSession) - { - var result = HandleClientConfigurationOnStartup(); - - if (result != OperationResult.Success) - { - return result; - } - } - } - - return OperationResult.Success; - } - - private bool IsAuthenticationRequiredForClientConfiguration(PasswordParameters password) - { - var requiresAuthentication = Context.Current?.Settings.AdminPasswordHash != null; - - if (requiresAuthentication) - { - var currentPassword = Context.Current.Settings.AdminPasswordHash; - var nextPassword = Context.Next.Settings.AdminPasswordHash; - var hasSettingsPassword = password.Password != null; - var sameAdminPassword = currentPassword.Equals(nextPassword, StringComparison.OrdinalIgnoreCase); - - requiresAuthentication = !sameAdminPassword; - - if (requiresAuthentication && hasSettingsPassword) - { - var settingsPassword = password.IsHash ? password.Password : hashAlgorithm.GenerateHashFor(password.Password); - var knowsAdminPassword = currentPassword.Equals(settingsPassword, StringComparison.OrdinalIgnoreCase); - - requiresAuthentication = !knowsAdminPassword; - } - } - - return requiresAuthentication; - } - - private OperationResult HandleClientConfigurationAuthentication() - { - var currentPassword = Context.Current.Settings.AdminPasswordHash; - var isSamePassword = false; - - for (int attempts = 0; attempts < 5 && !isSamePassword; attempts++) - { - var success = TryGetPassword(PasswordRequestPurpose.Administrator, out var password); - - if (success) - { - isSamePassword = currentPassword.Equals(hashAlgorithm.GenerateHashFor(password), StringComparison.OrdinalIgnoreCase); - } - else - { - logger.Info("Authentication was aborted."); - return OperationResult.Aborted; } - } - - if (isSamePassword) - { - logger.Info("Authentication was successful."); return OperationResult.Success; } - logger.Info("Authentication has failed!"); - ActionRequired?.Invoke(new InvalidPasswordMessageArgs()); + if (!success.HasValue) + { + return OperationResult.Aborted; + } return OperationResult.Failed; } - private OperationResult HandleClientConfigurationOnStartup() + private LoadStatus? TryLoadSettings(Uri uri, UriSource source, out PasswordParameters passwordParams, out Settings settings, string currentPassword = default(string)) + { + passwordParams = new PasswordParameters { Password = string.Empty, IsHash = true }; + + var status = configuration.TryLoadSettings(uri, out settings, passwordParams); + + if (status == LoadStatus.PasswordNeeded && currentPassword != default(string)) + { + passwordParams.Password = currentPassword; + passwordParams.IsHash = true; + + status = configuration.TryLoadSettings(uri, out settings, passwordParams); + } + + for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++) + { + var isLocalConfig = source == UriSource.AppData || source == UriSource.ProgramData; + var purpose = isLocalConfig ? PasswordRequestPurpose.LocalSettings : PasswordRequestPurpose.Settings; + var success = TryGetPassword(purpose, out var password); + + if (success) + { + passwordParams.Password = password; + passwordParams.IsHash = false; + } + else + { + return null; + } + + status = configuration.TryLoadSettings(uri, out settings, passwordParams); + } + + return status; + } + + private bool? TryConfigureClient(Uri uri, PasswordParameters passwordParams, string currentPassword = default(string)) + { + var mustAuthenticate = IsRequiredToAuthenticateForClientConfiguration(passwordParams, currentPassword); + + logger.Info("Starting client configuration..."); + + if (mustAuthenticate) + { + var authenticated = AuthenticateForClientConfiguration(currentPassword); + + if (authenticated == true) + { + logger.Info("Authentication was successful."); + } + + if (authenticated == false) + { + logger.Info("Authentication has failed!"); + ActionRequired?.Invoke(new InvalidPasswordMessageArgs()); + + return false; + } + + if (!authenticated.HasValue) + { + logger.Info("Authentication was aborted."); + + return null; + } + } + else + { + logger.Info("Authentication is not required."); + } + + var status = configuration.ConfigureClientWith(uri, passwordParams); + var success = status == SaveStatus.Success; + + if (success) + { + logger.Info("Client configuration was successful."); + } + else + { + logger.Error($"Client configuration failed with status '{status}'!"); + ActionRequired?.Invoke(new ClientConfigurationErrorMessageArgs()); + } + + return success; + } + + private bool IsRequiredToAuthenticateForClientConfiguration(PasswordParameters passwordParams, string currentPassword = default(string)) + { + var mustAuthenticate = currentPassword != default(string); + + if (mustAuthenticate) + { + var nextPassword = Context.Next.Settings.AdminPasswordHash; + var hasSettingsPassword = passwordParams.Password != null; + var sameAdminPassword = currentPassword.Equals(nextPassword, StringComparison.OrdinalIgnoreCase); + + if (sameAdminPassword) + { + mustAuthenticate = false; + } + else if (hasSettingsPassword) + { + var settingsPassword = passwordParams.IsHash ? passwordParams.Password : hashAlgorithm.GenerateHashFor(passwordParams.Password); + var knowsAdminPassword = currentPassword.Equals(settingsPassword, StringComparison.OrdinalIgnoreCase); + + mustAuthenticate = !knowsAdminPassword; + } + } + + return mustAuthenticate; + } + + private bool? AuthenticateForClientConfiguration(string currentPassword) + { + var authenticated = false; + + for (int attempts = 0; attempts < 5 && !authenticated; attempts++) + { + var success = TryGetPassword(PasswordRequestPurpose.LocalAdministrator, out var password); + + if (success) + { + authenticated = currentPassword.Equals(hashAlgorithm.GenerateHashFor(password), StringComparison.OrdinalIgnoreCase); + } + else + { + return null; + } + } + + return authenticated; + } + + private bool AbortAfterClientConfiguration() { var args = new ConfigurationCompletedEventArgs(); ActionRequired?.Invoke(args); logger.Info($"The user chose to {(args.AbortStartup ? "abort" : "continue")} startup after successful client configuration."); - if (args.AbortStartup) - { - return OperationResult.Aborted; - } - - return OperationResult.Success; + return args.AbortStartup; } private void ShowFailureMessage(LoadStatus status, Uri uri) @@ -337,32 +398,32 @@ namespace SafeExamBrowser.Runtime.Operations return args.Success; } - private bool TryInitializeSettingsUri(out Uri uri) + private bool TryInitializeSettingsUri(out Uri uri, out UriSource source) { - var path = default(string); var isValidUri = false; uri = null; + source = default(UriSource); if (commandLineArgs?.Length > 1) { - path = commandLineArgs[1]; - isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri); - logger.Info($"Found command-line argument for configuration resource: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}."); + isValidUri = Uri.TryCreate(commandLineArgs[1], UriKind.Absolute, out uri); + source = UriSource.CommandLine; + logger.Info($"Found command-line argument for configuration resource: '{uri}', the URI is {(isValidUri ? "valid" : "invalid")}."); } if (!isValidUri && File.Exists(ProgramDataFile)) { - path = ProgramDataFile; - isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri); - logger.Info($"Found configuration file in PROGRAMDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}."); + isValidUri = Uri.TryCreate(ProgramDataFile, UriKind.Absolute, out uri); + source = UriSource.ProgramData; + logger.Info($"Found configuration file in PROGRAMDATA directory: '{uri}'."); } if (!isValidUri && File.Exists(AppDataFile)) { - path = AppDataFile; - isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri); - logger.Info($"Found configuration file in APPDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}."); + isValidUri = Uri.TryCreate(AppDataFile, UriKind.Absolute, out uri); + source = UriSource.AppData; + logger.Info($"Found configuration file in APPDATA directory: '{uri}'."); } return isValidUri; @@ -393,5 +454,14 @@ namespace SafeExamBrowser.Runtime.Operations break; } } + + private enum UriSource + { + Undefined, + AppData, + CommandLine, + ProgramData, + Reconfiguration + } } } diff --git a/SafeExamBrowser.Runtime/Operations/SessionActivationOperation.cs b/SafeExamBrowser.Runtime/Operations/SessionActivationOperation.cs index c7aa8dfb..71548669 100644 --- a/SafeExamBrowser.Runtime/Operations/SessionActivationOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/SessionActivationOperation.cs @@ -26,6 +26,7 @@ namespace SafeExamBrowser.Runtime.Operations public override OperationResult Perform() { + SwitchLogSeverity(); ActivateNewSession(); return OperationResult.Success; @@ -33,6 +34,7 @@ namespace SafeExamBrowser.Runtime.Operations public override OperationResult Repeat() { + SwitchLogSeverity(); ActivateNewSession(); return OperationResult.Success; @@ -43,6 +45,18 @@ namespace SafeExamBrowser.Runtime.Operations return OperationResult.Success; } + private void SwitchLogSeverity() + { + if (logger.LogLevel != Context.Next.Settings.LogLevel) + { + var current = logger.LogLevel.ToString().ToUpper(); + var next = Context.Next.Settings.LogLevel.ToString().ToUpper(); + + logger.Info($"Switching from log severity '{current}' to '{next}' for new session."); + logger.LogLevel = Context.Next.Settings.LogLevel; + } + } + private void ActivateNewSession() { var isFirstSession = Context.Current == null; diff --git a/SafeExamBrowser.Runtime/RuntimeController.cs b/SafeExamBrowser.Runtime/RuntimeController.cs index 531bf694..08fd1573 100644 --- a/SafeExamBrowser.Runtime/RuntimeController.cs +++ b/SafeExamBrowser.Runtime/RuntimeController.cs @@ -452,9 +452,25 @@ namespace SafeExamBrowser.Runtime private void TryGetPasswordViaDialog(PasswordRequiredEventArgs args) { - var isAdmin = args.Purpose == PasswordRequestPurpose.Administrator; - var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired; - var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle; + var message = default(TextKey); + var title = default(TextKey); + + switch (args.Purpose) + { + case PasswordRequestPurpose.LocalAdministrator: + message = TextKey.PasswordDialog_LocalAdminPasswordRequired; + title = TextKey.PasswordDialog_LocalAdminPasswordRequiredTitle; + break; + case PasswordRequestPurpose.LocalSettings: + message = TextKey.PasswordDialog_LocalSettingsPasswordRequired; + title = TextKey.PasswordDialog_LocalSettingsPasswordRequiredTitle; + break; + case PasswordRequestPurpose.Settings: + message = TextKey.PasswordDialog_SettingsPasswordRequired; + title = TextKey.PasswordDialog_SettingsPasswordRequiredTitle; + break; + } + var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title)); var result = dialog.Show(runtimeWindow);