diff --git a/BasicUnitTest/SecurityEventTokenTests.cs b/BasicUnitTest/SecurityEventTokenTests.cs index ddddef9579bd34c02d80b3efa899cc57c4aad5a1..a889b1b4df25933d749edca259ce3b8fc268b0df 100644 --- a/BasicUnitTest/SecurityEventTokenTests.cs +++ b/BasicUnitTest/SecurityEventTokenTests.cs @@ -24,7 +24,7 @@ public class SecurityEventTokenTests { [Test] public void CreateJwt_AcceptSubmission() { var token = _encryption.CreateAcceptSecurityEventToken(new SubmissionForPickupDto { - SubmissionId = Guid.NewGuid().ToString(), CaseId = Guid.NewGuid().ToString(), + Id = Guid.NewGuid().ToString(), CaseId = Guid.NewGuid().ToString(), DestinationId = Guid.NewGuid().ToString() }); Console.WriteLine(token); diff --git a/DemoRunner/SubscriberDemo.cs b/DemoRunner/SubscriberDemo.cs index d08b9f6e51ed37bf55be0d21a7a410b1ca101399..5a8c96bd75a1f464731e43a92f13e9932fa9f6ee 100644 --- a/DemoRunner/SubscriberDemo.cs +++ b/DemoRunner/SubscriberDemo.cs @@ -33,7 +33,7 @@ public static class SubscriberDemo { foreach (var submission in submissions) try { var subscriberWithSubmission = - subscriber.RequestSubmission(submission.SubmissionId); + subscriber.RequestSubmission(submission.Id); var attachments = subscriberWithSubmission .GetAttachments(); diff --git a/FitConnect/Encryption/FitEncryption.cs b/FitConnect/Encryption/FitEncryption.cs index 95a2e905dbf60b6dd6d5394214734eea1cdd4c38..7f40e5295ecc08b5ab6ae47ac0c7287614c157ad 100644 --- a/FitConnect/Encryption/FitEncryption.cs +++ b/FitConnect/Encryption/FitEncryption.cs @@ -1,6 +1,7 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Cryptography; using System.Text; +using FitConnect.Models; using FitConnect.Models.v1.Api; using FitConnect.Services.Models.v1.Submission; using IdentityModel; @@ -74,7 +75,7 @@ public class FitEncryption { } public string Encrypt(byte[] plain, string key) { - return _encryptor.Encrypt(key, plain ); + return _encryptor.Encrypt(key, plain); } public string Encrypt(byte[] plain) { @@ -92,32 +93,56 @@ public class FitEncryption { new { problems = problemsArray }); } - public string CreateAcceptSecurityEventToken(SubmissionForPickupDto submission) { - // string submissionSubmissionId,string submissionCaseId, string submissionDestinationId) { - - #warning Dummy data is used for testing purposes, replace with actual data + private dynamic GenerateAuthenticationTags(Submission submission) { +#warning Dummy data is used for testing purposes, replace with actual data // NOMERGE Remove Dummy data - var payload = new { + + _logger?.LogInformation("Generating authentication tags"); + var attachmentDictionary = new Dictionary<string, string>(); + submission.Attachments.ForEach(a => + attachmentDictionary.Add(a.Id, CalculateAuthenticationHash(a.Content))); + + return new { authenticationTags = new { - data = "UCGiqJxhBI3IFVdPalHHvA", metadata = "XFBoMYUZodetZdvTiFvSkQ", - attachments = new Dictionary<string, string> { - { "0b799252-deb9-42b0-98d3-c50d24bbafe0", "rT99rwrBTbTI7IJM8fU3El" } - } + data = CalculateAuthenticationHash(submission?.Data ?? ""), + metadata = CalculateAuthenticationHash(submission?.Metadata?.ToString() ?? ""), + attachments = attachmentDictionary } }; + } - // NOMERGE Add payload - if (submission?.SubmissionId == null || submission?.CaseId == null || + private string CalculateAuthenticationHash(string data = "") { + return CalculateAuthenticationHash(Encoding.UTF8.GetBytes(data)); + } + + private string CalculateAuthenticationHash(byte[]? data = null) { + var result = MD5.Create().ComputeHash(data ?? Array.Empty<byte>()); + return System.Convert.ToHexString(result); + } + + + public string CreateAcceptSecurityEventToken(SubmissionForPickupDto submission, + dynamic payload = null) { + if (submission?.Id == null || submission?.CaseId == null || submission?.DestinationId == null) { throw new ArgumentException("SubmissionId, CaseId and DestinationId are required"); } - return CreateSecurityEventToken(submission.SubmissionId, submission.CaseId, + return CreateSecurityEventToken(submission.Id, submission.CaseId, submission.DestinationId, "https://schema.fitko.de/fit-connect/events/accept-submission", null); } + public string CreateAcceptSecurityEventToken(Submission submission) { + // NOMERGE Add payload + var payload = GenerateAuthenticationTags(submission); + return CreateSecurityEventToken(submission.Id, submission.CaseId, + submission.DestinationId, + "https://schema.fitko.de/fit-connect/events/accept-submission", payload); + } + + private string CreateSecurityEventToken(string submissionId, string caseId, string destinationId, @@ -179,6 +204,10 @@ public class FitEncryption { return ByteToHexString(SHA512.Create().ComputeHash(Encoding.UTF8.GetBytes(data))); } + public static string CalculateHash(byte[] data) { + return ByteToHexString(SHA512.Create().ComputeHash(data)); + } + private static string ByteToHexString(IEnumerable<byte> data) { var sb = new StringBuilder(); foreach (var b in data) sb.Append(b.ToString("x2")); diff --git a/FitConnect/Models/Submission.cs b/FitConnect/Models/Submission.cs index bd9b20e8dbba5e95beaeaa7f32d5ab49e0a52aef..a1d78af9af1f570479fd6f10c22ef682eb148c52 100644 --- a/FitConnect/Models/Submission.cs +++ b/FitConnect/Models/Submission.cs @@ -45,7 +45,7 @@ public class Submission { public static implicit operator SubmissionForPickupDto(Submission sub) { return new SubmissionForPickupDto { - SubmissionId = sub.Id, + Id = sub.Id, CaseId = sub.CaseId, DestinationId = sub.DestinationId }; @@ -53,7 +53,7 @@ public class Submission { public static explicit operator Submission(SubmissionForPickupDto dto) { return new Submission { - Id = dto.SubmissionId, + Id = dto.Id, Callback = null, DestinationId = dto.DestinationId ?? throw new NullReferenceException(nameof(dto.DestinationId)), diff --git a/FitConnect/Services/Models/v1/Api/Metadata.cs b/FitConnect/Services/Models/v1/Api/Metadata.cs index c5ccaf433011c00cc3ca3068b80d95a09ac78c45..3f8515902b5cfde3202fc9a8d5fc984498b74e1c 100644 --- a/FitConnect/Services/Models/v1/Api/Metadata.cs +++ b/FitConnect/Services/Models/v1/Api/Metadata.cs @@ -53,6 +53,8 @@ namespace FitConnect.Models.Api.Metadata [JsonProperty("replyChannel", NullValueHandling = NullValueHandling.Ignore)] public ReplyChannel ReplyChannel { get; set; } + + public override string ToString() => JsonConvert.SerializeObject(this); } /// <summary> diff --git a/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs b/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs index 7540c18ff8926a41e13d75ccfadd16e242339072..a3106e65e80ac8c9a405ff5a92b99f8627a1e22b 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs @@ -10,5 +10,5 @@ public class SubmissionForPickupDto { public string? DestinationId { get; set; } [JsonProperty("submissionId")] - public string? SubmissionId { get; set; } + public string? Id { get; set; } } diff --git a/FitConnect/Services/SubmissionService.cs b/FitConnect/Services/SubmissionService.cs index e8bd70073f58a664f5d554eefd48e6486cf88e53..b937358b8a2811609152e5224eddfe87ce9aca70 100644 --- a/FitConnect/Services/SubmissionService.cs +++ b/FitConnect/Services/SubmissionService.cs @@ -152,9 +152,7 @@ internal class SubmissionService : RestCallService, ISubmissionService { if (events == null) return null; - // Download well known keys var valid = await ValidateSignature(events, destinationId); - // TODO Check JSON Schema valid &= await ValidateSchema(events); if (!valid) { diff --git a/FitConnect/Subscriber.cs b/FitConnect/Subscriber.cs index 0fbf48a99d8a7178e37f22cbc6d80a4dd560868f..05819659eb04a753dff17534de86396dc7a1efc9 100644 --- a/FitConnect/Subscriber.cs +++ b/FitConnect/Subscriber.cs @@ -156,9 +156,9 @@ public class Subscriber : FitConnectClient, - private void CompleteSubmission(SubmissionForPickupDto submission, + private void CompleteSubmission(Submission submission, FinishSubmissionStatus status, Problems[]? problems = null) { - if (submission.SubmissionId == null || submission.CaseId == null || + if (submission.Id == null || submission.CaseId == null || submission.DestinationId == null) throw new ArgumentException("Submission does not contain all required fields"); @@ -167,7 +167,7 @@ public class Subscriber : FitConnectClient, var token = status switch { FinishSubmissionStatus.Rejected => - Encryption.CreateRejectSecurityEventToken(submission.SubmissionId, + Encryption.CreateRejectSecurityEventToken(submission.Id, submission.CaseId, submission.DestinationId, problems), FinishSubmissionStatus.Accepted => Encryption.CreateAcceptSecurityEventToken( diff --git a/IntegrationTests/Sender/ThreadTest.cs b/IntegrationTests/Sender/ThreadTest.cs index c59372b206b870948ef118094a0edf47158f3e8e..9de0bf1d2eacc495e89f8bb00e1fa5b3f777caef 100644 --- a/IntegrationTests/Sender/ThreadTest.cs +++ b/IntegrationTests/Sender/ThreadTest.cs @@ -75,7 +75,7 @@ public class ThreadTest { foreach (var submission in submissions) subscriber - .RequestSubmission(submission.SubmissionId) + .RequestSubmission(submission.Id) .AcceptSubmission(); submissions.Count.Should().Be(NumberOfThreads); diff --git a/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs b/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs index ee585fc6693fb33572091fb9dcfea7f372543d53..34917379c86191992e036e65eb68996e4582a5c9 100644 --- a/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs +++ b/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs @@ -42,7 +42,7 @@ public class SubscriberTestHappyPath : SubscriberTestBase { var submissions = Subscriber.GetAvailableSubmissions().ToList(); submissions.Count().Should().BeGreaterThan(0); var i = 0; - foreach (var submissionId in submissions.Select(s => s.SubmissionId)) { + foreach (var submissionId in submissions.Select(s => s.Id)) { // Act Console.WriteLine($"Getting submission {submissionId}"); var dto = Subscriber.RequestSubmission(submissionId); @@ -91,8 +91,8 @@ public class SubscriberTestHappyPath : SubscriberTestBase { foreach (var submission in submissions) { Console.WriteLine( - $"Getting submission {submission.SubmissionId} - case {submission.CaseId}"); - var submissionId = submission.SubmissionId!; + $"Getting submission {submission.Id} - case {submission.CaseId}"); + var submissionId = submission.Id!; if (!Directory.Exists($"./attachments/{submissionId}/")) Directory.CreateDirectory($"./attachments/{submissionId}/");