SEBWIN-442: Implemented mechanism to automatically select server exam via configuration.
This commit is contained in:
parent
1cf9d53121
commit
15be4cbaf7
8 changed files with 59 additions and 11 deletions
|
@ -49,18 +49,20 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustAppendCustomHeaders()
|
public void MustAppendCustomHeadersForSameDomain()
|
||||||
{
|
{
|
||||||
|
var browser = new Mock<IWebBrowser>();
|
||||||
var headers = default(NameValueCollection);
|
var headers = default(NameValueCollection);
|
||||||
var request = new Mock<IRequest>();
|
var request = new Mock<IRequest>();
|
||||||
|
|
||||||
|
browser.SetupGet(b => b.Address).Returns("http://www.host.org");
|
||||||
request.SetupGet(r => r.Headers).Returns(new NameValueCollection());
|
request.SetupGet(r => r.Headers).Returns(new NameValueCollection());
|
||||||
request.SetupGet(r => r.Url).Returns("http://www.host.org");
|
request.SetupGet(r => r.Url).Returns("http://www.host.org");
|
||||||
request.SetupSet(r => r.Headers = It.IsAny<NameValueCollection>()).Callback<NameValueCollection>((h) => headers = h);
|
request.SetupSet(r => r.Headers = It.IsAny<NameValueCollection>()).Callback<NameValueCollection>((h) => headers = h);
|
||||||
settings.SendConfigurationKey = true;
|
settings.SendConfigurationKey = true;
|
||||||
settings.SendExamKey = true;
|
settings.SendExamKey = true;
|
||||||
|
|
||||||
var result = sut.OnBeforeResourceLoad(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, Mock.Of<IRequestCallback>());
|
var result = sut.OnBeforeResourceLoad(browser.Object, Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, Mock.Of<IRequestCallback>());
|
||||||
|
|
||||||
request.VerifyGet(r => r.Headers, Times.AtLeastOnce);
|
request.VerifyGet(r => r.Headers, Times.AtLeastOnce);
|
||||||
request.VerifySet(r => r.Headers = It.IsAny<NameValueCollection>(), Times.AtLeastOnce);
|
request.VerifySet(r => r.Headers = It.IsAny<NameValueCollection>(), Times.AtLeastOnce);
|
||||||
|
@ -70,6 +72,30 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
||||||
Assert.IsNotNull(headers["X-SafeExamBrowser-RequestHash"]);
|
Assert.IsNotNull(headers["X-SafeExamBrowser-RequestHash"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MustNotAppendCustomHeadersForCrossDomain()
|
||||||
|
{
|
||||||
|
var browser = new Mock<IWebBrowser>();
|
||||||
|
var headers = new NameValueCollection();
|
||||||
|
var request = new Mock<IRequest>();
|
||||||
|
|
||||||
|
browser.SetupGet(b => b.Address).Returns("http://www.otherhost.org");
|
||||||
|
request.SetupGet(r => r.Headers).Returns(new NameValueCollection());
|
||||||
|
request.SetupGet(r => r.Url).Returns("http://www.host.org");
|
||||||
|
request.SetupSet(r => r.Headers = It.IsAny<NameValueCollection>()).Callback<NameValueCollection>((h) => headers = h);
|
||||||
|
settings.SendConfigurationKey = true;
|
||||||
|
settings.SendExamKey = true;
|
||||||
|
|
||||||
|
var result = sut.OnBeforeResourceLoad(browser.Object, Mock.Of<IBrowser>(), Mock.Of<IFrame>(), request.Object, Mock.Of<IRequestCallback>());
|
||||||
|
|
||||||
|
request.VerifyGet(r => r.Headers, Times.Never);
|
||||||
|
request.VerifySet(r => r.Headers = It.IsAny<NameValueCollection>(), Times.Never);
|
||||||
|
|
||||||
|
Assert.AreEqual(CefReturnValue.Continue, result);
|
||||||
|
Assert.IsNull(headers["X-SafeExamBrowser-ConfigKeyHash"]);
|
||||||
|
Assert.IsNull(headers["X-SafeExamBrowser-RequestHash"]);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustBlockMailToUrls()
|
public void MustBlockMailToUrls()
|
||||||
{
|
{
|
||||||
|
|
|
@ -114,14 +114,14 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
|
|
||||||
private void AppendCustomHeaders(IWebBrowser webBrowser, IRequest request)
|
private void AppendCustomHeaders(IWebBrowser webBrowser, IRequest request)
|
||||||
{
|
{
|
||||||
var headers = new NameValueCollection(request.Headers);
|
|
||||||
var urlWithoutFragment = request.Url.Split('#')[0];
|
|
||||||
|
|
||||||
Uri.TryCreate(webBrowser.Address, UriKind.Absolute, out var pageUrl);
|
Uri.TryCreate(webBrowser.Address, UriKind.Absolute, out var pageUrl);
|
||||||
Uri.TryCreate(request.Url, UriKind.Absolute, out var requestUrl);
|
Uri.TryCreate(request.Url, UriKind.Absolute, out var requestUrl);
|
||||||
|
|
||||||
if (pageUrl?.Host?.Equals(requestUrl?.Host) == true)
|
if (pageUrl?.Host?.Equals(requestUrl?.Host) == true)
|
||||||
{
|
{
|
||||||
|
var headers = new NameValueCollection(request.Headers);
|
||||||
|
var urlWithoutFragment = request.Url.Split('#')[0];
|
||||||
|
|
||||||
if (settings.SendConfigurationKey)
|
if (settings.SendConfigurationKey)
|
||||||
{
|
{
|
||||||
var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + settings.ConfigurationKey));
|
var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlWithoutFragment + settings.ConfigurationKey));
|
||||||
|
|
|
@ -60,6 +60,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
|
||||||
settings.Server.ClientSecret = secret;
|
settings.Server.ClientSecret = secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configuration.TryGetValue(Keys.Server.ExamId, out v) && v is string examId)
|
||||||
|
{
|
||||||
|
settings.Server.ExamId = examId;
|
||||||
|
}
|
||||||
|
|
||||||
if (configuration.TryGetValue(Keys.Server.Institution, out v) && v is string institution)
|
if (configuration.TryGetValue(Keys.Server.Institution, out v) && v is string institution)
|
||||||
{
|
{
|
||||||
settings.Server.Institution = institution;
|
settings.Server.Institution = institution;
|
||||||
|
|
|
@ -233,6 +233,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
internal const string ClientName = "clientName";
|
internal const string ClientName = "clientName";
|
||||||
internal const string ClientSecret = "clientSecret";
|
internal const string ClientSecret = "clientSecret";
|
||||||
internal const string Configuration = "sebServerConfiguration";
|
internal const string Configuration = "sebServerConfiguration";
|
||||||
|
internal const string ExamId = "exam";
|
||||||
internal const string FallbackPasswordHash = "sebServerFallbackPasswordHash";
|
internal const string FallbackPasswordHash = "sebServerFallbackPasswordHash";
|
||||||
internal const string Institution = "institution";
|
internal const string Institution = "institution";
|
||||||
internal const string PerformFallback = "sebServerFallback";
|
internal const string PerformFallback = "sebServerFallback";
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
|
@ -58,11 +59,21 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
(abort, fallback, success) = TryPerformWithFallback(() => server.GetAvailableExams(), out var exams);
|
(abort, fallback, success) = TryPerformWithFallback(() => server.GetAvailableExams(Context.Next.Settings.Server.ExamId), out var exams);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
success = TrySelectExam(exams, out var exam);
|
var exam = default(Exam);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Context.Next.Settings.Server.ExamId))
|
||||||
|
{
|
||||||
|
exam = exams.First();
|
||||||
|
logger.Info("Automatically selected exam as defined in configuration.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = TrySelectExam(exams, out exam);
|
||||||
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,9 +35,9 @@ namespace SafeExamBrowser.Server.Contracts
|
||||||
ServerResponse Disconnect();
|
ServerResponse Disconnect();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a list of all currently available exams.
|
/// Retrieves a list of all currently available exams, or a list containing the specified exam.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ServerResponse<IEnumerable<Exam>> GetAvailableExams();
|
ServerResponse<IEnumerable<Exam>> GetAvailableExams(string examId = default(string));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the URI of the configuration file for the given exam.
|
/// Retrieves the URI of the configuration file for the given exam.
|
||||||
|
|
|
@ -116,10 +116,10 @@ namespace SafeExamBrowser.Server
|
||||||
return new ServerResponse(success, message);
|
return new ServerResponse(success, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerResponse<IEnumerable<Exam>> GetAvailableExams()
|
public ServerResponse<IEnumerable<Exam>> GetAvailableExams(string examId = default(string))
|
||||||
{
|
{
|
||||||
var authorization = ("Authorization", $"Bearer {oauth2Token}");
|
var authorization = ("Authorization", $"Bearer {oauth2Token}");
|
||||||
var content = $"institutionId={settings.Institution}";
|
var content = $"institutionId={settings.Institution}{(examId == default(string) ? "" : $"&examId={examId}")}";
|
||||||
var contentType = "application/x-www-form-urlencoded";
|
var contentType = "application/x-www-form-urlencoded";
|
||||||
var exams = default(IList<Exam>);
|
var exams = default(IList<Exam>);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.Settings.Server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ClientSecret { get; set; }
|
public string ClientSecret { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identifier of the exam to be started. If present, the exam will be automatically started, i.e. the exam selection will be skipped.
|
||||||
|
/// </summary>
|
||||||
|
public string ExamId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hash code of the password required to perform a fallback.
|
/// The hash code of the password required to perform a fallback.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue