SEBWIN-405: Implemented scaffolding for detection of session identifier.
This commit is contained in:
parent
bc06a0c985
commit
22f6e8b664
12 changed files with 145 additions and 7 deletions
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Contracts.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event handler used to indicate that the browser has detected a session identifier of a LMS.
|
||||||
|
/// </summary>
|
||||||
|
public delegate void SessionIdentifierDetectedEventHandler(string identifier);
|
||||||
|
}
|
|
@ -21,6 +21,11 @@ namespace SafeExamBrowser.Browser.Contracts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when the browser application detects a session identifier of an LMS.
|
||||||
|
/// </summary>
|
||||||
|
event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the browser application detects a request to terminate SEB.
|
/// Event fired when the browser application detects a request to terminate SEB.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
<Compile Include="Events\DownloadEventArgs.cs" />
|
<Compile Include="Events\DownloadEventArgs.cs" />
|
||||||
<Compile Include="Events\DownloadFinishedCallback.cs" />
|
<Compile Include="Events\DownloadFinishedCallback.cs" />
|
||||||
<Compile Include="Events\DownloadRequestedEventHandler.cs" />
|
<Compile Include="Events\DownloadRequestedEventHandler.cs" />
|
||||||
|
<Compile Include="Events\SessionIdentifierDetectedEventHandler.cs" />
|
||||||
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
|
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
|
||||||
<Compile Include="Filters\IRequestFilter.cs" />
|
<Compile Include="Filters\IRequestFilter.cs" />
|
||||||
<Compile Include="Filters\IRule.cs" />
|
<Compile Include="Filters\IRule.cs" />
|
||||||
|
|
|
@ -10,6 +10,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Timers;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
|
@ -39,8 +40,10 @@ namespace SafeExamBrowser.Browser
|
||||||
private IFileSystemDialog fileSystemDialog;
|
private IFileSystemDialog fileSystemDialog;
|
||||||
private IMessageBox messageBox;
|
private IMessageBox messageBox;
|
||||||
private IModuleLogger logger;
|
private IModuleLogger logger;
|
||||||
|
private List<string> sessionCookies;
|
||||||
private BrowserSettings settings;
|
private BrowserSettings settings;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
private Timer timer;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
|
||||||
public bool AutoStart { get; private set; }
|
public bool AutoStart { get; private set; }
|
||||||
|
@ -50,8 +53,9 @@ namespace SafeExamBrowser.Browser
|
||||||
public string Tooltip { get; private set; }
|
public string Tooltip { get; private set; }
|
||||||
|
|
||||||
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||||
public event WindowsChangedEventHandler WindowsChanged;
|
public event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
|
||||||
public event TerminationRequestedEventHandler TerminationRequested;
|
public event TerminationRequestedEventHandler TerminationRequested;
|
||||||
|
public event WindowsChangedEventHandler WindowsChanged;
|
||||||
|
|
||||||
public BrowserApplication(
|
public BrowserApplication(
|
||||||
AppConfig appConfig,
|
AppConfig appConfig,
|
||||||
|
@ -67,8 +71,10 @@ namespace SafeExamBrowser.Browser
|
||||||
this.instances = new List<BrowserApplicationInstance>();
|
this.instances = new List<BrowserApplicationInstance>();
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.messageBox = messageBox;
|
this.messageBox = messageBox;
|
||||||
|
this.sessionCookies = new List<string>();
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
this.timer = new Timer();
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,12 +110,15 @@ namespace SafeExamBrowser.Browser
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
CreateNewInstance();
|
CreateNewInstance();
|
||||||
|
StartMonitoringCookies();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Terminate()
|
public void Terminate()
|
||||||
{
|
{
|
||||||
logger.Info("Initiating termination...");
|
logger.Info("Initiating termination...");
|
||||||
|
|
||||||
|
StopMonitoringCookies();
|
||||||
|
|
||||||
foreach (var instance in instances)
|
foreach (var instance in instances)
|
||||||
{
|
{
|
||||||
instance.Terminated -= Instance_Terminated;
|
instance.Terminated -= Instance_Terminated;
|
||||||
|
@ -294,6 +303,19 @@ namespace SafeExamBrowser.Browser
|
||||||
return userAgent;
|
return userAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StartMonitoringCookies()
|
||||||
|
{
|
||||||
|
timer.AutoReset = false;
|
||||||
|
timer.Interval = 1000;
|
||||||
|
timer.Elapsed += Timer_Elapsed;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopMonitoringCookies()
|
||||||
|
{
|
||||||
|
timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
private string ToScheme(ProxyProtocol protocol)
|
private string ToScheme(ProxyProtocol protocol)
|
||||||
{
|
{
|
||||||
switch (protocol)
|
switch (protocol)
|
||||||
|
@ -322,5 +344,35 @@ namespace SafeExamBrowser.Browser
|
||||||
instances.Remove(instances.First(i => i.Id == id));
|
instances.Remove(instances.First(i => i.Id == id));
|
||||||
WindowsChanged?.Invoke();
|
WindowsChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Timer_Elapsed(object sender, ElapsedEventArgs args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var manager = Cef.GetGlobalCookieManager();
|
||||||
|
var task = manager.VisitAllCookiesAsync();
|
||||||
|
var cookies = task.GetAwaiter().GetResult();
|
||||||
|
var edxLogin = cookies.FirstOrDefault(c => c.Name == "edxloggedin");
|
||||||
|
|
||||||
|
// TODO: MoodleSession
|
||||||
|
|
||||||
|
if (edxLogin != default(Cookie))
|
||||||
|
{
|
||||||
|
var edxSession = cookies.FirstOrDefault(c => c.Domain == edxLogin.Domain && c.Name == "sessionid");
|
||||||
|
|
||||||
|
if (edxSession != default(Cookie) && !sessionCookies.Contains(edxSession.Domain))
|
||||||
|
{
|
||||||
|
sessionCookies.Add(edxSession.Domain);
|
||||||
|
SessionIdentifierDetected?.Invoke(edxSession.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error("Failed to read cookies!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace SafeExamBrowser.Client
|
||||||
internal IClientHost ClientHost { get; set; }
|
internal IClientHost ClientHost { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The server proxy, if the current session mode is <see cref="SessionMode.Server"/>.
|
/// The server proxy (if the current session mode is <see cref="SessionMode.Server"/>).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal IServerProxy Server { get; set; }
|
internal IServerProxy Server { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
using SafeExamBrowser.Browser.Contracts;
|
using SafeExamBrowser.Browser.Contracts;
|
||||||
using SafeExamBrowser.Browser.Contracts.Events;
|
using SafeExamBrowser.Browser.Contracts.Events;
|
||||||
|
@ -183,6 +184,7 @@ namespace SafeExamBrowser.Client
|
||||||
applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted;
|
applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted;
|
||||||
applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed;
|
applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed;
|
||||||
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
|
||||||
|
Browser.SessionIdentifierDetected += Browser_SessionIdentifierDetected;
|
||||||
Browser.TerminationRequested += Browser_TerminationRequested;
|
Browser.TerminationRequested += Browser_TerminationRequested;
|
||||||
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
|
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
|
||||||
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
|
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
|
||||||
|
@ -218,6 +220,8 @@ namespace SafeExamBrowser.Client
|
||||||
if (Browser != null)
|
if (Browser != null)
|
||||||
{
|
{
|
||||||
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
|
||||||
|
Browser.SessionIdentifierDetected -= Browser_SessionIdentifierDetected;
|
||||||
|
Browser.TerminationRequested -= Browser_TerminationRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClientHost != null)
|
if (ClientHost != null)
|
||||||
|
@ -341,6 +345,24 @@ namespace SafeExamBrowser.Client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Browser_SessionIdentifierDetected(string identifier)
|
||||||
|
{
|
||||||
|
if (Settings.SessionMode == SessionMode.Server)
|
||||||
|
{
|
||||||
|
var response = Server.SendSessionIdentifier(identifier);
|
||||||
|
|
||||||
|
while (!response.Success)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to communicate session identifier with server! {response.Message}");
|
||||||
|
// TODO: Check that is running in separat thread (not UI thread!!) or use different mechanism to wait!
|
||||||
|
Thread.Sleep(Settings.Server.RequestAttemptInterval);
|
||||||
|
response = Server.SendSessionIdentifier(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.StartConnectivity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Browser_TerminationRequested()
|
private void Browser_TerminationRequested()
|
||||||
{
|
{
|
||||||
logger.Info("Attempting to shutdown as requested by the browser...");
|
logger.Info("Attempting to shutdown as requested by the browser...");
|
||||||
|
|
|
@ -244,6 +244,8 @@ namespace SafeExamBrowser.Client
|
||||||
var server = new ServerProxy(context.AppConfig, logger);
|
var server = new ServerProxy(context.AppConfig, logger);
|
||||||
var operation = new ServerOperation(actionCenter, context, logger, server, taskbar);
|
var operation = new ServerOperation(actionCenter, context, logger, server, taskbar);
|
||||||
|
|
||||||
|
context.Server = server;
|
||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,12 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
logger.Info("Initializing server...");
|
logger.Info("Initializing server...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
|
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
|
||||||
|
|
||||||
server.Initialize(Context.AppConfig.ServerApi, Context.AppConfig.ServerConnectionToken, Context.AppConfig.ServerOauth2Token, Context.Settings.Server);
|
server.Initialize(
|
||||||
|
Context.AppConfig.ServerApi,
|
||||||
|
Context.AppConfig.ServerConnectionToken,
|
||||||
|
Context.AppConfig.ServerExamId,
|
||||||
|
Context.AppConfig.ServerOauth2Token,
|
||||||
|
Context.Settings.Server);
|
||||||
|
|
||||||
// TODO: Add action center and taskbar notifications
|
// TODO: Add action center and taskbar notifications
|
||||||
}
|
}
|
||||||
|
@ -66,6 +71,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
|
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
|
||||||
|
|
||||||
// TODO: Stop sending pings and logs (or in controller?)
|
// TODO: Stop sending pings and logs (or in controller?)
|
||||||
|
server.StopConnectivity();
|
||||||
// TODO: Stop action center and taskbar notifications
|
// TODO: Stop action center and taskbar notifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,11 @@ namespace SafeExamBrowser.Configuration.Contracts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ServerConnectionToken { get; set; }
|
public string ServerConnectionToken { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identifier of the selected server exam.
|
||||||
|
/// </summary>
|
||||||
|
public string ServerExamId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The OAuth2 token for a server.
|
/// The OAuth2 token for a server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -77,11 +77,18 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (status == LoadStatus.Success)
|
if (status == LoadStatus.Success)
|
||||||
{
|
{
|
||||||
|
var serverSettings = Context.Next.Settings.Server;
|
||||||
|
|
||||||
Context.Next.AppConfig.ServerApi = info.Api;
|
Context.Next.AppConfig.ServerApi = info.Api;
|
||||||
Context.Next.AppConfig.ServerConnectionToken = info.ConnectionToken;
|
Context.Next.AppConfig.ServerConnectionToken = info.ConnectionToken;
|
||||||
|
Context.Next.AppConfig.ServerExamId = exam.Id;
|
||||||
Context.Next.AppConfig.ServerOauth2Token = info.Oauth2Token;
|
Context.Next.AppConfig.ServerOauth2Token = info.Oauth2Token;
|
||||||
|
|
||||||
Context.Next.Settings = settings;
|
Context.Next.Settings = settings;
|
||||||
Context.Next.Settings.Browser.StartUrl = exam.Url;
|
Context.Next.Settings.Browser.StartUrl = exam.Url;
|
||||||
|
Context.Next.Settings.Server = serverSettings;
|
||||||
|
Context.Next.Settings.SessionMode = SessionMode.Server;
|
||||||
|
|
||||||
result = OperationResult.Success;
|
result = OperationResult.Success;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -105,6 +112,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (fallback)
|
if (fallback)
|
||||||
{
|
{
|
||||||
|
Context.Next.Settings.SessionMode = SessionMode.Normal;
|
||||||
result = OperationResult.Success;
|
result = OperationResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,21 @@ namespace SafeExamBrowser.Server.Contracts
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the configuration and server settings to be used for communication.
|
/// Initializes the configuration and server settings to be used for communication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Initialize(string api, string connectionToken, string oauth2Token, ServerSettings settings);
|
void Initialize(string api, string connectionToken, string examId, string oauth2Token, ServerSettings settings);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TODO
|
/// TODO
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ServerResponse SendSessionInfo(string sessionId);
|
ServerResponse SendSessionIdentifier(string identifier);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TODO
|
||||||
|
/// </summary>
|
||||||
|
void StartConnectivity();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TODO
|
||||||
|
/// </summary>
|
||||||
|
void StopConnectivity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace SafeExamBrowser.Server
|
||||||
{
|
{
|
||||||
private ApiVersion1 api;
|
private ApiVersion1 api;
|
||||||
private string connectionToken;
|
private string connectionToken;
|
||||||
|
private string examId;
|
||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
private readonly AppConfig appConfig;
|
private readonly AppConfig appConfig;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
@ -173,20 +174,31 @@ namespace SafeExamBrowser.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(string api, string connectionToken, string oauth2Token, ServerSettings settings)
|
public void Initialize(string api, string connectionToken, string examId, string oauth2Token, ServerSettings settings)
|
||||||
{
|
{
|
||||||
this.api = JsonConvert.DeserializeObject<ApiVersion1>(api);
|
this.api = JsonConvert.DeserializeObject<ApiVersion1>(api);
|
||||||
this.connectionToken = connectionToken;
|
this.connectionToken = connectionToken;
|
||||||
|
this.examId = examId;
|
||||||
this.oauth2Token = oauth2Token;
|
this.oauth2Token = oauth2Token;
|
||||||
|
|
||||||
Initialize(settings);
|
Initialize(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerResponse SendSessionInfo(string sessionId)
|
public ServerResponse SendSessionIdentifier(string identifier)
|
||||||
{
|
{
|
||||||
return new ServerResponse(false, "TODO!");
|
return new ServerResponse(false, "TODO!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StartConnectivity()
|
||||||
|
{
|
||||||
|
// TODO: Start sending logs and pings
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopConnectivity()
|
||||||
|
{
|
||||||
|
// TODO: Stop sending logs and pings
|
||||||
|
}
|
||||||
|
|
||||||
private bool TryParseApi(HttpContent content)
|
private bool TryParseApi(HttpContent content)
|
||||||
{
|
{
|
||||||
var success = false;
|
var success = false;
|
||||||
|
|
Loading…
Reference in a new issue