SEBWIN-309: Implemented scaffolding for Configuration Key.
This commit is contained in:
parent
45e1b001e3
commit
5e131289b0
8 changed files with 188 additions and 8 deletions
|
@ -33,7 +33,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
this.filter = filter;
|
||||
this.logger = logger;
|
||||
this.settings = settings;
|
||||
this.resourceHandler = new ResourceHandler(appConfig, settings.Filter, filter, logger, text);
|
||||
this.resourceHandler = new ResourceHandler(appConfig, settings, filter, logger, text);
|
||||
}
|
||||
|
||||
protected override bool GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
|
||||
|
|
|
@ -10,30 +10,34 @@ using System;
|
|||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Contracts.Filters;
|
||||
using SafeExamBrowser.Browser.Filters;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Browser.Filter;
|
||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Handlers
|
||||
{
|
||||
internal class ResourceHandler : CefSharp.Handler.ResourceRequestHandler
|
||||
{
|
||||
private AppConfig appConfig;
|
||||
private FilterSettings settings;
|
||||
private SHA256Managed algorithm;
|
||||
private BrowserSettings settings;
|
||||
private ILogger logger;
|
||||
private IRequestFilter filter;
|
||||
private IResourceHandler contentHandler;
|
||||
private IResourceHandler pageHandler;
|
||||
private IText text;
|
||||
|
||||
internal ResourceHandler(AppConfig appConfig, FilterSettings settings, IRequestFilter filter, ILogger logger, IText text)
|
||||
internal ResourceHandler(AppConfig appConfig, BrowserSettings settings, IRequestFilter filter, ILogger logger, IText text)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.algorithm = new SHA256Managed();
|
||||
this.filter = filter;
|
||||
this.logger = logger;
|
||||
this.settings = settings;
|
||||
|
@ -52,14 +56,19 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
|
||||
protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
|
||||
{
|
||||
if (IsMailtoUrl(request.Url))
|
||||
{
|
||||
return CefReturnValue.Cancel;
|
||||
}
|
||||
|
||||
// TODO: CEF does not yet support intercepting requests from service workers, thus the user agent must be statically set at browser
|
||||
// startup for now. Once CEF has full support of service workers, the static user agent should be removed and the method below
|
||||
// reactivated. See https://bitbucket.org/chromiumembedded/cef/issues/2622 for the current status of development.
|
||||
// AppendCustomUserAgent(request);
|
||||
|
||||
if (IsMailtoUrl(request.Url))
|
||||
if (settings.SendCustomHeaders)
|
||||
{
|
||||
return CefReturnValue.Cancel;
|
||||
AppendCustomHeaders(request);
|
||||
}
|
||||
|
||||
ReplaceSebScheme(request);
|
||||
|
@ -76,9 +85,22 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
request.Headers = headers;
|
||||
}
|
||||
|
||||
private void AppendCustomHeaders(IRequest request)
|
||||
{
|
||||
var headers = new NameValueCollection(request.Headers);
|
||||
var urlWithoutFragment = request.Url.Split('#')[0];
|
||||
var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + settings.HashValue));
|
||||
var configurationKey = BitConverter.ToString(hash).Replace("-", string.Empty);
|
||||
|
||||
// TODO: Implement Browser Exam Key calculation.
|
||||
// headers["X-SafeExamBrowser-RequestHash"] = ...;
|
||||
headers["X-SafeExamBrowser-ConfigKeyHash"] = configurationKey;
|
||||
request.Headers = headers;
|
||||
}
|
||||
|
||||
private bool Block(IRequest request)
|
||||
{
|
||||
if (settings.ProcessContentRequests)
|
||||
if (settings.Filter.ProcessContentRequests)
|
||||
{
|
||||
var result = filter.Process(new Request { Url = request.Url });
|
||||
var block = result == FilterResult.Block;
|
||||
|
|
|
@ -96,6 +96,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
|
|||
case Keys.Browser.ShowToolbar:
|
||||
MapShowToolbar(settings, value);
|
||||
break;
|
||||
case Keys.Browser.SendCustomHeaders:
|
||||
MapSendCustomHeaders(settings, value);
|
||||
break;
|
||||
case Keys.Browser.StartUrl:
|
||||
MapStartUrl(settings, value);
|
||||
break;
|
||||
|
@ -275,6 +278,14 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
|
|||
}
|
||||
}
|
||||
|
||||
private void MapSendCustomHeaders(AppSettings settings, object value)
|
||||
{
|
||||
if (value is bool send)
|
||||
{
|
||||
settings.Browser.SendCustomHeaders = send;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapStartUrl(AppSettings settings, object value)
|
||||
{
|
||||
if (value is string url)
|
||||
|
|
131
SafeExamBrowser.Configuration/ConfigurationData/DataProcessor.cs
Normal file
131
SafeExamBrowser.Configuration/ConfigurationData/DataProcessor.cs
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using SafeExamBrowser.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||
{
|
||||
internal class DataProcessor
|
||||
{
|
||||
internal void Process(IDictionary<string, object> rawData, AppSettings settings)
|
||||
{
|
||||
CalculateHashValue(rawData, settings);
|
||||
}
|
||||
|
||||
private void CalculateHashValue(IDictionary<string, object> rawData, AppSettings settings)
|
||||
{
|
||||
using (var algorithm = new SHA256Managed())
|
||||
using (var stream = new MemoryStream())
|
||||
using (var writer = new StreamWriter(stream, Encoding.UTF8))
|
||||
{
|
||||
Serialize(rawData, writer);
|
||||
writer.Flush();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var hash = algorithm.ComputeHash(stream);
|
||||
var hashString = BitConverter.ToString(hash).Replace("-", string.Empty);
|
||||
|
||||
settings.Browser.HashValue = hashString;
|
||||
}
|
||||
}
|
||||
|
||||
private void Serialize(IDictionary<string, object> dictionary, StreamWriter stream)
|
||||
{
|
||||
var orderedByKey = dictionary.OrderBy(d => d.Key, StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
stream.Write('{');
|
||||
|
||||
foreach (var kvp in orderedByKey)
|
||||
{
|
||||
var process = true;
|
||||
|
||||
process &= !kvp.Key.Equals(Keys.General.OriginatorVersion, StringComparison.OrdinalIgnoreCase);
|
||||
process &= !(kvp.Value is IDictionary<string, object> d) || d.Any();
|
||||
|
||||
if (process)
|
||||
{
|
||||
stream.Write('"');
|
||||
stream.Write(kvp.Key);
|
||||
stream.Write('"');
|
||||
stream.Write(':');
|
||||
Serialize(kvp.Value, stream);
|
||||
|
||||
if (kvp.Key != orderedByKey.Last().Key)
|
||||
{
|
||||
stream.Write(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream.Write('}');
|
||||
}
|
||||
|
||||
private void Serialize(IList<object> list, StreamWriter stream)
|
||||
{
|
||||
stream.Write('[');
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
Serialize(item, stream);
|
||||
|
||||
if (item != list.Last())
|
||||
{
|
||||
stream.Write(',');
|
||||
}
|
||||
}
|
||||
|
||||
stream.Write(']');
|
||||
}
|
||||
|
||||
private void Serialize(object value, StreamWriter stream)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case IDictionary<string, object> dictionary:
|
||||
Serialize(dictionary, stream);
|
||||
break;
|
||||
case IList<object> list:
|
||||
Serialize(list, stream);
|
||||
break;
|
||||
case byte[] data:
|
||||
stream.Write('"');
|
||||
stream.Write(Convert.ToBase64String(data));
|
||||
stream.Write('"');
|
||||
break;
|
||||
case DateTime date:
|
||||
stream.Write(date.ToString("o"));
|
||||
break;
|
||||
case bool boolean:
|
||||
stream.Write(boolean.ToString().ToLower());
|
||||
break;
|
||||
case int integer:
|
||||
stream.Write(integer.ToString(NumberFormatInfo.InvariantInfo));
|
||||
break;
|
||||
case double number:
|
||||
stream.Write(number.ToString(NumberFormatInfo.InvariantInfo));
|
||||
break;
|
||||
case string text:
|
||||
stream.Write('"');
|
||||
stream.Write(text);
|
||||
stream.Write('"');
|
||||
break;
|
||||
case null:
|
||||
stream.Write('"');
|
||||
stream.Write('"');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
internal const string QuitUrl = "quitURL";
|
||||
internal const string QuitUrlConfirmation = "quitURLConfirm";
|
||||
internal const string ShowToolbar = "enableBrowserWindowToolbar";
|
||||
internal const string SendCustomHeaders = "sendBrowserExamKey";
|
||||
internal const string StartUrl = "startURL";
|
||||
internal const string UserAgentModeDesktop = "browserUserAgentWinDesktopMode";
|
||||
internal const string UserAgentModeMobile = "browserUserAgentWinTouchMode";
|
||||
|
@ -152,6 +153,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
{
|
||||
internal const string AllowApplicationLog = "allowApplicationLog";
|
||||
internal const string LogLevel = "logLevel";
|
||||
internal const string OriginatorVersion = "originatorVersion";
|
||||
}
|
||||
|
||||
internal static class Keyboard
|
||||
|
|
|
@ -15,8 +15,8 @@ using SafeExamBrowser.Configuration.Contracts;
|
|||
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||
using SafeExamBrowser.Configuration.Contracts.DataFormats;
|
||||
using SafeExamBrowser.Configuration.Contracts.DataResources;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
|
@ -26,6 +26,7 @@ namespace SafeExamBrowser.Configuration
|
|||
private IList<IDataParser> dataParsers;
|
||||
private IList<IDataSerializer> dataSerializers;
|
||||
private DataMapper dataMapper;
|
||||
private DataProcessor dataProcessor;
|
||||
private DataValues dataValues;
|
||||
private IHashAlgorithm hashAlgorithm;
|
||||
private ILogger logger;
|
||||
|
@ -49,6 +50,7 @@ namespace SafeExamBrowser.Configuration
|
|||
dataParsers = new List<IDataParser>();
|
||||
dataSerializers = new List<IDataSerializer>();
|
||||
dataMapper = new DataMapper();
|
||||
dataProcessor = new DataProcessor();
|
||||
dataValues = new DataValues(executablePath, programBuild, programCopyright, programTitle, programVersion);
|
||||
resourceLoaders = new List<IResourceLoader>();
|
||||
resourceSavers = new List<IResourceSaver>();
|
||||
|
@ -144,6 +146,7 @@ namespace SafeExamBrowser.Configuration
|
|||
if (status == LoadStatus.Success)
|
||||
{
|
||||
dataMapper.MapRawDataToSettings(data, settings);
|
||||
dataProcessor.Process(data, settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<Compile Include="ConfigurationData\DataMapping\InputDataMapper.cs" />
|
||||
<Compile Include="ConfigurationData\DataMapping\SecurityDataMapper.cs" />
|
||||
<Compile Include="ConfigurationData\DataMapping\UserInterfaceDataMapper.cs" />
|
||||
<Compile Include="ConfigurationData\DataProcessor.cs" />
|
||||
<Compile Include="ConfigurationData\Keys.cs" />
|
||||
<Compile Include="ConfigurationData\DataValues.cs" />
|
||||
<Compile Include="Cryptography\CertificateStore.cs" />
|
||||
|
|
|
@ -51,6 +51,11 @@ namespace SafeExamBrowser.Settings.Browser
|
|||
/// </summary>
|
||||
public FilterSettings Filter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The hash value of the raw settings data, used for integrity checks with server applications (see also <see cref="SendCustomHeaders"/>).
|
||||
/// </summary>
|
||||
public string HashValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The settings to be used for the main browser window.
|
||||
/// </summary>
|
||||
|
@ -71,6 +76,11 @@ namespace SafeExamBrowser.Settings.Browser
|
|||
/// </summary>
|
||||
public string QuitUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether custom request headers (e.g. for integrity checks) are sent with every HTTP request.
|
||||
/// </summary>
|
||||
public bool SendCustomHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL with which the main browser window will be loaded.
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in a new issue