SEBWIN-608: Implemented basic mechanism for app signature key exchange.
This commit is contained in:
parent
718a4550e9
commit
ae3755df84
4 changed files with 119 additions and 28 deletions
|
@ -51,6 +51,10 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (Context.Next.Settings.SessionMode == SessionMode.Server)
|
if (Context.Next.Settings.SessionMode == SessionMode.Server)
|
||||||
{
|
{
|
||||||
|
var exam = default(Exam);
|
||||||
|
var exams = default(IEnumerable<Exam>);
|
||||||
|
var uri = default(Uri);
|
||||||
|
|
||||||
logger.Info("Initializing server...");
|
logger.Info("Initializing server...");
|
||||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
|
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeServer);
|
||||||
|
|
||||||
|
@ -60,22 +64,27 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
if (success)
|
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)
|
if (success)
|
||||||
{
|
{
|
||||||
success = TrySelectExam(exams, out var exam);
|
success = TrySelectExam(exams, out exam);
|
||||||
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
(abort, fallback, success) = TryPerformWithFallback(() => server.GetConfigurationFor(exam), out var uri);
|
(abort, fallback, success) = TryPerformWithFallback(() => server.GetConfigurationFor(exam), out uri);
|
||||||
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
result = TryLoadServerSettings(exam, uri);
|
result = TryLoadServerSettings(exam, uri);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
if (success && result == OperationResult.Success)
|
||||||
|
{
|
||||||
|
(abort, fallback, success) = TryPerformWithFallback(() => server.SendSelectedExam(exam));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abort)
|
if (abort)
|
||||||
|
@ -97,25 +106,22 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
|
|
||||||
public override OperationResult Repeat()
|
public override OperationResult Repeat()
|
||||||
{
|
{
|
||||||
if (Context.Current.Settings.SessionMode == SessionMode.Server)
|
var result = OperationResult.Success;
|
||||||
{
|
|
||||||
if (Context.Next.Settings.SessionMode == SessionMode.Server)
|
|
||||||
{
|
|
||||||
ShowReconfigurationError();
|
|
||||||
|
|
||||||
return OperationResult.Aborted;
|
if (Context.Current.Settings.SessionMode == SessionMode.Server && Context.Next.Settings.SessionMode == SessionMode.Server)
|
||||||
}
|
{
|
||||||
else
|
result = AbortServerReconfiguration();
|
||||||
{
|
}
|
||||||
return Revert();
|
else if (Context.Current.Settings.SessionMode == SessionMode.Server)
|
||||||
}
|
{
|
||||||
|
result = Revert();
|
||||||
}
|
}
|
||||||
else if (Context.Next.Settings.SessionMode == SessionMode.Server)
|
else if (Context.Next.Settings.SessionMode == SessionMode.Server)
|
||||||
{
|
{
|
||||||
return Perform();
|
result = Perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
return OperationResult.Success;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override OperationResult Revert()
|
public override OperationResult Revert()
|
||||||
|
@ -254,7 +260,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowReconfigurationError()
|
private OperationResult AbortServerReconfiguration()
|
||||||
{
|
{
|
||||||
var args = new MessageEventArgs
|
var args = new MessageEventArgs
|
||||||
{
|
{
|
||||||
|
@ -263,9 +269,11 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
Message = TextKey.MessageBox_ServerReconfigurationWarning,
|
Message = TextKey.MessageBox_ServerReconfigurationWarning,
|
||||||
Title = TextKey.MessageBox_ServerReconfigurationWarningTitle
|
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);
|
ActionRequired?.Invoke(args);
|
||||||
|
|
||||||
|
return OperationResult.Aborted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,11 @@ namespace SafeExamBrowser.Server.Contracts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ServerResponse LowerHand();
|
ServerResponse LowerHand();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the selected exam to the server.
|
||||||
|
/// </summary>
|
||||||
|
ServerResponse SendSelectedExam(Exam exam);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the given user session identifier of a LMS and thus establishes a connection with the server.
|
/// Sends the given user session identifier of a LMS and thus establishes a connection with the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -105,6 +105,27 @@ namespace SafeExamBrowser.Server
|
||||||
return success;
|
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)
|
internal bool TryParseConnectionToken(HttpResponseMessage response, out string connectionToken)
|
||||||
{
|
{
|
||||||
connectionToken = default;
|
connectionToken = default;
|
||||||
|
|
|
@ -348,6 +348,38 @@ namespace SafeExamBrowser.Server
|
||||||
return new ServerResponse(success, response.ToLogString());
|
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)
|
public ServerResponse SendSessionIdentifier(string identifier)
|
||||||
{
|
{
|
||||||
var authorization = ("Authorization", $"Bearer {oauth2Token}");
|
var authorization = ("Authorization", $"Bearer {oauth2Token}");
|
||||||
|
@ -614,6 +646,31 @@ namespace SafeExamBrowser.Server
|
||||||
return success;
|
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(
|
private bool TryExecute(
|
||||||
HttpMethod method,
|
HttpMethod method,
|
||||||
string url,
|
string url,
|
||||||
|
|
Loading…
Add table
Reference in a new issue