SEBWIN-608: Implemented basic mechanism for app signature key exchange.

This commit is contained in:
Damian Büchel 2023-02-24 15:48:54 +01:00
parent 718a4550e9
commit ae3755df84
4 changed files with 119 additions and 28 deletions

View file

@ -51,6 +51,10 @@ namespace SafeExamBrowser.Runtime.Operations
if (Context.Next.Settings.SessionMode == SessionMode.Server)
{
var exam = default(Exam);
var exams = default(IEnumerable<Exam>);
var uri = default(Uri);
logger.Info("Initializing server...");
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
@ -60,22 +64,27 @@ namespace SafeExamBrowser.Runtime.Operations
if (success)
{
(abort, fallback, success) = TryPerformWithFallback(() => server.GetAvailableExams(Context.Next.Settings.Server.ExamId), out var exams);
(abort, fallback, success) = TryPerformWithFallback(() => server.GetAvailableExams(Context.Next.Settings.Server.ExamId), out exams);
}
if (success)
{
success = TrySelectExam(exams, out var exam);
if (success)
{
success = TrySelectExam(exams, out exam);
}
if (success)
{
(abort, fallback, success) = TryPerformWithFallback(() => server.GetConfigurationFor(exam), out var uri);
if (success)
{
(abort, fallback, success) = TryPerformWithFallback(() => server.GetConfigurationFor(exam), out uri);
}
if (success)
{
result = TryLoadServerSettings(exam, uri);
}
}
}
if (success)
{
result = TryLoadServerSettings(exam, uri);
}
if (success && result == OperationResult.Success)
{
(abort, fallback, success) = TryPerformWithFallback(() => server.SendSelectedExam(exam));
}
if (abort)
@ -97,25 +106,22 @@ namespace SafeExamBrowser.Runtime.Operations
public override OperationResult Repeat()
{
if (Context.Current.Settings.SessionMode == SessionMode.Server)
{
if (Context.Next.Settings.SessionMode == SessionMode.Server)
{
ShowReconfigurationError();
var result = OperationResult.Success;
return OperationResult.Aborted;
}
else
{
return Revert();
}
if (Context.Current.Settings.SessionMode == SessionMode.Server && Context.Next.Settings.SessionMode == SessionMode.Server)
{
result = AbortServerReconfiguration();
}
else if (Context.Current.Settings.SessionMode == SessionMode.Server)
{
result = Revert();
}
else if (Context.Next.Settings.SessionMode == SessionMode.Server)
{
return Perform();
result = Perform();
}
return OperationResult.Success;
return result;
}
public override OperationResult Revert()
@ -254,7 +260,7 @@ namespace SafeExamBrowser.Runtime.Operations
return success;
}
private void ShowReconfigurationError()
private OperationResult AbortServerReconfiguration()
{
var args = new MessageEventArgs
{
@ -263,9 +269,11 @@ namespace SafeExamBrowser.Runtime.Operations
Message = TextKey.MessageBox_ServerReconfigurationWarning,
Title = TextKey.MessageBox_ServerReconfigurationWarningTitle
};
logger.Warn("Server reconfiguration requested but is not allowed.");
logger.Warn("Server reconfiguration is currently not supported, aborting...");
ActionRequired?.Invoke(args);
return OperationResult.Aborted;
}
}
}

View file

@ -99,6 +99,11 @@ namespace SafeExamBrowser.Server.Contracts
/// </summary>
ServerResponse LowerHand();
/// <summary>
/// Sends the selected exam to the server.
/// </summary>
ServerResponse SendSelectedExam(Exam exam);
/// <summary>
/// Sends the given user session identifier of a LMS and thus establishes a connection with the server.
/// </summary>

View file

@ -105,6 +105,27 @@ namespace SafeExamBrowser.Server
return success;
}
internal bool TryParseAppSignatureKeySalt(HttpResponseMessage response, out string salt)
{
salt = default;
try
{
var hasHeader = response.Headers.TryGetValues("SEBExamSalt", out var values);
if (hasHeader)
{
salt = values.First();
}
}
catch (Exception e)
{
logger.Error("Failed to parse app signature key salt!", e);
}
return salt != default;
}
internal bool TryParseConnectionToken(HttpResponseMessage response, out string connectionToken)
{
connectionToken = default;

View file

@ -348,6 +348,38 @@ namespace SafeExamBrowser.Server
return new ServerResponse(success, response.ToLogString());
}
public ServerResponse SendSelectedExam(Exam exam)
{
var authorization = ("Authorization", $"Bearer {oauth2Token}");
var content = $"examId={exam.Id}";
var contentType = "application/x-www-form-urlencoded";
var token = ("SEBConnectionToken", connectionToken);
var success = TryExecute(new HttpMethod("PATCH"), api.HandshakeEndpoint, out var response, content, contentType, authorization, token);
var message = response.ToLogString();
if (success)
{
logger.Info("Successfully sent selected exam.");
}
else
{
logger.Error("Failed to send selected exam!");
}
if (parser.TryParseAppSignatureKeySalt(response, out var salt))
{
logger.Info("App signature key salt detected, performing key exchange...");
success = TrySendAppSignatureKey(out message);
}
else
{
logger.Info("No app signature key salt detected, skipping key exchange.");
}
return new ServerResponse(success, message);
}
public ServerResponse SendSessionIdentifier(string identifier)
{
var authorization = ("Authorization", $"Bearer {oauth2Token}");
@ -614,6 +646,31 @@ namespace SafeExamBrowser.Server
return success;
}
private bool TrySendAppSignatureKey(out string message)
{
// TODO:
// keyGenerator.CalculateAppSignatureKey(configurationKey, server.AppSignatureKeySalt)
var authorization = ("Authorization", $"Bearer {oauth2Token}");
var content = $"seb_signature_key={"WINDOWS-TEST-ASK-1234"}";
var contentType = "application/x-www-form-urlencoded";
var token = ("SEBConnectionToken", connectionToken);
var success = TryExecute(new HttpMethod("PATCH"), api.HandshakeEndpoint, out var response, content, contentType, authorization, token);
message = response.ToLogString();
if (success)
{
logger.Info("Successfully sent app signature key.");
}
else
{
logger.Error("Failed to send app signature key!");
}
return success;
}
private bool TryExecute(
HttpMethod method,
string url,