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…
	
	Add table
		
		Reference in a new issue