From dd801245d2e8a346373bac534e808b40e58276e7 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 26 Jun 2019 10:13:11 +0200 Subject: [PATCH] SEBWIN-301: Finished basic backup mechanism for service. --- .../ConfigurationData/DataValues.cs | 15 ++- .../Configuration/AppConfig.cs | 15 +++ .../Lockdown/IAutoRestoreMechanism.cs | 26 +++++ .../Lockdown/IFeatureConfiguration.cs | 14 ++- .../Lockdown/IFeatureConfigurationBackup.cs | 18 ++- .../Lockdown/IFeatureConfigurationFactory.cs | 26 +++-- .../SafeExamBrowser.Contracts.csproj | 1 + .../AutoRestoreMechanism.cs | 32 ++++++ .../FeatureConfigurationBackup.cs | 105 +++++++++++++++++- .../FeatureConfigurationFactory.cs | 49 ++++---- .../ChromeNotificationConfiguration.cs | 26 +++-- .../EaseOfAccessConfiguration.cs | 18 ++- .../FeatureConfiguration.cs | 48 ++++++++ .../NetworkOptionsConfiguration.cs | 18 ++- .../PasswordChangeConfiguration.cs | 18 ++- .../PowerOptionsConfiguration.cs | 18 ++- .../RemoteConnectionConfiguration.cs | 18 ++- .../SignoutConfiguration.cs | 18 ++- .../TaskManagerConfiguration.cs | 18 ++- .../UserLockConfiguration.cs | 18 ++- .../UserSwitchConfiguration.cs | 18 ++- .../VmwareOverlayConfiguration.cs | 18 ++- .../WindowsUpdateConfiguration.cs | 18 ++- .../SafeExamBrowser.Lockdown.csproj | 2 + .../SessionInitializationOperationTests.cs | 40 +++++-- SafeExamBrowser.Service/CompositionRoot.cs | 19 +++- .../Operations/LockdownOperation.cs | 37 +++--- .../Operations/RestoreOperation.cs | 14 ++- .../SessionInitializationOperation.cs | 28 ++++- SafeExamBrowser.Service/SessionContext.cs | 6 + 30 files changed, 552 insertions(+), 167 deletions(-) create mode 100644 SafeExamBrowser.Contracts/Lockdown/IAutoRestoreMechanism.cs create mode 100644 SafeExamBrowser.Lockdown/AutoRestoreMechanism.cs create mode 100644 SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index c5860cf4..ae35ed93 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -16,8 +16,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { internal class DataValues { - private const string BASE_ADDRESS = "net.pipe://localhost/safeexambrowser"; - private const string DEFAULT_FILE_NAME = "SebClientSettings.seb"; + private const string DEFAULT_CONFIGURATION_NAME = "SebClientSettings.seb"; private AppConfig appConfig; private string executablePath; @@ -48,26 +47,26 @@ namespace SafeExamBrowser.Configuration.ConfigurationData var logFilePrefix = startTime.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s"); appConfig = new AppConfig(); - appConfig.AppDataFilePath = Path.Combine(appDataRoamingFolder, DEFAULT_FILE_NAME); + appConfig.AppDataFilePath = Path.Combine(appDataRoamingFolder, DEFAULT_CONFIGURATION_NAME); appConfig.ApplicationStartTime = startTime; appConfig.BrowserCachePath = Path.Combine(appDataLocalFolder, "Cache"); appConfig.BrowserLogFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Browser.log"); appConfig.ClientId = Guid.NewGuid(); - appConfig.ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}"; + appConfig.ClientAddress = $"{AppConfig.BASE_ADDRESS}/client/{Guid.NewGuid()}"; appConfig.ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executablePath), $"{nameof(SafeExamBrowser)}.Client.exe"); appConfig.ClientLogFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Client.log"); appConfig.ConfigurationFileExtension = ".seb"; appConfig.DownloadDirectory = Path.Combine(appDataLocalFolder, "Downloads"); appConfig.ProgramCopyright = programCopyright; - appConfig.ProgramDataFilePath = Path.Combine(programDataFolder, DEFAULT_FILE_NAME); + appConfig.ProgramDataFilePath = Path.Combine(programDataFolder, DEFAULT_CONFIGURATION_NAME); appConfig.ProgramTitle = programTitle; appConfig.ProgramVersion = programVersion; appConfig.RuntimeId = Guid.NewGuid(); - appConfig.RuntimeAddress = $"{BASE_ADDRESS}/runtime/{Guid.NewGuid()}"; + appConfig.RuntimeAddress = $"{AppConfig.BASE_ADDRESS}/runtime/{Guid.NewGuid()}"; appConfig.RuntimeLogFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Runtime.log"); appConfig.SebUriScheme = "seb"; appConfig.SebUriSchemeSecure = "sebs"; - appConfig.ServiceAddress = $"{BASE_ADDRESS}/service"; + appConfig.ServiceAddress = $"{AppConfig.BASE_ADDRESS}/service"; appConfig.ServiceEventName = $@"Global\{nameof(SafeExamBrowser)}-{Guid.NewGuid()}"; appConfig.ServiceLogFilePath = Path.Combine(logFolder, $"{logFilePrefix}_Service.log"); @@ -79,7 +78,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData var configuration = new SessionConfiguration(); appConfig.ClientId = Guid.NewGuid(); - appConfig.ClientAddress = $"{BASE_ADDRESS}/client/{Guid.NewGuid()}"; + appConfig.ClientAddress = $"{AppConfig.BASE_ADDRESS}/client/{Guid.NewGuid()}"; appConfig.ServiceEventName = $@"Global\{nameof(SafeExamBrowser)}-{Guid.NewGuid()}"; configuration.AppConfig = appConfig.Clone(); diff --git a/SafeExamBrowser.Contracts/Configuration/AppConfig.cs b/SafeExamBrowser.Contracts/Configuration/AppConfig.cs index 8e8bfb06..9e6ff7e7 100644 --- a/SafeExamBrowser.Contracts/Configuration/AppConfig.cs +++ b/SafeExamBrowser.Contracts/Configuration/AppConfig.cs @@ -16,6 +16,21 @@ namespace SafeExamBrowser.Contracts.Configuration [Serializable] public class AppConfig { + /// + /// The name of the backup data file used by the service component. + /// + public const string BACKUP_FILE_NAME = "Backup.bin"; + + /// + /// The base address for all communication hosts of the application. + /// + public const string BASE_ADDRESS = "net.pipe://localhost/safeexambrowser"; + + /// + /// The communication address of the service component. + /// + public const string SERVICE_ADDRESS = BASE_ADDRESS + "/service"; + /// /// The file path of the local client configuration for the active user. /// diff --git a/SafeExamBrowser.Contracts/Lockdown/IAutoRestoreMechanism.cs b/SafeExamBrowser.Contracts/Lockdown/IAutoRestoreMechanism.cs new file mode 100644 index 00000000..48d8d423 --- /dev/null +++ b/SafeExamBrowser.Contracts/Lockdown/IAutoRestoreMechanism.cs @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.Contracts.Lockdown +{ + /// + /// Defines a mechanism which tries to restore all changes saved in a . + /// + public interface IAutoRestoreMechanism + { + /// + /// Starts the procedure. + /// + void Start(); + + /// + /// Stops the procedure. + /// + void Stop(); + } +} diff --git a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs index eff72b83..45d769f1 100644 --- a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs +++ b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs @@ -6,6 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; + namespace SafeExamBrowser.Contracts.Lockdown { /// @@ -13,6 +15,16 @@ namespace SafeExamBrowser.Contracts.Lockdown /// public interface IFeatureConfiguration { + /// + /// The unique identifier of this feature configuration. + /// + Guid Id { get; } + + /// + /// The identifier of the group of changes to which this feature configuration belongs. + /// + Guid GroupId { get; } + /// /// Disables the feature. /// @@ -29,7 +41,7 @@ namespace SafeExamBrowser.Contracts.Lockdown void Monitor(); /// - /// Restores the feature to its initial configuration. + /// Restores the feature to its previous configuration (i.e. before it was enabled or disabled). /// void Restore(); } diff --git a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationBackup.cs b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationBackup.cs index b430486c..6815e23c 100644 --- a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationBackup.cs +++ b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationBackup.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Collections.Generic; namespace SafeExamBrowser.Contracts.Lockdown @@ -15,19 +16,24 @@ namespace SafeExamBrowser.Contracts.Lockdown /// public interface IFeatureConfigurationBackup { + /// + /// Deletes the given from the backup repository. + /// + void Delete(IFeatureConfiguration configuration); + /// /// Gets all currently saved in the backup repository. /// - IList GetConfigurations(); + IList GetAllConfigurations(); + + /// + /// Gets all which are part of the given group. + /// + IList GetBy(Guid groupId); /// /// Saves the given in the backup repository. /// void Save(IFeatureConfiguration configuration); - - /// - /// Deletes the given from the backup repository. - /// - void Delete(IFeatureConfiguration configuration); } } diff --git a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs index 6d355c7f..96042d63 100644 --- a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs +++ b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs @@ -6,6 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; + namespace SafeExamBrowser.Contracts.Lockdown { /// @@ -16,61 +18,61 @@ namespace SafeExamBrowser.Contracts.Lockdown /// /// Creates an to control notifications of the Google Chrome browser. /// - IFeatureConfiguration CreateChromeNotificationConfiguration(); + IFeatureConfiguration CreateChromeNotificationConfiguration(Guid groupId); /// /// Creates an to control the ease of access options on the security screen. /// - IFeatureConfiguration CreateEaseOfAccessConfiguration(); + IFeatureConfiguration CreateEaseOfAccessConfiguration(Guid groupId); /// /// Creates an to control the network options on the security screen. /// - IFeatureConfiguration CreateNetworkOptionsConfiguration(); + IFeatureConfiguration CreateNetworkOptionsConfiguration(Guid groupId); /// /// Creates an to control the option to change the password of a user account via the security screen. /// - IFeatureConfiguration CreatePasswordChangeConfiguration(); + IFeatureConfiguration CreatePasswordChangeConfiguration(Guid groupId); /// /// Creates an to control the power options on the security screen. /// - IFeatureConfiguration CreatePowerOptionsConfiguration(); + IFeatureConfiguration CreatePowerOptionsConfiguration(Guid groupId); /// /// Creates an to control remote desktop connections. /// - IFeatureConfiguration CreateRemoteConnectionConfiguration(); + IFeatureConfiguration CreateRemoteConnectionConfiguration(Guid groupId); /// /// Creates an to control the option to sign out out via security screen. /// - IFeatureConfiguration CreateSignoutConfiguration(); + IFeatureConfiguration CreateSignoutConfiguration(Guid groupId); /// /// Creates an to control the task manager of Windows. /// - IFeatureConfiguration CreateTaskManagerConfiguration(); + IFeatureConfiguration CreateTaskManagerConfiguration(Guid groupId); /// /// Creates an to control the option to lock the computer via the security screen. /// - IFeatureConfiguration CreateUserLockConfiguration(); + IFeatureConfiguration CreateUserLockConfiguration(Guid groupId); /// /// Creates an to control the option to switch to another user account via the security screen. /// - IFeatureConfiguration CreateUserSwitchConfiguration(); + IFeatureConfiguration CreateUserSwitchConfiguration(Guid groupId); /// /// Creates an to control the user interface overlay for VMware clients. /// - IFeatureConfiguration CreateVmwareOverlayConfiguration(); + IFeatureConfiguration CreateVmwareOverlayConfiguration(Guid groupId); /// /// Creates an to control Windows Update. /// - IFeatureConfiguration CreateWindowsUpdateConfiguration(); + IFeatureConfiguration CreateWindowsUpdateConfiguration(Guid groupId); } } diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index fd10f1e7..880ad5ce 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -92,6 +92,7 @@ + diff --git a/SafeExamBrowser.Lockdown/AutoRestoreMechanism.cs b/SafeExamBrowser.Lockdown/AutoRestoreMechanism.cs new file mode 100644 index 00000000..9d042abd --- /dev/null +++ b/SafeExamBrowser.Lockdown/AutoRestoreMechanism.cs @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Contracts.Lockdown; + +namespace SafeExamBrowser.Lockdown +{ + public class AutoRestoreMechanism : IAutoRestoreMechanism + { + private IFeatureConfigurationBackup backup; + + public AutoRestoreMechanism(IFeatureConfigurationBackup backup) + { + this.backup = backup; + } + + public void Start() + { + + } + + public void Stop() + { + + } + } +} diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurationBackup.cs b/SafeExamBrowser.Lockdown/FeatureConfigurationBackup.cs index ab4eedf6..cb87b87a 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurationBackup.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurationBackup.cs @@ -6,7 +6,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; using SafeExamBrowser.Contracts.Lockdown; using SafeExamBrowser.Contracts.Logging; @@ -14,26 +19,114 @@ namespace SafeExamBrowser.Lockdown { public class FeatureConfigurationBackup : IFeatureConfigurationBackup { - private ILogger logger; + private readonly object @lock = new object(); - public FeatureConfigurationBackup(ILogger logger) + private string filePath; + private IModuleLogger logger; + + public FeatureConfigurationBackup(string filePath, IModuleLogger logger) { + this.filePath = filePath; this.logger = logger; } public void Delete(IFeatureConfiguration configuration) { - + lock (@lock) + { + var configurations = LoadFromFile(); + var obsolete = configurations.Find(c => c.Id == configuration.Id); + + if (obsolete != default(IFeatureConfiguration)) + { + configurations.Remove(obsolete); + SaveToFile(configurations); + logger.Info($"Successfully removed {configuration} from backup."); + } + else + { + logger.Warn($"Could not delete {configuration} as it does not exists in backup!"); + } + } } - public IList GetConfigurations() + public IList GetAllConfigurations() { - return new List(); + lock (@lock) + { + return LoadFromFile(); + } + } + + public IList GetBy(Guid groupId) + { + lock (@lock) + { + return LoadFromFile().Where(c => c.GroupId == groupId).ToList(); + } } public void Save(IFeatureConfiguration configuration) { - + lock (@lock) + { + var configurations = LoadFromFile(); + + configurations.Add(configuration); + SaveToFile(configurations); + logger.Info($"Successfully added {configuration} to backup."); + } + } + + private void SaveToFile(List configurations) + { + try + { + logger.Debug($"Attempting to save backup data to '{filePath}'..."); + + using (var stream = File.Open(filePath, FileMode.Create)) + { + new BinaryFormatter().Serialize(stream, configurations); + } + + logger.Debug($"Successfully saved {configurations.Count} items."); + } + catch (Exception e) + { + logger.Error($"Failed to save backup data to '{filePath}'!", e); + } + } + + private List LoadFromFile() + { + var configurations = new List(); + + try + { + if (File.Exists(filePath)) + { + var context = new StreamingContext(StreamingContextStates.All, logger); + + logger.Debug($"Attempting to load backup data from '{filePath}'..."); + + using (var stream = File.Open(filePath, FileMode.Open)) + { + configurations = (List) new BinaryFormatter(null, context).Deserialize(stream); + } + + logger.Debug($"Backup data successfully loaded, found {configurations.Count} items."); + } + else + { + logger.Debug($"No backup data found under '{filePath}'."); + } + } + catch (Exception e) + { + logger.Error($"Failed to load backup data from '{filePath}'!", e); + } + + return configurations; } } } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs b/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs index 304120e5..c3e9d0d2 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using SafeExamBrowser.Contracts.Lockdown; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Lockdown.FeatureConfigurations; @@ -21,64 +22,64 @@ namespace SafeExamBrowser.Lockdown this.logger = logger; } - public IFeatureConfiguration CreateChromeNotificationConfiguration() + public IFeatureConfiguration CreateChromeNotificationConfiguration(Guid groupId) { - return new ChromeNotificationConfiguration(); + return new ChromeNotificationConfiguration(groupId, logger.CloneFor(nameof(ChromeNotificationConfiguration))); } - public IFeatureConfiguration CreateEaseOfAccessConfiguration() + public IFeatureConfiguration CreateEaseOfAccessConfiguration(Guid groupId) { - return new EaseOfAccessConfiguration(); + return new EaseOfAccessConfiguration(groupId, logger.CloneFor(nameof(EaseOfAccessConfiguration))); } - public IFeatureConfiguration CreateNetworkOptionsConfiguration() + public IFeatureConfiguration CreateNetworkOptionsConfiguration(Guid groupId) { - return new NetworkOptionsConfiguration(); + return new NetworkOptionsConfiguration(groupId, logger.CloneFor(nameof(NetworkOptionsConfiguration))); } - public IFeatureConfiguration CreatePasswordChangeConfiguration() + public IFeatureConfiguration CreatePasswordChangeConfiguration(Guid groupId) { - return new PasswordChangeConfiguration(); + return new PasswordChangeConfiguration(groupId, logger.CloneFor(nameof(PasswordChangeConfiguration))); } - public IFeatureConfiguration CreatePowerOptionsConfiguration() + public IFeatureConfiguration CreatePowerOptionsConfiguration(Guid groupId) { - return new PowerOptionsConfiguration(); + return new PowerOptionsConfiguration(groupId, logger.CloneFor(nameof(PowerOptionsConfiguration))); } - public IFeatureConfiguration CreateRemoteConnectionConfiguration() + public IFeatureConfiguration CreateRemoteConnectionConfiguration(Guid groupId) { - return new RemoteConnectionConfiguration(); + return new RemoteConnectionConfiguration(groupId, logger.CloneFor(nameof(RemoteConnectionConfiguration))); } - public IFeatureConfiguration CreateSignoutConfiguration() + public IFeatureConfiguration CreateSignoutConfiguration(Guid groupId) { - return new SignoutConfiguration(); + return new SignoutConfiguration(groupId, logger.CloneFor(nameof(SignoutConfiguration))); } - public IFeatureConfiguration CreateTaskManagerConfiguration() + public IFeatureConfiguration CreateTaskManagerConfiguration(Guid groupId) { - return new TaskManagerConfiguration(); + return new TaskManagerConfiguration(groupId, logger.CloneFor(nameof(TaskManagerConfiguration))); } - public IFeatureConfiguration CreateUserLockConfiguration() + public IFeatureConfiguration CreateUserLockConfiguration(Guid groupId) { - return new UserLockConfiguration(); + return new UserLockConfiguration(groupId, logger.CloneFor(nameof(UserLockConfiguration))); } - public IFeatureConfiguration CreateUserSwitchConfiguration() + public IFeatureConfiguration CreateUserSwitchConfiguration(Guid groupId) { - return new UserSwitchConfiguration(); + return new UserSwitchConfiguration(groupId, logger.CloneFor(nameof(UserSwitchConfiguration))); } - public IFeatureConfiguration CreateVmwareOverlayConfiguration() + public IFeatureConfiguration CreateVmwareOverlayConfiguration(Guid groupId) { - return new VmwareOverlayConfiguration(); + return new VmwareOverlayConfiguration(groupId, logger.CloneFor(nameof(VmwareOverlayConfiguration))); } - public IFeatureConfiguration CreateWindowsUpdateConfiguration() + public IFeatureConfiguration CreateWindowsUpdateConfiguration(Guid groupId) { - return new WindowsUpdateConfiguration(); + return new WindowsUpdateConfiguration(groupId, logger.CloneFor(nameof(WindowsUpdateConfiguration))); } } } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/ChromeNotificationConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/ChromeNotificationConfiguration.cs index cae32eea..490af30c 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/ChromeNotificationConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/ChromeNotificationConfiguration.cs @@ -6,30 +6,36 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class ChromeNotificationConfiguration : IFeatureConfiguration + [Serializable] + internal class ChromeNotificationConfiguration : FeatureConfiguration { - public void DisableFeature() + public ChromeNotificationConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) { - } - public void EnableFeature() + public override void DisableFeature() { - + logger.Info("Disabling..."); } - public void Monitor() + public override void EnableFeature() { - + logger.Info("Enabling..."); } - public void Restore() + public override void Monitor() { - + logger.Info("Monitoring..."); + } + + public override void Restore() + { + logger.Info("Restoring..."); } } } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/EaseOfAccessConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/EaseOfAccessConfiguration.cs index 97ca0d01..3b876d95 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/EaseOfAccessConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/EaseOfAccessConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class EaseOfAccessConfiguration : IFeatureConfiguration + [Serializable] + internal class EaseOfAccessConfiguration : FeatureConfiguration { - public void DisableFeature() + public EaseOfAccessConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs new file mode 100644 index 00000000..63e00ddd --- /dev/null +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Runtime.Serialization; +using SafeExamBrowser.Contracts.Lockdown; +using SafeExamBrowser.Contracts.Logging; + +namespace SafeExamBrowser.Lockdown.FeatureConfigurations +{ + [Serializable] + internal abstract class FeatureConfiguration : IFeatureConfiguration + { + [NonSerialized] + protected ILogger logger; + + public Guid Id { get; } + public Guid GroupId { get; } + + public FeatureConfiguration(Guid groupId, ILogger logger) + { + this.GroupId = groupId; + this.Id = Guid.NewGuid(); + this.logger = logger; + } + + public abstract void DisableFeature(); + public abstract void EnableFeature(); + public abstract void Monitor(); + public abstract void Restore(); + + public override string ToString() + { + return $"{GetType().Name} ({Id})"; + } + + [OnDeserialized] + private void OnDeserializedMethod(StreamingContext context) + { + logger = (context.Context as IModuleLogger).CloneFor(GetType().Name); + } + } +} diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/NetworkOptionsConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/NetworkOptionsConfiguration.cs index 69732113..eedb2258 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/NetworkOptionsConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/NetworkOptionsConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class NetworkOptionsConfiguration : IFeatureConfiguration + [Serializable] + internal class NetworkOptionsConfiguration : FeatureConfiguration { - public void DisableFeature() + public NetworkOptionsConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/PasswordChangeConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/PasswordChangeConfiguration.cs index 32f8081c..f8051df9 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/PasswordChangeConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/PasswordChangeConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class PasswordChangeConfiguration : IFeatureConfiguration + [Serializable] + internal class PasswordChangeConfiguration : FeatureConfiguration { - public void DisableFeature() + public PasswordChangeConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/PowerOptionsConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/PowerOptionsConfiguration.cs index da9391f8..f7be1c5d 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/PowerOptionsConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/PowerOptionsConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class PowerOptionsConfiguration : IFeatureConfiguration + [Serializable] + internal class PowerOptionsConfiguration : FeatureConfiguration { - public void DisableFeature() + public PowerOptionsConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RemoteConnectionConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RemoteConnectionConfiguration.cs index f5ba59cc..e1b15e0c 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RemoteConnectionConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RemoteConnectionConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class RemoteConnectionConfiguration : IFeatureConfiguration + [Serializable] + internal class RemoteConnectionConfiguration : FeatureConfiguration { - public void DisableFeature() + public RemoteConnectionConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/SignoutConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/SignoutConfiguration.cs index d225acca..43d78ea0 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/SignoutConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/SignoutConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class SignoutConfiguration : IFeatureConfiguration + [Serializable] + internal class SignoutConfiguration : FeatureConfiguration { - public void DisableFeature() + public SignoutConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/TaskManagerConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/TaskManagerConfiguration.cs index 1bda3ab0..960ef92f 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/TaskManagerConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/TaskManagerConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class TaskManagerConfiguration : IFeatureConfiguration + [Serializable] + internal class TaskManagerConfiguration : FeatureConfiguration { - public void DisableFeature() + public TaskManagerConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/UserLockConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/UserLockConfiguration.cs index bb65bc96..03dd2578 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/UserLockConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/UserLockConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class UserLockConfiguration : IFeatureConfiguration + [Serializable] + internal class UserLockConfiguration : FeatureConfiguration { - public void DisableFeature() + public UserLockConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/UserSwitchConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/UserSwitchConfiguration.cs index 041028d4..602dbfbf 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/UserSwitchConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/UserSwitchConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class UserSwitchConfiguration : IFeatureConfiguration + [Serializable] + internal class UserSwitchConfiguration : FeatureConfiguration { - public void DisableFeature() + public UserSwitchConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/VmwareOverlayConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/VmwareOverlayConfiguration.cs index a1ff38d7..55454767 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/VmwareOverlayConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/VmwareOverlayConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class VmwareOverlayConfiguration : IFeatureConfiguration + [Serializable] + internal class VmwareOverlayConfiguration : FeatureConfiguration { - public void DisableFeature() + public VmwareOverlayConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/WindowsUpdateConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/WindowsUpdateConfiguration.cs index 82b5afc4..b89b4fbb 100644 --- a/SafeExamBrowser.Lockdown/FeatureConfigurations/WindowsUpdateConfiguration.cs +++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/WindowsUpdateConfiguration.cs @@ -6,28 +6,34 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.Lockdown; +using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Lockdown.FeatureConfigurations { - internal class WindowsUpdateConfiguration : IFeatureConfiguration + [Serializable] + internal class WindowsUpdateConfiguration : FeatureConfiguration { - public void DisableFeature() + public WindowsUpdateConfiguration(Guid groupId, ILogger logger) : base(groupId, logger) + { + } + + public override void DisableFeature() { } - public void EnableFeature() + public override void EnableFeature() { } - public void Monitor() + public override void Monitor() { } - public void Restore() + public override void Restore() { } diff --git a/SafeExamBrowser.Lockdown/SafeExamBrowser.Lockdown.csproj b/SafeExamBrowser.Lockdown/SafeExamBrowser.Lockdown.csproj index 63e5862c..80bac0d4 100644 --- a/SafeExamBrowser.Lockdown/SafeExamBrowser.Lockdown.csproj +++ b/SafeExamBrowser.Lockdown/SafeExamBrowser.Lockdown.csproj @@ -53,9 +53,11 @@ + + diff --git a/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs b/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs index 07ca7972..56f881d7 100644 --- a/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs +++ b/SafeExamBrowser.Service.UnitTests/Operations/SessionInitializationOperationTests.cs @@ -14,6 +14,7 @@ using Moq; using SafeExamBrowser.Contracts.Communication.Hosts; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Core.OperationModel; +using SafeExamBrowser.Contracts.Lockdown; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Service.Operations; @@ -22,6 +23,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations [TestClass] public class SessionInitializationOperationTests { + private Mock autoRestoreMechanism; private Mock logger; private Mock> logWriterFactory; private Mock serviceHost; @@ -32,6 +34,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations [TestInitialize] public void Initialize() { + autoRestoreMechanism = new Mock(); logger = new Mock(); logWriterFactory = new Mock>(); serviceHost = new Mock(); @@ -40,6 +43,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations logWriterFactory.Setup(f => f.Invoke(It.IsAny())).Returns(new Mock().Object); serviceEventFactory.Setup(f => f.Invoke(It.IsAny())).Returns(new EventStub()); + sessionContext.AutoRestoreMechanism = autoRestoreMechanism.Object; sessionContext.Configuration = new ServiceConfiguration { AppConfig = new AppConfig { ServiceEventName = $"{nameof(SafeExamBrowser)}-{nameof(SessionInitializationOperationTests)}" } @@ -74,18 +78,12 @@ namespace SafeExamBrowser.Service.UnitTests.Operations } [TestMethod] - public void Revert_MustSetServiceEvent() + public void Perform_MustStopAutoRestoreMechanism() { - sessionContext.ServiceEvent = new EventWaitHandle(false, EventResetMode.AutoReset); - - var wasSet = false; - var task = Task.Run(() => wasSet = sessionContext.ServiceEvent.WaitOne(1000)); - var result = sut.Revert(); - - task.Wait(); + var result = sut.Perform(); + autoRestoreMechanism.Verify(m => m.Stop(), Times.Once); Assert.AreEqual(OperationResult.Success, result); - Assert.IsTrue(wasSet); } [TestMethod] @@ -110,5 +108,29 @@ namespace SafeExamBrowser.Service.UnitTests.Operations serviceHost.VerifySet(h => h.AllowConnection = true, Times.Once); Assert.AreEqual(OperationResult.Success, result); } + + [TestMethod] + public void Revert_MustSetServiceEvent() + { + sessionContext.ServiceEvent = new EventWaitHandle(false, EventResetMode.AutoReset); + + var wasSet = false; + var task = Task.Run(() => wasSet = sessionContext.ServiceEvent.WaitOne(1000)); + var result = sut.Revert(); + + task.Wait(); + + Assert.AreEqual(OperationResult.Success, result); + Assert.IsTrue(wasSet); + } + + [TestMethod] + public void Revert_MustStartAutoRestoreMechanism() + { + var result = sut.Revert(); + + autoRestoreMechanism.Verify(m => m.Start(), Times.Once); + Assert.AreEqual(OperationResult.Success, result); + } } } diff --git a/SafeExamBrowser.Service/CompositionRoot.cs b/SafeExamBrowser.Service/CompositionRoot.cs index 189361ab..d391edca 100644 --- a/SafeExamBrowser.Service/CompositionRoot.cs +++ b/SafeExamBrowser.Service/CompositionRoot.cs @@ -14,6 +14,7 @@ using System.Security.Principal; using System.Threading; using SafeExamBrowser.Communication.Hosts; using SafeExamBrowser.Communication.Proxies; +using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Core.OperationModel; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Service; @@ -34,21 +35,23 @@ namespace SafeExamBrowser.Service internal void BuildObjectGraph() { - const string SERVICE_ADDRESS = "net.pipe://localhost/safeexambrowser/service"; const int FIVE_SECONDS = 5000; + var backupFile = BuildBackupFilePath(); InitializeLogging(); - var featureBackup = new FeatureConfigurationBackup(new ModuleLogger(logger, nameof(FeatureConfigurationBackup))); + var featureBackup = new FeatureConfigurationBackup(backupFile, new ModuleLogger(logger, nameof(FeatureConfigurationBackup))); var featureFactory = new FeatureConfigurationFactory(new ModuleLogger(logger, nameof(FeatureConfigurationFactory))); var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ProxyFactory))); - var serviceHost = new ServiceHost(SERVICE_ADDRESS, new HostObjectFactory(), new ModuleLogger(logger, nameof(ServiceHost)), FIVE_SECONDS); + var serviceHost = new ServiceHost(AppConfig.SERVICE_ADDRESS, new HostObjectFactory(), new ModuleLogger(logger, nameof(ServiceHost)), FIVE_SECONDS); var sessionContext = new SessionContext(); var bootstrapOperations = new Queue(); var sessionOperations = new Queue(); - bootstrapOperations.Enqueue(new RestoreOperation(logger)); + sessionContext.AutoRestoreMechanism = new AutoRestoreMechanism(featureBackup); + + bootstrapOperations.Enqueue(new RestoreOperation(featureBackup, logger, sessionContext)); bootstrapOperations.Enqueue(new CommunicationHostOperation(serviceHost, logger)); bootstrapOperations.Enqueue(new ServiceEventCleanupOperation(logger, sessionContext)); @@ -62,6 +65,14 @@ namespace SafeExamBrowser.Service ServiceController = new ServiceController(logger, bootstrapSequence, sessionSequence, serviceHost, sessionContext); } + private string BuildBackupFilePath() + { + var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), nameof(SafeExamBrowser)); + var filePath = Path.Combine(appDataFolder, AppConfig.BACKUP_FILE_NAME); + + return filePath; + } + internal void LogStartupInformation() { logger.Log($"# Service started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); diff --git a/SafeExamBrowser.Service/Operations/LockdownOperation.cs b/SafeExamBrowser.Service/Operations/LockdownOperation.cs index a84e001a..e7bc5808 100644 --- a/SafeExamBrowser.Service/Operations/LockdownOperation.cs +++ b/SafeExamBrowser.Service/Operations/LockdownOperation.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using SafeExamBrowser.Contracts.Core.OperationModel; using SafeExamBrowser.Contracts.Lockdown; using SafeExamBrowser.Contracts.Logging; @@ -17,6 +18,7 @@ namespace SafeExamBrowser.Service.Operations private IFeatureConfigurationBackup backup; private IFeatureConfigurationFactory factory; private ILogger logger; + private Guid groupId; public LockdownOperation( IFeatureConfigurationBackup backup, @@ -31,18 +33,21 @@ namespace SafeExamBrowser.Service.Operations public override OperationResult Perform() { - var chromeNotification = factory.CreateChromeNotificationConfiguration(); - var easeOfAccess = factory.CreateEaseOfAccessConfiguration(); - var networkOptions = factory.CreateNetworkOptionsConfiguration(); - var passwordChange = factory.CreatePasswordChangeConfiguration(); - var powerOptions = factory.CreatePowerOptionsConfiguration(); - var remoteConnection = factory.CreateRemoteConnectionConfiguration(); - var signout = factory.CreateSignoutConfiguration(); - var taskManager = factory.CreateTaskManagerConfiguration(); - var userLock = factory.CreateUserLockConfiguration(); - var userSwitch = factory.CreateUserSwitchConfiguration(); - var vmwareOverlay = factory.CreateVmwareOverlayConfiguration(); - var windowsUpdate = factory.CreateWindowsUpdateConfiguration(); + groupId = Guid.NewGuid(); + logger.Info($"Attempting to perform lockdown (feature configuration group: {groupId})..."); + + var chromeNotification = factory.CreateChromeNotificationConfiguration(groupId); + var easeOfAccess = factory.CreateEaseOfAccessConfiguration(groupId); + var networkOptions = factory.CreateNetworkOptionsConfiguration(groupId); + var passwordChange = factory.CreatePasswordChangeConfiguration(groupId); + var powerOptions = factory.CreatePowerOptionsConfiguration(groupId); + var remoteConnection = factory.CreateRemoteConnectionConfiguration(groupId); + var signout = factory.CreateSignoutConfiguration(groupId); + var taskManager = factory.CreateTaskManagerConfiguration(groupId); + var userLock = factory.CreateUserLockConfiguration(groupId); + var userSwitch = factory.CreateUserSwitchConfiguration(groupId); + var vmwareOverlay = factory.CreateVmwareOverlayConfiguration(groupId); + var windowsUpdate = factory.CreateWindowsUpdateConfiguration(groupId); SetConfiguration(chromeNotification, Context.Configuration.Settings.Service.DisableChromeNotifications); SetConfiguration(easeOfAccess, Context.Configuration.Settings.Service.DisableEaseOfAccessOptions); @@ -57,12 +62,16 @@ namespace SafeExamBrowser.Service.Operations SetConfiguration(vmwareOverlay, Context.Configuration.Settings.Service.DisableVmwareOverlay); SetConfiguration(windowsUpdate, Context.Configuration.Settings.Service.DisableWindowsUpdate); + logger.Info("Lockdown successful."); + return OperationResult.Success; } public override OperationResult Revert() { - var configurations = backup.GetConfigurations(); + logger.Info($"Attempting to revert lockdown (feature configuration group: {groupId})..."); + + var configurations = backup.GetBy(groupId); foreach (var configuration in configurations) { @@ -70,6 +79,8 @@ namespace SafeExamBrowser.Service.Operations backup.Delete(configuration); } + logger.Info("Lockdown reversion successful."); + return OperationResult.Success; } diff --git a/SafeExamBrowser.Service/Operations/RestoreOperation.cs b/SafeExamBrowser.Service/Operations/RestoreOperation.cs index 1ec3f861..b1cd1518 100644 --- a/SafeExamBrowser.Service/Operations/RestoreOperation.cs +++ b/SafeExamBrowser.Service/Operations/RestoreOperation.cs @@ -8,32 +8,40 @@ using SafeExamBrowser.Contracts.Core.OperationModel; using SafeExamBrowser.Contracts.Core.OperationModel.Events; +using SafeExamBrowser.Contracts.Lockdown; using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Service.Operations { internal class RestoreOperation : IOperation { + private readonly IFeatureConfigurationBackup backup; private ILogger logger; + private readonly SessionContext sessionContext; public event ActionRequiredEventHandler ActionRequired { add { } remove { } } public event StatusChangedEventHandler StatusChanged { add { } remove { } } - public RestoreOperation(ILogger logger) + public RestoreOperation(IFeatureConfigurationBackup backup, ILogger logger, SessionContext sessionContext) { + this.backup = backup; this.logger = logger; + this.sessionContext = sessionContext; } public OperationResult Perform() { - // TODO: Must not delay startup! If restore does not succeed on first attempt, try again in separate thread! - // -> Ensure session cannot be started until values are restored or alike! + logger.Info("Starting auto-restore mechanism..."); + sessionContext.AutoRestoreMechanism.Start(); return OperationResult.Success; } public OperationResult Revert() { + logger.Info("Stopping auto-restore mechanism..."); + sessionContext.AutoRestoreMechanism.Stop(); + return OperationResult.Success; } } diff --git a/SafeExamBrowser.Service/Operations/SessionInitializationOperation.cs b/SafeExamBrowser.Service/Operations/SessionInitializationOperation.cs index 6404c81c..3fe4747e 100644 --- a/SafeExamBrowser.Service/Operations/SessionInitializationOperation.cs +++ b/SafeExamBrowser.Service/Operations/SessionInitializationOperation.cs @@ -40,12 +40,16 @@ namespace SafeExamBrowser.Service.Operations InitializeSessionWriter(); logger.Info("Initializing new session..."); - - serviceHost.AllowConnection = false; logger.Info($" -> Client-ID: {Context.Configuration.AppConfig.ClientId}"); logger.Info($" -> Runtime-ID: {Context.Configuration.AppConfig.RuntimeId}"); logger.Info($" -> Session-ID: {Context.Configuration.SessionId}"); + logger.Info("Stopping auto-restore mechanism..."); + Context.AutoRestoreMechanism.Stop(); + + logger.Info("Disabling service host..."); + serviceHost.AllowConnection = false; + InitializeServiceEvent(); return OperationResult.Success; @@ -71,11 +75,17 @@ namespace SafeExamBrowser.Service.Operations } } - Context.Configuration = null; - logger.Unsubscribe(sessionWriter); - sessionWriter = null; + logger.Info("Starting auto-restore mechanism..."); + Context.AutoRestoreMechanism.Start(); + + logger.Info("Enabling service host..."); serviceHost.AllowConnection = true; + logger.Info("Clearing session data..."); + Context.Configuration = null; + + FinalizeSessionWriter(); + return success ? OperationResult.Success : OperationResult.Failed; } @@ -97,6 +107,14 @@ namespace SafeExamBrowser.Service.Operations { sessionWriter = logWriterFactory.Invoke(Context.Configuration.AppConfig.ServiceLogFilePath); logger.Subscribe(sessionWriter); + logger.Debug($"Created session log file {Context.Configuration.AppConfig.ServiceLogFilePath}."); + } + + private void FinalizeSessionWriter() + { + logger.Debug("Closed session log file."); + logger.Unsubscribe(sessionWriter); + sessionWriter = null; } } } diff --git a/SafeExamBrowser.Service/SessionContext.cs b/SafeExamBrowser.Service/SessionContext.cs index f6716a8e..33ecb318 100644 --- a/SafeExamBrowser.Service/SessionContext.cs +++ b/SafeExamBrowser.Service/SessionContext.cs @@ -8,6 +8,7 @@ using System.Threading; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Lockdown; namespace SafeExamBrowser.Service { @@ -16,6 +17,11 @@ namespace SafeExamBrowser.Service /// internal class SessionContext { + /// + /// The mechanism trying to restore all changes after an application or system failure. + /// + internal IAutoRestoreMechanism AutoRestoreMechanism { get; set; } + /// /// The configuration of the currently active session. ///