diff --git a/.gitignore b/.gitignore index 906aa3ecd39ffb7d3355cf89e2870a3736f3245c..13e13dd435fbfe8febcdb01de8f2410b7c9f92be 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ private_notes/ # Local History for Visual Studio Code .history/ .DS_Store - +private_notes/ **.nupkg ### JetBrains template diff --git a/BasicUnitTest/BasicUnitTest.csproj b/BasicUnitTest/BasicUnitTest.csproj index 87a4ad558fb5cab8be7c9ea8ad23e2cdac2ea72e..a25229d9e9f5e8e59e9fc82b1b505b8f02f4e46a 100644 --- a/BasicUnitTest/BasicUnitTest.csproj +++ b/BasicUnitTest/BasicUnitTest.csproj @@ -10,18 +10,18 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="FluentAssertions" Version="6.7.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> - <PackageReference Include="Moq" Version="4.18.1" /> - <PackageReference Include="NUnit" Version="3.13.2" /> - <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> - <PackageReference Include="coverlet.collector" Version="3.1.0" /> + <PackageReference Include="FluentAssertions" Version="6.7.0"/> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0"/> + <PackageReference Include="Moq" Version="4.18.1"/> + <PackageReference Include="NUnit" Version="3.13.2"/> + <PackageReference Include="NUnit3TestAdapter" Version="4.0.0"/> + <PackageReference Include="coverlet.collector" Version="3.1.0"/> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> - <ProjectReference Include="..\MockContainer\MockContainer.csproj" /> + <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> + <ProjectReference Include="..\MockContainer\MockContainer.csproj"/> </ItemGroup> </Project> diff --git a/BasicUnitTest/SecurityEventTokenTests.cs b/BasicUnitTest/SecurityEventTokenTests.cs index a2f752acaf07d45c9442e0f8e04e5e4e60b5e1f7..09fce920c718d9fcd65767072f87152924734748 100644 --- a/BasicUnitTest/SecurityEventTokenTests.cs +++ b/BasicUnitTest/SecurityEventTokenTests.cs @@ -4,6 +4,7 @@ using FitConnect.Encryption; using FitConnect.Models; using FitConnect.Models.v1.Api; using FluentAssertions; +using MockContainer; using NUnit.Framework; using SecurityEventToken = FitConnect.Models.SecurityEventToken; @@ -21,10 +22,11 @@ public class SecurityEventTokenTests { [SetUp] public void Setup() { - var container = MockContainer.Container.Create(); + var container = Container.Create(); _encryption = new FitEncryption(container.Resolve<KeySet>(), null); } + [Test] public void CreateJwt_AcceptSubmission() { var token = _encryption.CreateSecurityEventToken(Guid.NewGuid().ToString(), @@ -34,7 +36,7 @@ public class SecurityEventTokenTests { null ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(acceptSubmission); decoded.EventType.Should().Be(EventType.Accept); @@ -49,7 +51,7 @@ public class SecurityEventTokenTests { new[] { Problems.EncryptionIssue } ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); decoded.EventType.Should().Be(EventType.Reject); @@ -64,7 +66,7 @@ public class SecurityEventTokenTests { new[] { Problems.MissingSchema } ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); @@ -80,7 +82,7 @@ public class SecurityEventTokenTests { new[] { Problems.SchemaViolation } ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); decoded.EventType.Should().Be(EventType.Reject); @@ -96,7 +98,7 @@ public class SecurityEventTokenTests { ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); decoded.EventType.Should().Be(EventType.Reject); @@ -111,7 +113,7 @@ public class SecurityEventTokenTests { new[] { Problems.UnsupportedSchema } ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); decoded.EventType.Should().Be(EventType.Reject); @@ -126,7 +128,7 @@ public class SecurityEventTokenTests { new[] { Problems.IncorrectAuthenticationTag } ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); decoded.EventType.Should().Be(EventType.Reject); @@ -141,7 +143,7 @@ public class SecurityEventTokenTests { new[] { new Problems() { Description = "A real big issue" } } ); Console.WriteLine(token); - var decoded = new FitConnect.Models.SecurityEventToken(token); + var decoded = new SecurityEventToken(token); decoded.Event?.Type.Should() .Be(rejectSubmission); decoded.EventType.Should().Be(EventType.Reject); diff --git a/DemoRunner/SenderDemo.cs b/DemoRunner/SenderDemo.cs index e1735afffd8a09137a66448648db979c766ba405..8242b072004d9323bbff923c217fd143eec5fb4a 100644 --- a/DemoRunner/SenderDemo.cs +++ b/DemoRunner/SenderDemo.cs @@ -18,9 +18,8 @@ public static class SenderDemo { .GetSender(FitConnectEnvironment.Testing, clientId, clientSecret, logger) .WithDestination(destinationId) .WithServiceType("FIT Connect Demo", leikaKey) - .WithAttachments(new[] { new Attachment("Test.pdf", "Test Attachment") }) + .WithAttachments(new Attachment("Test.pdf", "Test Attachment")) .WithData("{\"message\":\"Hello World\"}") .Submit(); - } } diff --git a/E2ETest/E2ETest.csproj b/E2ETest/E2ETest.csproj index 9b68a3a077dc80a2ef5cfae445e642b7cf745aa3..974a92a07342e19b27e979c3c468d7658703bc45 100644 --- a/E2ETest/E2ETest.csproj +++ b/E2ETest/E2ETest.csproj @@ -9,16 +9,17 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> - <PackageReference Include="NUnit" Version="3.13.3" /> - <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" /> - <PackageReference Include="NUnit.Analyzers" Version="3.3.0" /> - <PackageReference Include="coverlet.collector" Version="3.1.2" /> + <PackageReference Include="FluentAssertions" Version="6.7.0"/> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0"/> + <PackageReference Include="NUnit" Version="3.13.3"/> + <PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/> + <PackageReference Include="NUnit.Analyzers" Version="3.3.0"/> + <PackageReference Include="coverlet.collector" Version="3.1.2"/> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> - <ProjectReference Include="..\MockContainer\MockContainer.csproj" /> + <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> + <ProjectReference Include="..\MockContainer\MockContainer.csproj"/> </ItemGroup> </Project> diff --git a/E2ETest/EndToEndTestBase.cs b/E2ETest/EndToEndTestBase.cs index d6a15f6d892d30fc7d46edd13943ded703cf7cc9..d4bd425041264b583e5895cf9a3288c9e740cb86 100644 --- a/E2ETest/EndToEndTestBase.cs +++ b/E2ETest/EndToEndTestBase.cs @@ -9,31 +9,34 @@ using MockContainer; namespace E2ETest; public abstract class EndToEndTestBase { - private ISender _sender; - private ISubscriber _subscriber; + protected ILogger Logger = null!; + protected ISender Sender = null!; + protected MockSettings Settings = null!; + protected ISubscriber Subscriber = null!; [OneTimeSetUp] public void Setup() { - var container = MockContainer.Container.Create(); - var settings = container.Resolve<MockSettings>(); + var container = Container.Create(); + Settings = container.Resolve<MockSettings>(); - var logger = LoggerFactory.Create( + Logger = LoggerFactory.Create( builder => { builder.AddSimpleConsole(); - builder.SetMinimumLevel(LogLevel.Trace); + builder.SetMinimumLevel(LogLevel.Information); }).CreateLogger("E2E Test"); - _sender = Client.GetSender(FitConnectEnvironment.Testing, - settings.SenderClientId, settings.SenderClientSecret, - logger); - _subscriber = Client.GetSubscriber(FitConnectEnvironment.Testing, - settings.SenderClientId, settings.SenderClientSecret, - settings.PrivateKeyDecryption, - settings.PrivateKeySigning, - settings.PublicKeyEncryption, - settings.PublicKeySignatureVerification, - logger + Sender = Client.GetSender(FitConnectEnvironment.Testing, + Settings.SenderClientId, Settings.SenderClientSecret, + Logger); + + Subscriber = Client.GetSubscriber(FitConnectEnvironment.Testing, + Settings.SubscriberClientId, Settings.SubscriberClientSecret, + Settings.PrivateKeyDecryption, + Settings.PrivateKeySigning, + Settings.PublicKeyEncryption, + Settings.PublicKeySignatureVerification, + Logger ); } } diff --git a/E2ETest/RejectSubmissionTest.cs b/E2ETest/RejectSubmissionTest.cs index 7279f8a56631301dba4a6028163c5218fac6fe87..4ee630072f9cd19fb1ffe863055a25a2adac1cc7 100644 --- a/E2ETest/RejectSubmissionTest.cs +++ b/E2ETest/RejectSubmissionTest.cs @@ -1,6 +1,85 @@ -using FitConnect.Encryption; +using FitConnect.Models; +using FitConnect.Models.v1.Api; +using FluentAssertions; +using Microsoft.Extensions.Logging; namespace E2ETest; public class RejectSubmissionTest : EndToEndTestBase { + private string? _caseId; + private string? _submissionId; + + [Order(10)] + [Test] + public void SendingSubmission() { + var submission = Sender.WithDestination(Settings.DestinationId) + .WithServiceType("Straight forward test", Settings.LeikaKey) + .WithAttachments(new Attachment("Test.pdf", "A simple PDF")) + .WithData(@"{""data"":""value""}") + .Submit(); + + _caseId = submission.CaseId; + _submissionId = submission.Id; + + _caseId.Should().NotBeNull(); + _submissionId.Should().NotBeNull(); + } + + [Test] + [Order(20)] + public void Sender_GetSubmissionState() { + // Act + var status = Sender.GetStatusForSubmission(_caseId); + + // Assert + status.Count.Should().BeGreaterThan(0); + status.ForEach( + s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); + } + + [Test] + [Order(30)] + public void Subscriber_GetSubmissionState() { + // Act + var status = Subscriber.GetStatusForSubmission(_caseId); + + // Assert + status.Count.Should().BeGreaterThan(0); + status.ForEach( + s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); + } + + [Test] + [Order(40)] + public void Reject_Submission() { + var subscriberWithSubmission = Subscriber.RequestSubmission(_submissionId); + + var data = subscriberWithSubmission.GetDataJson(); + Logger.LogInformation("Data {Data}", data); + + data.Should().Be(@"{""data"":""value""}"); + + var attachments = subscriberWithSubmission.GetAttachments(); + attachments.First().Filename.Should().Be("Test.pdf"); + + subscriberWithSubmission.RejectSubmission(Problems.SchemaViolation, + new Problems { Detail = "A critical problem" }); + } + + [Test] + [Order(50)] + public void Sender_GetSubmissionState_AfterRejecting() { + // Act + var status = Sender.GetStatusForSubmission(_caseId); + + // Assert + status.Count.Should().BeGreaterThan(0); + status.ForEach( + s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); + + var rejection = status.First(s => s.EventType == EventType.Reject); + + rejection.Problems.Should().NotBeNull(); + rejection.Problems?.ForEach(p => Logger.LogWarning(p.Detail)); + } } diff --git a/E2ETest/StraightForwardTest.cs b/E2ETest/StraightForwardTest.cs index f7b1e3312263ed59927209fb201b57564af5b97d..2826a3f7b3fb0a1366e471872ce4706447b3fb6a 100644 --- a/E2ETest/StraightForwardTest.cs +++ b/E2ETest/StraightForwardTest.cs @@ -1,9 +1,78 @@ +using FitConnect.Models; +using FluentAssertions; +using Microsoft.Extensions.Logging; + namespace E2ETest; public class StraightForwardTest : EndToEndTestBase { + private string? _caseId; + private string? _submissionId; + [Order(10)] [Test] - public void Test1() { - Assert.Pass(); + public void SendingSubmission() { + var submission = Sender.WithDestination(Settings.DestinationId) + .WithServiceType("Straight forward test", Settings.LeikaKey) + .WithAttachments(new Attachment("Test.pdf", "A simple PDF")) + .WithData(@"{""data"":""value""}") + .Submit(); + + _caseId = submission.CaseId; + _submissionId = submission.Id; + + _caseId.Should().NotBeNull(); + _submissionId.Should().NotBeNull(); + } + + [Test] + [Order(20)] + public void Sender_GetSubmissionState() { + // Act + var status = Sender.GetStatusForSubmission(_caseId); + + // Assert + status.Count.Should().BeGreaterThan(0); + status.ForEach( + s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); + } + + [Test] + [Order(30)] + public void Subscriber_GetSubmissionState() { + // Act + var status = Subscriber.GetStatusForSubmission(_caseId); + + // Assert + status.Count.Should().BeGreaterThan(0); + status.ForEach( + s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); + } + + [Test] + [Order(40)] + public void RequestSubmission() { + var subscriberWithSubmission = Subscriber.RequestSubmission(_submissionId); + + var data = subscriberWithSubmission.GetDataJson(); + Logger.LogInformation("Data {Data}", data); + + data.Should().Be(@"{""data"":""value""}"); + + var attachments = subscriberWithSubmission.GetAttachments(); + attachments.First().Filename.Should().Be("Test.pdf"); + + subscriberWithSubmission.AcceptSubmission(); + } + + [Test] + [Order(50)] + public void Sender_GetSubmissionState_AfterAccepting() { + // Act + var status = Sender.GetStatusForSubmission(_caseId); + + // Assert + status.Count.Should().BeGreaterThan(0); + status.ForEach( + s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType)); } } diff --git a/EncryptionTests/EncryptionTests.csproj b/EncryptionTests/EncryptionTests.csproj index 86c48ff27f44f56c75667c55b9446ac99c37e00a..075edba167f38f1e82e563b1ade734453e403914 100644 --- a/EncryptionTests/EncryptionTests.csproj +++ b/EncryptionTests/EncryptionTests.csproj @@ -10,22 +10,22 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="FluentAssertions" Version="6.7.0"/> - <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0"/> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0"/> - <PackageReference Include="NUnit" Version="3.13.2"/> - <PackageReference Include="NUnit3TestAdapter" Version="4.0.0"/> - <PackageReference Include="coverlet.collector" Version="3.1.0"/> + <PackageReference Include="FluentAssertions" Version="6.7.0" /> + <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> + <PackageReference Include="NUnit" Version="3.13.2" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> - <ProjectReference Include="..\MockContainer\MockContainer.csproj"/> + <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> + <ProjectReference Include="..\MockContainer\MockContainer.csproj" /> </ItemGroup> <ItemGroup> - <Folder Include="Certificates"/> + <Folder Include="Certificates" /> </ItemGroup> <ItemGroup> diff --git a/FitConnect/Client.cs b/FitConnect/Client.cs index 5de16d8f385d049e05fef785750f118498a5d934..e08bcd53b051360eb8e551a71e37369bbdf122bc 100644 --- a/FitConnect/Client.cs +++ b/FitConnect/Client.cs @@ -3,19 +3,34 @@ using FitConnect.Interfaces.Sender; using FitConnect.Interfaces.Subscriber; using FitConnect.Models; using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Logging; namespace FitConnect; public static class Client { + static Client() { +#if DEBUG + IdentityModelEventSource.ShowPII = true; +#endif + } + + /// <summary> + /// Creates the Sender Client + /// </summary> + /// <param name="environment">FIT-Connect Environment</param> + /// <param name="clientId">Client ID</param> + /// <param name="clientSecret">Client Secret</param> + /// <param name="logger">An instance of an ILogger</param> + /// <returns></returns> public static ISender GetSender(FitConnectEnvironment environment, string clientId, string clientSecret, ILogger? logger = null) { return new Sender(environment, clientId, clientSecret, logger); } /// <summary> - /// Creates a subscriber client + /// Creates a subscriber client /// </summary> - /// <param name="environment">FIT Connect Environment</param> + /// <param name="environment">FIT-Connect Environment</param> /// <param name="clientId">Client ID</param> /// <param name="clientSecret">Client Secret</param> /// <param name="privateKeyDecryption">Private key for decryption</param> @@ -35,6 +50,18 @@ public static class Client { privateKeySigning, publicKeyEncryption, publicKeySignatureVerification, logger); } + + /// <summary> + /// Returns a Router API implementation + /// </summary> + /// <param name="environment">FIT-Connect Environment</param> + /// <param name="logger">An instance of an ILogger</param> + /// <returns></returns> + public static IRouter + GetRouter(FitConnectEnvironment environment, ILogger? logger = null) { + return new Router(environment, logger); + } + #if DEBUG public static ISender GetSender(FitConnectEnvironment environment, string clientId, string clientSecret, IContainer container) { diff --git a/FitConnect/Encryption/FitEncryption.cs b/FitConnect/Encryption/FitEncryption.cs index 7b0720f522dcd27a1b1ed1adf493ca3b7283542c..e337765e8054ac21b1787c52ee7ca00d9a0dea7e 100644 --- a/FitConnect/Encryption/FitEncryption.cs +++ b/FitConnect/Encryption/FitEncryption.cs @@ -5,8 +5,8 @@ using FitConnect.Models.v1.Api; using IdentityModel; using Jose; using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; -using Newtonsoft.Json; namespace FitConnect.Encryption; @@ -99,7 +99,9 @@ public class FitEncryption { // { "alg", "PS512" } }; - object problems = problemsArray == null ? new { } : new { problems = problemsArray }; + object problems = problemsArray == null + ? new { } + : new { problems = problemsArray }; _jwtHeader["typ"] = "secevent+jwt"; @@ -133,4 +135,48 @@ public class FitEncryption { return sb.ToString(); } + + + public static bool VerifyJwt(string signature, string secret, + ILogger? logger = null) => VerifyJwt(signature, + new JsonWebKey(secret), logger); + + public static bool VerifyJwt(string signature, JsonWebKey key, + ILogger? logger = null) { + var tokenHandler = new JsonWebTokenHandler(); + + logger?.LogTrace("Verifying JWT {Token}", signature); + + if (key.KeySize != 4096) + throw new Exception("Key size must be 4096"); + + var result = tokenHandler.ValidateToken(signature, new TokenValidationParameters { + ValidAlgorithms = new[] { "PS512" }, + IssuerSigningKey = key, + ValidateIssuerSigningKey = true, + ValidateIssuer = false, + ValidateAudience = false, + ValidateLifetime = true, + ValidateActor = true, + ValidateSignatureLast = true, + ValidateTokenReplay = true, + ValidateWithLKG = true, + RequireAudience = true, + RefreshBeforeValidation = true, + RequireSignedTokens = true, + RequireExpirationTime = false, + IgnoreTrailingSlashWhenValidatingAudience = true, + TryAllIssuerSigningKeys = true, + }); + + var error = result.Exception?.Message; + + if (error != null) + logger?.LogWarning("Validation error {Error}", error); + else { + logger?.LogInformation("JWT is valid"); + } + + return result.IsValid; + } } diff --git a/FitConnect/Encryption/JoseEncryptor.cs b/FitConnect/Encryption/JoseEncryptor.cs index 91ca13ad3b441165fb71911b374561180ac55d45..ef6bd4c98786dea596ea7b6adb3d18681581401b 100644 --- a/FitConnect/Encryption/JoseEncryptor.cs +++ b/FitConnect/Encryption/JoseEncryptor.cs @@ -1,4 +1,10 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Principal; +using System.Text; using Jose; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; // ReSharper disable RedundantExplicitArrayCreation @@ -64,6 +70,15 @@ public class JoseEncryptor : IEncryptor { } } + // public bool TokenValidator(string signature, string key) { + // Jose.Jwk jwk = Jwk.FromJson(key, new JsonMapper()); + // var token = Jose.JweToken.FromString(signature); + // Jose. + // + // + // + // } + private (string plainText, byte[] plainBytes, byte[] tag) Decrypt(Jwk key, string payload) { var result = JWE.Decrypt(payload, key, Algorithm, Encryption); diff --git a/FitConnect/FitConnectClient.cs b/FitConnect/FitConnectClient.cs index 8968ff7f4eff54900500801c3638949b3693cca1..0348804c8289987b9625b8ff167a4da02073a832 100644 --- a/FitConnect/FitConnectClient.cs +++ b/FitConnect/FitConnectClient.cs @@ -30,7 +30,7 @@ public abstract class FitConnectClient { OAuthService = new OAuthService(environment.TokenUrl, "V1", clientId, clientSecret, logger); SubmissionService = new SubmissionService(environment.SubmissionUrl[0], OAuthService, logger: logger); - RouteService = new RouteService(environment.RoutingUrl, OAuthService, logger: logger); + RouteService = new RouteService(environment.RoutingUrl, logger: logger); CasesService = new CasesService(environment.SubmissionUrl[0], OAuthService, logger: logger); DestinationService = new DestinationService(environment.SubmissionUrl[0], OAuthService, logger: logger); diff --git a/FitConnect/HttpCalls/RoutingApi.http b/FitConnect/HttpCalls/RoutingApi.http index ca26f34339125366d1cef16c841c87716c31ba9f..7b497a04e04b1251671cbf77d6ad88ebeb42af1f 100644 --- a/FitConnect/HttpCalls/RoutingApi.http +++ b/FitConnect/HttpCalls/RoutingApi.http @@ -6,3 +6,19 @@ Accept: application/json GET {{routing_api_url}}/v1/routes?leikaKey=99012070006000 Accept: application/json +### Get areas +GET {{routing_api_url}}/v1/routes?ars=064350014014&leikaKey=99123456760610 +Accept: application/json + +### Get Route +GET {{routing_api_url}}/v1/routes?ars=064350014014&leikaKey=99123456760610 + + +### Get Route +GET {{routing_api_url}}/v1/areas?areaSearchexpression=Furth* +Accept: application/json + +### +GET https://submission-api-testing.fit-connect.fitko.dev/.well-known/jwks.json +Accept: application/json +Content-Type: application/json diff --git a/FitConnect/HttpCalls/SenderCalls.http b/FitConnect/HttpCalls/SenderCalls.http index 6834bb4b14fef316283551bb70a4897c2edba7aa..57695ee4231e76bfee2aa9e4e4680f911f97789b 100644 --- a/FitConnect/HttpCalls/SenderCalls.http +++ b/FitConnect/HttpCalls/SenderCalls.http @@ -1,3 +1,10 @@ +### Get Destination +GET {{submission_api_url}}/.well-known/jwks.json +Accept: application/json +Content-Type: application/json +Authorization: Bearer {{token}} + + ### Get Destination infos GET {{submission_api_url}}/v1/destinations/{{destinationId}} Accept: application/json @@ -65,3 +72,25 @@ Authorization: Bearer {{token}} "encryptedMetadata": "l3--gxZp131zyqCOWmdzxHiNySKGSlyOI63eIBoPDg1-f9v-GPFLCjNANFbW8y96orN0RYLsWQEa4JAV93lvz_caJQXMyFiE8VdRr7SjS4ivBfyizdplnnBQ2V_vZCL7t65GneogIF-xpiXF4zxOH6dY5BJxq9IC-6EkWK76fSa5xfe2k-SXDQXlqP6fWqkR2iECKO16cY5rrneMzkvC9nPNzeMKtlcnirQfKPEklK5Kp_6gLRT8nQrBUma5bDhctpOweSIiVeuv_zgHOzvxvuK6_Xoc1M0WHniR4y_qUA8YzLUI1-FfMu1N88TI0brcngbF4zVarQXv7q8gzGynEgTln11JrL0Fx87U_-Gfc5RUsjxMynEgZ8Qr72UpYF3HcMEg4xRTeivlWiOu4s9hvSyE2RJanp6amB68CPG-TUaS5tKbEPjHc5zmTOedUAgw-mfLOJNAleW_J-7L07pWCYxR0Jr5hVMFBBCuh1mbeMoW1kF1mfmDwT_X6U-cC_srvXQiSVk7kub0NJRpG9mx6FvHapVZRO709Luslj4Fw9d8Jnw6zw_MAxbBPOvNAVVm20Nqm66_aB4wv-qJDWA3SQZFW5dO4Zuh8eubLhOBes0jHTEFQSh6q4r1zVNYC1nSJUYzYpK9eaNa43oXF-HVp4rdXNaTyE6M0Vd5YgZwbOLrVS4QyvvURMgOcD5xRQCi6F89ZrAN09aoCAeaKuB-r5VuDfquYB5J6RMSXNLvXuHOR1iHwcC6EFvNnqzDystsDXJudPLSdiQJBszpOjM28DZgtl-I0hw7-FVKdTWlkB9IpbjTNMOdJcWMUCpoJIkAIiWYlAsmZ0K22mj_fFY08kPKyuEOJNBB_dDf2O_kF92PNY51I1Npa_PE2uXEaBp95772KvSdvn6fDri42iGJGIGS5cADQDHiDTYGrBsluzdLD6PKD4XBrGipM9jkWbTRNG8lY4lkNtUwtKU5rVDcbdstAivwdlTpeLKHVjPE-ITW-5QhM13HCgZ6eJPFpwpT4VpAUT4euikzoRccyJOYqkzKr1Z0JP-7kop-0GnKNZ1zBJEaEq_gf53lYInrV9f3EQM8ynQpp_0wMNwVU6_0xOjEMX5DMt2io_whkNEvuTa56A" } + +### https://git.fitko.de/fit-connect/planning/-/issues/487 + + +### Get well known keys +GET {{submission_api_url}}/.well-known/jwks.json +Accept: application/json +Content-Type: application/json +Authorization: Bearer {{token}} + + +### Get well known keys +GET https://submission-api-testing.fit-connect.fitko.dev/.well-known/jwks.json +Accept: application/json +Content-Type: application/json +Authorization: Bearer {{token}} + + +### GET Destination from DVDV +GET https://dvdv-testsystem.governikus.de/dvdv-fitconnect/v1/destinations/{{destinationId}} +Accept: application/json +Content-Type: application/json diff --git a/FitConnect/HttpCalls/StaticTests.http b/FitConnect/HttpCalls/StaticTests.http index f2996b8a2a3a4bff6684e2cc0d09e9b4b8128824..7cfb63e4e49b90c1728b4fd4ea41f90c147bb67a 100644 --- a/FitConnect/HttpCalls/StaticTests.http +++ b/FitConnect/HttpCalls/StaticTests.http @@ -22,3 +22,14 @@ Authorization: Bearer {{token}} "encryptedMetadata": "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJjdHkiOiJhcHBsaWNhdGlvbi9qc29uIiwiZW5jIjoiQTI1NkdDTSIsImtpZCI6InZyN2NXS0dsLWc0V2FfQ1JHb3dOaEFZV19nUWItYWtNYmlpZ3hOMEVrREkiLCJ6aXAiOiJERUYifQ.MMPBbWa7gnK-bu2Iocp0WVT7IeVqpwdV23cH3t9qGmkARXLF14bVQh8oT0wIaZRhn0DLUEwv9tsQch7oZvOj4KZdyip9F-cvt4Z0re74nzC1pC9FGGVdUmOWOiOeh8KSnpP6iVWUlA5HVotao0yOt6OqeqdnbgSt_MT7ARPURAvqvTCTgZNtY3_dBKhm0AQMyaGlQdMZitogXNgXXiXPbydWpgoLvOEB_Y43cIPdqBN1iK1zhuwHHeXVSfxCtYNOkh_mqSAvDy-lHK9rYschhjhynOBEQYzFv66tiCn7HjJpSoFY2XaOM07PYy45dMUEzQv_bkQlnlNhAn58K_FUvwsT0BhRX12pq27Xpg6X7qa4KYrxByKHsiPSegJtsIMT-24BSU8vU3KEEqIvwlp5XtPgPCi4mrzU_wqGozxlbrAlT59mvcxhd3LUQWBjd5EByIZZXRkq9b2jvsiauZahzUppMX8r5iswrlteB7SkVJUMVA3_uGPFPfxGyIBAykS28DB7i9M-_MIoEEkT07xNMHApU9Q95I02c8q9dnQb146ZwqlQ8oGepparaCQrUVIIjD--6oh67ta5M2e1NesK_iWEgzTEOsh_ymyv7TFNmTO9iMQ7HuK8Mf6tozyqruzAHTqiPcd9DdrO3TJMrTyYIXQSnsFz_uyxJ_09bcVDD4M.WNkZENRbSaFdfaPA.YVVkbO3aHaTiNbRO33F2R99gh0PAMyUV6Az_q_Po7mUFTXfvgdRI__VPjYVlktRkkZXmQs13n8BVLbLGH_OkobOvLD3Ufxdn8z0Lot3f_ydXOGsdc1ID-OqAx3mhxzrQi9JdO4QYSWtCIHXi96iyyljQmVwj27ioukNOLbfiH2WVjXR1m7v92ePc8FLDNUMh-epXYk-lSyV3T5w1xRXljZrS53ictqFXrQd31crDVfbCilXwlndYLJCp7NvvyoprtOZIEXsUpiFLpOT3du5PhNrPoAXPbjpYFAKLaI3F56vaSwqF820NJlJWXyRE18m8MVpELRllPUl1D96w7-YnsUbsMWgB2rqoPS8ArzbkIpEa-CIpgnNVTEptnFLAye3Qnb9kCnkjQNdE8AfMfneOcW2Jdox2hwM178tqR5jxxRN3sucfqQ_vuqSo3CcLgnFnYP1GpYBdSv_ehus4VrMEtjRtp5rjjpnqUYydyP3JX7FSUmvxYigq5_-yO24UZQLozcnwL04_oMMbqPfMsiyY_GOS-jA5xl4Qt6wooixoH1nQgJpcVvIniaRdZ7oz3uUhmNVxB5aSkC8UO9KCtp2Warg.VajPcUlW2bShHc09-7KQ8Q", "encryptedData": "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJjdHkiOiJhcHBsaWNhdGlvbi9qc29uIiwiZW5jIjoiQTI1NkdDTSIsImtpZCI6InZyN2NXS0dsLWc0V2FfQ1JHb3dOaEFZV19nUWItYWtNYmlpZ3hOMEVrREkiLCJ6aXAiOiJERUYifQ.qbMW9T1LYYA1jmcjWZi0AYiUrg_124Fk8Hmfx6Fjt6usv0PKHLzMHt3Z7j_yKr9nSLbosoKB6a5FwjgZvkaq_ffuPdCQt36YIGoEdpxP2y3lkEdx8662S-wVKpjukRJi1vFK5Ymq6W6bk2Tsh2GAgwkXr_7q_WjIzRtBRrVmzmHjoDB8jUrQv9_7yQJy-1lCs0_efhmxZPHeHTmOgkHy8w-xAhjVlhGH2ErgFeUZESGjHGGKVg3kancxeNpLz0hIRAej2C8M7QKMTpcuim_J0M70vOK5VFDcDeYxJSUaaIXGMYv2-foISVAA5Dp0t5BZcQTNUT5MbMGBTGcFnICaBEEAef5jWG6320heQavyDLpdS96ddCuWRGIJHlG0wLORPuJqR47kxfR_9BPc2eYJEG8bEFeyPmDQ83Qqi8JTX5Tz1mLGHyUIA8y_tl3qTV1emc6MAAeG-TWTmrds5msjEWaZ3Q9Ee3m55b0PKVMR8lT5P_i0amhZwQIVUXmZYwRepXqXhezJrF-G2Pltu7ge83nCu7i9a5q740sR25cKv3qv3KLBgi-mliSFswTP1rAOCs_UkjN1GmOOQD0mgtPpuY_-yAhl2XOOBgfkHcDKzGP4abTCsEabAaQlbe3bwIKmh2IJuPfPB-YbT7cdrEbJdRo2YBsJksAqm_mDRbLqCtA.fdb92PBWLFD6m8iw.Yxo8kvGgCEgJL-MVWtu64b5Bc0OxlsNedNmCcwCsQXiCuqkucNWxHacpk7AbOr_3ik_8IxFFRt0gnRYXfiiUuKLH1kvuePgY_eQY.iJ3f1rHtnDxvG2qz_snZ-A" } + + +### Well knwon +GET https://portal.auth-testing.fit-connect.fitko.dev/.well-known/jwks.json +Accept: application/json +Content-Type: application/json + +### +GET https://dvdv-testsystem.governikus.de/dvdv-fitconnect/v1/destinations/d40e7b13-da98-4b09-9e16-bbd61ca81510 +Accept: application/json +Content-Type: application/json diff --git a/FitConnect/IRouter.cs b/FitConnect/IRouter.cs new file mode 100644 index 0000000000000000000000000000000000000000..aa8b07c8d4aa9737d81d5625f3d738b3a325f240 --- /dev/null +++ b/FitConnect/IRouter.cs @@ -0,0 +1,26 @@ +using FitConnect.Models; +using Route = FitConnect.Services.Models.v1.Routes.Route; + +namespace FitConnect; + +public interface IRouter { + /// <summary> + /// Finding areas for the filter with paging + /// </summary> + /// <param name="filter">Search string for the area, use * as wildcard</param> + /// <param name="totalCount">out var for the total count</param> + /// <param name="offset"></param> + /// <param name="limit"></param> + /// <example> + /// var areas = GetAreas("Erlang*", out var _, 0, 10) + /// </example> + /// <returns></returns> + public IEnumerable<Area> GetAreas(string filter, out int totalCount, int offset = 0, + int limit = 100); + + + public Task<List<Route>> FindDestinationsAsync( + string leiaKey, string? ags = null, + string? ars = null, + string? areaId = null, bool skipValidation = false); +} diff --git a/FitConnect/Interfaces/Sender/ISender.cs b/FitConnect/Interfaces/Sender/ISender.cs index 2e6824ef707adb7cf146490925244910d6b656d7..4f481f3578d80aa8421e854532030da91e15caf7 100644 --- a/FitConnect/Interfaces/Sender/ISender.cs +++ b/FitConnect/Interfaces/Sender/ISender.cs @@ -1,6 +1,4 @@ using FitConnect.Interfaces.Subscriber; -using FitConnect.Models; -using FitConnect.Services.Interfaces; namespace FitConnect.Interfaces.Sender; @@ -28,19 +26,4 @@ public interface ISender : IFitConnectClient { /// </param> /// <returns>the upload step for attachments</returns> public ISenderWithDestination WithDestination(string destinationId); - - - /// <summary> - /// Finding areas for the filter with paging - /// </summary> - /// <param name="filter">Search string for the area, use * as wildcard</param> - /// <param name="totalCount">out var for the total count</param> - /// <param name="offset"></param> - /// <param name="limit"></param> - /// <example> - /// var areas = GetAreas("Erlang*", out var _, 0, 10) - /// </example> - /// <returns></returns> - public IEnumerable<Area> GetAreas(string filter, out int totalCount, int offset = 0, - int limit = 100); } diff --git a/FitConnect/Interfaces/Sender/ISenderWithDestination.cs b/FitConnect/Interfaces/Sender/ISenderWithDestination.cs index 247da7e20f18b05b360ddff2d01e7aca8881ebf8..1aa81a764571ffb8dec41a679e23d26ac231d727 100644 --- a/FitConnect/Interfaces/Sender/ISenderWithDestination.cs +++ b/FitConnect/Interfaces/Sender/ISenderWithDestination.cs @@ -13,6 +13,4 @@ public interface ISenderWithDestination { /// </param> /// <returns></returns> ISenderWithService WithServiceType(string serviceName, string leikaKey); - - } diff --git a/FitConnect/Interfaces/Sender/ISenderWithService.cs b/FitConnect/Interfaces/Sender/ISenderWithService.cs index e86042f50a9534fa7f464d2511b0b01463b33b22..8eaef30e0d76cd322e309051735d5e07fbff6ad9 100644 --- a/FitConnect/Interfaces/Sender/ISenderWithService.cs +++ b/FitConnect/Interfaces/Sender/ISenderWithService.cs @@ -11,7 +11,7 @@ public interface ISenderWithService { /// <param name="attachments">that are sent with the submission</param> /// <returns>the step where additional data can be added to the submission</returns> public ISenderWithAttachments WithAttachments(IEnumerable<Attachment> attachments); - + /// <summary> /// Sends the submission with a list of attachments /// </summary> diff --git a/FitConnect/Interfaces/Subscriber/ISubscriber.cs b/FitConnect/Interfaces/Subscriber/ISubscriber.cs index d782ef47c4b05b780eeb52420a295704f3418c5f..7f478989ddacb801680cad62b171c20d1b9633bf 100644 --- a/FitConnect/Interfaces/Subscriber/ISubscriber.cs +++ b/FitConnect/Interfaces/Subscriber/ISubscriber.cs @@ -24,13 +24,11 @@ public interface ISubscriber : IFitConnectClient { bool skipSchemaTest = false); } -public interface IFitConnectClient{ - -/// <summary> - /// Receives the SecurityEventTokens for a given case +public interface IFitConnectClient { + /// <summary> + /// Receives the SecurityEventTokens for a given case /// </summary> /// <param name="caseId">ID of the case</param> - /// <returns>List of the <see cref="SecurityEventToken"/></returns> + /// <returns>List of the <see cref="SecurityEventToken" /></returns> public List<SecurityEventToken> GetStatusForSubmission(string caseId); - } diff --git a/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs b/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs index dccc20a60a95dae09317486f5e4ce854d7d64258..ada7ea0de673e21ccef1d7432df7815441ffd6b2 100644 --- a/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs +++ b/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs @@ -1,6 +1,5 @@ using FitConnect.Models; using FitConnect.Models.v1.Api; -using Data = FitConnect.Models.Data; namespace FitConnect.Interfaces.Subscriber; @@ -8,10 +7,12 @@ public interface ISubscriberWithSubmission { public Submission Submission { get; } /// <summary> - /// Returns the data (Fachdaten) of the submission + /// Returns the data (Fachdaten) of the submission /// </summary> /// <returns></returns> - public string? GetDataJson() => Submission.Data; + public string? GetDataJson() { + return Submission.Data; + } /// <summary> /// Loads the <see cref="Attachment" />s for the given <see cref="Submission" />. @@ -25,18 +26,18 @@ public interface ISubscriberWithSubmission { public void AcceptSubmission(); /// <summary> - /// Rejects the submission + /// Rejects the submission /// </summary> /// <param name="problems">Reasons for the rejection</param> public void RejectSubmission(params Problems[] problems); /// <summary> - /// Set submission state to forwarded + /// Set submission state to forwarded /// </summary> public void ForwardSubmission(); /// <summary> - /// Set submission state + /// Set submission state /// </summary> /// <param name="status">state the submission has to be set to</param> public void CompleteSubmission(FinishSubmissionStatus status); diff --git a/FitConnect/Models/Area.cs b/FitConnect/Models/Area.cs index d02e2b530240f66483f1720416af2939cbc79052..8ba0965ec305fa809615cf4b46ccfa402eda2f41 100644 --- a/FitConnect/Models/Area.cs +++ b/FitConnect/Models/Area.cs @@ -1,29 +1,29 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Models; // Root myDeserializedClass = JsonSerializer.Deserialize<Root>(myJsonResponse); public class Area { - [JsonPropertyName("id")] + [JsonProperty("id")] public string Id { get; set; } = ""; - [JsonPropertyName("name")] + [JsonProperty("name")] public string Name { get; set; } = ""; - [JsonPropertyName("type")] + [JsonProperty("type")] public string Type { get; set; } = ""; } public class AreaList { - [JsonPropertyName("count")] + [JsonProperty("count")] public int Count { get; set; } - [JsonPropertyName("offset")] + [JsonProperty("offset")] public int Offset { get; set; } - [JsonPropertyName("totalCount")] + [JsonProperty("totalCount")] public int TotalCount { get; set; } - [JsonPropertyName("areas")] + [JsonProperty("areas")] public List<Area> Areas { get; set; } = new(); } diff --git a/FitConnect/Models/FitConnectEnvironment.cs b/FitConnect/Models/FitConnectEnvironment.cs index 6bd051ba110b9b27058a613703653896f203ad1f..104a1e0fc67c567ddb7974318c6b7ee0480656c9 100644 --- a/FitConnect/Models/FitConnectEnvironment.cs +++ b/FitConnect/Models/FitConnectEnvironment.cs @@ -1,28 +1,26 @@ namespace FitConnect.Models; -// public enum FitConnectEnvironment { -// Development, -// Testing, -// Production -// } - public class FitConnectEnvironment { + public static readonly FitConnectEnvironment Testing = new( "https://auth-testing.fit-connect.fitko.dev/token", new[] { "https://submission-api-testing.fit-connect.fitko.dev" }, - "https://routing-api-testing.fit-connect.fitko.dev" + "https://routing-api-testing.fit-connect.fitko.dev", + "https://portal.auth-testing.fit-connect.fitko.dev" ); public static readonly FitConnectEnvironment Staging = new( "https://auth-refz.fit-connect.fitko.dev/token", new[] { "https://submission-api-refz.fit-connect.fitko.dev" }, - "https://routing-api-refz.fit-connect.fitko.dev" + "https://routing-api-refz.fit-connect.fitko.dev", + "https://portal.auth-testing.fit-connect.fitko.dev/.well-known/jwks.json" ); public static readonly FitConnectEnvironment Production = new( "https://auth.fit-connect.fitko.net/token", new[] { "https://submission-api.fit-connect.fitko.net" }, - "https://routing-api.fit-connect.fitko.net" + "https://routing-api.fit-connect.fitko.net", + "https://portal.auth-testing.fit-connect.fitko.dev/.well-known/jwks.json" ); public FitConnectEnvironment() { @@ -34,12 +32,18 @@ public class FitConnectEnvironment { /// <param name="tokenUrl">URL for receiving the OAuth token</param> /// <param name="submissionUrl">URL for the submission API</param> /// <param name="routingUrl">URL for the routing API</param> - public FitConnectEnvironment(string tokenUrl, string[] submissionUrl, string routingUrl) { + public FitConnectEnvironment(string tokenUrl, string[] submissionUrl, string routingUrl, + string sspUrl) { + SspUrl = sspUrl; TokenUrl = tokenUrl; SubmissionUrl = submissionUrl; RoutingUrl = routingUrl; } + /// <summary> + /// Self service portal URL + /// </summary> + public string SspUrl { get; } /// <summary> /// URL for receiving the OAuth token. /// </summary> diff --git a/FitConnect/Models/SecurityEventToken.cs b/FitConnect/Models/SecurityEventToken.cs index 815c9cd344fbc3afb1229270015366b20d266c62..94fba7ac5a4a94f5e7b5b6e7ac6243e42c4ba7c8 100644 --- a/FitConnect/Models/SecurityEventToken.cs +++ b/FitConnect/Models/SecurityEventToken.cs @@ -2,6 +2,7 @@ using System.Security.Claims; using FitConnect.Models.v1.Api; using Microsoft.IdentityModel.JsonWebTokens; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace FitConnect.Models; @@ -17,13 +18,26 @@ public enum EventType { } public class SecurityEventToken { - public const string CreateSubmissionSchema = "https://schema.fitko.de/fit-connect/events/create-submission"; - public const string SubmitSubmissionSchema = "https://schema.fitko.de/fit-connect/events/submit-submission"; - public const string NotifySubmissionSchema = "https://schema.fitko.de/fit-connect/events/notify-submission"; - public const string ForwardSubmissionSchema = "https://schema.fitko.de/fit-connect/events/forward-submission"; - public const string RejectSubmissionSchema = "https://schema.fitko.de/fit-connect/events/reject-submission"; - public const string AcceptSubmissionSchema = "https://schema.fitko.de/fit-connect/events/accept-submission"; - public const string DeleteSubmissionSchema = "https://schema.fitko.de/fit-connect/events/delete-submission"; + public const string CreateSubmissionSchema = + "https://schema.fitko.de/fit-connect/events/create-submission"; + + public const string SubmitSubmissionSchema = + "https://schema.fitko.de/fit-connect/events/submit-submission"; + + public const string NotifySubmissionSchema = + "https://schema.fitko.de/fit-connect/events/notify-submission"; + + public const string ForwardSubmissionSchema = + "https://schema.fitko.de/fit-connect/events/forward-submission"; + + public const string RejectSubmissionSchema = + "https://schema.fitko.de/fit-connect/events/reject-submission"; + + public const string AcceptSubmissionSchema = + "https://schema.fitko.de/fit-connect/events/accept-submission"; + + public const string DeleteSubmissionSchema = + "https://schema.fitko.de/fit-connect/events/delete-submission"; public SecurityEventToken(string jwtEncodedString) { Token = new JsonWebToken(jwtEncodedString); @@ -31,8 +45,6 @@ public class SecurityEventToken { var iat = Token.Claims.FirstOrDefault(c => c.Type == "iat").Value; if (long.TryParse(iat, out var timeEpoch)) EventTime = DateTime.UnixEpoch.AddSeconds(timeEpoch); - - // TODO Fill problems } public DateTime EventTime { get; set; } @@ -50,8 +62,9 @@ public class SecurityEventToken { var events = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(eventsClaim.Value); Payload = JsonConvert .DeserializeObject<dynamic>( - events.Values.FirstOrDefault().ToString()); + events?.Values?.FirstOrDefault()?.ToString()); + var contentData = JsonConvert.DeserializeObject(eventsClaim.Value); if (eventsClaim.Value.Contains( CreateSubmissionSchema)) @@ -68,15 +81,35 @@ public class SecurityEventToken { ForwardSubmissionSchema)) return EventType.Forward; if (eventsClaim.Value.Contains( - RejectSubmissionSchema)) + RejectSubmissionSchema)) { + Problems = GetProblems(events?.Values?.FirstOrDefault()?.ToString() ?? ""); return EventType.Reject; - if (eventsClaim.Value.Contains( - AcceptSubmissionSchema)) + } + + + if (eventsClaim.Value.Contains(AcceptSubmissionSchema)) return EventType.Accept; + + if (eventsClaim.Value.Contains( DeleteSubmissionSchema)) return EventType.Delete; return EventType.NotSet; } + + private static List<Problems> GetProblems(string payload) { + if (payload == "") return new List<Problems>(); + return (JsonConvert.DeserializeObject<dynamic>(payload)?.problems as JArray) + ?.Select(j => j as dynamic).ToList() + ?.Select(p => new Problems { + Title = p.Title, + Description = p.Description, + Items = p.Items, + Type = p.Type, + Detail = p.Detail, + Instance = p.Instance + }) + ?.ToList() ?? new List<Problems>(); + } } diff --git a/FitConnect/Properties/AssemblyInfo.cs b/FitConnect/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..49986d47feefcf501c1b2de8b2b4b8d7025ecd6f --- /dev/null +++ b/FitConnect/Properties/AssemblyInfo.cs @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; + + +[assembly:InternalsVisibleTo("IntegrationTests")] + +// Von der MSBuild WriteCodeFragment-Klasse generiert. + diff --git a/FitConnect/Router.cs b/FitConnect/Router.cs new file mode 100644 index 0000000000000000000000000000000000000000..6f2976853794c7802c73fdf480818c4f7ab167df --- /dev/null +++ b/FitConnect/Router.cs @@ -0,0 +1,155 @@ +using System.Data; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using System.Text.Encodings.Web; +using FitConnect.Encryption; +using FitConnect.Models; +using FitConnect.Services; +using FitConnect.Services.Interfaces; +using Jose; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Base64Url = IdentityModel.Base64Url; +using Route = FitConnect.Services.Models.v1.Routes.Route; + +namespace FitConnect; + +public class Router : IRouter { + private readonly FitConnectEnvironment _environment; + private readonly ILogger? _logger; + private readonly IRouteService _routeService; + private readonly ISelfServicePortalService _selfServicePortalService; + + + public Router(FitConnectEnvironment environment, ILogger? logger = null) { + _environment = environment; + _logger = logger; + _routeService = new RouteService(environment.RoutingUrl, "v1", logger); + _selfServicePortalService = new SelfServicePortalService(environment.SspUrl, "v1", logger); + } + + public async Task<List<Route>> FindDestinationsAsync(string leiaKey, string? ags = null, + string? ars = null, + string? areaId = null, bool skipValidation = false) { + var routes = await _routeService.GetDestinationIdAsync(leiaKey, ags, ars, areaId); + if (skipValidation) return routes; + + + foreach (var route in routes) { + _logger?.LogInformation("Testing destination {DestinationId}", route.DestinationId); + + var verifyJwt = await VerifyDestinationSignature(route); + if (!verifyJwt) { + throw new Exception($"Invalid destination signature"); + } + + verifyJwt &= await VerifyDestinationParametersSignature(route); + + if (!verifyJwt) { + throw new Exception($"Invalid destination parameter signature"); + } + + verifyJwt &= VerifySubmissionHost(route); + + if (!verifyJwt) { + throw new Exception( + $"SubmissionHost does not match DestinationParameters SubmissionUrl"); + } + } + + return routes; + } + + private bool VerifySubmissionHost(Route route) { + var signature = new JsonWebToken(route.DestinationSignature); + var payload = + JsonConvert.DeserializeObject<dynamic>( + Base64UrlEncoder.Decode(signature.EncodedPayload)); + + string? submissionHost = payload?.submissionHost; + if (submissionHost == null) return false; + + var destinationUri = new Uri(route.DestinationParameters.SubmissionUrl); + + return destinationUri.Host == submissionHost; + } + + private async Task<bool> VerifyDestinationParametersSignature(Route route) { + // Get Key from SubmissionAPI + var submissionKey = + await GetSubmissionServiceValidationJwk(route.DestinationParameters.SubmissionUrl); + + var parameterJson = JsonConvert.SerializeObject(route.DestinationParameters, + new JsonSerializerSettings { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + ContractResolver = new OrderedContractResolver() + }); + + var encodedParameter = Base64Url.Encode(Encoding.UTF8.GetBytes(parameterJson)); + + var signature = + route.DestinationParametersSignature.Replace("..", $".{encodedParameter}."); + + + // KID to check is in signature header kid + var header = JsonConvert.DeserializeObject<dynamic>( + Base64UrlEncoder.Decode(route.DestinationParametersSignature.Split('.')[0]) + ); + var kid = (string)header.kid; + + _logger?.LogInformation("Testing with kid: {kid}", kid); + return FitEncryption.VerifyJwt(signature, + new JsonWebKeySet(submissionKey).Keys.First(k => k.Kid == kid), _logger); + } + + private async Task<bool> VerifyDestinationSignature(Route route) { + var validation = await _selfServicePortalService.GetValidationJwk(); + var token = new JsonWebToken(route.DestinationSignature); + var key = validation.Keys.First(k => k.Kid == token.Kid); + var verifyJwt = + FitEncryption.VerifyJwt(route.DestinationSignature, key, _logger); + return verifyJwt; + } + + /// <summary> + /// + /// </summary> + /// <returns></returns> + public async Task<string> GetSubmissionServiceValidationJwk(string baseUrl) { + var client = new HttpClient() { + BaseAddress = new Uri(baseUrl), + }; + + var result = await client.GetAsync("/.well-known/jwks.json"); + return await result.Content.ReadAsStringAsync(); + } + + + /// <summary> + /// Finding Areas + /// </summary> + /// <param name="filter"></param> + /// <param name="totalCount"></param> + /// <param name="offset"></param> + /// <param name="limit"></param> + /// <returns></returns> + public IEnumerable<Area> GetAreas(string filter, out int totalCount, int offset = 0, + int limit = 100) { + var dto = _routeService.GetAreas(filter, offset, limit).Result; + totalCount = dto?.TotalCount ?? 0; + return dto?.Areas ?? new List<Area>(); + } +} + +public class OrderedContractResolver : DefaultContractResolver { + protected override System.Collections.Generic.IList<JsonProperty> CreateProperties( + System.Type type, MemberSerialization memberSerialization) { + NamingStrategy = new CamelCaseNamingStrategy(); + return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName) + .ToList(); + } +} diff --git a/FitConnect/Sender.cs b/FitConnect/Sender.cs index f56fe72f6b981dcceda3dbaa364321c85b64086b..c82db00bf21d6fd24491318586ea0d57a6073895 100644 --- a/FitConnect/Sender.cs +++ b/FitConnect/Sender.cs @@ -74,7 +74,7 @@ public class Sender : FitConnectClient, ISender, ISenderWithDestination, Submission!.Data = data; return this; } - + public Submission? Submission { get; set; } Submission ISenderReady.Submit() { @@ -85,6 +85,15 @@ public class Sender : FitConnectClient, ISender, ISenderWithDestination, var metadata = CreateMetadata(Submission); Logger?.LogTrace("MetaData: {metadata}", metadata); + var validationErrors = Subscriber.VerifyMetadata(metadata); + if (validationErrors.Count != 0) { + validationErrors.ToList() + .ForEach(v => Logger?.LogError("Validation error: {error}", v)); + Logger?.LogError("Sending submission aborted due to validation errors"); + throw new InvalidOperationException("Submission is not ready"); + } + + Logger?.LogInformation("MetaData validation check, done"); Logger?.LogInformation("Sending submission"); var encryptedMeta = Encryption.Encrypt(metadata); Logger?.LogTrace("Encrypted metadata: {encryptedMeta}", encryptedMeta); @@ -115,14 +124,14 @@ public class Sender : FitConnectClient, ISender, ISenderWithDestination, } /// <summary> - /// /// </summary> /// <param name="attachments"></param> /// <returns></returns> - public ISenderWithAttachments WithAttachments(params Attachment[] attachments) => - WithAttachments(attachments.ToList()); - - + public ISenderWithAttachments WithAttachments(params Attachment[] attachments) { + return WithAttachments(attachments.ToList()); + } + + /// <summary> /// </summary> /// <param name="attachments"></param> @@ -217,12 +226,6 @@ public class Sender : FitConnectClient, ISender, ISenderWithDestination, return JsonConvert.SerializeObject(metaData); } - public IEnumerable<Area> GetAreas(string filter, out int totalCount, int offset = 0, - int limit = 100) { - var dto = RouteService.GetAreas(filter, offset, limit).Result; - totalCount = dto?.TotalCount ?? 0; - return dto?.Areas ?? new List<Area>(); - } /// <summary> /// Uploading the encrypted data to the server diff --git a/FitConnect/Services/CasesService.cs b/FitConnect/Services/CasesService.cs index 5012c6bde657c1faef9e8f8d3481f8d83761bf11..65be9c6b296fa1d6115bc79a4efab7ac315a7822 100644 --- a/FitConnect/Services/CasesService.cs +++ b/FitConnect/Services/CasesService.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; namespace FitConnect.Services; -public class CasesService : RestCallService, ICasesService { +internal class CasesService : RestCallService, ICasesService { private readonly IOAuthService _oAuthService; public CasesService(string baseUrl, IOAuthService oAuthService, string version = "v1", diff --git a/FitConnect/Services/DestinationService.cs b/FitConnect/Services/DestinationService.cs index dfe7b95357dc910501a82415094da74792b64169..5c72c36c9436b11878d5f056b0864fe3a0bbf85e 100644 --- a/FitConnect/Services/DestinationService.cs +++ b/FitConnect/Services/DestinationService.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; namespace FitConnect.Services; -public class DestinationService : RestCallService, IDestinationService { +internal class DestinationService : RestCallService, IDestinationService { private const string ApiVersion = "v1"; private readonly IOAuthService _oAuthService; @@ -19,7 +19,7 @@ public class DestinationService : RestCallService, IDestinationService { /// </summary> /// <param name="createDestination">RequestBody</param> /// <returns></returns> - public PrivateDestinationDto CreateDestination(CreateDestinationDto createDestination) { + public PrivateDestinationDto CreateDestination(CreateDestinationDto createDestination) { throw new NotImplementedException(); } @@ -28,7 +28,7 @@ public class DestinationService : RestCallService, IDestinationService { /// <para>@GetMapping("/destinations/{destinationId}")</para> /// </summary> /// <param name="destinationId">PathVariable</param> - public void GetDestination(string destinationId) { + public void GetDestination(string destinationId) { throw new NotImplementedException(); } @@ -38,7 +38,7 @@ public class DestinationService : RestCallService, IDestinationService { /// </summary> /// <param name="destinationId">PathVariable</param> /// <returns></returns> - public bool DeleteDestination(string destinationId) { + public bool DeleteDestination(string destinationId) { throw new NotImplementedException(); } @@ -49,7 +49,7 @@ public class DestinationService : RestCallService, IDestinationService { /// <param name="destinationId">PathVariable</param> /// <param name="patchDestination">RequestBody</param> /// <returns></returns> - public PrivateDestinationDto PatchDestination(string destinationId, + public PrivateDestinationDto PatchDestination(string destinationId, PatchDestinationDto patchDestination) { throw new NotImplementedException(); } @@ -61,7 +61,7 @@ public class DestinationService : RestCallService, IDestinationService { /// <param name="offset">RequestParam</param> /// <param name="limit">RequestParam</param> /// <returns></returns> - public DestinationListDto ListDestinations(int offset, int limit) { + public DestinationListDto ListDestinations(int offset, int limit) { throw new NotImplementedException(); } @@ -72,7 +72,7 @@ public class DestinationService : RestCallService, IDestinationService { /// <param name="destinationId">PathVariable</param> /// <param name="updateDestination">RequestBody</param> /// <returns></returns> - public PrivateDestinationDto UpdateDestination(string destinationId, + public PrivateDestinationDto UpdateDestination(string destinationId, UpdateDestinationDto updateDestination) { throw new NotImplementedException(); } diff --git a/FitConnect/Services/DvdvService.cs b/FitConnect/Services/DvdvService.cs new file mode 100644 index 0000000000000000000000000000000000000000..97afeab1e6b4d4f28d84dff39e9dfa2b7263a0d8 --- /dev/null +++ b/FitConnect/Services/DvdvService.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Logging; + +namespace FitConnect.Services; + +internal class DvdvService : RestCallService { + public DvdvService(string baseUrl, string version = "v1", ILogger? logger = null) : base( + $"{baseUrl}/{version}", logger) { + } + + public async Task<string> GetDestinationJson(string destinationId) { + var json = await RestCallForString("/destinations/" + destinationId, HttpMethod.Get); + return json; + } +} diff --git a/FitConnect/Services/InfoService.cs b/FitConnect/Services/InfoService.cs index 86dcd83a1d752b2e0993d90cb5b39cdbdcc1e3a0..bd7566ec9336d9fce1574009fa9f4084272b0d2f 100644 --- a/FitConnect/Services/InfoService.cs +++ b/FitConnect/Services/InfoService.cs @@ -1,6 +1,6 @@ namespace FitConnect.Services; -public class InfoService : RestCallService { +internal class InfoService : RestCallService { public InfoService(string baseUrl) : base(baseUrl) { } @@ -8,7 +8,7 @@ public class InfoService : RestCallService { /// @GetMapping("/info") /// </summary> /// <returns></returns> - public string GetInfo() { + public string GetInfo() { throw new NotImplementedException(); } } diff --git a/FitConnect/Services/Interfaces/IRouteService.cs b/FitConnect/Services/Interfaces/IRouteService.cs index 42e0c535c2a38f80e255168ab37538174ed8b91e..490ca74c633330f56a6537d8b08dfba86928e37e 100644 --- a/FitConnect/Services/Interfaces/IRouteService.cs +++ b/FitConnect/Services/Interfaces/IRouteService.cs @@ -12,7 +12,7 @@ public interface IRouteService : IRestCallService { /// <param name="ars"></param> /// <param name="areaId"></param> /// <returns></returns> - Task<List<Route>> GetDestinationIdAsync(string leiaKey, + Task<List<Route>> GetDestinationIdAsync(string leiaKey, string? ags = null, string? ars = null, string? areaId = null); diff --git a/FitConnect/Services/Interfaces/ISelfServicePortalService.cs b/FitConnect/Services/Interfaces/ISelfServicePortalService.cs new file mode 100644 index 0000000000000000000000000000000000000000..dce0390c717dbc7e6df5c696f1a6f8c57f265c27 --- /dev/null +++ b/FitConnect/Services/Interfaces/ISelfServicePortalService.cs @@ -0,0 +1,7 @@ +using Microsoft.IdentityModel.Tokens; + +namespace FitConnect.Services.Interfaces; + +public interface ISelfServicePortalService { + public Task<JsonWebKeySet> GetValidationJwk(); +} diff --git a/FitConnect/Services/Interfaces/ISubmissionService.cs b/FitConnect/Services/Interfaces/ISubmissionService.cs index becef9e08764b194886c1031e3c118d0174d3a84..caf0054cfa16b03c9475b9d309f67bf1bce6c70f 100644 --- a/FitConnect/Services/Interfaces/ISubmissionService.cs +++ b/FitConnect/Services/Interfaces/ISubmissionService.cs @@ -8,7 +8,7 @@ public interface ISubmissionService : IRestCallService { /// </summary> /// <param name="submissionDto">RequestBody</param> /// <returns></returns> - SubmissionCreatedDto CreateSubmission(CreateSubmissionDto submissionDto); + SubmissionCreatedDto CreateSubmission(CreateSubmissionDto submissionDto); /// <summary> /// <para> @@ -20,7 +20,7 @@ public interface ISubmissionService : IRestCallService { /// <param name="attachmentId">PathVariable</param> /// <param name="encryptedAttachmentContent">RequestBody</param> /// <returns></returns> - bool AddSubmissionAttachment(string submissionId, string attachmentId, + bool AddSubmissionAttachment(string submissionId, string attachmentId, string encryptedAttachmentContent); /// <summary> @@ -29,7 +29,7 @@ public interface ISubmissionService : IRestCallService { /// <param name="submissionId">PathVariable</param> /// <param name="submitSubmission">RequestBody</param> /// <returns></returns> - Task<SubmissionReducedDto?> SubmitSubmission(string submissionId, + Task<SubmissionReducedDto?> SubmitSubmission(string submissionId, SubmitSubmissionDto submitSubmission); /// <summary> @@ -39,7 +39,7 @@ public interface ISubmissionService : IRestCallService { /// <param name="offset">RequestParam</param> /// <param name="limit">RequestParam</param> /// <returns></returns> - Task<SubmissionsForPickupDto> ListSubmissions(string? destinationId, int offset, + Task<SubmissionsForPickupDto> ListSubmissions(string? destinationId, int offset, int limit); /// <summary> @@ -47,7 +47,7 @@ public interface ISubmissionService : IRestCallService { /// </summary> /// <param name="submissionId">PathVariable</param> /// <returns></returns> - SubmissionDto GetSubmission(string submissionId); + SubmissionDto GetSubmission(string submissionId); /// <summary> /// <para> @@ -58,7 +58,7 @@ public interface ISubmissionService : IRestCallService { /// <param name="submissionId">PathVariable</param> /// <param name="attachmentId">PathVariable</param> /// <returns></returns> - string GetAttachment(string submissionId, string attachmentId); + string GetAttachment(string submissionId, string attachmentId); /// <summary> /// Receiving the encryption key from the submission api diff --git a/FitConnect/Services/Models/CallbackDto.cs b/FitConnect/Services/Models/CallbackDto.cs index 0228e1f89d81fb88a94ded3a2d5f45f55f8789f0..61b0723807e94b530d94e3584325a49d6350f624 100644 --- a/FitConnect/Services/Models/CallbackDto.cs +++ b/FitConnect/Services/Models/CallbackDto.cs @@ -1,11 +1,11 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models; public class CallbackDto { - [JsonPropertyName("url")] + [JsonProperty("url")] public string? Url { get; set; } - [JsonPropertyName("secret")] + [JsonProperty("secret")] public string? Secret { get; set; } } diff --git a/FitConnect/Services/Models/OAuthAccessToken.cs b/FitConnect/Services/Models/OAuthAccessToken.cs index 077cb92c3c859057dc72e6d848ad72272a401b70..d6b7a2a2f8347de74d541b4286f07ed30e3a2144 100644 --- a/FitConnect/Services/Models/OAuthAccessToken.cs +++ b/FitConnect/Services/Models/OAuthAccessToken.cs @@ -1,20 +1,20 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models; public class OAuthAccessToken { private readonly DateTime createdAt = DateTime.Now; - [JsonPropertyName("access_token")] + [JsonProperty("access_token")] public string? AccessToken { get; set; } - [JsonPropertyName("scope")] + [JsonProperty("scope")] public string? Scope { get; set; } - [JsonPropertyName("token_type")] + [JsonProperty("token_type")] public string? TokenType { get; set; } - [JsonPropertyName("expires_in")] + [JsonProperty("expires_in")] public int ExpiresIn { get; set; } public bool IsValid => createdAt.AddSeconds(ExpiresIn) > DateTime.Now; diff --git a/FitConnect/Services/Models/ServiceTypeDto.cs b/FitConnect/Services/Models/ServiceTypeDto.cs index 97b5a604fec11305eb21684cc6675b828f121ddb..c34a7521674d279968d1b07a9c36c8421563055b 100644 --- a/FitConnect/Services/Models/ServiceTypeDto.cs +++ b/FitConnect/Services/Models/ServiceTypeDto.cs @@ -1,14 +1,14 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models; public class ServiceTypeDto { - [JsonPropertyName("name")] + [JsonProperty("name")] public string? Name { get; set; } - [JsonPropertyName("description")] + [JsonProperty("description")] public string? Description { get; set; } - [JsonPropertyName("identifier")] + [JsonProperty("identifier")] public string? Identifier { get; set; } } diff --git a/FitConnect/Services/Models/v1/Api/SecEventToken.cs b/FitConnect/Services/Models/v1/Api/SecEventToken.cs index a6d73d83b95a49eab53be6f110bdb4145d6966f9..ecb69eb12c3e78c66c1116e09c41e5111b6faffa 100644 --- a/FitConnect/Services/Models/v1/Api/SecEventToken.cs +++ b/FitConnect/Services/Models/v1/Api/SecEventToken.cs @@ -202,13 +202,49 @@ namespace FitConnect.Models.v1.Api } public partial class Problems { - public static readonly Problems IncorrectAuthenticationTag = new Problems(); - public static readonly Problems EncryptionIssue = new Problems(); - public static readonly Problems SyntaxViolation = new Problems(); - public static readonly Problems MissingSchema = new Problems(); - public static readonly Problems UnsupportedSchema = new Problems(); - public static readonly Problems SchemaViolation = new Problems(); - + public static readonly Problems IncorrectAuthenticationTag = new Problems{ + Type = "https://schema.fitko.de/fit-connect/events/problems/incorrect-authentication-tag", + Title = "Authentication-Tag ungültig", + Detail = "Das Authentication-Tag des Metadatensatzes ist ungültig.", + Instance = "metadata" + }; + public static readonly Problems EncryptionIssue = new Problems{ + Type = "https://schema.fitko.de/fit-connect/events/problems/encryption-issue", + Title = "Entschlüsselungs-Fehler", + Detail = "Der Schlüssel {kid} ist nicht der zu diesem Zweck vorgesehene Schlüssel.", + Instance = "metadata" + }; + public static readonly Problems SyntaxViolation = new Problems{ + Type = "https://schema.fitko.de/fit-connect/events/problems/syntax-violation", + Title = "Syntax-Fehler", + Detail= "Der Metadatensatz ist kein valides JSON.", + Instance= "metadata" + }; + public static readonly Problems MissingSchema = new Problems{ + Type = "https://schema.fitko.de/fit-connect/events/problems/missing-schema", + Title = "Schema-Referenz fehlt", + Detail = "Die Schema-Referenz fehlt im Metadatensatz.", + Instance = "metadata" + }; + public static readonly Problems UnsupportedSchema = new Problems{ + Type = "https://schema.fitko.de/fit-connect/events/problems/unsupported-schema", + Title = "Metadatenschema nicht unterstützt", + Detail = "Die angegebene Metadatenschema-URI ('$schema') ist keines der unterstützten Metadatenschemas.", + Instance = "metadata" + }; + public static readonly Problems SchemaViolation = new Problems { + Type = "https://schema.fitko.de/fit-connect/events/problems/schema-violation", + Title = "Schema-Fehler", + Detail = "Der Metadatensatz ist nicht schema-valide.", + Instance = "metadata" + }; + + [JsonProperty("instance")] + public string Instance { get; set; } + + [JsonProperty("detail")] + public string Detail { get; set; } + [JsonProperty("title")] public string Title { get; set; } diff --git a/FitConnect/Services/Models/v1/Case/EventLogDto.cs b/FitConnect/Services/Models/v1/Case/EventLogDto.cs index df39168a2c5f9566476a35c78e095409418e3d34..31879f80f34ab7e9f0dc6bddd5ebd9b42c278b72 100644 --- a/FitConnect/Services/Models/v1/Case/EventLogDto.cs +++ b/FitConnect/Services/Models/v1/Case/EventLogDto.cs @@ -1,17 +1,17 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Case; public class EventLogDto { - [JsonPropertyName("count")] + [JsonProperty("count")] public int Count { get; set; } - [JsonPropertyName("eventLog")] + [JsonProperty("eventLog")] public List<string>? EventLog { get; set; } - [JsonPropertyName("offset")] + [JsonProperty("offset")] public int Offset { get; set; } - [JsonPropertyName("totalCount")] + [JsonProperty("totalCount")] public long TotalCount { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/ContactInformationDto.cs b/FitConnect/Services/Models/v1/Destination/ContactInformationDto.cs index f017503cf6981a04ec603c6a30b4ed6c0d92d017..df520ee45a8ad2f2d7af6fde7522e49451b79dbc 100644 --- a/FitConnect/Services/Models/v1/Destination/ContactInformationDto.cs +++ b/FitConnect/Services/Models/v1/Destination/ContactInformationDto.cs @@ -1,20 +1,21 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class ContactInformationDto { - [JsonPropertyName("address")] + [JsonProperty("address")] public string? Address { get; set; } - [JsonPropertyName("email")] + [JsonProperty("email")] public string? Email { get; set; } - [JsonPropertyName("legalName")] + [JsonProperty("legalName")] public string? LegalName { get; set; } - [JsonPropertyName("phone")] + [JsonProperty("phone")] public string? Phone { get; set; } - [JsonPropertyName("unit")] + [JsonProperty("unit")] public string? Unit { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/CreateDestinationDto.cs b/FitConnect/Services/Models/v1/Destination/CreateDestinationDto.cs index a4fce8a96ccc7363d4c8da5c3925dde9bdfffda3..e1c700789cd820a9a2777ca6d580a60c46c64b5a 100644 --- a/FitConnect/Services/Models/v1/Destination/CreateDestinationDto.cs +++ b/FitConnect/Services/Models/v1/Destination/CreateDestinationDto.cs @@ -1,35 +1,35 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class CreateDestinationDto { - [JsonPropertyName("callback")] + [JsonProperty("callback")] public CallbackDto? Callback { get; set; } - [JsonPropertyName("contactInformation")] + [JsonProperty("contactInformation")] public ContactInformationDto? ContactInformation { get; set; } - [JsonPropertyName("encryptionKid")] + [JsonProperty("encryptionKid")] public string? EncryptionKid { get; set; } - [JsonPropertyName("encryptionPublicKey")] + [JsonProperty("encryptionPublicKey")] public string? EncryptionPublicKey { get; set; } - [JsonPropertyName("metadataVersions")] + [JsonProperty("metadataVersions")] public List<string>? MetadataVersions { get; set; } - [JsonPropertyName("replyChannels")] + [JsonProperty("replyChannels")] public DestinationReplyChannelsDto? ReplyChannels { get; set; } - [JsonPropertyName("services")] + [JsonProperty("services")] public List<DestinationServiceDto>? Services { get; set; } - [JsonPropertyName("signingPublicKey")] + [JsonProperty("signingPublicKey")] public string? SigningPublicKey { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/DestinationListDto.cs b/FitConnect/Services/Models/v1/Destination/DestinationListDto.cs index 9acf39e097ce0e50c90b4b70930068ddacc06710..738290fa1b477e4c912e45fba4e0e81fce8c6a90 100644 --- a/FitConnect/Services/Models/v1/Destination/DestinationListDto.cs +++ b/FitConnect/Services/Models/v1/Destination/DestinationListDto.cs @@ -1,20 +1,20 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class DestinationListDto { - [JsonPropertyName("count")] + [JsonProperty("count")] public int Count { get; set; } - [JsonPropertyName("destinations")] + [JsonProperty("destinations")] public List<PrivateDestinationDto>? Destinations { get; set; } - [JsonPropertyName("offset")] + [JsonProperty("offset")] public int Offset { get; set; } - [JsonPropertyName("totalCount")] + [JsonProperty("totalCount")] public long TotalCount { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/DestinationServiceDto.cs b/FitConnect/Services/Models/v1/Destination/DestinationServiceDto.cs index cc100b7fbfe68cede5635dac205a4b25243436bb..9758111f2920aec0f478de6910b3540430e06684 100644 --- a/FitConnect/Services/Models/v1/Destination/DestinationServiceDto.cs +++ b/FitConnect/Services/Models/v1/Destination/DestinationServiceDto.cs @@ -1,15 +1,15 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class DestinationServiceDto { - [JsonPropertyName("identifier")] + [JsonProperty("identifier")] public string? Identifier { get; set; } - [JsonPropertyName("regions")] + [JsonProperty("regions")] public List<string>? Regions { get; set; } - [JsonPropertyName("submissionSchemas")] + [JsonProperty("submissionSchemas")] public List<SubmissionSchemaDto>? SubmissionSchemas { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/PatchDestinationDto.cs b/FitConnect/Services/Models/v1/Destination/PatchDestinationDto.cs index 8ae416957d56358e743dc3cb8f82fd8b686c677a..2e910cd1e79e926bda38937d52a4ebb27893d8c1 100644 --- a/FitConnect/Services/Models/v1/Destination/PatchDestinationDto.cs +++ b/FitConnect/Services/Models/v1/Destination/PatchDestinationDto.cs @@ -1,31 +1,31 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class PatchDestinationDto { - [JsonPropertyName("callback")] + [JsonProperty("callback")] public CallbackDto? Callback { get; set; } - [JsonPropertyName("contactInformation")] + [JsonProperty("contactInformation")] public ContactInformationDto? ContactInformation { get; set; } - [JsonPropertyName("encryptionKid")] + [JsonProperty("encryptionKid")] public string? EncryptionKid { get; set; } - [JsonPropertyName("metadataVersions")] + [JsonProperty("metadataVersions")] public List<string>? metadataVersions { get; set; } - [JsonPropertyName("replyChannels")] + [JsonProperty("replyChannels")] public DestinationReplyChannelsDto? ReplyChannels { get; set; } - [JsonPropertyName("services")] + [JsonProperty("services")] public List<DestinationServiceDto>? Services { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string? Status { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/PrivateDestinationDto.cs b/FitConnect/Services/Models/v1/Destination/PrivateDestinationDto.cs index b6d9098af49e0de7597a6b667dc7827e7b3e39ae..36bf2afeaaa310e0c5ab23c44a1a46af38c1ad54 100644 --- a/FitConnect/Services/Models/v1/Destination/PrivateDestinationDto.cs +++ b/FitConnect/Services/Models/v1/Destination/PrivateDestinationDto.cs @@ -1,35 +1,35 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class PrivateDestinationDto { - [JsonPropertyName("callback")] + [JsonProperty("callback")] public CallbackDto? Callback { get; set; } - [JsonPropertyName("contactInformation")] + [JsonProperty("contactInformation")] public ContactInformationDto? ContactInformation { get; set; } - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string? DestinationId { get; set; } - [JsonPropertyName("encryptionKid")] + [JsonProperty("encryptionKid")] public string? EncryptionKid { get; set; } - [JsonPropertyName("metadataVersions")] + [JsonProperty("metadataVersions")] public List<string>? MetadataVersions { get; set; } - [JsonPropertyName("replyChannels")] + [JsonProperty("replyChannels")] public DestinationReplyChannelsDto? ReplyChannels { get; set; } - [JsonPropertyName("services")] + [JsonProperty("services")] public List<DestinationServiceDto>? Services { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string? Status { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/PublicDestinationDto.cs b/FitConnect/Services/Models/v1/Destination/PublicDestinationDto.cs index b188491e560a2bd5b3e9b7d071773e5cfb33cc02..414fbd7e3c3ee7ae8c295ec50b5afece6e298834 100644 --- a/FitConnect/Services/Models/v1/Destination/PublicDestinationDto.cs +++ b/FitConnect/Services/Models/v1/Destination/PublicDestinationDto.cs @@ -1,29 +1,29 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; // ReSharper disable once ClassNeverInstantiated.Global public class PublicDestinationDto { - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string? DestinationId { get; set; } - [JsonPropertyName("encryptionKid")] + [JsonProperty("encryptionKid")] public string? EncryptionKid { get; set; } - [JsonPropertyName("metadataVersions")] + [JsonProperty("metadataVersions")] public List<string>? MetadataVersions { get; set; } - [JsonPropertyName("replyChannels")] + [JsonProperty("replyChannels")] public DestinationReplyChannelsDto? ReplyChannels { get; set; } - [JsonPropertyName("services")] + [JsonProperty("services")] public List<DestinationServiceDto>? Services { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string? Status { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/SubmissionSchemaDto.cs b/FitConnect/Services/Models/v1/Destination/SubmissionSchemaDto.cs index 5beadb55742385a881f1c09d3120c097636e32bd..8da11c5cdbd92303e6b7269c980d860349407716 100644 --- a/FitConnect/Services/Models/v1/Destination/SubmissionSchemaDto.cs +++ b/FitConnect/Services/Models/v1/Destination/SubmissionSchemaDto.cs @@ -1,12 +1,12 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class SubmissionSchemaDto { - [JsonPropertyName("mimeType")] + [JsonProperty("mimeType")] // private SubmissionSchemaMimeTypeDto mimeType; public string mimeType; - [JsonPropertyName("schemaUri")] + [JsonProperty("schemaUri")] public string? SchemaUri { get; set; } } diff --git a/FitConnect/Services/Models/v1/Destination/UpdateDestinationDto.cs b/FitConnect/Services/Models/v1/Destination/UpdateDestinationDto.cs index 18a7bd98092524ffc2c6725d394dfcdcce103fe0..f5ed24b0eefa25ed0b0e6da036d7e894faea407c 100644 --- a/FitConnect/Services/Models/v1/Destination/UpdateDestinationDto.cs +++ b/FitConnect/Services/Models/v1/Destination/UpdateDestinationDto.cs @@ -1,31 +1,31 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Destination; public class UpdateDestinationDto { - [JsonPropertyName("callback")] + [JsonProperty("callback")] public CallbackDto? Callback { get; set; } - [JsonPropertyName("contactInformation")] + [JsonProperty("contactInformation")] public ContactInformationDto? ContactInformation { get; set; } - [JsonPropertyName("encryptionKid")] + [JsonProperty("encryptionKid")] public string? EncryptionKid { get; set; } - [JsonPropertyName("metadataVersions")] + [JsonProperty("metadataVersions")] public List<string>? metadataVersions { get; set; } - [JsonPropertyName("replyChannels")] + [JsonProperty("replyChannels")] public DestinationReplyChannelsDto? ReplyChannels { get; set; } - [JsonPropertyName("services")] + [JsonProperty("services")] public List<DestinationServiceDto>? Services { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string? Status { get; set; } } diff --git a/FitConnect/Services/Models/v1/Routes/Routes.cs b/FitConnect/Services/Models/v1/Routes/Routes.cs index 286dbccfa43d8d03238c8c96fb9ef8c5ac1bd8bf..a1b912b7492a56aada6f6258a14c701342d86289 100644 --- a/FitConnect/Services/Models/v1/Routes/Routes.cs +++ b/FitConnect/Services/Models/v1/Routes/Routes.cs @@ -1,58 +1,57 @@ // Root myDeserializedClass = JsonSerializer.Deserialize<Root>(myJsonResponse); -using System.Text.Json.Serialization; using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Routes; public class DestinationParameters { - [JsonPropertyName("encryptionKid")] + [JsonProperty("encryptionKid")] public string EncryptionKid { get; set; } - [JsonPropertyName("metadataVersions")] + [JsonProperty("metadataVersions")] public List<string> MetadataVersions { get; set; } - [JsonPropertyName("publicKeys")] + [JsonProperty("publicKeys")] public PublicKeys PublicKeys { get; set; } - [JsonPropertyName("replyChannels")] + [JsonProperty("replyChannels")] public ReplyChannels ReplyChannels { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string Status { get; set; } - [JsonPropertyName("submissionSchemas")] + [JsonProperty("submissionSchemas")] public List<SubmissionSchema> SubmissionSchemas { get; set; } - [JsonPropertyName("submissionUrl")] + [JsonProperty("submissionUrl")] public string SubmissionUrl { get; set; } } public class EMail { - [JsonPropertyName("usePgp")] + [JsonProperty("usePgp")] public bool UsePgp { get; set; } } public class Key { - [JsonPropertyName("kty")] + [JsonProperty("kty")] public string Kty { get; set; } - [JsonPropertyName("key_ops")] + [JsonProperty("key_ops")] public List<string> KeyOps { get; set; } - [JsonPropertyName("alg")] + [JsonProperty("alg")] public string Alg { get; set; } - [JsonPropertyName("x5c")] + [JsonProperty("x5c")] public List<string> X5c { get; set; } - [JsonPropertyName("kid")] + [JsonProperty("kid")] public string Kid { get; set; } - [JsonPropertyName("n")] + [JsonProperty("n")] public string N { get; set; } - [JsonPropertyName("e")] + [JsonProperty("e")] public string E { get; set; } public string ToString() { @@ -61,50 +60,54 @@ public class Key { } public class PublicKeys { - [JsonPropertyName("keys")] + [JsonProperty("keys")] public List<Key> Keys { get; set; } } public class ReplyChannels { - [JsonPropertyName("eMail")] + [JsonProperty("email")] public EMail EMail { get; set; } } public class RoutesListDto { - [JsonPropertyName("count")] + [JsonProperty("count")] public int Count { get; set; } - [JsonPropertyName("offset")] + [JsonProperty("offset")] public int Offset { get; set; } - [JsonPropertyName("totalCount")] + [JsonProperty("totalCount")] public int TotalCount { get; set; } - [JsonPropertyName("routes")] + [JsonProperty("routes")] public List<Route> Routes { get; set; } } public class Route { - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string DestinationId { get; set; } - [JsonPropertyName("destinationSignature")] + [JsonProperty("destinationSignature")] public string DestinationSignature { get; set; } - [JsonPropertyName("destinationParameters")] + [JsonProperty("destinationParameters")] public DestinationParameters DestinationParameters { get; set; } - [JsonPropertyName("destinationParametersSignature")] + [JsonProperty("destinationParametersSignature")] public string DestinationParametersSignature { get; set; } - [JsonPropertyName("destinationName")] + [JsonProperty("destinationName")] public string DestinationName { get; set; } + + + [System.Text.Json.Serialization.JsonIgnore] + public string DestinationParameterString { get;set; } } public class SubmissionSchema { - [JsonPropertyName("schemaUri")] + [JsonProperty("schemaUri")] public string SchemaUri { get; set; } - [JsonPropertyName("mimeType")] + [JsonProperty("mimeType")] public string MimeType { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/CreateSubmissionDto.cs b/FitConnect/Services/Models/v1/Submission/CreateSubmissionDto.cs index bf340a6f82255a75febc5c8ce53ed6f2dcbafad9..b188d7968606d7bd314d8e58383bb42752fb3355 100644 --- a/FitConnect/Services/Models/v1/Submission/CreateSubmissionDto.cs +++ b/FitConnect/Services/Models/v1/Submission/CreateSubmissionDto.cs @@ -1,22 +1,22 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class CreateSubmissionDto { - [JsonPropertyName("callback")] + [JsonProperty("callback")] public CallbackDto? Callback { get; set; } - [JsonPropertyName("serviceType")] + [JsonProperty("serviceType")] public ServiceTypeDto? ServiceType { get; set; } - [JsonPropertyName("announcedAttachments")] + [JsonProperty("announcedAttachments")] public List<string>? AnnouncedAttachments { get; set; } - [JsonPropertyName("caseId")] + [JsonProperty("caseId")] public string? CaseId { get; set; } - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string? DestinationId { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/SubmissionCreatedDto.cs b/FitConnect/Services/Models/v1/Submission/SubmissionCreatedDto.cs index 307ff526a51be2db21cb5906542e951759def4ff..fa607ae2dfa44a67008a0052ee68f75abd6d6fb8 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmissionCreatedDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmissionCreatedDto.cs @@ -1,14 +1,14 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class SubmissionCreatedDto { - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string? DestinationId { get; set; } - [JsonPropertyName("submissionId")] + [JsonProperty("submissionId")] public string? SubmissionId { get; set; } - [JsonPropertyName("caseId")] + [JsonProperty("caseId")] public string? CaseId { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/SubmissionDto.cs b/FitConnect/Services/Models/v1/Submission/SubmissionDto.cs index fc2203507fe54203974b3096e5ee91241983d8bb..9a4f1aa1c17a3796cb435cc7ee5a6022597931de 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmissionDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmissionDto.cs @@ -1,35 +1,35 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class SubmissionDto { - [JsonPropertyName("attachments")] + [JsonProperty("attachments")] public List<string>? Attachments { get; set; } - [JsonPropertyName("callback")] + [JsonProperty("callback")] public CallbackDto? Callback { get; set; } - [JsonPropertyName("caseId")] + [JsonProperty("caseId")] public string? CaseId { get; set; } - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string? DestinationId { get; set; } - [JsonPropertyName("encryptedData")] + [JsonProperty("encryptedData")] public string? EncryptedData { get; set; } - [JsonPropertyName("encryptedMetadata")] + [JsonProperty("encryptedMetadata")] public string? EncryptedMetadata { get; set; } - [JsonPropertyName("serviceType")] + [JsonProperty("serviceType")] public ServiceTypeDto? ServiceType { get; set; } - [JsonPropertyName("submissionId")] + [JsonProperty("submissionId")] public string? SubmissionId { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs b/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs index b01e4ac60bbbf8d2e82b9dff39abacc0ad9d0299..7540c18ff8926a41e13d75ccfadd16e242339072 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmissionForPickupDto.cs @@ -1,14 +1,14 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class SubmissionForPickupDto { - [JsonPropertyName("caseId")] + [JsonProperty("caseId")] public string? CaseId { get; set; } - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] public string? DestinationId { get; set; } - [JsonPropertyName("submissionId")] + [JsonProperty("submissionId")] public string? SubmissionId { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/SubmissionReducedDto.cs b/FitConnect/Services/Models/v1/Submission/SubmissionReducedDto.cs index e98939b1b72de6f74467e26116e9ec0e978842c7..36deb67e518f1fcf6b1c79cd800573dc5e603b3d 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmissionReducedDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmissionReducedDto.cs @@ -1,27 +1,27 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class SubmissionReducedDto { - [JsonPropertyName("serviceType")] + [JsonProperty("serviceType")] private ServiceTypeDto _serviceTypeDto { get; set; } - [JsonPropertyName("attachments")] + [JsonProperty("attachments")] private List<string>? Attachments { get; set; } - [JsonPropertyName("callback")] + [JsonProperty("callback")] private CallbackDto? Callback { get; set; } - [JsonPropertyName("caseId")] + [JsonProperty("caseId")] private string? CaseId { get; set; } - [JsonPropertyName("destinationId")] + [JsonProperty("destinationId")] private string? DestinationId { get; set; } - [JsonPropertyName("submissionId")] + [JsonProperty("submissionId")] private string? SubmissionId { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/SubmissionsForPickupDto.cs b/FitConnect/Services/Models/v1/Submission/SubmissionsForPickupDto.cs index a6e98a2320c872a4f5f98e924697eefd2778a0a8..dffb9cbce74f30461627e397be45e148564d1752 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmissionsForPickupDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmissionsForPickupDto.cs @@ -1,17 +1,17 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class SubmissionsForPickupDto { - [JsonPropertyName("count")] + [JsonProperty("count")] public int Count { get; set; } - [JsonPropertyName("offset")] + [JsonProperty("offset")] public int Offset { get; set; } - [JsonPropertyName("submissions")] + [JsonProperty("submissions")] public List<SubmissionForPickupDto>? Submissions { get; set; } - [JsonPropertyName("totalCount")] + [JsonProperty("totalCount")] public long TotalCount { get; set; } } diff --git a/FitConnect/Services/Models/v1/Submission/SubmitSubmissionDto.cs b/FitConnect/Services/Models/v1/Submission/SubmitSubmissionDto.cs index b5e206ca846215e34fb4c12c3490793f7f905c7f..d743a5f2457878585f51b3de9a4ff5e26fb8780e 100644 --- a/FitConnect/Services/Models/v1/Submission/SubmitSubmissionDto.cs +++ b/FitConnect/Services/Models/v1/Submission/SubmitSubmissionDto.cs @@ -1,11 +1,11 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FitConnect.Services.Models.v1.Submission; public class SubmitSubmissionDto { - [JsonPropertyName("encryptedData")] + [JsonProperty("encryptedData")] public string? EncryptedData { get; set; } - [JsonPropertyName("encryptedMetadata")] + [JsonProperty("encryptedMetadata")] public string? EncryptedMetadata { get; set; } } diff --git a/FitConnect/Services/OAuthService.cs b/FitConnect/Services/OAuthService.cs index bef055daa97122340cd26fe332fa9315d4af4abc..cad62fefe305cdc265e666be14dd62958f90c54a 100644 --- a/FitConnect/Services/OAuthService.cs +++ b/FitConnect/Services/OAuthService.cs @@ -1,13 +1,15 @@ using System.Net; using System.Net.Http.Json; +using System.Runtime.CompilerServices; using System.Security.Authentication; using FitConnect.Services.Interfaces; using FitConnect.Services.Models; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; namespace FitConnect.Services; -public class OAuthService : RestCallService, IOAuthService { +internal class OAuthService : RestCallService, IOAuthService { private readonly string _clientId; private readonly string _clientSecret; private readonly ILogger? _logger; @@ -64,7 +66,7 @@ public class OAuthService : RestCallService, IOAuthService { var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { - var result = await response.Content.ReadFromJsonAsync<OAuthAccessToken>(); + var result = JsonConvert.DeserializeObject<OAuthAccessToken>(await response.Content.ReadAsStringAsync()); if (result == null) throw new AuthenticationException("Failed to authenticate"); Token = result; @@ -79,4 +81,4 @@ public class OAuthService : RestCallService, IOAuthService { public void EnsureAuthenticated() { if (!IsAuthenticated) AuthenticateAsync().Wait(); } -} +} \ No newline at end of file diff --git a/FitConnect/Services/RestCallService.cs b/FitConnect/Services/RestCallService.cs index 90a572003c24d2b07f6069df412a41d8dddecdcc..9c40b4a13fcbd48f6d42c7d378ea6cb61fbaab9a 100644 --- a/FitConnect/Services/RestCallService.cs +++ b/FitConnect/Services/RestCallService.cs @@ -1,8 +1,10 @@ using System.Net; using System.Net.Http.Headers; +using System.Runtime.CompilerServices; using System.Text; -using System.Text.Json; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using JsonException = System.Text.Json.JsonException; namespace FitConnect.Services; @@ -10,7 +12,7 @@ public interface IRestCallService { public WebProxy? Proxy { get; set; } } -public abstract class RestCallService : IRestCallService { +internal class RestCallService : IRestCallService { private readonly string _baseUrl; private readonly ILogger? _logger; @@ -35,6 +37,12 @@ public abstract class RestCallService : IRestCallService { } protected async Task<string> RestCallForString(string endpoint, HttpMethod method, + string? body = null, string contentType = "application/json", + string accept = "application/json") => + await RestCallForString(new Uri($"{_baseUrl}{endpoint}"), method, body, contentType, + accept); + + protected async Task<string> RestCallForString(Uri requestUri, HttpMethod method, string? body = null, string contentType = "application/json", string accept = "application/json") { var client = CreateClient(); @@ -49,7 +57,7 @@ public abstract class RestCallService : IRestCallService { request.Method = method; - request.RequestUri = new Uri($"{_baseUrl}{endpoint}"); + request.RequestUri = requestUri; if (body != null) { request.Content = new StringContent(body, Encoding.UTF8, contentType); @@ -57,6 +65,9 @@ public abstract class RestCallService : IRestCallService { } var response = await client.SendAsync(request); + + if (response.Headers.Contains("jws-signature")) + Console.WriteLine(response.Headers.GetValues("jws-signature").Aggregate((a,b)=>$"{a},{b}")); _logger?.LogDebug("Server call: {Method} {Uri} - {StatusCode}", method, request.RequestUri, response.StatusCode); @@ -67,7 +78,7 @@ public abstract class RestCallService : IRestCallService { } _logger?.LogError("Error calling {Method} - {Endpoint} with {Body} => {Status}", method, - endpoint, + requestUri.AbsolutePath, body, response.StatusCode); throw new HttpRequestException("Error calling FitConnect API", new HttpRequestException( @@ -80,7 +91,7 @@ public abstract class RestCallService : IRestCallService { where T : class { var content = await RestCallForString(endpoint, method, body, contentType, accept); try { - var result = JsonSerializer.Deserialize<T>(content); + var result = JsonConvert.DeserializeObject<T>(content); if (result != null) return result; diff --git a/FitConnect/Services/RouteService.cs b/FitConnect/Services/RouteService.cs index e1673d0cffa2208cdeec420a431a8cf4e2e146f3..5a17a872274d0efa5238d7da0c4473fa7f429017 100644 --- a/FitConnect/Services/RouteService.cs +++ b/FitConnect/Services/RouteService.cs @@ -6,12 +6,9 @@ using Route = FitConnect.Services.Models.v1.Routes.Route; namespace FitConnect.Services; -public class RouteService : RestCallService, IRouteService { - private readonly IOAuthService _oAuthService; - - public RouteService(string baseUrl, IOAuthService oAuthService, string version = "v1", +internal class RouteService : RestCallService, IRouteService { + public RouteService(string baseUrl, string version = "v1", ILogger? logger = null) : base($"{baseUrl}/{version}", logger) { - _oAuthService = oAuthService; } /// <summary> @@ -22,11 +19,10 @@ public class RouteService : RestCallService, IRouteService { /// <param name="ars"></param> /// <param name="areaId"></param> /// <returns></returns> - public async Task<List<Route>> GetDestinationIdAsync(string leikaKey, + public async Task<List<Route>> GetDestinationIdAsync(string leikaKey, string? ags, string? ars, string? areaId) { - if (ars == null && ags == null && areaId == null) - throw new ArgumentException("Either ars, ags or areaId must be specified."); + ValidateParametersForGetDestinationId(ags, ars, areaId); var result = await RestCall<RoutesListDto>($"/routes?leikaKey={leikaKey}" + (ags != null ? $"&ags={ags}" : "") + @@ -37,6 +33,19 @@ public class RouteService : RestCallService, IRouteService { return result?.Routes?.ToList() ?? new List<Route>(); } + private void ValidateParametersForGetDestinationId(string? ags, string? ars, string? areaId) { + if (ars == null && ags == null && areaId == null) + throw new ArgumentException("Either ars, ags or areaId must be specified."); + + var paramCount = 0; + if (ags != null) paramCount++; + if (ars != null) paramCount++; + if (areaId != null) paramCount++; + + if (paramCount != 1) + throw new ArgumentException("Only one of ars, ags or areaId must be specified."); + } + public async Task<AreaList?> GetAreas(string filter, int offset = 0, int limit = 100) { var result = await RestCall<AreaList>( $"/areas?areaSearchexpression={filter}&offset={offset}&limit={limit}", diff --git a/FitConnect/Services/SelfServicePortalService.cs b/FitConnect/Services/SelfServicePortalService.cs new file mode 100644 index 0000000000000000000000000000000000000000..34d520ec72967f316f74891ad147bd277325c9f1 --- /dev/null +++ b/FitConnect/Services/SelfServicePortalService.cs @@ -0,0 +1,17 @@ +using FitConnect.Services.Interfaces; +using Jose; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; + +namespace FitConnect.Services; + +internal class SelfServicePortalService : RestCallService, ISelfServicePortalService { + public SelfServicePortalService(string baseUrl, string version = "v1", + ILogger? logger = null) : base($"{baseUrl}", logger) { + } + + public async Task<JsonWebKeySet> GetValidationJwk() { + var content = await RestCallForString("/.well-known/jwks.json", HttpMethod.Get); + return new JsonWebKeySet(content); + } +} diff --git a/FitConnect/Services/SubmissionService.cs b/FitConnect/Services/SubmissionService.cs index 198106f82d119ab73cf2fd0b9554160bd03e7eee..a59e5b27450a17b56a9eb1cbb21ecb3ec789bcfc 100644 --- a/FitConnect/Services/SubmissionService.cs +++ b/FitConnect/Services/SubmissionService.cs @@ -1,14 +1,16 @@ using System.Text.Encodings.Web; using System.Text.Json; -using System.Text.Json.Serialization; +using Newtonsoft.Json; using FitConnect.Services.Interfaces; using FitConnect.Services.Models.v1.Case; using FitConnect.Services.Models.v1.Submission; using Microsoft.Extensions.Logging; +using JsonSerializer = System.Text.Json.JsonSerializer; + namespace FitConnect.Services; -public class SubmissionService : RestCallService, ISubmissionService { +internal class SubmissionService : RestCallService, ISubmissionService { private readonly ILogger? _logger; private readonly IOAuthService _oAuthService; @@ -24,12 +26,12 @@ public class SubmissionService : RestCallService, ISubmissionService { /// </summary> /// <param name="submissionDto">RequestBody</param> /// <returns></returns> - public SubmissionCreatedDto CreateSubmission(CreateSubmissionDto submissionDto) { + public SubmissionCreatedDto CreateSubmission(CreateSubmissionDto submissionDto) { _oAuthService.EnsureAuthenticated(); var result = RestCall<SubmissionCreatedDto>( "/submissions", HttpMethod.Post, - JsonSerializer.Serialize(submissionDto)).Result; + JsonConvert.SerializeObject(submissionDto)).Result; if (result == null) throw new ArgumentException("Submission creation failed"); @@ -48,7 +50,7 @@ public class SubmissionService : RestCallService, ISubmissionService { /// <param name="attachmentId">PathVariable</param> /// <param name="encryptedAttachmentContent">RequestBody</param> /// <returns></returns> - public bool AddSubmissionAttachment(string submissionId, string attachmentId, + public bool AddSubmissionAttachment(string submissionId, string attachmentId, string encryptedAttachmentContent) { _oAuthService.EnsureAuthenticated(); var result = RestCallForString( @@ -65,13 +67,12 @@ public class SubmissionService : RestCallService, ISubmissionService { /// <param name="submissionId">PathVariable</param> /// <param name="submitSubmission">RequestBody</param> /// <returns></returns> - public async Task<SubmissionReducedDto?> SubmitSubmission(string submissionId, + public async Task<SubmissionReducedDto?> SubmitSubmission(string submissionId, SubmitSubmissionDto submitSubmission) { _oAuthService.EnsureAuthenticated(); - var body = JsonSerializer.Serialize(submitSubmission, new JsonSerializerOptions { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - WriteIndented = true, - Encoder = JavaScriptEncoder.Default + var body = JsonConvert.SerializeObject(submitSubmission, new JsonSerializerSettings() { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.Indented }); var result = await RestCall<SubmissionReducedDto>($"/submissions/{submissionId}", @@ -89,7 +90,7 @@ public class SubmissionService : RestCallService, ISubmissionService { /// <param name="offset">RequestParam</param> /// <param name="limit">RequestParam</param> /// <returns></returns> - public async Task<SubmissionsForPickupDto> ListSubmissions(string? destinationId, + public async Task<SubmissionsForPickupDto> ListSubmissions(string? destinationId, int offset = 0, int limit = 100) { _oAuthService.EnsureAuthenticated(); @@ -105,7 +106,7 @@ public class SubmissionService : RestCallService, ISubmissionService { /// </summary> /// <param name="submissionId">PathVariable</param> /// <returns></returns> - public SubmissionDto GetSubmission(string submissionId) { + public SubmissionDto GetSubmission(string submissionId) { _oAuthService.EnsureAuthenticated(); var result = RestCall<SubmissionDto>($"/submissions/{submissionId}", HttpMethod.Get).Result ?? @@ -124,7 +125,7 @@ public class SubmissionService : RestCallService, ISubmissionService { /// <param name="submissionId">PathVariable</param> /// <param name="attachmentId">PathVariable</param> /// <returns></returns> - public string GetAttachment(string submissionId, string attachmentId) { + public string GetAttachment(string submissionId, string attachmentId) { _oAuthService.EnsureAuthenticated(); var result = RestCallForString($"/submissions/{submissionId}/attachments/{attachmentId}", HttpMethod.Get, @@ -144,4 +145,8 @@ public class SubmissionService : RestCallService, ISubmissionService { var events = await RestCall<EventLogDto>($"/cases/{caseId}/events", HttpMethod.Get); return events.EventLog.ToList(); } + + public async Task GetValidationJwk() { + throw new NotImplementedException(); + } } diff --git a/FitConnect/Subscriber.cs b/FitConnect/Subscriber.cs index c0c6a3ae301153d7f0dd4cdf6816f5da4129240f..d528b62b023b1fc20a31c801c51b88e0d88add67 100644 --- a/FitConnect/Subscriber.cs +++ b/FitConnect/Subscriber.cs @@ -1,9 +1,7 @@ -using System.Net; using System.Reflection; using System.Security.Cryptography; using System.Text; using Autofac; -using Autofac.Core.Activators.Reflection; using FitConnect.Encryption; using FitConnect.Interfaces.Subscriber; using FitConnect.Models; @@ -76,14 +74,10 @@ public class Subscriber : FitConnectClient, /// <param name="submissionId"></param> /// <param name="skipSchemaTest"></param> /// <returns></returns> - public ISubscriberWithSubmission RequestSubmission(string? submissionId, + public ISubscriberWithSubmission RequestSubmission(string submissionId, bool skipSchemaTest = false) { - if (submissionId == null) { - throw new ArgumentNullException($"{nameof(submissionId)} has to be set"); - } - var submission = (Submission)SubmissionService.GetSubmission(submissionId); - var (metaDataString, _, metaHash) = Encryption.Decrypt(submission.EncryptedMetadata!); + var (metaDataString, _, metaHash) = Encryption.Decrypt(submission.EncryptedMetadata); if (!skipSchemaTest) { var errors = VerifyMetadata(metaDataString); @@ -223,9 +217,8 @@ public class Subscriber : FitConnectClient, throw new ArgumentException("Missing callback-timestamp header"); var timeStampString = request.Headers["callback-timestamp"].ToString(); - if (!long.TryParse(timeStampString, out var timestamp)) { + if (!long.TryParse(timeStampString, out var timestamp)) throw new ArgumentException("Invalid callback-timestamp header"); - } var authentication = request.Headers["callback-authentication"]; diff --git a/IntegrationTests/CallbackTest.cs b/IntegrationTests/CallbackTest.cs index 3a932de134e19b42904b8140d93b862317610152..503ca89c6bd85dfeff8590bb81987eae1b2dde78 100644 --- a/IntegrationTests/CallbackTest.cs +++ b/IntegrationTests/CallbackTest.cs @@ -1,12 +1,8 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net; -using System.Net.Http; -using System.Text; using Autofac; using FluentAssertions; -using IdentityModel; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using MockContainer; @@ -20,6 +16,7 @@ public class CallbackTest { private HttpRequest _request = null!; private string _callbackSecret = ""; + [SetUp] public void Setup() { var memoryStream = new MemoryStream(); @@ -30,7 +27,12 @@ public class CallbackTest { streamWriter.Flush(); memoryStream.Position = 0; - var headers = new HeaderDictionary(new Dictionary<string, StringValues>() { + + // Request = new DefaultHttpRequest(new DefaultHttpContext()) { + // Body = new StreamBody(memoryStream) + // }; + + var headers = new HeaderDictionary(new Dictionary<string, StringValues> { { "callback-timestamp", "1672527599" }, { "callback-authentication", "798cd0edb70c08e5b32aa8a18cbbc8ff6b3078c51af6d011ff4e32e470c746234fc4314821fe5185264b029e962bd37de33f3b9fc5f1a93c40ce6672845e90df" @@ -47,9 +49,10 @@ public class CallbackTest { _request = mock.Object; - _callbackSecret = MockContainer.Container.Create().Resolve<MockSettings>().CallbackSecret; + _callbackSecret = Container.Create().Resolve<MockSettings>().CallbackSecret; } + [Test] public void ValidRequest_WithSingeValues() { // Arrange diff --git a/IntegrationTests/JwtTokenValidation.cs b/IntegrationTests/JwtTokenValidation.cs new file mode 100644 index 0000000000000000000000000000000000000000..7cafa1d712982e9e7447ae4ed7da7de78fcfdd4d --- /dev/null +++ b/IntegrationTests/JwtTokenValidation.cs @@ -0,0 +1,38 @@ +using System; +using FitConnect.Encryption; +using FluentAssertions; +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.Tokens; +using NUnit.Framework; + +namespace IntegrationTests; + +[TestFixture] +public class JwtTokenValidation { + [OneTimeSetUp] + public void OneTimeSetUp() { + IdentityModelEventSource.ShowPII = true; + } + + + [Test] + public void ExampleFromFitConnect_passes() { + var result = FitEncryption.VerifyJwt( + "eyJraWQiOiJhZUJVaFFTOHVhSnZ0ek1jVHlpRUFOM0tXNG02NXVEbUwwWDFBQUlxZENFIiwidHlwIjoiSldUIiwiYWxnIjoiUFM1MTIifQ.eyJzdWJtaXNzaW9uSG9zdCI6InN1Ym1pc3Npb24tYXBpLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2IiwiaXNzIjoiaHR0cHM6XC9cL3BvcnRhbC5hdXRoLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2Iiwic2VydmljZXMiOlt7ImdlYmlldElEcyI6WyJ1cm46ZGU6YnVuZDpkZXN0YXRpczpiZXZvZWxrZXJ1bmdzc3RhdGlzdGlrOnNjaGx1ZXNzZWw6cnM6MDY0MzUwMDE0MDE0Il0sImxlaXN0dW5nSURzIjpbInVybjpkZTpmaW06bGVpa2E6bGVpc3R1bmc6OTkxMjM0NTY3NjA2MTAiXX1dLCJkZXN0aW5hdGlvbklkIjoiZDQwZTdiMTMtZGE5OC00YjA5LTllMTYtYmJkNjFjYTgxNTEwIiwiaWF0IjoxNjUyMjkxMzkwLCJqdGkiOiJkOGI1NTM2NS1mNDMzLTRiNjMtYjg3Yi0xZWRiNTY3YzlmYWMifQ.RSdgZWBwPvsnlCajXF3Rh8uPDEKkAwgxNbzuO5HWCaAKroHQ8NQtoDGHe2iXFULR8ML7Ca5aHmGKR34CgGmdpxitbzDn_rjHe2WModuRclu8n_eEmGhMTAkcH1aQ8pcDnQAcfI44KPqQZ_D8X6IGqxOEMtoYiETay8OAN3Vzk1Ew9n4vrvK5r5eWIx-nu5uMtHhMqT7xg09jH0Ma4owfCiOrobEdM5fz9a5sWoi0aBTufEMR9ai-SuDR1ibNmwD7s7wYCdqCgaOtj-_dNbPNOYVUdHdRKMvPuFYEx8rs32mehgEEHX649m8QN0FAHsuXdPeagFv7ndceH2vrPPenKk6fz6W68fGZhfs6MzaoUBaz2p3uZJdTCk5gPrJu46TBW0uPEI8dY8Aw_SNMGWsyfviAzjbuhJ3JBoKk8tjPjkERWF9hovlrXu9l9s-jbAn-U-PYWsLYNAaCqvMEGLNmyTnsEMQuKWCQDr1mi0K8QqPiPNDe4NHmy49ObcesLB64LIE5did6XVUGOu3qOACg-s9dN0tFmqEw_-CWOhiWoAQRcu4uyzjCUWKoa6zpw_G3I5STzV328bwHf4hBDnTzZ8PH9OwG0vwqX1jeGdqYz3fWEz8gdU_N18t10393BYJy1tEggCnZzIVBqjQXAjV4pcI6G19D-xT3ITonxdMTAZw", + new JsonWebKey( + "{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"aeBUhQS8uaJvtzMcTyiEAN3KW4m65uDmL0X1AAIqdCE\",\"kty\":\"RSA\",\"n\":\"4Y0sJhadfrQnNZXeS7Pqh73FvtFPXLvLw11h7OiZM0DlqvRNgoYHO5k-kxJKOVCaFek0LjKM1_VQxMVpdChCkHeapdTg60oQTQZj3pG0boR3LStbqN3hNEx_JZC4aHH16kau0vqBBPiOOoq-ExUz-hXz_GMLsp9QVqIkw9okO_tzNPjQOo--GM8r4eSsKzgSHZzmepc9Gfk16eraGicBevlkclk32TmWIE_ErD31dtVbBlK-7GG2NUe-o_5rkiCJ2EwKRHZlLkBYJkkj_IjeUdKc4dawXoE8L83DSBPyapX47_L1VHTnT0hJdOVe6WHtvzzpusZ0Au-YDhp6LSwXnU9d0-VzBJmQvtrep1FM0d9aQrz0e0lVf8wCn13VdKO_FBZw9D7i0XRhF8JqQRblqhcCY7UGshbTTM8HORMFONHFmSQm10qfV29PLmztOhIuubMyYe1DPnlfRkpn5jnt8IPoopl6MliDKSc3m4dgG23KylBpTLr3U-XGQrTlerjrYh4t1LXiJ-jQhLefkak_WnExZJSXv601BgmbGj3GdIhS6lxdMX62cOuwKLVISOmHHxvimpQwhtYwiFR9OmGoKVgtCQ5eMKLwGWVwXSvUJ5YXH-yUyNW1_vOrt0DAtYmXwS_Ij0bMg9WoXKJ-5NtQpnnIzw1lr5bW5fNn2TgWpHk\"}")); + + result.Should().BeTrue(); + } + + + [Test] + public void ExampleFromFitConnect_fails() { + var result = FitEncryption.VerifyJwt( + "eyJraWQiOiJhZUJVaFFTOHVhSnZ0ek1jVHlpRUFOM0tXNG02NXVEbUwwWDFBQUlxZENFIiwidHlwIjoiSldUIiwiYWxnIjoiUFM1MTIifQ.eyJzdWJtaXNzaW9uSG9zdCI6InN1Ym1pc3Npb24tYXBpLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2IiwiaXNzIjoiaHR0cHM6XC9cL3BvcnRhbC5hdXRoLXRlc3RpbmcuZml0LWNvbm5lY3QuZml0a28uZGV2Iiwic2VydmljZXMiOlt7ImdlYmlldElEcyI6WyJ1cm46ZGU6YnVuZDpkZXN0YXRpczpiZXZvZWxrZXJ1bmdzc3RhdGlzdGlrOnNjaGx1ZXNzZWw6cnM6MDY0MzUwMDE0MDE0Il0sImxlaXN0dW5nSURzIjpbInVybjpkZTpmaW06bGVpa2E6bGVpc3R1bmc6OTkxMjM0NTY3NjA2MTAiXX1dLCJkZXN0aW5hdGlvbklkIjoiZDQwZTdiMTMtZGE5OC00YjA5LTllMTYtYmJkNjFjYTgxNTEwIiwiaWF0IjoxNjUyMjkxMzkwLCJqdGkiOiJkOGI1NTM2NS1mNDMzLTRiNjMtYjg3Yi0xZWRiNTY3YzlmYWMifQ.RSdgZWBwPvsnlCajXF3Rh8uPDEKkAwgxNbzuO5HWCaAKroHQ8NQtoDGHe2iXFULR8ML7Ca5aHmGKR34CgGmdpxitbzDn_rjHe2WModuRclu8n_eEmGhMTAkcH1aQ8pcDnQAcfI44KPqQZ_D8X6IGqxOEMtoYiETay8OAN3Vzk1Ew9n4vrvK5r5eWIx-nu5uMtHhMqT7xg09jH0Ma4owfCiOrobEdM5fz9a5sWoi0aBTufEMR9ai-SuDR1ibNmwD7s7wYCdqCgaOtj-_dNbPNOYVUdHdRKMvPuFYEx8rs32mehgEEHX649m8QN0FAHsuXdPeagFv7ndceH2vrPPenKk6fz6W68fGZhfs6MzaoUBaz2p3uZJdTCk5gPrJu46TBW0uPEI8dY8Aw_SNMGWsyfviAzjbuhJ3JBoKk8tjPjkERWF9hovlrXu9l9s-jbAn-U-PYWsLYNAaCqvMEGLNmyTnsEMQuKWCQDr1mi0K8QqPiPNDe4NHmy49ObcesLB64LIE5did6XVUGOu3qOACg-s9dN0tFmqEw_-CWOhiWoAQRcu4uyzjCUWKoa6zpw_G3I5STzV328bwHf4hBDnTzZ8PH9OwG0vwqX1jeGdqYz3fWEz8gdU_N18t10393BYJy1tEggCnZzIVBqjQXAjV4pcI6G19D-xT3ITonxdMTAZw", + new JsonWebKey( + "{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"aeBUhQS8uaJvtzMcTyiEAN3KW4m65uDmL0X1AAIqdCE\",\"kty\":\"RSA\",\"n\":\"4Y0KJhadfrQnNZXeS7Pqh73FvtFPXLvLw11h7OiZM0DlqvRNgoYHO5k-kxJKOVCaFek0LjKM1_VQxMVpdChCkHeapdTg60oQTQZj3pG0boR3LStbqN3hNEx_JZC4aHH16kau0vqBBPiOOoq-ExUz-hXz_GMLsp9QVqIkw9okO_tzNPjQOo--GM8r4eSsKzgSHZzmepc9Gfk16eraGicBevlkclk32TmWIE_ErD31dtVbBlK-7GG2NUe-o_5rkiCJ2EwKRHZlLkBYJkkj_IjeUdKc4dawXoE8L83DSBPyapX47_L1VHTnT0hJdOVe6WHtvzzpusZ0Au-YDhp6LSwXnU9d0-VzBJmQvtrep1FM0d9aQrz0e0lVf8wCn13VdKO_FBZw9D7i0XRhF8JqQRblqhcCY7UGshbTTM8HORMFONHFmSQm10qfV29PLmztOhIuubMyYe1DPnlfRkpn5jnt8IPoopl6MliDKSc3m4dgG23KylBpTLr3U-XGQrTlerjrYh4t1LXiJ-jQhLefkak_WnExZJSXv601BgmbGj3GdIhS6lxdMX62cOuwKLVISOmHHxvimpQwhtYwiFR9OmGoKVgtCQ5eMKLwGWVwXSvUJ5YXH-yUyNW1_vOrt0DAtYmXwS_Ij0bMg9WoXKJ-5NtQpnnIzw1lr5bW5fNn2TgWpHk\"}")); + + result.Should().BeFalse(); + } +} diff --git a/IntegrationTests/ProxyTest.cs b/IntegrationTests/ProxyTest.cs index 7503e959b26a48d09255021fff5bfca11fa2b385..2024efe0d5098ffba29e1c07ba7e63581702ac1b 100644 --- a/IntegrationTests/ProxyTest.cs +++ b/IntegrationTests/ProxyTest.cs @@ -85,7 +85,7 @@ public class ProxyTest { FitConnectEnvironment.Testing, "", "") .WithProxy("localhost", 3128); - (sender as FitConnect.Sender).OAuthService.Proxy.Should().NotBeNull(); + sender.OAuthService.Proxy.Should().NotBeNull(); } [Test] diff --git a/IntegrationTests/Routing/RoutingTests.cs b/IntegrationTests/Routing/RoutingTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..3635e72c0ad53c422b14b1ad955501014a0b1d95 --- /dev/null +++ b/IntegrationTests/Routing/RoutingTests.cs @@ -0,0 +1,207 @@ +using System; +using System.Linq; +using System.Text; +using FitConnect; +using FitConnect.Encryption; +using FitConnect.Models; +using FitConnect.Services; +using FitConnect.Services.Models.v1.Routes; +using FluentAssertions; +using Jose; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace IntegrationTests.Routing; + +[TestFixture] +public class RoutingTests { + private IRouter _router; + private ILogger _logger; + private string _body; + private string _detached; + + [SetUp] + public void Setup() { + _logger = LoggerFactory.Create( + c => { + c.AddConsole(); + c.SetMinimumLevel(LogLevel.Information); + } + ).CreateLogger("FIT-Connect"); + _router = Client.GetRouter(FitConnectEnvironment.Testing, _logger); + _detached = + "eyJraWQiOiIzMjg1ODE0Ny1mMDkwLTQzYTktYjJmZC1kMjZhZTViNDFjMDMiLCJjdHkiOiJhcHBsaWNhdGlvblwvam9zZSIsInR5cCI6IkpPU0UiLCJhbGciOiJQUzUxMiJ9..gOj_e9VS3pAJAtwkGa_SXSOeu-uX-40oD69kR9lwrfYV1_71rHLRcD8fDpD8sFXAXUvg8WNdBjXu5AgKR7jfOsAZezc5IUsh-VbPsRVG7ArZuwD1Q2RRJRDBbGEqsTT2wjxvGEnRDnPEXdrfPE6X3ron0ePk6KkVwBj4sY_g0be1Zq7GAL7C7cA_aVFPfkD3w-4-0F-Jrha9RG6w7j4r4ZvGrHierxHtm78JpSRG5rNxxa_Zhdrr7d_HiYdwVg0npfvRYHcI5ZxUP2bCS24NKn_oKNhPxyTWFwxIFrd0RQo6WQKxqmRfsJQ3Vt1SvgpgSHguogFuhfSlvt3Gu66b8XLvjwIoAF74Q7ry3h8EsHseGyYLWy076dggaRAh-HBYM8dZjSisEpCw5eYsemHBN6iVAxinkAFsTB0UYLwYsoKo7Lybsfb9ohz-IzHwufwOKJXTmHtxCrXlvCFliohOT9i6aHzBCRYT09l-ZcgnbfEMY4Jy8KiMZleMgJTIgGg3xMI80vdOZZAtQsosgT39JnKQ6GzPAfNxLnV3AB7VDlT-5xwaV28DexmoHTcFZoU8rYqB4SFfSsg6VHC6UHjLJFaGPtCS4de_S8sHTVKnxmfX8xBKU3U54dTSztn1UdQ4bDD8iTOKXX24uEUqWe6IV1D19lF8X8TyyOXm_fb0oPM"; + _body = + @"{""encryptionKid"":""1e95f036-ccff-425c-a0de-3d89d5cc59fa"",""metadataVersions"":[""1.0.0""],""publicKeys"":{""keys"":[{""alg"":""RSA-OAEP-256"",""e"":""AQAB"",""key_ops"":[""wrapKey""],""kid"":""1e95f036-ccff-425c-a0de-3d89d5cc59fa"",""kty"":""RSA"",""n"":""2ch1Ir3_Lyb9_HxW9RqIodxi9fXhix6APKwqiSfi-JlRqVa1FoAFsW1nW0IbQjkW6sNkWUFWuA9AfVoKT9nnIcnLSjSQ84SI-if6qTbornyKvBjXg8BSecSUUPYyT0-4NmxrXMGHPYbJV7fQq6jPXzkWC5P5jqQ7ObraQp752BcE_JVQUmFk1ydhhbnroHpGUkA-8jG_kiVL-lAz7uUmZCh6i3ZJD5HN1JOE5LMyzUQOgOFUUPiviBywQAbPQuDLydZ2diO5wqm4mwBadAAzC27OllSkNXSgnd9MVajXmtBVpz2ksMaSCAbfB4rK9q5jXd5YMwu1ZlA-ZuWKYm_p1GjbZdx4xk9w23Zkgnrr3SvWnW98686fd03MG1ACAGatq5FcAvGp8BXCKwz5FpyYtOONx-tECYHcHhx_SafOe9siLYObLmBSsLF3TAjigZjpGOuEjBtKyv5OwJj-6YfIYYjlofuqv6GHUGDvv8iQsy6U4eHCoRpKJzmX6L22MUQgisYvQdGY2jbdEni3g_MpciMIbnZFLENVrqHXYcgHN-SbXl_GVR5b3F0ompES55xA7fuYlt4lp5j0IUo0OWM2_tYYHtASZicVAwnbzLQZEA0u-wXZr0ByMWE07Od_KaLUomlBPi1Ac_FU3KOx0APKJUm7D3__aiLZll3Sh9EnIvE"",""x5c"":[""MIIE6jCCAtKgAwIBAgIGAXo1pG0GMA0GCSqGSIb3DQEBCwUAMDYxNDAyBgNVBAMMK2FaV0ptMG1XRmFxRGFOTkJOaDNabVluVmw3eG52SVMxVEJ5SHhaVnNUNm8wHhcNMjEwNjIyMjEzMzI2WhcNMjIwNDE4MjEzMzI2WjA2MTQwMgYDVQQDDCthWldKbTBtV0ZhcURhTk5CTmgzWm1ZblZsN3hudklTMVRCeUh4WlZzVDZvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ch1Ir3/Lyb9/HxW9RqIodxi9fXhix6APKwqiSfi+JlRqVa1FoAFsW1nW0IbQjkW6sNkWUFWuA9AfVoKT9nnIcnLSjSQ84SI+if6qTbornyKvBjXg8BSecSUUPYyT0+4NmxrXMGHPYbJV7fQq6jPXzkWC5P5jqQ7ObraQp752BcE/JVQUmFk1ydhhbnroHpGUkA+8jG/kiVL+lAz7uUmZCh6i3ZJD5HN1JOE5LMyzUQOgOFUUPiviBywQAbPQuDLydZ2diO5wqm4mwBadAAzC27OllSkNXSgnd9MVajXmtBVpz2ksMaSCAbfB4rK9q5jXd5YMwu1ZlA+ZuWKYm/p1GjbZdx4xk9w23Zkgnrr3SvWnW98686fd03MG1ACAGatq5FcAvGp8BXCKwz5FpyYtOONx+tECYHcHhx/SafOe9siLYObLmBSsLF3TAjigZjpGOuEjBtKyv5OwJj+6YfIYYjlofuqv6GHUGDvv8iQsy6U4eHCoRpKJzmX6L22MUQgisYvQdGY2jbdEni3g/MpciMIbnZFLENVrqHXYcgHN+SbXl/GVR5b3F0ompES55xA7fuYlt4lp5j0IUo0OWM2/tYYHtASZicVAwnbzLQZEA0u+wXZr0ByMWE07Od/KaLUomlBPi1Ac/FU3KOx0APKJUm7D3//aiLZll3Sh9EnIvECAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAFi24JFEmYL2sOqaaQOMHCVm+WQ9QyN/rkvjHLG8th5TIF8NJ4uwxl+n6GBO2uOZOBixHbU5pK9slyt9Xryw7CbL/hhRGSs3GSFR2hkxoBHdzfFnAwegnd1H5XHQwSgh43jGOn9AxsyISpkvFo7+DObh9Cv8NsjpL57No4UJ62XggfYJW43u4+I/fHcDwnvIN0dvnYpQkCbTmrjLa5IkGim9BynfW1k6VuxLya1SsyjBHWw2YNQ4xBJI4OzXhL6OmBSrohF1RbIKOpjtqGfkXZpxufLNV2CnL36r/41c1nop6cmCIMDtnFEQdAmGe8m/8wvVpLnks59C02/WotlK3iORHCYB6G0pHMKFB4zOVANYtLFgqTgN4HNciV3FN0TvI19qzjkAdcB+m+L+LdseIzcQ/BToGyPvWkJ1mvJZIp0ejnlMWIl3VlNpMKeZ7lJbPpZvABO00lK+FynhITtb6N29toE+7JgHAlWmxw6PFFY1x+3xTHBTOU0oUR/TyKsEU0+bNSb/0S+ZyodmnIFbgYWarjK5pUwfTRyPyeVEukg1Gf30c/7f/5KZ/dpLFUNBb/YTNIzYEhGNUyLJ1mrSz33gr4MtvI4uSu0Jpr1NrwdMGvFhr5QOCULuoC9KlokusUpi0GTH0gK3K/TUi6qvU+Wztfa7mqah17BVVFT1wATs=""]}]},""replyChannels"":{""email"":{""usePgp"":true}},""status"":""active"",""submissionSchemas"":[{""mimeType"":""application/json"",""schemaUri"":""https://schema.fitko.de/fim/s06000178_0.4.schema.json""}],""submissionUrl"":""https://submission-api-testing.fit-connect.fitko.dev""}"; + } + + + [Test] + [TestCase("99123456760610", "064350014014")] + public void FindDestination_WithArs(string leika, string ars) { + // Arrange + + // Act + var routes = _router.FindDestinationsAsync(leika, ars: ars).Result; + + // Assert + routes.Count.Should().BeGreaterThan(0); + var route = routes.First(); + + route.DestinationId.Should().NotBeNull(); + route.DestinationSignature.Should().NotBeNull(); + } + + [TestCase("99123456760610", "06435014")] + public void FindDestination_WithAgsSkipValidation(string leika, string ags) { + // Arrange + + // Act + var routes = _router + .FindDestinationsAsync(leika, ags, skipValidation: true).Result; + + // Assert + routes.Count.Should().BeGreaterThan(0); + var route = routes.First(); + + route.DestinationId.Should().NotBeNull(); + route.DestinationSignature.Should().NotBeNull(); + } + + [TestCase("99123456760610", "931")] + public void FindDestination_WithAreaId(string leika, string areaId) { + // Arrange + + // Act + var routes = _router.FindDestinationsAsync(leika, areaId: areaId).Result; + + // Assert + routes.Count.Should().BeGreaterThan(0); + var route = routes.First(); + + route.DestinationId.Should().NotBeNull(); + route.DestinationSignature.Should().NotBeNull(); + } + + [Test] + public void GetAreas_ShouldGetAreasFromServer() { + // Arrange + var areas = _router.GetAreas("Furth*", out var _); + areas.Should().HaveCountGreaterThan(0); + } + + [Test] + public void FindDestination_WithAreaIdAndAgs_ShouldThrowException() { + // Arrange + var leika = "99123456760610"; + var ags = "06435014"; + var areaId = "931"; + + // Act + Action action = () => _router.FindDestinationsAsync(leika, ags, areaId).Wait(); + + // Assert + action.Should().Throw<ArgumentException>(); + } + + [Test] + public void FindDestination_WithoutAgsAndAreaId_ShouldThrowException() { + // Arrange + var leika = "99123456760610"; + + // Act + Action action = () => _router.FindDestinationsAsync(leika).Wait(); + + // Assert + action.Should().Throw<ArgumentException>(); + } + + [Test] + [Order(80)] + public void BaseSignatureTest() { + var parameter = JsonConvert.DeserializeObject(_body); + // Get Key from SubmissionAPI + var parameterJson = JsonConvert.SerializeObject(parameter, + new JsonSerializerSettings { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + ContractResolver = new OrderedContractResolver() + }).Trim(); + + Console.WriteLine(parameterJson); + var combined = _detached.Replace("..", + $".{Base64Url.Encode(Encoding.UTF8.GetBytes(parameterJson))}."); + + var secret = + "{\"alg\":\"PS512\",\"e\":\"AQAB\",\"key_ops\":[\"verify\"],\"kid\":\"32858147-f090-43a9-b2fd-d26ae5b41c03\",\"kty\":\"RSA\",\"n\":\"3UltHnOKF38UbpfQ-sG6_p-_SiWTzDohXE1PT6I5xpnQncczwyAF8j-PZv8TxxtvuVxYVJdt610B3bMCwPaD1Kw2ht1mS_Iu2d_SqTxhCDF4S0yrCovo6fKVQXG-IPsbs59-1lefUqjrUbkxRRxH335p22Lmg9Wf0XBJqMWsMBNnul8lKjLP7krk9TKQKR35js42oIliEakByWpq6kzPPlgV4mkFlivnseQaLxItFMh6rs5lLS1kHdrYfwCWS97wf5TO2ubygo_617qKAeN3e6mYYb6k_30WYwnH-vc1_gMf8JuBOZ7sO-OpW09XrQLBkUXTHbIcmLExpm3yOizc-UI9NrLgwomPyg0Ml1n3bKpIWq6dIpyO2LJ6euu8CzPDs2NNv12Z_FUuJMPQWvt-nv3g6AgOHPJZQJ8TjI27yPgjFwtef91OT1jQ_IzgCVp7EFNn-rZtgxhV2PLmhXick8jLszodEgcki5Ooj5oBbze0yV7zPZ3cdXle_NwDKlxkwbAs3WCyTY7mOVA0avsW9cDDwplQnBMDbwKSGOqjDHVI2EY2SN4ur0lYp-gm5IxtTMm2d4CjAXh4XVHBvNNLxBJb9byDA7qM1QgJa1DaKdV5yoTL2VNTWUBYbK4ag7K6avACM7KjL9YvzUIYNnegu5qFtUVXfjBlE_5wNbYzBTk\"}"; + + var result = FitEncryption.VerifyJwt(combined, secret, _logger); + + Assert.IsTrue(result); + } + + + [Test] + [Order(90)] + public void BaseSignatureTest_DownloadKey() { + var parameter = JsonConvert.DeserializeObject(_body); + // Get Key from SubmissionAPI + var parameterJson = JsonConvert.SerializeObject(parameter, + new JsonSerializerSettings { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + ContractResolver = new OrderedContractResolver() + }).Trim(); + + + var combined = _detached.Replace("..", + $".{Base64Url.Encode(Encoding.UTF8.GetBytes(parameterJson))}."); + + var secret = new Router(FitConnectEnvironment.Testing, _logger) + .GetSubmissionServiceValidationJwk( + "https://submission-api-testing.fit-connect.fitko.dev").Result; + + var keySet = new JsonWebKeySet(secret); + var result = FitEncryption.VerifyJwt(combined, (JsonWebKey)keySet.Keys[0], _logger); + + Assert.IsTrue(result); + } + + [Test] + [Order(100)] + public void BaseSignatureTest_DownloadKeyAndRoute() { + // GET destination from here: https://dvdv-testsystem.governikus.de/dvdv-fitconnect/v1/destinations/{id + + var body = + ((new DvdvService("https://dvdv-testsystem.governikus.de/dvdv-fitconnect", + logger: _logger)).GetDestinationJson("d40e7b13-da98-4b09-9e16-bbd61ca81510") + .Result); + var parameter = JsonConvert.DeserializeObject<DestinationParameters>(body); + + // Get Key from SubmissionAPI + var parameterJson = JsonConvert.SerializeObject(parameter, + new JsonSerializerSettings { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + ContractResolver = new OrderedContractResolver() + }).Trim(); + + Console.WriteLine(parameterJson); + + var combined = _detached.Replace("..", + $".{Base64Url.Encode(Encoding.UTF8.GetBytes(parameterJson))}."); + + Console.WriteLine(combined); + + var secret = new Router(FitConnectEnvironment.Testing, _logger) + .GetSubmissionServiceValidationJwk( + "https://submission-api-testing.fit-connect.fitko.dev").Result; + + var keySet = new JsonWebKeySet(secret); + var result = FitEncryption.VerifyJwt(combined, (JsonWebKey)keySet.Keys[0], _logger); + + Assert.IsTrue(result); + } +} diff --git a/IntegrationTests/Sender/SenderTestBase.cs b/IntegrationTests/Sender/SenderTestBase.cs index 6ba21abe72cbf05d2f5a2dc0afffb5632560e587..24fc1c7a1cf226a82fb21701ca4daae0c6297079 100644 --- a/IntegrationTests/Sender/SenderTestBase.cs +++ b/IntegrationTests/Sender/SenderTestBase.cs @@ -12,8 +12,6 @@ namespace IntegrationTests.Sender; [Order(100)] [TestFixture] public abstract class SenderTestBase { - protected string LeikaKey = ""; - /// <summary> /// Setup creates json file for credentials if not found /// </summary> @@ -51,6 +49,8 @@ public abstract class SenderTestBase { _clientId, _clientSecret, logger); } + protected string LeikaKey = ""; + protected const string desitnationId = "aa3704d6-8bd7-4d40-a8af-501851f93934"; protected string _clientId = "73a8ff88-076b-4263-9a80-8ebadac97b0d"; protected string _clientSecret = "rdlXms-4ikO47AbTmmCTdzFoE4cTSt13JmSbcY5Dhsw"; diff --git a/IntegrationTests/Sender/SenderTestHappyPath.cs b/IntegrationTests/Sender/SenderTestHappyPath.cs index 44612373f725f6a6a3ba45a6614032b24c1f8ec1..a3c451c1fe1628a69aecc3127b237a8ab3dfa8e3 100644 --- a/IntegrationTests/Sender/SenderTestHappyPath.cs +++ b/IntegrationTests/Sender/SenderTestHappyPath.cs @@ -169,12 +169,6 @@ public class SenderTestHappyPath : SenderTestBase { submission.Should().NotBeNull(); } - [Test] - public void GetAreas_ShouldGetAreasFromServer() { - // Arrange - var areas = Sender.GetAreas("Furth*", out var _); - areas.Should().HaveCountGreaterThan(0); - } [Test] public void GetDestinations_ShouldGetDestinationsFromServer() { diff --git a/IntegrationTests/Sender/SenderTestUnhappyPath.cs b/IntegrationTests/Sender/SenderTestUnhappyPath.cs index fd6fdc47b1a3faab2f43bc1252169b10b32b800f..f2de015cf55858ab1b1aeb18f9ab057dbc98dcf9 100644 --- a/IntegrationTests/Sender/SenderTestUnhappyPath.cs +++ b/IntegrationTests/Sender/SenderTestUnhappyPath.cs @@ -25,7 +25,7 @@ public class SenderTestUnhappyPath : SenderTestBase { public void WithData_DataIsInvalidJson_ShouldThrowArgumentException() { Assert.Throws<ArgumentException>(() => { Sender.WithDestination(desitnationId) - .WithServiceType("Name", leikaKey: "urn:de:fim:leika:leistung:00000000000000") + .WithServiceType("Name", "urn:de:fim:leika:leistung:00000000000000") .WithAttachments(new Attachment("Test.pdf", "Test PDF")) .WithData("This is very wrong"); }) diff --git a/IntegrationTests/Sender/ThreadTest.cs b/IntegrationTests/Sender/ThreadTest.cs index 7e932904170ed4297c50436ee9a3188d6e83cc1c..4342d36af08a42eeeeb329ac83720470752b5ce5 100644 --- a/IntegrationTests/Sender/ThreadTest.cs +++ b/IntegrationTests/Sender/ThreadTest.cs @@ -1,10 +1,10 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Autofac; +using FitConnect; using FitConnect.Models; using FluentAssertions; using Microsoft.Extensions.Logging; @@ -15,31 +15,31 @@ using NUnit.Framework; namespace IntegrationTests.Sender; /// <summary> -/// This test runs multi sender and one subscriber which "cleans" the server -/// so other subscriber won't get any submissions. +/// This test runs multi sender and one subscriber which "cleans" the server +/// so other subscriber won't get any submissions. /// </summary> [Ignore("Can not be combined with other tests - need to be run separately")] [TestFixture] public class ThreadTest { - private IContainer _container; - private MockSettings _setting; - private ILogger _logger; - private const int NumberOfThreads = 34; - [SetUp] public void Setup() { - _container = MockContainer.Container.Create(); + _container = Container.Create(); _setting = _container.Resolve<MockSettings>(); _logger = LoggerFactory.Create(b => b.AddConsole()) .CreateLogger<FitConnect.Sender>(); } + private IContainer _container; + private MockSettings _setting; + private ILogger _logger; + private const int NumberOfThreads = 34; + [Test] [Order(1)] public void ThreadedSender() { var tasks = new List<Task>(); - for (int i = 0; i < NumberOfThreads; i++) { + for (var i = 0; i < NumberOfThreads; i++) tasks.Add(Task.Run(() => { var counter = Thread.CurrentThread.ManagedThreadId; var Sender = new FitConnect.Sender( @@ -58,7 +58,6 @@ public class ThreadTest { })) .Submit(); })); - } while (!tasks.All(t => t.IsCompleted)) { } @@ -67,18 +66,17 @@ public class ThreadTest { [Test] [Order(2)] public void GetSubmissions() { - var subscriber = FitConnect.Client.GetSubscriber(FitConnectEnvironment.Testing, + var subscriber = Client.GetSubscriber(FitConnectEnvironment.Testing, _setting.SubscriberClientId, _setting.SubscriberClientSecret, _setting.PrivateKeyDecryption, _setting.PrivateKeySigning, _setting.PublicKeyEncryption, _setting.PublicKeySignatureVerification, _logger); var submissions = subscriber.GetAvailableSubmissions().ToList(); - foreach (var submission in submissions) { + foreach (var submission in submissions) subscriber .RequestSubmission(submission.SubmissionId) .AcceptSubmission(); - } submissions.Count.Should().Be(NumberOfThreads); } diff --git a/IntegrationTests/Subscriber/SubscriberTestBase.cs b/IntegrationTests/Subscriber/SubscriberTestBase.cs index 9b5dfa8863edc9d31f4073cebb872ba43ffd9d54..f4b2684a0c0b53d8279b4203f8f62d733332b7ae 100644 --- a/IntegrationTests/Subscriber/SubscriberTestBase.cs +++ b/IntegrationTests/Subscriber/SubscriberTestBase.cs @@ -12,8 +12,8 @@ public abstract class SubscriberTestBase { protected string _clientId = "20175c2b-c4dd-4a01-99b1-3a08436881a1"; protected string _clientSecret = "KV2qd7qc5n-xESB6dvfrTlMDx2BWHJd5hXJ6pKKnbEQ"; private IContainer _container; - protected ISubscriber subscriber { get; set; } protected ILogger Logger; + protected ISubscriber subscriber { get; set; } [OneTimeSetUp] public void OneTimeSetUp() { diff --git a/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs b/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs index bfe0ed58a6adb48c12f44abc14dadec2fa55c889..0837029663223585e5bdc0d60d4c96ab6cf401db 100644 --- a/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs +++ b/IntegrationTests/Subscriber/SubscriberTestHappyPath.cs @@ -53,7 +53,7 @@ public class SubscriberTestHappyPath : SubscriberTestBase { if (i++ % 2 == 0) dto.AcceptSubmission(); else - dto.RejectSubmission(new Problems() { Description = "A really critical problem" }); + dto.RejectSubmission(new Problems { Description = "A really critical problem" }); } } @@ -75,11 +75,10 @@ public class SubscriberTestHappyPath : SubscriberTestBase { var submissions = subscriber.GetAvailableSubmissions().ToList(); submissions.Count().Should().BeGreaterThan(0); - foreach (var submission in submissions) { + foreach (var submission in submissions) subscriber.GetStatusForSubmission(submission.CaseId).ForEach(s => Logger.LogInformation("{SubmissionCaseId} - {ObjEventTime} - {ObjEventType}", submission.CaseId, s.EventTime, s.EventType)); - } } //[Ignore("Takes a while")] diff --git a/IntegrationTests/Subscriber/SubscriberTestUnHappyPath.cs b/IntegrationTests/Subscriber/SubscriberTestUnHappyPath.cs new file mode 100644 index 0000000000000000000000000000000000000000..ff8cda3c79431e77d1771ab9f70d6cd0849aa1a5 --- /dev/null +++ b/IntegrationTests/Subscriber/SubscriberTestUnHappyPath.cs @@ -0,0 +1,35 @@ +using System.Linq; +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace IntegrationTests.Subscriber; + +[TestFixture] +public class SubscriberTestUnHappyPath : SubscriberTestBase { + [Test] + public void TestMetaData_InvalidData() { + // Arrange + var wrongData = "{\"name\":\"value\"}"; + + // Act + var validationErrors = FitConnect.Subscriber.VerifyMetadata(wrongData); + validationErrors.ToList().ForEach(v => Logger?.LogWarning("ERROR: {V}", v.ToString())); + + // Assert + validationErrors.Count.Should().BeGreaterThan(0); + } + + [Test] + public void TestMetaData_EmptyString() { + // Arrange + var wrongData = ""; + + // Act && Assert + Assert.Throws<JsonReaderException>(() => { + var validationErrors = FitConnect.Subscriber.VerifyMetadata(wrongData); + validationErrors.ToList().ForEach(v => Logger.LogWarning("ERROR: {V}", v.ToString())); + }); + } +} diff --git a/IntegrationTests/temp.txt b/IntegrationTests/temp.txt new file mode 100644 index 0000000000000000000000000000000000000000..756963df246e0dfda2776d722e292d39a5795f1b --- /dev/null +++ b/IntegrationTests/temp.txt @@ -0,0 +1,7 @@ +{"encryptionKid":"1e95f036-ccff-425c-a0de-3d89d5cc59fa","metadataVersions":["1.0.0"],"publicKeys":{"keys":[{"alg":"RSA-OAEP-256","e":"AQAB","key_ops":["wrapKey"],"kid":"1e95f036-ccff-425c-a0de-3d89d5cc59fa","kty":"RSA","n":"2ch1Ir3_Lyb9_HxW9RqIodxi9fXhix6APKwqiSfi-JlRqVa1FoAFsW1nW0IbQjkW6sNkWUFWuA9AfVoKT9nnIcnLSjSQ84SI-if6qTbornyKvBjXg8BSecSUUPYyT0-4NmxrXMGHPYbJV7fQq6jPXzkWC5P5jqQ7ObraQp752BcE_JVQUmFk1ydhhbnroHpGUkA-8jG_kiVL-lAz7uUmZCh6i3ZJD5HN1JOE5LMyzUQOgOFUUPiviBywQAbPQuDLydZ2diO5wqm4mwBadAAzC27OllSkNXSgnd9MVajXmtBVpz2ksMaSCAbfB4rK9q5jXd5YMwu1ZlA-ZuWKYm_p1GjbZdx4xk9w23Zkgnrr3SvWnW98686fd03MG1ACAGatq5FcAvGp8BXCKwz5FpyYtOONx-tECYHcHhx_SafOe9siLYObLmBSsLF3TAjigZjpGOuEjBtKyv5OwJj-6YfIYYjlofuqv6GHUGDvv8iQsy6U4eHCoRpKJzmX6L22MUQgisYvQdGY2jbdEni3g_MpciMIbnZFLENVrqHXYcgHN-SbXl_GVR5b3F0ompES55xA7fuYlt4lp5j0IUo0OWM2_tYYHtASZicVAwnbzLQZEA0u-wXZr0ByMWE07Od_KaLUomlBPi1Ac_FU3KOx0APKJUm7D3__aiLZll3Sh9EnIvE","x5c":["MIIE6jCCAtKgAwIBAgIGAXo1pG0GMA0GCSqGSIb3DQEBCwUAMDYxNDAyBgNVBAMMK2FaV0ptMG1XRmFxRGFOTkJOaDNabVluVmw3eG52SVMxVEJ5SHhaVnNUNm8wHhcNMjEwNjIyMjEzMzI2WhcNMjIwNDE4MjEzMzI2WjA2MTQwMgYDVQQDDCthWldKbTBtV0ZhcURhTk5CTmgzWm1ZblZsN3hudklTMVRCeUh4WlZzVDZvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ch1Ir3/Lyb9/HxW9RqIodxi9fXhix6APKwqiSfi+JlRqVa1FoAFsW1nW0IbQjkW6sNkWUFWuA9AfVoKT9nnIcnLSjSQ84SI+if6qTbornyKvBjXg8BSecSUUPYyT0+4NmxrXMGHPYbJV7fQq6jPXzkWC5P5jqQ7ObraQp752BcE/JVQUmFk1ydhhbnroHpGUkA+8jG/kiVL+lAz7uUmZCh6i3ZJD5HN1JOE5LMyzUQOgOFUUPiviBywQAbPQuDLydZ2diO5wqm4mwBadAAzC27OllSkNXSgnd9MVajXmtBVpz2ksMaSCAbfB4rK9q5jXd5YMwu1ZlA+ZuWKYm/p1GjbZdx4xk9w23Zkgnrr3SvWnW98686fd03MG1ACAGatq5FcAvGp8BXCKwz5FpyYtOONx+tECYHcHhx/SafOe9siLYObLmBSsLF3TAjigZjpGOuEjBtKyv5OwJj+6YfIYYjlofuqv6GHUGDvv8iQsy6U4eHCoRpKJzmX6L22MUQgisYvQdGY2jbdEni3g/MpciMIbnZFLENVrqHXYcgHN+SbXl/GVR5b3F0ompES55xA7fuYlt4lp5j0IUo0OWM2/tYYHtASZicVAwnbzLQZEA0u+wXZr0ByMWE07Od/KaLUomlBPi1Ac/FU3KOx0APKJUm7D3//aiLZll3Sh9EnIvECAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAFi24JFEmYL2sOqaaQOMHCVm+WQ9QyN/rkvjHLG8th5TIF8NJ4uwxl+n6GBO2uOZOBixHbU5pK9slyt9Xryw7CbL/hhRGSs3GSFR2hkxoBHdzfFnAwegnd1H5XHQwSgh43jGOn9AxsyISpkvFo7+DObh9Cv8NsjpL57No4UJ62XggfYJW43u4+I/fHcDwnvIN0dvnYpQkCbTmrjLa5IkGim9BynfW1k6VuxLya1SsyjBHWw2YNQ4xBJI4OzXhL6OmBSrohF1RbIKOpjtqGfkXZpxufLNV2CnL36r/41c1nop6cmCIMDtnFEQdAmGe8m/8wvVpLnks59C02/WotlK3iORHCYB6G0pHMKFB4zOVANYtLFgqTgN4HNciV3FN0TvI19qzjkAdcB+m+L+LdseIzcQ/BToGyPvWkJ1mvJZIp0ejnlMWIl3VlNpMKeZ7lJbPpZvABO00lK+FynhITtb6N29toE+7JgHAlWmxw6PFFY1x+3xTHBTOU0oUR/TyKsEU0+bNSb/0S+ZyodmnIFbgYWarjK5pUwfTRyPyeVEukg1Gf30c/7f/5KZ/dpLFUNBb/YTNIzYEhGNUyLJ1mrSz33gr4MtvI4uSu0Jpr1NrwdMGvFhr5QOCULuoC9KlokusUpi0GTH0gK3K/TUi6qvU+Wztfa7mqah17BVVFT1wATs="]}]},"replyChannels":{"email":{"usePgp":true}},"status":"active","submissionSchemas":[{"mimeType":"application/json","schemaUri":"https://schema.fitko.de/fim/s06000178_0.4.schema.json"}],"submissionUrl":"https://submission-api-testing.fit-connect.fitko.dev"} +{"encryptionKid":"1e95f036-ccff-425c-a0de-3d89d5cc59fa","metadataVersions":["1.0.0"],"publicKeys":{"keys":[{"key_ops":["wrapKey"],"x5c":["MIIE6jCCAtKgAwIBAgIGAXo1pG0GMA0GCSqGSIb3DQEBCwUAMDYxNDAyBgNVBAMMK2FaV0ptMG1XRmFxRGFOTkJOaDNabVluVmw3eG52SVMxVEJ5SHhaVnNUNm8wHhcNMjEwNjIyMjEzMzI2WhcNMjIwNDE4MjEzMzI2WjA2MTQwMgYDVQQDDCthWldKbTBtV0ZhcURhTk5CTmgzWm1ZblZsN3hudklTMVRCeUh4WlZzVDZvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ch1Ir3/Lyb9/HxW9RqIodxi9fXhix6APKwqiSfi+JlRqVa1FoAFsW1nW0IbQjkW6sNkWUFWuA9AfVoKT9nnIcnLSjSQ84SI+if6qTbornyKvBjXg8BSecSUUPYyT0+4NmxrXMGHPYbJV7fQq6jPXzkWC5P5jqQ7ObraQp752BcE/JVQUmFk1ydhhbnroHpGUkA+8jG/kiVL+lAz7uUmZCh6i3ZJD5HN1JOE5LMyzUQOgOFUUPiviBywQAbPQuDLydZ2diO5wqm4mwBadAAzC27OllSkNXSgnd9MVajXmtBVpz2ksMaSCAbfB4rK9q5jXd5YMwu1ZlA+ZuWKYm/p1GjbZdx4xk9w23Zkgnrr3SvWnW98686fd03MG1ACAGatq5FcAvGp8BXCKwz5FpyYtOONx+tECYHcHhx/SafOe9siLYObLmBSsLF3TAjigZjpGOuEjBtKyv5OwJj+6YfIYYjlofuqv6GHUGDvv8iQsy6U4eHCoRpKJzmX6L22MUQgisYvQdGY2jbdEni3g/MpciMIbnZFLENVrqHXYcgHN+SbXl/GVR5b3F0ompES55xA7fuYlt4lp5j0IUo0OWM2/tYYHtASZicVAwnbzLQZEA0u+wXZr0ByMWE07Od/KaLUomlBPi1Ac/FU3KOx0APKJUm7D3//aiLZll3Sh9EnIvECAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAFi24JFEmYL2sOqaaQOMHCVm+WQ9QyN/rkvjHLG8th5TIF8NJ4uwxl+n6GBO2uOZOBixHbU5pK9slyt9Xryw7CbL/hhRGSs3GSFR2hkxoBHdzfFnAwegnd1H5XHQwSgh43jGOn9AxsyISpkvFo7+DObh9Cv8NsjpL57No4UJ62XggfYJW43u4+I/fHcDwnvIN0dvnYpQkCbTmrjLa5IkGim9BynfW1k6VuxLya1SsyjBHWw2YNQ4xBJI4OzXhL6OmBSrohF1RbIKOpjtqGfkXZpxufLNV2CnL36r/41c1nop6cmCIMDtnFEQdAmGe8m/8wvVpLnks59C02/WotlK3iORHCYB6G0pHMKFB4zOVANYtLFgqTgN4HNciV3FN0TvI19qzjkAdcB+m+L+LdseIzcQ/BToGyPvWkJ1mvJZIp0ejnlMWIl3VlNpMKeZ7lJbPpZvABO00lK+FynhITtb6N29toE+7JgHAlWmxw6PFFY1x+3xTHBTOU0oUR/TyKsEU0+bNSb/0S+ZyodmnIFbgYWarjK5pUwfTRyPyeVEukg1Gf30c/7f/5KZ/dpLFUNBb/YTNIzYEhGNUyLJ1mrSz33gr4MtvI4uSu0Jpr1NrwdMGvFhr5QOCULuoC9KlokusUpi0GTH0gK3K/TUi6qvU+Wztfa7mqah17BVVFT1wATs="],"kid":"1e95f036-ccff-425c-a0de-3d89d5cc59fa","kty":"RSA","alg":"RSA-OAEP-256","n":"2ch1Ir3_Lyb9_HxW9RqIodxi9fXhix6APKwqiSfi-JlRqVa1FoAFsW1nW0IbQjkW6sNkWUFWuA9AfVoKT9nnIcnLSjSQ84SI-if6qTbornyKvBjXg8BSecSUUPYyT0-4NmxrXMGHPYbJV7fQq6jPXzkWC5P5jqQ7ObraQp752BcE_JVQUmFk1ydhhbnroHpGUkA-8jG_kiVL-lAz7uUmZCh6i3ZJD5HN1JOE5LMyzUQOgOFUUPiviBywQAbPQuDLydZ2diO5wqm4mwBadAAzC27OllSkNXSgnd9MVajXmtBVpz2ksMaSCAbfB4rK9q5jXd5YMwu1ZlA-ZuWKYm_p1GjbZdx4xk9w23Zkgnrr3SvWnW98686fd03MG1ACAGatq5FcAvGp8BXCKwz5FpyYtOONx-tECYHcHhx_SafOe9siLYObLmBSsLF3TAjigZjpGOuEjBtKyv5OwJj-6YfIYYjlofuqv6GHUGDvv8iQsy6U4eHCoRpKJzmX6L22MUQgisYvQdGY2jbdEni3g_MpciMIbnZFLENVrqHXYcgHN-SbXl_GVR5b3F0ompES55xA7fuYlt4lp5j0IUo0OWM2_tYYHtASZicVAwnbzLQZEA0u-wXZr0ByMWE07Od_KaLUomlBPi1Ac_FU3KOx0APKJUm7D3__aiLZll3Sh9EnIvE","e":"AQAB"}]},"replyChannels":{"email":{"usePgp":true}},"status":"active","submissionSchemas":[{"mimeType":"application/json","schemaUri":"https://schema.fitko.de/fim/s06000178_0.4.schema.json"}],"submissionUrl":"https://submission-api-testing.fit-connect.fitko.dev"} + +eyJraWQiOiIzMjg1ODE0Ny1mMDkwLTQzYTktYjJmZC1kMjZhZTViNDFjMDMiLCJjdHkiOiJhcHBsaWNhdGlvblwvam9zZSIsInR5cCI6IkpPU0UiLCJhbGciOiJQUzUxMiJ9..gOj_e9VS3pAJAtwkGa_SXSOeu-uX-40oD69kR9lwrfYV1_71rHLRcD8fDpD8sFXAXUvg8WNdBjXu5AgKR7jfOsAZezc5IUsh-VbPsRVG7ArZuwD1Q2RRJRDBbGEqsTT2wjxvGEnRDnPEXdrfPE6X3ron0ePk6KkVwBj4sY_g0be1Zq7GAL7C7cA_aVFPfkD3w-4-0F-Jrha9RG6w7j4r4ZvGrHierxHtm78JpSRG5rNxxa_Zhdrr7d_HiYdwVg0npfvRYHcI5ZxUP2bCS24NKn_oKNhPxyTWFwxIFrd0RQo6WQKxqmRfsJQ3Vt1SvgpgSHguogFuhfSlvt3Gu66b8XLvjwIoAF74Q7ry3h8EsHseGyYLWy076dggaRAh-HBYM8dZjSisEpCw5eYsemHBN6iVAxinkAFsTB0UYLwYsoKo7Lybsfb9ohz-IzHwufwOKJXTmHtxCrXlvCFliohOT9i6aHzBCRYT09l-ZcgnbfEMY4Jy8KiMZleMgJTIgGg3xMI80vdOZZAtQsosgT39JnKQ6GzPAfNxLnV3AB7VDlT-5xwaV28DexmoHTcFZoU8rYqB4SFfSsg6VHC6UHjLJFaGPtCS4de_S8sHTVKnxmfX8xBKU3U54dTSztn1UdQ4bDD8iTOKXX24uEUqWe6IV1D19lF8X8TyyOXm_fb0oPM +eyJraWQiOiIzMjg1ODE0Ny1mMDkwLTQzYTktYjJmZC1kMjZhZTViNDFjMDMiLCJjdHkiOiJhcHBsaWNhdGlvblwvam9zZSIsInR5cCI6IkpPU0UiLCJhbGciOiJQUzUxMiJ9..gOj_e9VS3pAJAtwkGa_SXSOeu-uX-40oD69kR9lwrfYV1_71rHLRcD8fDpD8sFXAXUvg8WNdBjXu5AgKR7jfOsAZezc5IUsh-VbPsRVG7ArZuwD1Q2RRJRDBbGEqsTT2wjxvGEnRDnPEXdrfPE6X3ron0ePk6KkVwBj4sY_g0be1Zq7GAL7C7cA_aVFPfkD3w-4-0F-Jrha9RG6w7j4r4ZvGrHierxHtm78JpSRG5rNxxa_Zhdrr7d_HiYdwVg0npfvRYHcI5ZxUP2bCS24NKn_oKNhPxyTWFwxIFrd0RQo6WQKxqmRfsJQ3Vt1SvgpgSHguogFuhfSlvt3Gu66b8XLvjwIoAF74Q7ry3h8EsHseGyYLWy076dggaRAh-HBYM8dZjSisEpCw5eYsemHBN6iVAxinkAFsTB0UYLwYsoKo7Lybsfb9ohz-IzHwufwOKJXTmHtxCrXlvCFliohOT9i6aHzBCRYT09l-ZcgnbfEMY4Jy8KiMZleMgJTIgGg3xMI80vdOZZAtQsosgT39JnKQ6GzPAfNxLnV3AB7VDlT-5xwaV28DexmoHTcFZoU8rYqB4SFfSsg6VHC6UHjLJFaGPtCS4de_S8sHTVKnxmfX8xBKU3U54dTSztn1UdQ4bDD8iTOKXX24uEUqWe6IV1D19lF8X8TyyOXm_fb0oPM + +eyJraWQiOiIzMjg1ODE0Ny1mMDkwLTQzYTktYjJmZC1kMjZhZTViNDFjMDMiLCJjdHkiOiJhcHBsaWNhdGlvblwvam9zZSIsInR5cCI6IkpPU0UiLCJhbGciOiJQUzUxMiJ9.eyJlbmNyeXB0aW9uS2lkIjoiMWU5NWYwMzYtY2NmZi00MjVjLWEwZGUtM2Q4OWQ1Y2M1OWZhIiwibWV0YWRhdGFWZXJzaW9ucyI6WyIxLjAuMCJdLCJwdWJsaWNLZXlzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsImtleV9vcHMiOlsid3JhcEtleSJdLCJhbGciOiJSU0EtT0FFUC0yNTYiLCJ4NWMiOlsiTUlJRTZqQ0NBdEtnQXdJQkFnSUdBWG8xcEcwR01BMEdDU3FHU0liM0RRRUJDd1VBTURZeE5EQXlCZ05WQkFNTUsyRmFWMHB0TUcxWFJtRnhSR0ZPVGtKT2FETmFiVmx1Vm13M2VHNTJTVk14VkVKNVNIaGFWbk5VTm04d0hoY05NakV3TmpJeU1qRXpNekkyV2hjTk1qSXdOREU0TWpFek16STJXakEyTVRRd01nWURWUVFEREN0aFdsZEtiVEJ0VjBaaGNVUmhUazVDVG1neldtMVpibFpzTjNodWRrbFRNVlJDZVVoNFdsWnpWRFp2TUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUEyY2gxSXIzL0x5YjkvSHhXOVJxSW9keGk5ZlhoaXg2QVBLd3FpU2ZpK0psUnFWYTFGb0FGc1cxblcwSWJRamtXNnNOa1dVRld1QTlBZlZvS1Q5bm5JY25MU2pTUTg0U0kraWY2cVRib3JueUt2QmpYZzhCU2VjU1VVUFl5VDArNE5teHJYTUdIUFliSlY3ZlFxNmpQWHprV0M1UDVqcVE3T2JyYVFwNzUyQmNFL0pWUVVtRmsxeWRoaGJucm9IcEdVa0ErOGpHL2tpVkwrbEF6N3VVbVpDaDZpM1pKRDVITjFKT0U1TE15elVRT2dPRlVVUGl2aUJ5d1FBYlBRdURMeWRaMmRpTzV3cW00bXdCYWRBQXpDMjdPbGxTa05YU2duZDlNVmFqWG10QlZwejJrc01hU0NBYmZCNHJLOXE1alhkNVlNd3UxWmxBK1p1V0tZbS9wMUdqYlpkeDR4azl3MjNaa2ducnIzU3ZXblc5ODY4NmZkMDNNRzFBQ0FHYXRxNUZjQXZHcDhCWENLd3o1RnB5WXRPT054K3RFQ1lIY0hoeC9TYWZPZTlzaUxZT2JMbUJTc0xGM1RBamlnWmpwR091RWpCdEt5djVPd0pqKzZZZklZWWpsb2Z1cXY2R0hVR0R2djhpUXN5NlU0ZUhDb1JwS0p6bVg2TDIyTVVRZ2lzWXZRZEdZMmpiZEVuaTNnL01wY2lNSWJuWkZMRU5WcnFIWFljZ0hOK1NiWGwvR1ZSNWIzRjBvbXBFUzU1eEE3ZnVZbHQ0bHA1ajBJVW8wT1dNMi90WVlIdEFTWmljVkF3bmJ6TFFaRUEwdSt3WFpyMEJ5TVdFMDdPZC9LYUxVb21sQlBpMUFjL0ZVM0tPeDBBUEtKVW03RDMvL2FpTFpsbDNTaDlFbkl2RUNBd0VBQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQUZpMjRKRkVtWUwyc09xYWFRT01IQ1ZtK1dROVF5Ti9ya3ZqSExHOHRoNVRJRjhOSjR1d3hsK242R0JPMnVPWk9CaXhIYlU1cEs5c2x5dDlYcnl3N0NiTC9oaFJHU3MzR1NGUjJoa3hvQkhkemZGbkF3ZWduZDFINVhIUXdTZ2g0M2pHT245QXhzeUlTcGt2Rm83K0RPYmg5Q3Y4TnNqcEw1N05vNFVKNjJYZ2dmWUpXNDN1NCtJL2ZIY0R3bnZJTjBkdm5ZcFFrQ2JUbXJqTGE1SWtHaW05QnluZlcxazZWdXhMeWExU3N5akJIV3cyWU5RNHhCSkk0T3pYaEw2T21CU3JvaEYxUmJJS09wanRxR2ZrWFpweHVmTE5WMkNuTDM2ci80MWMxbm9wNmNtQ0lNRHRuRkVRZEFtR2U4bS84d3ZWcExua3M1OUMwMi9Xb3RsSzNpT1JIQ1lCNkcwcEhNS0ZCNHpPVkFOWXRMRmdxVGdONEhOY2lWM0ZOMFR2STE5cXpqa0FkY0IrbStMK0xkc2VJemNRL0JUb0d5UHZXa0oxbXZKWklwMGVqbmxNV0lsM1ZsTnBNS2VaN2xKYlBwWnZBQk8wMGxLK0Z5bmhJVHRiNk4yOXRvRSs3SmdIQWxXbXh3NlBGRlkxeCszeFRIQlRPVTBvVVIvVHlLc0VVMCtiTlNiLzBTK1p5b2RtbklGYmdZV2Fyaks1cFV3ZlRSeVB5ZVZFdWtnMUdmMzBjLzdmLzVLWi9kcExGVU5CYi9ZVE5JellFaEdOVXlMSjFtclN6MzNncjRNdHZJNHVTdTBKcHIxTnJ3ZE1HdkZocjVRT0NVTHVvQzlLbG9rdXNVcGkwR1RIMGdLM0svVFVpNnF2VStXenRmYTdtcWFoMTdCVlZGVDF3QVRzPSJdLCJraWQiOiIxZTk1ZjAzNi1jY2ZmLTQyNWMtYTBkZS0zZDg5ZDVjYzU5ZmEiLCJuIjoiMmNoMUlyM19MeWI5X0h4VzlScUlvZHhpOWZYaGl4NkFQS3dxaVNmaS1KbFJxVmExRm9BRnNXMW5XMEliUWprVzZzTmtXVUZXdUE5QWZWb0tUOW5uSWNuTFNqU1E4NFNJLWlmNnFUYm9ybnlLdkJqWGc4QlNlY1NVVVBZeVQwLTRObXhyWE1HSFBZYkpWN2ZRcTZqUFh6a1dDNVA1anFRN09icmFRcDc1MkJjRV9KVlFVbUZrMXlkaGhibnJvSHBHVWtBLThqR19raVZMLWxBejd1VW1aQ2g2aTNaSkQ1SE4xSk9FNUxNeXpVUU9nT0ZVVVBpdmlCeXdRQWJQUXVETHlkWjJkaU81d3FtNG13QmFkQUF6QzI3T2xsU2tOWFNnbmQ5TVZhalhtdEJWcHoya3NNYVNDQWJmQjRySzlxNWpYZDVZTXd1MVpsQS1adVdLWW1fcDFHamJaZHg0eGs5dzIzWmtnbnJyM1N2V25XOTg2ODZmZDAzTUcxQUNBR2F0cTVGY0F2R3A4QlhDS3d6NUZweVl0T09OeC10RUNZSGNIaHhfU2FmT2U5c2lMWU9iTG1CU3NMRjNUQWppZ1pqcEdPdUVqQnRLeXY1T3dKai02WWZJWVlqbG9mdXF2NkdIVUdEdnY4aVFzeTZVNGVIQ29ScEtKem1YNkwyMk1VUWdpc1l2UWRHWTJqYmRFbmkzZ19NcGNpTUliblpGTEVOVnJxSFhZY2dITi1TYlhsX0dWUjViM0Ywb21wRVM1NXhBN2Z1WWx0NGxwNWowSVVvME9XTTJfdFlZSHRBU1ppY1ZBd25iekxRWkVBMHUtd1hacjBCeU1XRTA3T2RfS2FMVW9tbEJQaTFBY19GVTNLT3gwQVBLSlVtN0QzX19haUxabGwzU2g5RW5JdkUiLCJlIjoiQVFBQiJ9XX0sInJlcGx5Q2hhbm5lbHMiOnsiZW1haWwiOnsidXNlUGdwIjp0cnVlfX0sInN0YXR1cyI6ImFjdGl2ZSIsInN1Ym1pc3Npb25TY2hlbWFzIjpbeyJzY2hlbWFVcmkiOiJodHRwczovL3NjaGVtYS5maXRrby5kZS9maW0vczA2MDAwMTc4XzAuNC5zY2hlbWEuanNvbiIsIm1pbWVUeXBlIjoiYXBwbGljYXRpb24vanNvbiJ9XSwic3VibWlzc2lvblVybCI6Imh0dHBzOi8vc3VibWlzc2lvbi1hcGktdGVzdGluZy5maXQtY29ubmVjdC5maXRrby5kZXYifQ.gOj_e9VS3pAJAtwkGa_SXSOeu-uX-40oD69kR9lwrfYV1_71rHLRcD8fDpD8sFXAXUvg8WNdBjXu5AgKR7jfOsAZezc5IUsh-VbPsRVG7ArZuwD1Q2RRJRDBbGEqsTT2wjxvGEnRDnPEXdrfPE6X3ron0ePk6KkVwBj4sY_g0be1Zq7GAL7C7cA_aVFPfkD3w-4-0F-Jrha9RG6w7j4r4ZvGrHierxHtm78JpSRG5rNxxa_Zhdrr7d_HiYdwVg0npfvRYHcI5ZxUP2bCS24NKn_oKNhPxyTWFwxIFrd0RQo6WQKxqmRfsJQ3Vt1SvgpgSHguogFuhfSlvt3Gu66b8XLvjwIoAF74Q7ry3h8EsHseGyYLWy076dggaRAh-HBYM8dZjSisEpCw5eYsemHBN6iVAxinkAFsTB0UYLwYsoKo7Lybsfb9ohz-IzHwufwOKJXTmHtxCrXlvCFliohOT9i6aHzBCRYT09l-ZcgnbfEMY4Jy8KiMZleMgJTIgGg3xMI80vdOZZAtQsosgT39JnKQ6GzPAfNxLnV3AB7VDlT-5xwaV28DexmoHTcFZoU8rYqB4SFfSsg6VHC6UHjLJFaGPtCS4de_S8sHTVKnxmfX8xBKU3U54dTSztn1UdQ4bDD8iTOKXX24uEUqWe6IV1D19lF8X8TyyOXm_fb0oPM diff --git a/MockContainer/MockContainer.cs b/MockContainer/MockContainer.cs index 5fd91d97126af1503d3d4699f2c2881d80b5342d..cc86b4352d92891d372d4f840a684244c5e77289 100644 --- a/MockContainer/MockContainer.cs +++ b/MockContainer/MockContainer.cs @@ -1,13 +1,11 @@ -using System.Text.Encodings.Web; +using System.Text.Encodings.Web; using System.Text.Json; -using System.Text.Json.Serialization; +using Newtonsoft.Json; using Autofac; using FitConnect.Encryption; -using FitConnect.Models; using FitConnect.Models.Api.Metadata; using FitConnect.Services.Interfaces; using FitConnect.Services.Models; -using FitConnect.Services.Models.v1.Destination; using FitConnect.Services.Models.v1.Submission; using Microsoft.Extensions.Logging; using Moq; @@ -137,10 +135,9 @@ public static class Container { (string id, SubmitSubmissionDto dto) => { Console.WriteLine( $@"Submitting submission {id} with - {JsonSerializer.Serialize(dto, new JsonSerializerOptions { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - WriteIndented = true, - Encoder = JavaScriptEncoder.Default + {JsonConvert.SerializeObject(dto, new JsonSerializerSettings() { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.Indented })}"); return Task.Run(() => new SubmissionReducedDto()); }); diff --git a/MockContainer/MockContainer.csproj b/MockContainer/MockContainer.csproj index aa996437736a92a58456a8e7d0d74f0a15a938c7..03e55b64f93c6c39a7595c0cef690d4358101994 100644 --- a/MockContainer/MockContainer.csproj +++ b/MockContainer/MockContainer.csproj @@ -8,14 +8,14 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Autofac" Version="6.4.0" /> - <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" /> - <PackageReference Include="Moq" Version="4.18.1" /> + <PackageReference Include="Autofac" Version="6.4.0"/> + <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0"/> + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/> + <PackageReference Include="Moq" Version="4.18.1"/> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FitConnect\FitConnect.csproj" /> + <ProjectReference Include="..\FitConnect\FitConnect.csproj"/> </ItemGroup> <ItemGroup> @@ -38,7 +38,7 @@ <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> <None Update="encryptionKeys\credentials.json"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> </ItemGroup> diff --git a/Test.pdf b/Test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..50a038977b732f8c86889b164166410d5d60e0de Binary files /dev/null and b/Test.pdf differ diff --git a/readme.md b/readme.md index d0bb3ba619e726acd20c1b28467989dc1b258ab9..db5f6de9e31ebdc0b5e4be302eb2bc7d4b10ac5e 100644 --- a/readme.md +++ b/readme.md @@ -200,4 +200,12 @@ Weißt die Submission zurück. } ``` +# Router + +Die Client-Implementierung der Router API + +```csharp +Client.GetRouter(FitConnectEnvironment.Development, logger); +``` + [glossary](https://docs.fitko.de/fit-connect/docs/glossary/) diff --git a/test.Dockerfile b/test.Dockerfile index 7c37cb3a64135354d516de3366e209896dfc16a8..a1c39c831d29bfd8ea93cbe0654a32cca1d852f6 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -3,4 +3,4 @@ WORKDIR /test COPY . . RUN dotnet restore RUN dotnet build -RUN dotnet test --filter E2ETests.SenderTest +RUN dotnet test