SEBWIN-405: Implemented scaffolding for detection of session identifier.

This commit is contained in:
Damian Büchel 2020-07-29 23:39:05 +02:00
parent bc06a0c985
commit 22f6e8b664
12 changed files with 145 additions and 7 deletions

View file

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

View file

@ -21,6 +21,11 @@ namespace SafeExamBrowser.Browser.Contracts
/// </summary>
event DownloadRequestedEventHandler ConfigurationDownloadRequested;
/// <summary>
/// Event fired when the browser application detects a session identifier of an LMS.
/// </summary>
event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
/// <summary>
/// Event fired when the browser application detects a request to terminate SEB.
/// </summary>

View file

@ -57,6 +57,7 @@
<Compile Include="Events\DownloadEventArgs.cs" />
<Compile Include="Events\DownloadFinishedCallback.cs" />
<Compile Include="Events\DownloadRequestedEventHandler.cs" />
<Compile Include="Events\SessionIdentifierDetectedEventHandler.cs" />
<Compile Include="Events\TerminationRequestedEventHandler.cs" />
<Compile Include="Filters\IRequestFilter.cs" />
<Compile Include="Filters\IRule.cs" />

View file

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Timers;
using CefSharp;
using CefSharp.WinForms;
using SafeExamBrowser.Applications.Contracts;
@ -39,8 +40,10 @@ namespace SafeExamBrowser.Browser
private IFileSystemDialog fileSystemDialog;
private IMessageBox messageBox;
private IModuleLogger logger;
private List<string> sessionCookies;
private BrowserSettings settings;
private IText text;
private Timer timer;
private IUserInterfaceFactory uiFactory;
public bool AutoStart { get; private set; }
@ -50,8 +53,9 @@ namespace SafeExamBrowser.Browser
public string Tooltip { get; private set; }
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
public event WindowsChangedEventHandler WindowsChanged;
public event SessionIdentifierDetectedEventHandler SessionIdentifierDetected;
public event TerminationRequestedEventHandler TerminationRequested;
public event WindowsChangedEventHandler WindowsChanged;
public BrowserApplication(
AppConfig appConfig,
@ -67,8 +71,10 @@ namespace SafeExamBrowser.Browser
this.instances = new List<BrowserApplicationInstance>();
this.logger = logger;
this.messageBox = messageBox;
this.sessionCookies = new List<string>();
this.settings = settings;
this.text = text;
this.timer = new Timer();
this.uiFactory = uiFactory;
}
@ -104,12 +110,15 @@ namespace SafeExamBrowser.Browser
public void Start()
{
CreateNewInstance();
StartMonitoringCookies();
}
public void Terminate()
{
logger.Info("Initiating termination...");
StopMonitoringCookies();
foreach (var instance in instances)
{
instance.Terminated -= Instance_Terminated;
@ -294,6 +303,19 @@ namespace SafeExamBrowser.Browser
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)
{
switch (protocol)
@ -322,5 +344,35 @@ namespace SafeExamBrowser.Browser
instances.Remove(instances.First(i => i.Id == id));
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();
}
}
}

View file

@ -49,7 +49,7 @@ namespace SafeExamBrowser.Client
internal IClientHost ClientHost { get; set; }
/// <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>
internal IServerProxy Server { get; set; }

View file

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Browser.Contracts;
using SafeExamBrowser.Browser.Contracts.Events;
@ -183,6 +184,7 @@ namespace SafeExamBrowser.Client
applicationMonitor.ExplorerStarted += ApplicationMonitor_ExplorerStarted;
applicationMonitor.TerminationFailed += ApplicationMonitor_TerminationFailed;
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
Browser.SessionIdentifierDetected += Browser_SessionIdentifierDetected;
Browser.TerminationRequested += Browser_TerminationRequested;
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
@ -218,6 +220,8 @@ namespace SafeExamBrowser.Client
if (Browser != null)
{
Browser.ConfigurationDownloadRequested -= Browser_ConfigurationDownloadRequested;
Browser.SessionIdentifierDetected -= Browser_SessionIdentifierDetected;
Browser.TerminationRequested -= Browser_TerminationRequested;
}
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()
{
logger.Info("Attempting to shutdown as requested by the browser...");

View file

@ -244,6 +244,8 @@ namespace SafeExamBrowser.Client
var server = new ServerProxy(context.AppConfig, logger);
var operation = new ServerOperation(actionCenter, context, logger, server, taskbar);
context.Server = server;
return operation;
}

View file

@ -48,7 +48,12 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Initializing server...");
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
}
@ -66,6 +71,7 @@ namespace SafeExamBrowser.Client.Operations
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
// TODO: Stop sending pings and logs (or in controller?)
server.StopConnectivity();
// TODO: Stop action center and taskbar notifications
}

View file

@ -161,6 +161,11 @@ namespace SafeExamBrowser.Configuration.Contracts
/// </summary>
public string ServerConnectionToken { get; set; }
/// <summary>
/// The identifier of the selected server exam.
/// </summary>
public string ServerExamId { get; set; }
/// <summary>
/// The OAuth2 token for a server.
/// </summary>

View file

@ -77,11 +77,18 @@ namespace SafeExamBrowser.Runtime.Operations
if (status == LoadStatus.Success)
{
var serverSettings = Context.Next.Settings.Server;
Context.Next.AppConfig.ServerApi = info.Api;
Context.Next.AppConfig.ServerConnectionToken = info.ConnectionToken;
Context.Next.AppConfig.ServerExamId = exam.Id;
Context.Next.AppConfig.ServerOauth2Token = info.Oauth2Token;
Context.Next.Settings = settings;
Context.Next.Settings.Browser.StartUrl = exam.Url;
Context.Next.Settings.Server = serverSettings;
Context.Next.Settings.SessionMode = SessionMode.Server;
result = OperationResult.Success;
}
else
@ -105,6 +112,7 @@ namespace SafeExamBrowser.Runtime.Operations
if (fallback)
{
Context.Next.Settings.SessionMode = SessionMode.Normal;
result = OperationResult.Success;
}
}

View file

@ -51,11 +51,21 @@ namespace SafeExamBrowser.Server.Contracts
/// <summary>
/// Initializes the configuration and server settings to be used for communication.
/// </summary>
void Initialize(string api, string connectionToken, string oauth2Token, ServerSettings settings);
void Initialize(string api, string connectionToken, string examId, string oauth2Token, ServerSettings settings);
/// <summary>
/// TODO
/// </summary>
ServerResponse SendSessionInfo(string sessionId);
ServerResponse SendSessionIdentifier(string identifier);
/// <summary>
/// TODO
/// </summary>
void StartConnectivity();
/// <summary>
/// TODO
/// </summary>
void StopConnectivity();
}
}

View file

@ -29,6 +29,7 @@ namespace SafeExamBrowser.Server
{
private ApiVersion1 api;
private string connectionToken;
private string examId;
private HttpClient httpClient;
private readonly AppConfig appConfig;
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.connectionToken = connectionToken;
this.examId = examId;
this.oauth2Token = oauth2Token;
Initialize(settings);
}
public ServerResponse SendSessionInfo(string sessionId)
public ServerResponse SendSessionIdentifier(string identifier)
{
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)
{
var success = false;