SEBWIN-220: Corrected configuration algorithm to also verify the current administrator password when reconfiguring during application startup.

This commit is contained in:
dbuechel 2019-01-30 14:43:41 +01:00
parent 5641dc3e4b
commit 7173109d05
10 changed files with 304 additions and 176 deletions

View file

@ -129,7 +129,7 @@ namespace SafeExamBrowser.Client.UnitTests.Communication
public void MustHandlePasswordRequestCorrectly() public void MustHandlePasswordRequestCorrectly()
{ {
var passwordRequested = false; var passwordRequested = false;
var purpose = PasswordRequestPurpose.Administrator; var purpose = PasswordRequestPurpose.LocalAdministrator;
var requestId = Guid.NewGuid(); var requestId = Guid.NewGuid();
var resetEvent = new AutoResetEvent(false); var resetEvent = new AutoResetEvent(false);

View file

@ -285,13 +285,28 @@ namespace SafeExamBrowser.Client
private void ClientHost_PasswordRequested(PasswordRequestEventArgs args) private void ClientHost_PasswordRequested(PasswordRequestEventArgs args)
{ {
var isAdmin = args.Purpose == PasswordRequestPurpose.Administrator; var message = default(TextKey);
var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired; var title = default(TextKey);
var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle;
var dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title));
logger.Info($"Received input request with id '{args.RequestId}' for the {args.Purpose.ToString().ToLower()} password."); 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(); var result = dialog.Show();
runtime.SubmitPassword(args.RequestId, result.Success, result.Password); runtime.SubmitPassword(args.RequestId, result.Success, result.Password);

View file

@ -252,7 +252,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
if (status != LoadStatus.Success) if (status != LoadStatus.Success)
{ {
logger.Error($"Element '{element}' is not supported!"); logger.Error($"Element '{element}' is not a supported value type!");
} }
return status; return status;

View file

@ -14,9 +14,14 @@ namespace SafeExamBrowser.Contracts.Communication.Data
public enum PasswordRequestPurpose public enum PasswordRequestPurpose
{ {
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
Administrator, LocalAdministrator,
/// <summary>
/// The password is to be used as settings password for the local client configuration.
/// </summary>
LocalSettings,
/// <summary> /// <summary>
/// The password is to be used as settings password for an application configuration. /// The password is to be used as settings password for an application configuration.

View file

@ -85,10 +85,12 @@ namespace SafeExamBrowser.Contracts.I18n
OperationStatus_WaitExplorerStartup, OperationStatus_WaitExplorerStartup,
OperationStatus_WaitExplorerTermination, OperationStatus_WaitExplorerTermination,
OperationStatus_WaitRuntimeDisconnection, OperationStatus_WaitRuntimeDisconnection,
PasswordDialog_AdminPasswordRequired,
PasswordDialog_AdminPasswordRequiredTitle,
PasswordDialog_Cancel, PasswordDialog_Cancel,
PasswordDialog_Confirm, PasswordDialog_Confirm,
PasswordDialog_LocalAdminPasswordRequired,
PasswordDialog_LocalAdminPasswordRequiredTitle,
PasswordDialog_LocalSettingsPasswordRequired,
PasswordDialog_LocalSettingsPasswordRequiredTitle,
PasswordDialog_QuitPasswordRequired, PasswordDialog_QuitPasswordRequired,
PasswordDialog_QuitPasswordRequiredTitle, PasswordDialog_QuitPasswordRequiredTitle,
PasswordDialog_SettingsPasswordRequired, PasswordDialog_SettingsPasswordRequired,

View file

@ -213,18 +213,24 @@
<Entry key="OperationStatus_WaitRuntimeDisconnection"> <Entry key="OperationStatus_WaitRuntimeDisconnection">
Waiting for the runtime to disconnect Waiting for the runtime to disconnect
</Entry> </Entry>
<Entry key="PasswordDialog_AdminPasswordRequired">
Please enter the administrator password for the application configuration:
</Entry>
<Entry key="PasswordDialog_AdminPasswordRequiredTitle">
Administrator Password Required
</Entry>
<Entry key="PasswordDialog_Cancel"> <Entry key="PasswordDialog_Cancel">
Cancel Cancel
</Entry> </Entry>
<Entry key="PasswordDialog_Confirm"> <Entry key="PasswordDialog_Confirm">
Confirm Confirm
</Entry> </Entry>
<Entry key="PasswordDialog_LocalAdminPasswordRequired">
Please enter the administrator password for the local client configuration:
</Entry>
<Entry key="PasswordDialog_LocalAdminPasswordRequiredTitle">
Administrator Password Required
</Entry>
<Entry key="PasswordDialog_LocalSettingsPasswordRequired">
Please enter the settings password for the local client configuration:
</Entry>
<Entry key="PasswordDialog_LocalSettingsPasswordRequiredTitle">
Settings Password Required
</Entry>
<Entry key="PasswordDialog_QuitPasswordRequired"> <Entry key="PasswordDialog_QuitPasswordRequired">
Please enter the quit password in order to terminate the application: Please enter the quit password in order to terminate the application:
</Entry> </Entry>
@ -232,7 +238,7 @@
Quit Password Required Quit Password Required
</Entry> </Entry>
<Entry key="PasswordDialog_SettingsPasswordRequired"> <Entry key="PasswordDialog_SettingsPasswordRequired">
Please enter the settings password for the application configuration: Please enter the settings password for the selected application configuration:
</Entry> </Entry>
<Entry key="PasswordDialog_SettingsPasswordRequiredTitle"> <Entry key="PasswordDialog_SettingsPasswordRequiredTitle">
Settings Password Required Settings Password Required

View file

@ -102,7 +102,7 @@ namespace SafeExamBrowser.Runtime.Operations
var clientExecutable = Context.Next.AppConfig.ClientExecutablePath; var clientExecutable = Context.Next.AppConfig.ClientExecutablePath;
var clientLogFile = $"{'"' + Context.Next.AppConfig.ClientLogFile + '"'}"; 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 runtimeHostUri = Context.Next.AppConfig.RuntimeAddress;
var startupToken = Context.Next.StartupToken.ToString("D"); var startupToken = Context.Next.StartupToken.ToString("D");

View file

@ -59,11 +59,11 @@ namespace SafeExamBrowser.Runtime.Operations
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration);
var result = OperationResult.Failed; var result = OperationResult.Failed;
var isValidUri = TryInitializeSettingsUri(out Uri uri); var isValidUri = TryInitializeSettingsUri(out var uri, out var source);
if (isValidUri) if (isValidUri)
{ {
result = LoadSettings(uri); result = LoadSettingsForStartup(uri, source);
} }
else else
{ {
@ -81,11 +81,11 @@ namespace SafeExamBrowser.Runtime.Operations
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeConfiguration);
var result = OperationResult.Failed; var result = OperationResult.Failed;
var isValidUri = TryValidateSettingsUri(Context.ReconfigurationFilePath, out Uri uri); var isValidUri = TryValidateSettingsUri(Context.ReconfigurationFilePath, out var uri);
if (isValidUri) if (isValidUri)
{ {
result = LoadSettings(uri); result = LoadSettingsForReconfiguration(uri);
} }
else else
{ {
@ -104,66 +104,88 @@ namespace SafeExamBrowser.Runtime.Operations
private OperationResult LoadDefaultSettings() 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(); Context.Next.Settings = configuration.LoadDefaultSettings();
return OperationResult.Success; 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 currentPassword = default(string);
var status = configuration.TryLoadSettings(uri, out var settings, passwordParams); 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; var hasAppDataFile = File.Exists(AppDataFile);
passwordParams.IsHash = true; var hasProgramDataFile = File.Exists(ProgramDataFile);
status = configuration.TryLoadSettings(uri, out settings, passwordParams); if (hasProgramDataFile)
}
for (int attempts = 0; attempts < 5 && status == LoadStatus.PasswordNeeded; attempts++)
{
var success = TryGetPassword(PasswordRequestPurpose.Settings, out var password);
if (success)
{ {
passwordParams.Password = password; status = TryLoadSettings(new Uri(ProgramDataFile, UriKind.Absolute), UriSource.ProgramData, out _, out settings);
passwordParams.IsHash = false;
} }
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);
}
} }
else
Context.Next.Settings = settings;
if (settings != null)
{ {
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) var currentPassword = Context.Current.Settings.AdminPasswordHash;
{ var source = UriSource.Reconfiguration;
return HandleBrowserResource(uri); 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);
} }
else
if (status == LoadStatus.Success)
{ {
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; return OperationResult.Success;
} }
@ -180,132 +202,171 @@ namespace SafeExamBrowser.Runtime.Operations
return OperationResult.Success; 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 isFirstSession = Context.Current == null;
var success = TryConfigureClient(uri, passwordParams, currentPassword);
if (!isAppDataFile && !isProgramDataFile) if (success == true)
{ {
var requiresAuthentication = IsAuthenticationRequiredForClientConfiguration(password); if (isFirstSession && AbortAfterClientConfiguration())
logger.Info("Starting client configuration...");
if (requiresAuthentication)
{ {
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; return OperationResult.Aborted;
} }
}
if (isSamePassword)
{
logger.Info("Authentication was successful.");
return OperationResult.Success; return OperationResult.Success;
} }
logger.Info("Authentication has failed!"); if (!success.HasValue)
ActionRequired?.Invoke(new InvalidPasswordMessageArgs()); {
return OperationResult.Aborted;
}
return OperationResult.Failed; 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(); var args = new ConfigurationCompletedEventArgs();
ActionRequired?.Invoke(args); ActionRequired?.Invoke(args);
logger.Info($"The user chose to {(args.AbortStartup ? "abort" : "continue")} startup after successful client configuration."); logger.Info($"The user chose to {(args.AbortStartup ? "abort" : "continue")} startup after successful client configuration.");
if (args.AbortStartup) return args.AbortStartup;
{
return OperationResult.Aborted;
}
return OperationResult.Success;
} }
private void ShowFailureMessage(LoadStatus status, Uri uri) private void ShowFailureMessage(LoadStatus status, Uri uri)
@ -337,32 +398,32 @@ namespace SafeExamBrowser.Runtime.Operations
return args.Success; 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; var isValidUri = false;
uri = null; uri = null;
source = default(UriSource);
if (commandLineArgs?.Length > 1) if (commandLineArgs?.Length > 1)
{ {
path = commandLineArgs[1]; isValidUri = Uri.TryCreate(commandLineArgs[1], UriKind.Absolute, out uri);
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri); source = UriSource.CommandLine;
logger.Info($"Found command-line argument for configuration resource: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}."); logger.Info($"Found command-line argument for configuration resource: '{uri}', the URI is {(isValidUri ? "valid" : "invalid")}.");
} }
if (!isValidUri && File.Exists(ProgramDataFile)) if (!isValidUri && File.Exists(ProgramDataFile))
{ {
path = ProgramDataFile; isValidUri = Uri.TryCreate(ProgramDataFile, UriKind.Absolute, out uri);
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri); source = UriSource.ProgramData;
logger.Info($"Found configuration file in PROGRAMDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}."); logger.Info($"Found configuration file in PROGRAMDATA directory: '{uri}'.");
} }
if (!isValidUri && File.Exists(AppDataFile)) if (!isValidUri && File.Exists(AppDataFile))
{ {
path = AppDataFile; isValidUri = Uri.TryCreate(AppDataFile, UriKind.Absolute, out uri);
isValidUri = Uri.TryCreate(path, UriKind.Absolute, out uri); source = UriSource.AppData;
logger.Info($"Found configuration file in APPDATA: '{path}', the URI is {(isValidUri ? "valid" : "invalid")}."); logger.Info($"Found configuration file in APPDATA directory: '{uri}'.");
} }
return isValidUri; return isValidUri;
@ -393,5 +454,14 @@ namespace SafeExamBrowser.Runtime.Operations
break; break;
} }
} }
private enum UriSource
{
Undefined,
AppData,
CommandLine,
ProgramData,
Reconfiguration
}
} }
} }

View file

@ -26,6 +26,7 @@ namespace SafeExamBrowser.Runtime.Operations
public override OperationResult Perform() public override OperationResult Perform()
{ {
SwitchLogSeverity();
ActivateNewSession(); ActivateNewSession();
return OperationResult.Success; return OperationResult.Success;
@ -33,6 +34,7 @@ namespace SafeExamBrowser.Runtime.Operations
public override OperationResult Repeat() public override OperationResult Repeat()
{ {
SwitchLogSeverity();
ActivateNewSession(); ActivateNewSession();
return OperationResult.Success; return OperationResult.Success;
@ -43,6 +45,18 @@ namespace SafeExamBrowser.Runtime.Operations
return OperationResult.Success; 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() private void ActivateNewSession()
{ {
var isFirstSession = Context.Current == null; var isFirstSession = Context.Current == null;

View file

@ -452,9 +452,25 @@ namespace SafeExamBrowser.Runtime
private void TryGetPasswordViaDialog(PasswordRequiredEventArgs args) private void TryGetPasswordViaDialog(PasswordRequiredEventArgs args)
{ {
var isAdmin = args.Purpose == PasswordRequestPurpose.Administrator; var message = default(TextKey);
var message = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequired : TextKey.PasswordDialog_SettingsPasswordRequired; var title = default(TextKey);
var title = isAdmin ? TextKey.PasswordDialog_AdminPasswordRequiredTitle : TextKey.PasswordDialog_SettingsPasswordRequiredTitle;
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 dialog = uiFactory.CreatePasswordDialog(text.Get(message), text.Get(title));
var result = dialog.Show(runtimeWindow); var result = dialog.Show(runtimeWindow);