SEBWIN-301: Finished basic backup mechanism for service.

This commit is contained in:
dbuechel 2019-06-26 10:13:11 +02:00
parent b96bbfcd78
commit dd801245d2
30 changed files with 552 additions and 167 deletions

View file

@ -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();

View file

@ -16,6 +16,21 @@ namespace SafeExamBrowser.Contracts.Configuration
[Serializable]
public class AppConfig
{
/// <summary>
/// The name of the backup data file used by the service component.
/// </summary>
public const string BACKUP_FILE_NAME = "Backup.bin";
/// <summary>
/// The base address for all communication hosts of the application.
/// </summary>
public const string BASE_ADDRESS = "net.pipe://localhost/safeexambrowser";
/// <summary>
/// The communication address of the service component.
/// </summary>
public const string SERVICE_ADDRESS = BASE_ADDRESS + "/service";
/// <summary>
/// The file path of the local client configuration for the active user.
/// </summary>

View file

@ -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
{
/// <summary>
/// Defines a mechanism which tries to restore all changes saved in a <see cref="IFeatureConfigurationBackup"/>.
/// </summary>
public interface IAutoRestoreMechanism
{
/// <summary>
/// Starts the procedure.
/// </summary>
void Start();
/// <summary>
/// Stops the procedure.
/// </summary>
void Stop();
}
}

View file

@ -6,6 +6,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
namespace SafeExamBrowser.Contracts.Lockdown
{
/// <summary>
@ -13,6 +15,16 @@ namespace SafeExamBrowser.Contracts.Lockdown
/// </summary>
public interface IFeatureConfiguration
{
/// <summary>
/// The unique identifier of this feature configuration.
/// </summary>
Guid Id { get; }
/// <summary>
/// The identifier of the group of changes to which this feature configuration belongs.
/// </summary>
Guid GroupId { get; }
/// <summary>
/// Disables the feature.
/// </summary>
@ -29,7 +41,7 @@ namespace SafeExamBrowser.Contracts.Lockdown
void Monitor();
/// <summary>
/// Restores the feature to its initial configuration.
/// Restores the feature to its previous configuration (i.e. before it was enabled or disabled).
/// </summary>
void Restore();
}

View file

@ -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
/// </summary>
public interface IFeatureConfigurationBackup
{
/// <summary>
/// Deletes the given <see cref="IFeatureConfiguration"/> from the backup repository.
/// </summary>
void Delete(IFeatureConfiguration configuration);
/// <summary>
/// Gets all <see cref="IFeatureConfiguration"/> currently saved in the backup repository.
/// </summary>
IList<IFeatureConfiguration> GetConfigurations();
IList<IFeatureConfiguration> GetAllConfigurations();
/// <summary>
/// Gets all <see cref="IFeatureConfiguration"/> which are part of the given group.
/// </summary>
IList<IFeatureConfiguration> GetBy(Guid groupId);
/// <summary>
/// Saves the given <see cref="IFeatureConfiguration"/> in the backup repository.
/// </summary>
void Save(IFeatureConfiguration configuration);
/// <summary>
/// Deletes the given <see cref="IFeatureConfiguration"/> from the backup repository.
/// </summary>
void Delete(IFeatureConfiguration configuration);
}
}

View file

@ -6,6 +6,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
namespace SafeExamBrowser.Contracts.Lockdown
{
/// <summary>
@ -16,61 +18,61 @@ namespace SafeExamBrowser.Contracts.Lockdown
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control notifications of the Google Chrome browser.
/// </summary>
IFeatureConfiguration CreateChromeNotificationConfiguration();
IFeatureConfiguration CreateChromeNotificationConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the ease of access options on the security screen.
/// </summary>
IFeatureConfiguration CreateEaseOfAccessConfiguration();
IFeatureConfiguration CreateEaseOfAccessConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the network options on the security screen.
/// </summary>
IFeatureConfiguration CreateNetworkOptionsConfiguration();
IFeatureConfiguration CreateNetworkOptionsConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the option to change the password of a user account via the security screen.
/// </summary>
IFeatureConfiguration CreatePasswordChangeConfiguration();
IFeatureConfiguration CreatePasswordChangeConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the power options on the security screen.
/// </summary>
IFeatureConfiguration CreatePowerOptionsConfiguration();
IFeatureConfiguration CreatePowerOptionsConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control remote desktop connections.
/// </summary>
IFeatureConfiguration CreateRemoteConnectionConfiguration();
IFeatureConfiguration CreateRemoteConnectionConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the option to sign out out via security screen.
/// </summary>
IFeatureConfiguration CreateSignoutConfiguration();
IFeatureConfiguration CreateSignoutConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the task manager of Windows.
/// </summary>
IFeatureConfiguration CreateTaskManagerConfiguration();
IFeatureConfiguration CreateTaskManagerConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the option to lock the computer via the security screen.
/// </summary>
IFeatureConfiguration CreateUserLockConfiguration();
IFeatureConfiguration CreateUserLockConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the option to switch to another user account via the security screen.
/// </summary>
IFeatureConfiguration CreateUserSwitchConfiguration();
IFeatureConfiguration CreateUserSwitchConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control the user interface overlay for VMware clients.
/// </summary>
IFeatureConfiguration CreateVmwareOverlayConfiguration();
IFeatureConfiguration CreateVmwareOverlayConfiguration(Guid groupId);
/// <summary>
/// Creates an <see cref="IFeatureConfiguration"/> to control Windows Update.
/// </summary>
IFeatureConfiguration CreateWindowsUpdateConfiguration();
IFeatureConfiguration CreateWindowsUpdateConfiguration(Guid groupId);
}
}

View file

@ -92,6 +92,7 @@
<Compile Include="Applications\Events\NameChangedEventHandler.cs" />
<Compile Include="Applications\IApplicationController.cs" />
<Compile Include="Applications\InstanceIdentifier.cs" />
<Compile Include="Lockdown\IAutoRestoreMechanism.cs" />
<Compile Include="Lockdown\IFeatureConfiguration.cs" />
<Compile Include="Lockdown\IFeatureConfigurationBackup.cs" />
<Compile Include="Lockdown\IFeatureConfigurationFactory.cs" />

View file

@ -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()
{
}
}
}

View file

@ -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<IFeatureConfiguration> GetConfigurations()
public IList<IFeatureConfiguration> GetAllConfigurations()
{
return new List<IFeatureConfiguration>();
lock (@lock)
{
return LoadFromFile();
}
}
public IList<IFeatureConfiguration> 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<IFeatureConfiguration> 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<IFeatureConfiguration> LoadFromFile()
{
var configurations = new List<IFeatureConfiguration>();
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<IFeatureConfiguration>) 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;
}
}
}

View file

@ -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)));
}
}
}

View file

@ -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...");
}
}
}

View file

@ -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()
{
}

View file

@ -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);
}
}
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -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()
{
}

View file

@ -53,9 +53,11 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="AutoRestoreMechanism.cs" />
<Compile Include="FeatureConfigurationFactory.cs" />
<Compile Include="FeatureConfigurationBackup.cs" />
<Compile Include="FeatureConfigurations\ChromeNotificationConfiguration.cs" />
<Compile Include="FeatureConfigurations\FeatureConfiguration.cs" />
<Compile Include="FeatureConfigurations\TaskManagerConfiguration.cs" />
<Compile Include="FeatureConfigurations\EaseOfAccessConfiguration.cs" />
<Compile Include="FeatureConfigurations\NetworkOptionsConfiguration.cs" />

View file

@ -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<IAutoRestoreMechanism> autoRestoreMechanism;
private Mock<ILogger> logger;
private Mock<Func<string, ILogObserver>> logWriterFactory;
private Mock<IServiceHost> serviceHost;
@ -32,6 +34,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations
[TestInitialize]
public void Initialize()
{
autoRestoreMechanism = new Mock<IAutoRestoreMechanism>();
logger = new Mock<ILogger>();
logWriterFactory = new Mock<Func<string, ILogObserver>>();
serviceHost = new Mock<IServiceHost>();
@ -40,6 +43,7 @@ namespace SafeExamBrowser.Service.UnitTests.Operations
logWriterFactory.Setup(f => f.Invoke(It.IsAny<string>())).Returns(new Mock<ILogObserver>().Object);
serviceEventFactory.Setup(f => f.Invoke(It.IsAny<string>())).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);
}
}
}

View file

@ -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<IOperation>();
var sessionOperations = new Queue<IOperation>();
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")}");

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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
/// </summary>
internal class SessionContext
{
/// <summary>
/// The mechanism trying to restore all changes after an application or system failure.
/// </summary>
internal IAutoRestoreMechanism AutoRestoreMechanism { get; set; }
/// <summary>
/// The configuration of the currently active session.
/// </summary>