diff --git a/.azuredevops/pipelines/build-dcr-func.yml b/.azuredevops/pipelines/build-dcr-func.yml index d0ad755..30991af 100644 --- a/.azuredevops/pipelines/build-dcr-func.yml +++ b/.azuredevops/pipelines/build-dcr-func.yml @@ -21,10 +21,10 @@ pool: steps: - task: UseDotNet@2 - displayName: 'Install .NET 8 SDK' + displayName: 'Install .NET 10 SDK' inputs: packageType: 'sdk' - version: '8.0.x' + version: '10.0.x' performMultiLevelLookup: true - script: | diff --git a/.azuredevops/pipelines/build-dh-func.yml b/.azuredevops/pipelines/build-dh-func.yml index 6277334..d38b4ca 100644 --- a/.azuredevops/pipelines/build-dh-func.yml +++ b/.azuredevops/pipelines/build-dh-func.yml @@ -21,10 +21,10 @@ pool: steps: - task: UseDotNet@2 - displayName: 'Install .NET 8 SDK' + displayName: 'Install .NET 10 SDK' inputs: packageType: 'sdk' - version: '8.0.x' + version: '10.0.x' performMultiLevelLookup: true - script: | diff --git a/.azuredevops/pipelines/build-no-tests.yml b/.azuredevops/pipelines/build-no-tests.yml index 44b9984..42a4f7c 100644 --- a/.azuredevops/pipelines/build-no-tests.yml +++ b/.azuredevops/pipelines/build-no-tests.yml @@ -60,11 +60,11 @@ steps: artifact: Container Images - task: UseDotNet@2 - displayName: 'Use .NET 6 sdk' + displayName: 'Use .NET 10 sdk' condition: always() inputs: packageType: sdk - version: '8.0.x' + version: '10.0.x' performMultiLevelLookup: true - task: CmdLine@2 diff --git a/.azuredevops/pipelines/build-v2.yml b/.azuredevops/pipelines/build-v2.yml index 4c72668..832c07c 100644 --- a/.azuredevops/pipelines/build-v2.yml +++ b/.azuredevops/pipelines/build-v2.yml @@ -111,17 +111,24 @@ jobs: inputs: command: images - # Run unit tests - - script: | - docker compose --file $(dockerComposeDirectory)/docker-compose.UnitTests.yml up --abort-on-container-exit --exit-code-from mock-data-recipient-unit-tests - displayName: Unit Tests - Up - condition: always() - - # Remove unit tests - - script: | - docker compose --file $(dockerComposeDirectory)/docker-compose.UnitTests.yml down - displayName: 'Unit Tests - Down' - condition: always() +## Refer to #96438, the SQL Unit tests have been broken for a long time and have now been included but not been fixed (out of scope) + # # Run unit tests + # - script: | + # docker compose --file $(dockerComposeDirectory)/docker-compose.UnitTests.yml up --abort-on-container-exit --exit-code-from mock-data-recipient-unit-tests + # displayName: Unit Tests - Up + # condition: always() + + # # Remove unit tests + # - script: | + # docker compose --file $(dockerComposeDirectory)/docker-compose.UnitTests.yml down + # displayName: 'Unit Tests - Down' + # condition: always() + + # # Publish mock-data-recipient unit tests results + # - publish: $(dockerComposeDirectory)/_temp/mock-data-recipient-unit-tests/testresults + # displayName: Publish unit tests + # condition: always() + # artifact: Mock-Data-Recipient - Unit tests # Run integration tests - script: | @@ -207,12 +214,6 @@ jobs: path: $(build.artifactstagingdirectory)/mock-data-recipient.image.tar artifact: Container Images - # Publish mock-data-recipient unit tests results - - publish: $(dockerComposeDirectory)/_temp/mock-data-recipient-unit-tests/testresults - displayName: Publish unit tests - condition: always() - artifact: Mock-Data-Recipient - Unit tests - # Run trx formatter to output .MD and .CSV - script: | docker run \ @@ -244,11 +245,11 @@ jobs: artifact: Mock-Data-Recipient - E2E tests - task: UseDotNet@2 - displayName: 'Use .NET 8 sdk' + displayName: 'Use .NET 10 sdk' condition: always() inputs: packageType: sdk - version: '8.0.x' + version: '10.0.x' performMultiLevelLookup: true - task: CmdLine@2 diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 1976cd5..e8e8d6b 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -25,9 +25,10 @@ on: env: buildConfiguration: 'Release' - buildRuntime: 'win-x64' + buildRuntime: 'linux-x64' runEnvironment: 'Release' ASPNETCORE_ENVIRONMENT: 'Release' + DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_SKIPSERVERCERTIFICATEVALIDATION: 'true' jobs: build-and-test: diff --git a/.github/workflows/sonarcloud-analysis.yml b/.github/workflows/sonarcloud-analysis.yml index e4b9503..210f573 100644 --- a/.github/workflows/sonarcloud-analysis.yml +++ b/.github/workflows/sonarcloud-analysis.yml @@ -70,5 +70,5 @@ jobs: shell: powershell run: | .\.sonar\scanner\dotnet-sonarscanner begin /k:"ConsumerDataRight_mock-data-recipient" /o:"consumerdataright" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" - dotnet build .\source\DataRecipient.sln + dotnet build .\source\DataRecipient.slnx .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f88bf4..9af27e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [3.1.0] - 2026-09-30 +### Changed +- Migrated from .NET 8 to .NET 10 +- Migrated xUnit from v2 to v3 +- Updated NuGet packages + ## [3.0.5] - 2026-07-08 ### Changed - Updated nuget package versions diff --git a/README.md b/README.md index a18bd39..1443645 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Consumer Data Right Logo](./cdr-logo.png?raw=true) -[![Consumer Data Standards v1.34.0](https://img.shields.io/badge/Consumer%20Data%20Standards-v1.34.0-blue.svg)](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) +[![Consumer Data Standards v1.36.0](https://img.shields.io/badge/Consumer%20Data%20Standards-v1.36.0-blue.svg)](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) [![made-with-dotnet](https://img.shields.io/badge/Made%20with-.NET-1f425Ff.svg)](https://dotnet.microsoft.com/) [![made-with-csharp](https://img.shields.io/badge/Made%20with-C%23-1f425Ff.svg)](https://docs.microsoft.com/en-us/dotnet/csharp/) [![MIT License](https://img.shields.io/github/license/ConsumerDataRight/mock-data-recipient)](./LICENSE) @@ -13,7 +13,7 @@ This repository contains a mock implementation of a Data Recipient and is offere ## Mock Data Recipient - Alignment The Mock Data Recipient in this release: -* aligns to [v1.34.0](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction) of the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction); +* aligns to [v1.36.0](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.36.0/#introduction) of the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.34.0/#introduction); * can connect to and complete authentication against both [FAPI 1.0 Migration Phase 2 and Phase 3](https://consumerdatastandardsaustralia.github.io/standards/#authentication-flows) compliant data holders. ## Getting Started diff --git a/SECURITY.md b/SECURITY.md index d49b8d6..72af26d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,7 +11,7 @@ Visit our [Responsible disclosure of security vulnerabilities policy](https://ww | Version | Supported | | ------- | ------------------ | -| 3.0.x | :white_check_mark: | +| 3.x.x | :white_check_mark: | | 2.x.x | :x: | | 1.x.x | :x: | diff --git a/Source/CDR.DCR/CDR.DCR.csproj b/Source/CDR.DCR/CDR.DCR.csproj index 1ac2463..9d4970d 100644 --- a/Source/CDR.DCR/CDR.DCR.csproj +++ b/Source/CDR.DCR/CDR.DCR.csproj @@ -16,7 +16,6 @@ - diff --git a/Source/CDR.DCR/DCR.cs b/Source/CDR.DCR/DCR.cs index 978d893..2bbb926 100644 --- a/Source/CDR.DCR/DCR.cs +++ b/Source/CDR.DCR/DCR.cs @@ -39,13 +39,13 @@ public DynamicClientRegistrationFunction(ILogger keyValues = httpContext.Response.Headers.Keys.Select(key => key + ": " + string.Join(",", httpContext.Response.Headers[key].ToArray())); @@ -240,7 +241,7 @@ private async Task ExtractResponseProperties(HttpContext httpContext) // This is for middleware hooked before us to see our changes. // Otherwise the original stream would be seen which cannot be read again. // The middleware that sends the response to the client is affected as well. - await responseBody.CopyToAsync(originalBodyStream); + await responseBody.CopyToAsync(originalBodyStream, CancellationToken.None); } } diff --git a/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs b/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs index 33670eb..4d8e50a 100644 --- a/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs +++ b/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Xunit; #nullable enable @@ -10,7 +10,7 @@ public class AATestPlaywrightInstallation : BaseTest, IClassFixture [Fact] public async Task ShouldDisplayGoogleHomePage() { - await Task.Delay(10000); // NOTE - This test sometimes just fails in build pipeline with error about google hanging up the connection, maybe just need to give the network a little extra time to get ready? + await Task.Delay(10000, TestContext.Current.CancellationToken); // NOTE - This test sometimes just fails in build pipeline with error about google hanging up the connection, maybe just need to give the network a little extra time to get ready? await TestAsync($"{nameof(AATestPlaywrightInstallation)} - {nameof(ShouldDisplayGoogleHomePage)}", async (page) => { @@ -24,4 +24,4 @@ await TestAsync($"{nameof(AATestPlaywrightInstallation)} - {nameof(ShouldDisplay }); } } -} \ No newline at end of file +} diff --git a/Source/CDR.DataRecipient.E2ETests/BaseTest.cs b/Source/CDR.DataRecipient.E2ETests/BaseTest.cs index 22c6b9d..91ce973 100644 --- a/Source/CDR.DataRecipient.E2ETests/BaseTest.cs +++ b/Source/CDR.DataRecipient.E2ETests/BaseTest.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using CDR.DataRecipient.E2ETests.Pages; +using CDR.DataRecipient.E2ETests.XUnit.Orderers; using FluentAssertions; using FluentAssertions.Execution; using Microsoft.Data.SqlClient; @@ -26,7 +27,7 @@ namespace CDR.DataRecipient.E2ETests { // Put all tests in same collection because we need them to run sequentially since some tests are mutating DB. [Collection("E2ETests")] - [TestCaseOrderer("CDR.DataRecipient.E2ETests.XUnit.Orderers.AlphabeticalOrderer", "CDR.DataRecipient.E2ETests")] + [TestMethodOrderer(typeof(AlphabeticalOrderer))] [DisplayTestMethodName] public class BaseTest { diff --git a/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj b/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj index 6e01535..4f32e78 100644 --- a/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj +++ b/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj @@ -1,32 +1,20 @@  false + Exe $(TargetFrameworkVersion) $(Version) $(Version) $(Version) - - - - - - Always - - - Always - - - Always - - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -41,6 +29,12 @@ + + PreserveNewest + + + PreserveNewest + Always diff --git a/Source/CDR.DataRecipient.E2ETests/DisplayTestMethodNameAttribute.cs b/Source/CDR.DataRecipient.E2ETests/DisplayTestMethodNameAttribute.cs index 0d28241..f86527e 100644 --- a/Source/CDR.DataRecipient.E2ETests/DisplayTestMethodNameAttribute.cs +++ b/Source/CDR.DataRecipient.E2ETests/DisplayTestMethodNameAttribute.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Reflection; using Xunit.Sdk; +using Xunit.v3; #nullable enable @@ -10,13 +11,13 @@ class DisplayTestMethodNameAttribute : BeforeAfterTestAttribute { static int count = 0; - public override void Before(MethodInfo methodUnderTest) + public override void Before(MethodInfo methodUnderTest, IXunitTest test) { Console.WriteLine($"Test #{++count} - {methodUnderTest.DeclaringType?.Name}.{methodUnderTest.Name}"); } - public override void After(MethodInfo methodUnderTest) + public override void After(MethodInfo methodUnderTest, IXunitTest test) { } } -} \ No newline at end of file +} diff --git a/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs b/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs index ca87e98..0dd28da 100644 --- a/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs +++ b/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Xunit; #nullable enable @@ -10,7 +10,7 @@ public class TestFixture : IAsyncLifetime private static readonly string[] installArguments = ["install"]; private static readonly string[] installDepsArguments = ["install-deeps"]; - public Task InitializeAsync() + public ValueTask InitializeAsync() { // Only install Playwright if not running in container, since Dockerfile.e2e-tests already installed Playwright if (!BaseTest.RUNNING_IN_CONTAINER) @@ -20,12 +20,12 @@ public Task InitializeAsync() Microsoft.Playwright.Program.Main(installDepsArguments); } - return Task.CompletedTask; + return ValueTask.CompletedTask; } - public Task DisposeAsync() + public ValueTask DisposeAsync() { - return Task.CompletedTask; + return ValueTask.CompletedTask; } } -} \ No newline at end of file +} diff --git a/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs b/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs index 348906e..da7e291 100644 --- a/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs +++ b/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -109,7 +109,7 @@ static string BuildContent(string scope, string grant_type, string client_id, st // Attach client certificate to handler if (CertificateFilename != null) { - var clientCertificate = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable); + var clientCertificate = X509CertificateLoader.LoadPkcs12FromFile(CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable); _clientHandler.ClientCertificates.Add(clientCertificate); } diff --git a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs index c129a09..30013cf 100644 --- a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs +++ b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs @@ -809,7 +809,7 @@ await iFrame.SelectOptionAsync( await iFrame.ClickAsync("text=Try it out"); // Arrange - Set x-v - await iFrame.FillAsync("[placeholder=\"x-v\"]", "1"); + await iFrame.FillAsync("[placeholder=\"x-v\"]", "2"); // Act - Click Execute await iFrame.ClickAsync("text=Execute"); diff --git a/Source/CDR.DataRecipient.E2ETests/XUnit/AlphabeticalOrderer.cs b/Source/CDR.DataRecipient.E2ETests/XUnit/AlphabeticalOrderer.cs deleted file mode 100644 index 5439003..0000000 --- a/Source/CDR.DataRecipient.E2ETests/XUnit/AlphabeticalOrderer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace CDR.DataRecipient.E2ETests.XUnit.Orderers -{ - public class AlphabeticalOrderer : ITestCaseOrderer - { - public IEnumerable OrderTestCases(IEnumerable testCases) where TTestCase : ITestCase => - testCases.OrderBy(testCase => testCase.TestMethod.Method.Name); - } -} \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/XUnit/E2ETestsCollection.cs b/Source/CDR.DataRecipient.E2ETests/XUnit/E2ETestsCollection.cs new file mode 100644 index 0000000..547a087 --- /dev/null +++ b/Source/CDR.DataRecipient.E2ETests/XUnit/E2ETestsCollection.cs @@ -0,0 +1,12 @@ +using Xunit; + +namespace CDR.DataRecipient.E2ETests +{ + // Test method ordering (AlphabeticalOrderer) is applied via [TestMethodOrderer] on BaseTest, + // since ITestMethodOrderer/[TestMethodOrderer] only supports Assembly/Class targets, not + // collection definitions. + [CollectionDefinition("E2ETests")] + public class E2ETestsCollection + { + } +} diff --git a/Source/CDR.DataRecipient.E2ETests/XUnit/Orderers/AlphabeticalOrderer.cs b/Source/CDR.DataRecipient.E2ETests/XUnit/Orderers/AlphabeticalOrderer.cs new file mode 100644 index 0000000..1b45e80 --- /dev/null +++ b/Source/CDR.DataRecipient.E2ETests/XUnit/Orderers/AlphabeticalOrderer.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Linq; +using Xunit.Sdk; +using Xunit.v3; + +namespace CDR.DataRecipient.E2ETests.XUnit.Orderers +{ + + public class AlphabeticalOrderer : ITestMethodOrderer + { + public IReadOnlyCollection OrderTestMethods( + IReadOnlyCollection testMethods) + where TTestMethod : notnull, ITestMethod + { + return testMethods + .OrderBy(tm => tm?.MethodName ?? string.Empty) + .ToList() + .AsReadOnly(); + } + } +} diff --git a/Source/CDR.DataRecipient.E2ETests/appsettings.Development-WithDockerCompose.json b/Source/CDR.DataRecipient.E2ETests/appsettings.Development-WithDockerCompose.json index 1c20f3a..85bc813 100644 --- a/Source/CDR.DataRecipient.E2ETests/appsettings.Development-WithDockerCompose.json +++ b/Source/CDR.DataRecipient.E2ETests/appsettings.Development-WithDockerCompose.json @@ -1,11 +1,11 @@ { "ConnectionStrings": { - "DataHolder": "Server=localhost,9933;Database=cdr-mdh;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True", - "DataHolderEnergy": "Server=localhost,9933;Database=cdr-mdhe;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True", - "DataHolderIdentityServer": "Server=localhost,9933;Database=cdr-mdh-auth-server;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True", - "DataHolderEnergyIdentityServer": "Server=localhost,9933;Database=cdr-mdhe-auth-server;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True", - "Register": "Server=localhost,9933;Database=cdr-register;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True", - "DataRecipient": "Server=localhost,9933;Database=cdr-mdr;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True" + "DataHolder": "Server=localhost,1433;Database=cdr-mdh;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True;Encrypt=False", + "DataHolderEnergy": "Server=localhost,1433;Database=cdr-mdhe;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True;Encrypt=False", + "DataHolderIdentityServer": "Server=localhost,1433;Database=cdr-mdh-auth-server;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True;Encrypt=False", + "DataHolderEnergyIdentityServer": "Server=localhost,1433;Database=cdr-mdhe-auth-server;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True;Encrypt=False", + "Register": "Server=localhost,1433;Database=cdr-register;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True;Encrypt=False", + "DataRecipient": "Server=localhost,1433;Database=cdr-mdr;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True;Encrypt=False" }, "CreateMedia": true, "MediaFolder": "C:\\cdr\\Media", diff --git a/Source/CDR.DataRecipient.IntegrationTests/BaseTest.cs b/Source/CDR.DataRecipient.IntegrationTests/BaseTest.cs index eab8db1..9d3432c 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/BaseTest.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/BaseTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -8,11 +8,13 @@ using System.Security.Claims; using System.Threading.Tasks; using CDR.DataRecipient.IntegrationTests.Extensions; +using CdrAuthServer.GetDataRecipients.IntegrationTests.XUnit.Orderers; using FluentAssertions; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using Xunit; using Xunit.Sdk; +using Xunit.v3; #nullable enable @@ -22,19 +24,19 @@ class DisplayTestMethodNameAttribute : BeforeAfterTestAttribute { static int count = 0; - public override void Before(MethodInfo methodUnderTest) + public override void Before(MethodInfo methodUnderTest, IXunitTest test) { Console.WriteLine($"Test #{++count} - {methodUnderTest.DeclaringType?.Name}.{methodUnderTest.Name}"); } - public override void After(MethodInfo methodUnderTest) + public override void After(MethodInfo methodUnderTest, IXunitTest test) { } } // Put all tests in same collection because we need them to run sequentially since some tests are mutating DB. [Collection("IntegrationTests")] - [TestCaseOrderer("CDR.DataRecipient.IntegrationTests.XUnit.Orderers.AlphabeticalOrderer", "CDR.DataRecipient.IntegrationTests")] + [TestCaseOrderer(typeof(AlphabeticalOrderer))] [DisplayTestMethodName] abstract public class BaseTest { diff --git a/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj b/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj index f84e28e..7ab9114 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj +++ b/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj @@ -1,6 +1,7 @@  false + Exe $(TargetFrameworkVersion) $(Version) $(Version) @@ -19,7 +20,8 @@ - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/API.cs b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/API.cs index 95677e8..439f1ab 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/API.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/API.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Cryptography.X509Certificates; @@ -160,7 +160,7 @@ HttpClient GetClient() // Attach client certificate if (CertificateFilename != null) { - clientHandler.ClientCertificates.Add(new X509Certificate2( + clientHandler.ClientCertificates.Add(X509CertificateLoader.LoadPkcs12FromFile( CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable diff --git a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/AccessToken.cs b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/AccessToken.cs index 864b0a4..3c0a331 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/AccessToken.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/AccessToken.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -109,7 +109,7 @@ static string BuildContent(string scope, string grant_type, string client_id, st // Attach client certificate to handler if (CertificateFilename != null) { - var clientCertificate = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable); + var clientCertificate = X509CertificateLoader.LoadPkcs12FromFile(CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable); _clientHandler.ClientCertificates.Add(clientCertificate); } diff --git a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/JWT.cs b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/JWT.cs index 8a36465..cd0d048 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/JWT.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/JWT.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using Microsoft.IdentityModel.Tokens; @@ -29,7 +29,7 @@ static public string CreateJWT(string certificateFilename, string certificatePas { JwtHeaderParameterNames.Kid, kid }, }; - var cert = new X509Certificate2(certificateFilename, certificatePassword); + var cert = X509CertificateLoader.LoadPkcs12FromFile(certificateFilename, certificatePassword); var jwt = Jose.JWT.Encode(payload, cert.GetRSAPrivateKey(), JwsAlgorithm.PS256, jwtHeader); @@ -75,7 +75,7 @@ SecurityAlgorithm securityAlgorithm /// static private byte[] GetRSAPrivateKeyBytes(string certificateFilename, string certificatePassword) { - var certificate = new X509Certificate2(certificateFilename, certificatePassword, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12FromFile(certificateFilename, certificatePassword, X509KeyStorageFlags.Exportable); var rsa = certificate.GetRSAPrivateKey(); if (rsa == null) @@ -168,4 +168,4 @@ static private string GetKeyId(RSA rsa) return Base64UrlEncoder.Encode(hashBytes); } } -} \ No newline at end of file +} diff --git a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt.cs b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt.cs index 462ca7b..5aa30ac 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt.cs @@ -47,7 +47,7 @@ public PrivateKeyJwt(string privateKey) /// The password of the certificate. public PrivateKeyJwt(string certFilePath, string pwd) { - var cert = new X509Certificate2(certFilePath, pwd, X509KeyStorageFlags.Exportable); + var cert = X509CertificateLoader.LoadPkcs12FromFile(certFilePath, pwd, X509KeyStorageFlags.Exportable); var rsa = cert.GetRSAPrivateKey(); var pvtKeyBytes = rsa.ExportPkcs8PrivateKey(); this.PrivateKeyBase64 = Convert.ToBase64String(pvtKeyBytes); diff --git a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt2.cs b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt2.cs index 920923e..58d6192 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt2.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/Infrastructure/PrivateKeyJwt2.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography.X509Certificates; +using System.Security.Cryptography.X509Certificates; using System.Collections.Generic; using System; using Microsoft.IdentityModel.Tokens; @@ -30,7 +30,7 @@ public string Generate() private string Generate(IEnumerable claims, DateTime expires) { - var certificate = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12FromFile(CertificateFilename, CertificatePassword, X509KeyStorageFlags.Exportable); var x509SigningCredentials = new X509SigningCredentials(certificate, SecurityAlgorithms.RsaSsaPssSha256); diff --git a/Source/CDR.DataRecipient.IntegrationTests/US12964_MDR_Jwks.cs b/Source/CDR.DataRecipient.IntegrationTests/US12964_MDR_Jwks.cs index 384536f..3dbe571 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/US12964_MDR_Jwks.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/US12964_MDR_Jwks.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net; using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; @@ -51,7 +51,7 @@ public async Task AC01_Get_ShouldRespondWith_200OK_ValidJWKS() Assert_HasContentType_ApplicationJson(response.Content); // Assert - Check JWKS - var actualJson = await response.Content.ReadAsStringAsync(); + var actualJson = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); var actual = JsonConvert.DeserializeObject(actualJson); actual.Keys.Length.Should().Be(3); var sigKey = actual.Keys.FirstOrDefault(k => k.use == "sig"); diff --git a/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs b/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs index 5b0d7c2..2db10ad 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using Xunit; using System.Linq; using CDR.DataRecipient.SDK.Models; @@ -14,7 +14,6 @@ using Microsoft.Extensions.Logging; using CDR.DataRecipient.SDK.Services.Tokens; using System; -using Xunit.Abstractions; using Newtonsoft.Json; namespace CDR.DataRecipient.IntegrationTests diff --git a/Source/CDR.DataRecipient.IntegrationTests/XUnit/AlphabeticalOrderer.cs b/Source/CDR.DataRecipient.IntegrationTests/XUnit/AlphabeticalOrderer.cs index 7c7d20d..d8f1173 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/XUnit/AlphabeticalOrderer.cs +++ b/Source/CDR.DataRecipient.IntegrationTests/XUnit/AlphabeticalOrderer.cs @@ -1,13 +1,27 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using Xunit.Abstractions; using Xunit.Sdk; +using Xunit.v3; -namespace CDR.DataRecipient.IntegrationTests.XUnit.Orderers +namespace CdrAuthServer.GetDataRecipients.IntegrationTests.XUnit.Orderers { public class AlphabeticalOrderer : ITestCaseOrderer { - public IEnumerable OrderTestCases(IEnumerable testCases) where TTestCase : ITestCase => - testCases.OrderBy(testCase => testCase.TestMethod.Method.Name); + IReadOnlyCollection ITestCaseOrderer.OrderTestCases( + IReadOnlyCollection testCases) + { + return testCases.OrderBy(tc => ExtractTestName(tc)).ToList().AsReadOnly(); + } + + private static string ExtractTestName(ITestCase testCase) + { + var testMethod = testCase?.TestMethod; + if (testMethod is ITestMethodMetadata testMethodMetadata) + { + return testMethodMetadata.MethodName ?? string.Empty; + } + + return string.Empty; + } } -} \ No newline at end of file +} diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/CDR.DataRecipient.Repository.SQL.UnitTests.csproj b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/CDR.DataRecipient.Repository.SQL.UnitTests.csproj index 1aa1e05..21b6ded 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/CDR.DataRecipient.Repository.SQL.UnitTests.csproj +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/CDR.DataRecipient.Repository.SQL.UnitTests.csproj @@ -1,11 +1,9 @@  - net6.0 - false - 1.2.3 - 1.2.3 - 1.2.3 + net10.0 + false + Exe @@ -27,22 +25,19 @@ - - - - - - - - - - - - + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataFixture.cs b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataFixture.cs index 3ec9e3d..aa8142b 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataFixture.cs +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataFixture.cs @@ -1,10 +1,10 @@ -using CDR.DataRecipient.Infrastructure; +using System; +using System.IO; +using CDR.DataRecipient.Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Serilog; -using System; -using System.IO; namespace CDR.DataRecipient.Repository.SQL.UnitTests { @@ -29,6 +29,8 @@ public SqlDataFixture() var connectionStr = configuration.GetConnectionString("DataRecipient_DB"); var recipientDatabaseContext = CreateDbContext(connectionStr); + recipientDatabaseContext.Database.Migrate(); + RecreateDatabaseWithForTests(recipientDatabaseContext.Database); services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true)); @@ -54,5 +56,63 @@ public static RecipientDatabaseContext CreateDbContext(string connectionString) return new RecipientDatabaseContext(options); } + + //For Unit Testing only - recreated from https://dev.azure.com/CDR-AU/Participant%20Tooling/_git/sb-mock-data-recipient?path=/Source/CDR.DataRecipient.Repository.SQL/SqlDataAccess.cs&version=GC6249e9a579bbad383425d950b5f3336de3763448&line=1153&lineEnd=1233&lineStartColumn=9&lineEndColumn=14&lineStyle=plain&_a=contents + public static void RecreateDatabaseWithForTests(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade database) + { + // Not clear why drop and recreate scripts were used originally, but assuming it was for a good reason so maintaining this approach over truncation + //Purging all existing data + FormattableString sqlQuery = + $""" + IF EXISTS (SELECT * FROM sysobjects WHERE name='CdrArrangement' AND xtype='U') DROP TABLE IF EXISTS CdrArrangement; + IF EXISTS (SELECT * FROM sysobjects WHERE name='DataHolderBrand' AND xtype='U') DROP TABLE IF EXISTS DataHolderBrand; + IF EXISTS (SELECT * FROM sysobjects WHERE name='Registration' AND xtype='U') DROP TABLE IF EXISTS Registration; + """; + + database.ExecuteSql(sqlQuery); + + //Create fresh db. + sqlQuery = + $""" + IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='CdrArrangement' AND xtype='U') CREATE TABLE CdrArrangement ([CdrArrangementId] [uniqueidentifier] NOT NULL, [ClientId] [uniqueidentifier] NOT NULL, JsonDocument VARCHAR(MAX), [UserId] nvarchar(100) NULL); + IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='DataHolderBrand' AND xtype='U') CREATE TABLE DataHolderBrand ([DataHolderBrandId] [uniqueidentifier] NOT NULL, JsonDocument VARCHAR(MAX)); + IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Registration' AND xtype='U') CREATE TABLE Registration ([ClientId] [uniqueidentifier] NOT NULL, JsonDocument VARCHAR(MAX), [DataHolderBrandId] [uniqueidentifier] NULL); + """; + + database.ExecuteSql(sqlQuery); + + //Insert test data + InsertTestData(database); + } + public static void InsertTestData(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade database) + { + //Insert data holders data for testing + var brandId = "cf217aba-e00d-48d5-9c3d-03af0b91cb80"; + var jsonDocument = @"{""_id"":{""$oid"":""613ef59c1a0ee5d9fd426a80""},""DataHolderBrandId"":""cf217aba-e00d-48d5-9c3d-03af0b91cb80"",""BrandName"":""Hall Bank"",""LegalEntity"":{""LegalEntityId"":""924ca498-0f19-402d-ae07-2cb61088f8aa"",""LegalEntityName"":""Hall Bank""},""Status"":""ACTIVE"",""EndpointDetail"":{""Version"":""1"",""PublicBaseUri"":""https://publicapi.hallbank"",""ResourceBaseUri"":""https://api.hallbank"",""InfoSecBaseUri"":""https://idp.hallbank"",""ExtensionBaseUri"":"""",""WebsiteUri"":""https://hallbank/""},""AuthDetails"":[{""RegisterUType"":""SIGNED-JWT"",""JwksEndpoint"":""https://hallbank/idp/jwks""}]}"; + FormattableString sqlQuery = $"INSERT INTO DataHolderBrand (DataHolderBrandId, JsonDocument) VALUES ({brandId}, {jsonDocument})"; + database.ExecuteSql(sqlQuery); + + brandId = "cf217aba-e00d-48d5-9c3d-03af0b91cb81"; + jsonDocument = @"{""_id"":{""$oid"":""613ef59c1a0ee5d9fd426a81""},""DataHolderBrandId"":""cf217aba-e00d-48d5-9c3d-03af0b91cb81"",""BrandName"":""Hall Bank"",""LegalEntity"":{""LegalEntityId"":""924ca498-0f19-402d-ae07-2cb61088f8aa"",""LegalEntityName"":""Hall Bank""},""Status"":""ACTIVE"",""EndpointDetail"":{""Version"":""1"",""PublicBaseUri"":""https://publicapi.hallbank"",""ResourceBaseUri"":""https://api.hallbank"",""InfoSecBaseUri"":""https://idp.hallbank"",""ExtensionBaseUri"":"""",""WebsiteUri"":""https://hallbank/""},""AuthDetails"":[{""RegisterUType"":""SIGNED-JWT"",""JwksEndpoint"":""https://hallbank/idp/jwks""}]}"; + sqlQuery = $"INSERT INTO DataHolderBrand (DataHolderBrandId, JsonDocument) VALUES ({brandId}, {jsonDocument})"; + database.ExecuteSql(sqlQuery); + + //Insert cdr arrangements data for testing + var clientId = "bad06794-39e2-400c-9e1b-f15a0bb67f46"; + var cdrArrangementId = "92d260c1-a625-41e2-a777-c0af1912a74a"; + jsonDocument = @"{""_id"":{""$oid"":""613ef5b11a0ee5d9fd426a99""},""DataHolderBrandId"":""804fc2fb-18a7-4235-9a49-2af393d18bc7"",""ClientId"":""bad06794-39e2-400c-9e1b-f15a0bb67f46"",""SharingDuration"":null,""CdrArrangementId"":""92d260c1-a625-41e2-a777-c0af1912a74a"",""IdToken"":null,""AccessToken"":null,""RefreshToken"":null,""ExpiresIn"":null,""Scope"":null,""TokenType"":null,""CreatedOn"":null}"; + sqlQuery = $"INSERT INTO CdrArrangement (CdrArrangementId, ClientId, JsonDocument) VALUES ({cdrArrangementId}, {clientId}, {jsonDocument})"; + database.ExecuteSql(sqlQuery); + + cdrArrangementId = "92d260c1-a625-41e2-a777-c0af1912a74b"; + jsonDocument = @"{""_id"":{""$oid"":""613ef5b11a0ee5d9fd426a99""},""DataHolderBrandId"":""804fc2fb-18a7-4235-9a49-2af393d18bc7"",""ClientId"":""bad06794-39e2-400c-9e1b-f15a0bb67f46"",""SharingDuration"":null,""CdrArrangementId"":""92d260c1-a625-41e2-a777-c0af1912a74b"",""IdToken"":null,""AccessToken"":null,""RefreshToken"":null,""ExpiresIn"":null,""Scope"":null,""TokenType"":null,""CreatedOn"":null}"; + sqlQuery = $"INSERT INTO CdrArrangement (CdrArrangementId, ClientId, JsonDocument) VALUES ({cdrArrangementId}, {clientId}, {jsonDocument})"; + database.ExecuteSql(sqlQuery); + + //Insert cdr-registrations data for testing + jsonDocument = @"{""_id"":{""$oid"":""6143d52c4433e41a861ea58d""},""DataHolderBrandId"":""804fc2fb-18a7-4235-9a49-2af393d18bc7"",""ClientId"":""bad06794-39e2-400c-9e1b-f15a0bb67f46"",""ClientIdIssuedAt"":1631835434,""ClientDescription"":""A product to help you manage your budget"",""ClientUri"":""https://mocksoftware/mybudgetapp"",""OrgId"":""ffb1c8ba-279e-44d8-96f0-1bc34a6b436f"",""OrgName"":""Mock Finance Tools"",""RedirectUris"":[""https://localhost:9001/consent/callback""],""LogoUri"":""https://mocksoftware/mybudgetapp/img/logo.png"",""TosUri"":""https://mocksoftware/mybudgetapp/terms"",""PolicyUri"":""https://mocksoftware/mybudgetapp/policy"",""JwksUri"":""https://localhost:9001/jwks"",""RevocationUri"":""https://localhost:9001/revocation"",""RecipientBaseUri"":""https://localhost:9001"",""TokenEndpointAuthSigningAlg"":""PS256"",""TokenEndpointAuthMethod"":""private_key_jwt"",""GrantTypes"":[""client_credentials"",""authorization_code"",""refresh_token""],""ResponseTypes"":[""code id_token""],""ApplicationType"":""web"",""IdTokenSignedResponseAlg"":""PS256"",""IdTokenEncryptedResponseAlg"":""RSA-OAEP"",""IdTokenEncryptedResponseEnc"":""A256GCM"",""RequestObjectSigningAlg"":""PS256"",""SoftwareStatement"":""eyJhbGciOiJQUzI1NiIsImtpZCI6IjU0MkE5QjkxNjAwNDg4MDg4Q0Q0RDgxNjkxNkE5RjQ0ODhERDI2NTEiLCJ0eXAiOiJKV1QifQ.ew0KICAicmVjaXBpZW50X2Jhc2VfdXJpIjogImh0dHBzOi8vbG9jYWxob3N0OjkwMDEiLA0KICAibGVnYWxfZW50aXR5X2lkIjogIjE4Yjc1YTc2LTU4MjEtNGM5ZS1iNDY1LTQ3MDkyOTFjZjBmNCIsDQogICJsZWdhbF9lbnRpdHlfbmFtZSI6ICJNb2NrIFNvZnR3YXJlIENvbXBhbnkiLA0KICAiaXNzIjogImNkci1yZWdpc3RlciIsDQogICJpYXQiOiAxNjMxODM1NDE3LA0KICAiZXhwIjogMTYzMTgzNjAxNywNCiAgImp0aSI6ICJjNzYzYjU4NzJkNGY0MzIwOWE3NmUzOTU3YTAzMDgwNCIsDQogICJvcmdfaWQiOiAiZmZiMWM4YmEtMjc5ZS00NGQ4LTk2ZjAtMWJjMzRhNmI0MzZmIiwNCiAgIm9yZ19uYW1lIjogIk1vY2sgRmluYW5jZSBUb29scyIsDQogICJjbGllbnRfbmFtZSI6ICJNeUJ1ZGdldEhlbHBlciIsDQogICJjbGllbnRfZGVzY3JpcHRpb24iOiAiQSBwcm9kdWN0IHRvIGhlbHAgeW91IG1hbmFnZSB5b3VyIGJ1ZGdldCIsDQogICJjbGllbnRfdXJpIjogImh0dHBzOi8vbW9ja3NvZnR3YXJlL215YnVkZ2V0YXBwIiwNCiAgInJlZGlyZWN0X3VyaXMiOiBbDQogICAgImh0dHBzOi8vbG9jYWxob3N0OjkwMDEvY29uc2VudC9jYWxsYmFjayINCiAgXSwNCiAgImxvZ29fdXJpIjogImh0dHBzOi8vbW9ja3NvZnR3YXJlL215YnVkZ2V0YXBwL2ltZy9sb2dvLnBuZyIsDQogICJ0b3NfdXJpIjogImh0dHBzOi8vbW9ja3NvZnR3YXJlL215YnVkZ2V0YXBwL3Rlcm1zIiwNCiAgInBvbGljeV91cmkiOiAiaHR0cHM6Ly9tb2Nrc29mdHdhcmUvbXlidWRnZXRhcHAvcG9saWN5IiwNCiAgImp3a3NfdXJpIjogImh0dHBzOi8vbG9jYWxob3N0OjkwMDEvandrcyIsDQogICJyZXZvY2F0aW9uX3VyaSI6ICJodHRwczovL2xvY2FsaG9zdDo5MDAxL3Jldm9jYXRpb24iLA0KICAic29mdHdhcmVfaWQiOiAiYzYzMjdmODctNjg3YS00MzY5LTk5YTQtZWFhY2QzYmI4MjEwIiwNCiAgInNvZnR3YXJlX3JvbGVzIjogImRhdGEtcmVjaXBpZW50LXNvZnR3YXJlLXByb2R1Y3QiLA0KICAic2NvcGUiOiAib3BlbmlkIHByb2ZpbGUgYmFuazphY2NvdW50cy5iYXNpYzpyZWFkIGJhbms6YWNjb3VudHMuZGV0YWlsOnJlYWQgYmFuazp0cmFuc2FjdGlvbnM6cmVhZCBiYW5rOnBheWVlczpyZWFkIGJhbms6cmVndWxhcl9wYXltZW50czpyZWFkIGNvbW1vbjpjdXN0b21lci5iYXNpYzpyZWFkIGNvbW1vbjpjdXN0b21lci5kZXRhaWw6cmVhZCBjZHI6cmVnaXN0cmF0aW9uIg0KfQ.j_UwVV2g28047YN12KdsGxE3pQwXVkF_ZSCwq7_HLdrlnQKZHsReQCprtxk-MV9vH0EGwpMw46WFQV5pTB-mxwZZfhkQx0-U30ufJfmPwvpxxAI90gFl3MFtQbwgC5a8IkkVfjSUoK1-m-pgG3X79rf0zUB9aRZoSigXgVemKfnQeiB-Gx_TI3zi0QkF1Uw052dAATQvUvaZ040oyqWuTFKETG7AzTV6M1ZcxVJYX5gGhemFIoWA0bVqrP3-dEMUOLFhhFwe3otMMB7iaBfOjBmQ9xtlnnmxFGIGvHErBiHouwfGzG0jCqI5dwtKkicjNKoa4uq-ul3EGup8FWY4Vw"",""SoftwareId"":""c6327f87-687a-4369-99a4-eaacd3bb8210"",""Scope"":""openid profile bank:accounts.basic:read bank:transactions:read common:customer.basic:read cdr:registration""}"; + sqlQuery = $"INSERT INTO Registration (ClientId, JsonDocument) VALUES ({clientId}, {jsonDocument})"; + database.ExecuteSql(sqlQuery); + } } } diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataTests.cs b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataTests.cs index c167776..800d3b0 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataTests.cs +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/SqlDataTests.cs @@ -1,4 +1,4 @@ -using CDR.DataRecipient.Infrastructure; +using CDR.DataRecipient.Infrastructure; using CDR.DataRecipient.Models; using CDR.DataRecipient.SDK.Models; using Microsoft.Extensions.DependencyInjection; @@ -27,8 +27,8 @@ public async Task GetDataHolderBrand_Success() { //Arrange var dataHoldersRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await dataHoldersRepository.GetDataHolderBrand("cf217aba-e00d-48d5-9c3d-03af0b91cb80"); @@ -43,8 +43,8 @@ public async Task GetDataHolderBrands_Success() { //Arrange var dataHoldersRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var dataHolders = await dataHoldersRepository.GetDataHolderBrands(); @@ -59,8 +59,8 @@ public async Task PersistDataHolderBrands_Success() { //Arrange var dataHoldersRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var dataHolders = await dataHoldersRepository.GetDataHolderBrands(); @@ -78,8 +78,8 @@ public async Task GetConsentArrangement_Success() { //Arrange var consentRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await consentRepository.GetConsentByArrangement("92d260c1-a625-41e2-a777-c0af1912a74a"); @@ -95,8 +95,8 @@ public async Task GetConsentArrangements_Success() { //Arrange var consentRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await consentRepository.GetConsents("","","mdr-user"); @@ -135,8 +135,8 @@ public async Task PersistConsentArrangementsUpdate_Success() { //Arrange var consentRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await consentRepository.GetConsentByArrangement("92d260c1-a625-41e2-a777-c0af1912a74a"); @@ -157,8 +157,8 @@ public async Task ConsentArrangementsUpdateTokens_Success() { //Arrange var consentRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); var cdrArrangementId = "92d260c1-a625-41e2-a777-c0af1912a74a"; //Act @@ -178,8 +178,8 @@ public async Task ConsentArrangementsDeleteConsent_Success() { //Arrange var consentRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); var cdrArrangementId = "92d260c1-a625-41e2-a777-c0af1912a74a"; //Act @@ -195,8 +195,8 @@ public async Task ConsentArrangementsRevokeConsent_Success() { //Arrange var consentRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await consentRepository.GetConsentByArrangement("92d260c1-a625-41e2-a777-c0af1912a74a"); @@ -215,8 +215,8 @@ public async Task GetCDRRegistration_Success() { //Arrange var registrationRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await registrationRepository.GetRegistration("bad06794-39e2-400c-9e1b-f15a0bb67f46", "804fc2fb-18a7-4235-9a49-2af393d18bc7"); @@ -235,8 +235,8 @@ public async Task GetCDRRegistrations_Success() { //Arrange var registrationRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var data = await registrationRepository.GetRegistrations(); @@ -251,8 +251,8 @@ public async Task CDRRegistrationDeleteRegistration_Success() { //Arrange var registrationRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var ClientId = "bad06794-39e2-400c-9e1b-f15a0bb67f46"; @@ -298,8 +298,8 @@ public async Task RegistrationUpdate_Success() { //Arrange var registrationRepository = _serviceProvider.GetRequiredService(); - var sqliteDataAccess = _serviceProvider.GetRequiredService(); - sqliteDataAccess.RecreateDatabaseWithForTests(); + ////var sqliteDataAccess = _serviceProvider.GetRequiredService(); + ////sqliteDataAccess.RecreateDatabaseWithForTests(); //Act var ClientId = "bad06794-39e2-400c-9e1b-f15a0bb67f46"; diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Container.json b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Container.json index 1012ca4..33ed2ad 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Container.json +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Container.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DataRecipient_DB": "Server=mssql;Database=cdr-mdr;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True" + "DataRecipient_DB": "Server=mssql;Database=cdr-mdr-unit-tests;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True" }, "Logging": { "LogLevel": { diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Development.json b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Development.json index 4bc545e..88287a1 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Development.json +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Development.json @@ -1,7 +1,7 @@ { - "ConnectionStrings": { - "DataRecipient_DB": "Server=(localdb)\\MSSQLLocalDB;Database=cdr-mdr;Integrated Security=true" - }, + "ConnectionStrings": { + "DataRecipient_DB": "Server=(localdb)\\MSSQLLocalDB;Database=cdr-mdr-unit-tests;trusted_connection=yes;Max Pool Size=500;Timeout=200;" + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Release.json b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Release.json index 1012ca4..33ed2ad 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Release.json +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.Release.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DataRecipient_DB": "Server=mssql;Database=cdr-mdr;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True" + "DataRecipient_DB": "Server=mssql;Database=cdr-mdr-unit-tests;User Id='SA';Password='Pa{}w0rd2019';MultipleActiveResultSets=True" }, "Logging": { "LogLevel": { diff --git a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.json b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.json index 4bc545e..8ff412b 100644 --- a/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.json +++ b/Source/CDR.DataRecipient.Repository.SQL.UnitTests/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DataRecipient_DB": "Server=(localdb)\\MSSQLLocalDB;Database=cdr-mdr;Integrated Security=true" + "DataRecipient_DB": "Server=(localdb)\\MSSQLLocalDB;Database=cdr-mdr-unit-tests;Integrated Security=true" }, "Logging": { "LogLevel": { diff --git a/Source/CDR.DataRecipient.SDK/Extensions/HttpExtensions.cs b/Source/CDR.DataRecipient.SDK/Extensions/HttpExtensions.cs index e716089..fa0b804 100644 --- a/Source/CDR.DataRecipient.SDK/Extensions/HttpExtensions.cs +++ b/Source/CDR.DataRecipient.SDK/Extensions/HttpExtensions.cs @@ -12,7 +12,7 @@ public static class HttpExtensions { public static void SetClientCertificate(this HttpClientHandler clientHandler, string certificateFileName, string certificatePassword) { - clientHandler.ClientCertificates.Add(new X509Certificate2(certificateFileName, certificatePassword, X509KeyStorageFlags.Exportable)); + clientHandler.ClientCertificates.Add(X509CertificateLoader.LoadPkcs12FromFile(certificateFileName, certificatePassword, X509KeyStorageFlags.Exportable)); } public static bool IsSuccessful(this HttpStatusCode statusCode) diff --git a/Source/CDR.DataRecipient.SDK/Extensions/StringExtensions.cs b/Source/CDR.DataRecipient.SDK/Extensions/StringExtensions.cs index bcce808..1958e77 100644 --- a/Source/CDR.DataRecipient.SDK/Extensions/StringExtensions.cs +++ b/Source/CDR.DataRecipient.SDK/Extensions/StringExtensions.cs @@ -21,10 +21,18 @@ public static string Sha256(this string value) return builder.ToString(); } + // SHA-1 is used here solely to derive a non-secret lookup identifier (JWK "kid") that matches the + // SHA-1-based X.509 certificate thumbprint convention ("kid") used by Data Holders/Register in the + // CDR ecosystem for the "RSA-OAEP-256" JWE encryption key (see CDR.DataRecipient.Web.Common.Extensions. + // GetEncryptionCredentials). It is not used for any cryptographic integrity/confidentiality guarantee, + // so the collision weaknesses of SHA-1 are not a security concern in this context. Do not change the + // algorithm without confirming compatibility with Data Holder "kid" matching. +#pragma warning disable CA5350, S4790 // Do Not Use Weak Cryptographic Algorithms / Use a stronger hashing algorithm public static string Sha1(this string value) { // ComputeHash - returns byte array byte[] bytes = SHA1.HashData(Encoding.UTF8.GetBytes(value)); +#pragma warning restore CA5350, S4790 // Convert byte array to a string var builder = new StringBuilder(); diff --git a/Source/CDR.DataRecipient.SDK/Models/Certificate.cs b/Source/CDR.DataRecipient.SDK/Models/Certificate.cs index 78733c4..0048305 100644 --- a/Source/CDR.DataRecipient.SDK/Models/Certificate.cs +++ b/Source/CDR.DataRecipient.SDK/Models/Certificate.cs @@ -29,12 +29,12 @@ public X509Certificate2 X509Certificate if (!string.IsNullOrEmpty(this.Path) && !string.IsNullOrEmpty(this.Password)) { - this._certificate = new X509Certificate2(this.Path, this.Password, X509KeyStorageFlags.Exportable); + this._certificate = X509CertificateLoader.LoadPkcs12FromFile(this.Path, this.Password, X509KeyStorageFlags.Exportable); } else if (!string.IsNullOrEmpty(this.Url) && !string.IsNullOrEmpty(this.Password)) { // Retrieve the raw bytes from the URL value. - this._certificate = new X509Certificate2(DownloadData(this.Url), this.Password, X509KeyStorageFlags.Exportable); + this._certificate = X509CertificateLoader.LoadPkcs12(DownloadData(this.Url), this.Password, X509KeyStorageFlags.Exportable); } else if (!string.IsNullOrEmpty(this.KVSecretsStorePath)) { @@ -43,7 +43,7 @@ public X509Certificate2 X509Certificate // The cert loaded into the volume by secrets-store-csi-driver-provider-azure is in base64 var certBytes = Convert.FromBase64String(certString); - this._certificate = new X509Certificate2(certBytes, string.Empty, X509KeyStorageFlags.Exportable); + this._certificate = X509CertificateLoader.LoadPkcs12(certBytes, string.Empty, X509KeyStorageFlags.Exportable); } return this._certificate; diff --git a/Source/CDR.DataRecipient.SDK/Services/PrivateKeyJwt.cs b/Source/CDR.DataRecipient.SDK/Services/PrivateKeyJwt.cs index 5d708fe..92b2a7c 100644 --- a/Source/CDR.DataRecipient.SDK/Services/PrivateKeyJwt.cs +++ b/Source/CDR.DataRecipient.SDK/Services/PrivateKeyJwt.cs @@ -21,7 +21,7 @@ public class PrivateKeyJwt /// The path to the certificate. /// The password of the certificate. public PrivateKeyJwt(string certFilePath, string pwd) - : this(new X509Certificate2(certFilePath, pwd, X509KeyStorageFlags.Exportable)) + : this(X509CertificateLoader.LoadPkcs12FromFile(certFilePath, pwd, X509KeyStorageFlags.Exportable)) { } diff --git a/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj b/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj index 970cf30..acd28ec 100644 --- a/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj +++ b/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj @@ -40,7 +40,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - all @@ -50,7 +49,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/Source/CDR.DataRecipient.Web/Startup.cs b/Source/CDR.DataRecipient.Web/Startup.cs index dba78cc..0fd7884 100644 --- a/Source/CDR.DataRecipient.Web/Startup.cs +++ b/Source/CDR.DataRecipient.Web/Startup.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Http; using System.Security.Claims; +using System.Threading; using System.Threading.Tasks; using CDR.DataRecipient.API.Logger; using CDR.DataRecipient.Infrastructure; @@ -419,7 +420,8 @@ private static Task CustomResponseWriter(HttpContext context, HealthReport healt value = e.Value.Status.ToString(), }), }); - return context.Response.WriteAsync(result); + + return context.Response.WriteAsync(result, CancellationToken.None); } private bool UseDistributedCache() diff --git a/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj b/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj index cce3664..06a30e3 100644 --- a/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj +++ b/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj @@ -17,7 +17,6 @@ - diff --git a/Source/CDR.DiscoverDataHolders/DHHttpClientHandler.cs b/Source/CDR.DiscoverDataHolders/DHHttpClientHandler.cs index e4e675e..8657149 100644 --- a/Source/CDR.DiscoverDataHolders/DHHttpClientHandler.cs +++ b/Source/CDR.DiscoverDataHolders/DHHttpClientHandler.cs @@ -16,7 +16,7 @@ public DHHttpClientHandler( logger.LogInformation("Loading the client certificate..."); byte[] clientCertBytes = Convert.FromBase64String(dhOptions.Client_Certificate); - X509Certificate2 clientCertificate = new(clientCertBytes, dhOptions.Client_Certificate_Password, X509KeyStorageFlags.MachineKeySet); + X509Certificate2 clientCertificate = X509CertificateLoader.LoadPkcs12(clientCertBytes, dhOptions.Client_Certificate_Password, X509KeyStorageFlags.MachineKeySet); logger.LogInformation("Client certificate loaded: {thumbprint}", clientCertificate.Thumbprint); ClientCertificates.Add(clientCertificate); @@ -26,4 +26,4 @@ public DHHttpClientHandler( } } } -} \ No newline at end of file +} diff --git a/Source/CDR.DiscoverDataHolders/DiscoverDataHolders.cs b/Source/CDR.DiscoverDataHolders/DiscoverDataHolders.cs index 1445ff0..4e9fc4a 100644 --- a/Source/CDR.DiscoverDataHolders/DiscoverDataHolders.cs +++ b/Source/CDR.DiscoverDataHolders/DiscoverDataHolders.cs @@ -35,12 +35,12 @@ public DiscoverDataHoldersFunction(ILogger logger, _options = options.Value; byte[] clientCertBytes = Convert.FromBase64String(_options.Client_Certificate); - X509Certificate2 clientCertificate = new(clientCertBytes, _options.Client_Certificate_Password, X509KeyStorageFlags.MachineKeySet); + X509Certificate2 clientCertificate = X509CertificateLoader.LoadPkcs12(clientCertBytes, _options.Client_Certificate_Password, X509KeyStorageFlags.MachineKeySet); _logger.LogInformation("Client certificate loaded: {thumbprint}", clientCertificate.Thumbprint); _logger.LogInformation("Loading the signing certificate..."); byte[] signCertBytes = Convert.FromBase64String(_options.Signing_Certificate); - _signCertificate = new(signCertBytes, _options.Signing_Certificate_Password, X509KeyStorageFlags.MachineKeySet); + _signCertificate = X509CertificateLoader.LoadPkcs12(signCertBytes, _options.Signing_Certificate_Password, X509KeyStorageFlags.MachineKeySet); _logger.LogInformation("Signing certificate loaded: {thumbprint}", _signCertificate.Thumbprint); _httpClientFactory = httpClientFactory; } diff --git a/Source/DataRecipient.sln b/Source/DataRecipient.sln deleted file mode 100644 index 5573a08..0000000 --- a/Source/DataRecipient.sln +++ /dev/null @@ -1,103 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32112.339 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient.Web", "CDR.DataRecipient.Web\CDR.DataRecipient.Web.csproj", "{83AAC80E-D102-4DB9-9BF7-80CDBFC833DC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient.SDK", "CDR.DataRecipient.SDK\CDR.DataRecipient.SDK.csproj", "{55AD141E-5AC7-43AA-AE1F-CA85FC644EDE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient", "CDR.DataRecipient\CDR.DataRecipient.csproj", "{F4F7FD1E-3A58-49F8-8039-39EE0553F845}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient.IntegrationTests", "CDR.DataRecipient.IntegrationTests\CDR.DataRecipient.IntegrationTests.csproj", "{9055ADF8-152F-4FDE-B951-C2F225B12084}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{56CFBFDE-5522-4AC1-9592-C74FB04EADF6}" - ProjectSection(SolutionItems) = preProject - .dockerignore = .dockerignore - .editorconfig = .editorconfig - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - docker-compose.E2ETests.yml = docker-compose.E2ETests.yml - docker-compose.IntegrationTests.yml = docker-compose.IntegrationTests.yml - docker-compose.UnitTests.yml = docker-compose.UnitTests.yml - Dockerfile = Dockerfile - Dockerfile.container = Dockerfile.container - Dockerfile.e2e-tests = Dockerfile.e2e-tests - Dockerfile.integration-tests = Dockerfile.integration-tests - Dockerfile.unit-tests = Dockerfile.unit-tests - run-e2e-tests.ps1 = run-e2e-tests.ps1 - run-integration-tests.ps1 = run-integration-tests.ps1 - run-unit-tests.ps1 = run-unit-tests.ps1 - supervisord.conf = supervisord.conf - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient.Repository.SQL", "CDR.DataRecipient.Repository.SQL\CDR.DataRecipient.Repository.SQL.csproj", "{468788C3-0C9D-4508-8408-BFE15EC18636}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient.E2ETests", "CDR.DataRecipient.E2ETests\CDR.DataRecipient.E2ETests.csproj", "{B12C2074-2FF3-4693-A465-6BFA586241FB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D8F9A30A-AD71-4D76-8294-C358C2614DCF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DiscoverDataHolders", "CDR.DiscoverDataHolders\CDR.DiscoverDataHolders.csproj", "{68F1AD6C-432B-49A8-AC6B-3705182F1885}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DCR", "CDR.DCR\CDR.DCR.csproj", "{D2D3303C-0CA9-46B3-A8FF-F150CC1036C4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Functions", "Functions", "{B323E55A-B38C-46DF-9EB0-35343763FD3D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CDR.DataRecipient.API.Logger", "CDR.DataRecipient.API.Logger\CDR.DataRecipient.API.Logger.csproj", "{00BC926F-6850-4071-BB2A-DBF3A6276674}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {83AAC80E-D102-4DB9-9BF7-80CDBFC833DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {83AAC80E-D102-4DB9-9BF7-80CDBFC833DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {83AAC80E-D102-4DB9-9BF7-80CDBFC833DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {83AAC80E-D102-4DB9-9BF7-80CDBFC833DC}.Release|Any CPU.Build.0 = Release|Any CPU - {55AD141E-5AC7-43AA-AE1F-CA85FC644EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {55AD141E-5AC7-43AA-AE1F-CA85FC644EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {55AD141E-5AC7-43AA-AE1F-CA85FC644EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {55AD141E-5AC7-43AA-AE1F-CA85FC644EDE}.Release|Any CPU.Build.0 = Release|Any CPU - {F4F7FD1E-3A58-49F8-8039-39EE0553F845}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F4F7FD1E-3A58-49F8-8039-39EE0553F845}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F4F7FD1E-3A58-49F8-8039-39EE0553F845}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F4F7FD1E-3A58-49F8-8039-39EE0553F845}.Release|Any CPU.Build.0 = Release|Any CPU - {9055ADF8-152F-4FDE-B951-C2F225B12084}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9055ADF8-152F-4FDE-B951-C2F225B12084}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9055ADF8-152F-4FDE-B951-C2F225B12084}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9055ADF8-152F-4FDE-B951-C2F225B12084}.Release|Any CPU.Build.0 = Release|Any CPU - {468788C3-0C9D-4508-8408-BFE15EC18636}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {468788C3-0C9D-4508-8408-BFE15EC18636}.Debug|Any CPU.Build.0 = Debug|Any CPU - {468788C3-0C9D-4508-8408-BFE15EC18636}.Release|Any CPU.ActiveCfg = Release|Any CPU - {468788C3-0C9D-4508-8408-BFE15EC18636}.Release|Any CPU.Build.0 = Release|Any CPU - {B12C2074-2FF3-4693-A465-6BFA586241FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B12C2074-2FF3-4693-A465-6BFA586241FB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B12C2074-2FF3-4693-A465-6BFA586241FB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B12C2074-2FF3-4693-A465-6BFA586241FB}.Release|Any CPU.Build.0 = Release|Any CPU - {68F1AD6C-432B-49A8-AC6B-3705182F1885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68F1AD6C-432B-49A8-AC6B-3705182F1885}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68F1AD6C-432B-49A8-AC6B-3705182F1885}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68F1AD6C-432B-49A8-AC6B-3705182F1885}.Release|Any CPU.Build.0 = Release|Any CPU - {D2D3303C-0CA9-46B3-A8FF-F150CC1036C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D2D3303C-0CA9-46B3-A8FF-F150CC1036C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2D3303C-0CA9-46B3-A8FF-F150CC1036C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D2D3303C-0CA9-46B3-A8FF-F150CC1036C4}.Release|Any CPU.Build.0 = Release|Any CPU - {00BC926F-6850-4071-BB2A-DBF3A6276674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00BC926F-6850-4071-BB2A-DBF3A6276674}.Debug|Any CPU.Build.0 = Debug|Any CPU - {00BC926F-6850-4071-BB2A-DBF3A6276674}.Release|Any CPU.ActiveCfg = Release|Any CPU - {00BC926F-6850-4071-BB2A-DBF3A6276674}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9055ADF8-152F-4FDE-B951-C2F225B12084} = {D8F9A30A-AD71-4D76-8294-C358C2614DCF} - {B12C2074-2FF3-4693-A465-6BFA586241FB} = {D8F9A30A-AD71-4D76-8294-C358C2614DCF} - {68F1AD6C-432B-49A8-AC6B-3705182F1885} = {B323E55A-B38C-46DF-9EB0-35343763FD3D} - {D2D3303C-0CA9-46B3-A8FF-F150CC1036C4} = {B323E55A-B38C-46DF-9EB0-35343763FD3D} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {04A0366C-D2E6-406F-A6B9-A405D04613D9} - EndGlobalSection -EndGlobal diff --git a/Source/DataRecipient.slnx b/Source/DataRecipient.slnx new file mode 100644 index 0000000..82fe99f --- /dev/null +++ b/Source/DataRecipient.slnx @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index bb52568..c27a108 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -1,7 +1,7 @@ - net8.0 - 3.0.5 + net10.0 + 3.1.0 true true true diff --git a/Source/Directory.Packages.props b/Source/Directory.Packages.props index c94daa3..ac47720 100644 --- a/Source/Directory.Packages.props +++ b/Source/Directory.Packages.props @@ -6,53 +6,56 @@ - + - + - - - - - + + + + + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + + - + + - + - - - - - - + + + + + + \ No newline at end of file diff --git a/Source/Dockerfile b/Source/Dockerfile index 1a8f35a..9bae4a9 100644 --- a/Source/Dockerfile +++ b/Source/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base WORKDIR /app EXPOSE 9001 @@ -8,7 +8,7 @@ ENV ASPNETCORE_ENVIRONMENT=Release # https://liupeirong.github.io/dynamicReloadConfigK8s/ ENV DOTNET_USE_POLLING_FILE_WATCHER true -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY . ./ @@ -44,16 +44,8 @@ RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/* RUN sudo cp ./web/Certificates/ca.crt /usr/local/share/ca-certificates/ca.crt RUN sudo update-ca-certificates -RUN addgroup --group appgroup --gid 2000 \ -&& adduser \ - --uid 1000 \ - --gid 2000 \ - "appuser" - -RUN chown -R appuser:appgroup /app -RUN chown -R appuser:appgroup /usr/bin/ -RUN chown -R appuser:appgroup /tmp -USER appuser:appgroup +RUN chown -R app:app /app +USER app ENV ASPNETCORE_URLS=https://+:9001 -ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf", "-u", "1000"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/supervisord", "-c", "/app/supervisord.conf"] \ No newline at end of file diff --git a/Source/Dockerfile.e2e-tests b/Source/Dockerfile.e2e-tests index c5f60b2..709f572 100644 --- a/Source/Dockerfile.e2e-tests +++ b/Source/Dockerfile.e2e-tests @@ -1,6 +1,6 @@ # Dockerfile for E2E tests -# NB: Ensure playwright version used in CDR.DataRecipient.E2ETests and base image below are same (ie currently 1.43.0) +# NB: Ensure playwright version used in CDR.DataRecipient.E2ETests and base image below are same (ie currently 1.60.0) FROM mcr.microsoft.com/playwright/dotnet:v1.60.0-noble AS build ############################################################################### @@ -21,9 +21,13 @@ RUN dotnet dev-certs https WORKDIR /src/CDR.DataRecipient.E2ETests RUN dotnet build --configuration Release +# Ensure Playwright browsers matching the installed Microsoft.Playwright package are present, +# regardless of what the base image happens to have pre-installed. +RUN pwsh bin/Release/net10.0/playwright.ps1 install --with-deps chromium + ############################################################################### # Run E2E tests ############################################################################### -ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--no-build", "--logger", "trx;verbosity=detailed;LogFileName=results.trx", "--results-directory", "/testresults"] +ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--no-build", "--report-trx", "--report-trx-filename", "results.trx", "--results-directory", "/testresults"] # ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--no-build", "--filter", "AC04_DynamicClientRegistration", "--logger", "trx;verbosity=detailed;LogFileName=results.trx", "-r", "/testresults"] # ENTRYPOINT ["tail", "-f", "/dev/null"] diff --git a/Source/Dockerfile.integration-tests b/Source/Dockerfile.integration-tests index 6ca1d81..e0e16de 100644 --- a/Source/Dockerfile.integration-tests +++ b/Source/Dockerfile.integration-tests @@ -1,6 +1,6 @@ # Dockerfile for running integration tests -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src # Default ASPNETCORE_ENVIRONMENT to Release @@ -21,4 +21,4 @@ RUN sudo update-ca-certificates WORKDIR /src/CDR.DataRecipient.IntegrationTests RUN dotnet build --configuration Release -ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--no-build", "--logger", "trx;verbosity=detailed;LogFileName=results.trx", "--results-directory", "/testresults"] +ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--no-build", "--report-trx", "--report-trx-filename", "results.trx", "--results-directory", "/testresults"] diff --git a/Source/Dockerfile.mdr.integration-tests b/Source/Dockerfile.mdr.integration-tests index 3964bb5..1028733 100644 --- a/Source/Dockerfile.mdr.integration-tests +++ b/Source/Dockerfile.mdr.integration-tests @@ -1,11 +1,11 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base WORKDIR /app EXPOSE 9001 # Default ASPNETCORE_ENVIRONMENT to Release ENV ASPNETCORE_ENVIRONMENT=Release -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY . ./ diff --git a/Source/Dockerfile.unit-tests b/Source/Dockerfile.unit-tests index 073e86a..16049ea 100644 --- a/Source/Dockerfile.unit-tests +++ b/Source/Dockerfile.unit-tests @@ -1,6 +1,6 @@ # Dockerfile for running unit tests -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src # Default ASPNETCORE_ENVIRONMENT to Release @@ -18,5 +18,9 @@ RUN sudo update-ca-certificates WORKDIR /src RUN dotnet build --configuration Release +RUN dotnet tool install --global PowerShell +ENV PATH="$PATH:/root/.dotnet/tools" +RUN pwsh CDR.DataRecipient.E2ETests/bin/Release/net10.0/playwright.ps1 install --with-deps chromium + # Run tests -ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--filter", "UnitTests", "--no-build", "--logger", "trx;verbosity=detailed", "--results-directory", "/testresults"] +ENTRYPOINT ["dotnet", "test", "--configuration", "Release", "--no-build", "--no-launch-profile", "--report-trx", "--results-directory", "/testresults"] diff --git a/Source/global.json b/Source/global.json new file mode 100644 index 0000000..802ab21 --- /dev/null +++ b/Source/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} \ No newline at end of file