From e0b4f97e4e4afe0f00ba08b047287ee459d8becb Mon Sep 17 00:00:00 2001
From: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com>
Date: Mon, 26 Aug 2024 09:52:58 +0200
Subject: [PATCH] chore: deploy test resources w/ new test packages (#433)
* chore: deploy test resources
* pr-fix: missing assignment keyword
* pr-fix: correct rg assignment
* pr-fix: key vault name assignment
* pr-fix: add location param + correct existing service principal condition
* pr-fix: add depends on
* pr-fix: use correct way to retrieve secret version
* pr-fix: add logging for sp-related commands
* pr-fix: use solely security-related resources
* pr-fix: add logging for secret version
* pr-fix: add secret version other way
* pr-fix: use property outputs
* pr-fix: add logging for deploy outputs
* pr-fix: correct new output variable assignment
* pr-fix: mark as string
* pr-add: integrate tests and key vault
* pr-fix: hashicorp template path
* pr-fix: add devops resources
* pr-fix: add test variables
* pr-fix: az identity vulnerability
* pr-fix: correct secret value
* pr-fix: run secret retrieval as a pre-job
* pr-fix: get own key vault secrets
* pr-fix: correct parameters
* pr-fix: install module az.keyvault
* pr-fix: use az keyvault
* pr-fix: use client id as var
* pr-fix: remove app insights reference
* pr-fix: add infra smoke tests
* pr-fix: use az cli task
* pr-fix: argument syntax
* pr-fix: add enabled assertion
* pr-fix: correct running
* pr-fix: add az module
* pr-fix: use new arguments syntax
* pr-fix: use higher version of pester
* pr-fix: use at least 5.3.0
* pr-fix: use env variables
* pr-fix: correct test result
* pr-fix: import module
* pr-fix: remove param
* pr-fix: enable test result
* pr-fix: correct env vars
* pr-fix: use other env vars
* pr-fix: use correct secret version extraction
* pr-fix: use pester container for external data
* pr-fix: broaden test assertion + trim secret version setup
* pr-fix: simplify config value retrieval
* pr-fix: remove any spaces from version and secret
* pr-fix: use direct setting of variable
* pr-fix: clean tests
* pr-fix: remove tried smoke tests
* Update Arcus.Security.Providers.AzureKeyVault.csproj
* Update Arcus.Security.Providers.AzureKeyVault.csproj
* pr-fix: use most recent test fixtures
* pr-fix: use correct unauthorized secret names
* pr-fix: remove remote resource group
* Update deploy-test-resources.yml
* Update deploy-test-resources.yml
* Update deploy-test-resources.yml
---
build/ci-build.yml | 13 +-
build/deploy-test-resources.yml | 54 ++++++
build/nuget-release.yml | 7 -
build/templates/deploy-test-resources.bicep | 56 ++++++
build/templates/run-integration-tests.yml | 33 ++++
build/variables/test.yml | 11 +-
...us.Security.Providers.AzureKeyVault.csproj | 4 +-
.../Arcus.Security.Tests.Core.csproj | 8 +-
.../Stubs/SpyLogger.cs | 45 -----
.../Stubs/TestLoggerProvider.cs | 36 ----
.../Arcus.Security.Tests.Integration.csproj | 1 +
.../AzureFunctions/SecretStoreBuilderTests.cs | 16 +-
.../Fixture/TestConfig.cs | 165 ------------------
.../Fixture/TestConfigExtensions.cs | 121 +++++++++++++
.../Fixture/XunitTestLogSink.cs | 37 ----
.../HashiCorp/HashiCorpSecretProviderTests.cs | 75 +++-----
.../Hosting/HashiCorpVaultTestServer.cs | 4 +-
.../SecretStoreBuilderExtensionsTests.cs | 41 +----
.../IntegrationTest.cs | 29 ++-
.../TemporaryManagedIdentityConnection.cs | 36 ++++
...aultSecretProvider.ManagedIdentityTests.cs | 78 +++------
...ultSecretProvider.ServicePrincipalTests.cs | 12 +-
.../KeyVault/KeyVaultSecretProviderTests.cs | 21 ++-
.../appsettings.json | 26 +--
.../Extensions/IHostBuilderExtensionsTests.cs | 9 +-
.../IServiceCollectionExtensionsTests.cs | 8 +-
26 files changed, 433 insertions(+), 513 deletions(-)
create mode 100644 build/deploy-test-resources.yml
create mode 100644 build/templates/deploy-test-resources.bicep
delete mode 100644 src/Arcus.Security.Tests.Core/Stubs/SpyLogger.cs
delete mode 100644 src/Arcus.Security.Tests.Core/Stubs/TestLoggerProvider.cs
delete mode 100644 src/Arcus.Security.Tests.Integration/Fixture/TestConfig.cs
create mode 100644 src/Arcus.Security.Tests.Integration/Fixture/TestConfigExtensions.cs
delete mode 100644 src/Arcus.Security.Tests.Integration/Fixture/XunitTestLogSink.cs
create mode 100644 src/Arcus.Security.Tests.Integration/KeyVault/Fixture/TemporaryManagedIdentityConnection.cs
diff --git a/build/ci-build.yml b/build/ci-build.yml
index 266e1937..a551999b 100644
--- a/build/ci-build.yml
+++ b/build/ci-build.yml
@@ -18,6 +18,10 @@ parameters:
- name: 'Package.Version.ManualTrigger'
type: string
default: 'preview'
+ - name: azureServiceConnection
+ displayName: 'Azure service connection'
+ type: string
+ default: 'Azure Codit-Arcus Service Principal'
resources:
repositories:
@@ -27,9 +31,6 @@ resources:
endpoint: arcus-azure
variables:
- # 'Arcus_ServicePrincipal_AccessKey' is added as secret on build in Azure DevOps
- - group: 'Arcus Security - Integration Testing'
- - group: 'Arcus - GitHub Package Registry'
- group: 'Build Configuration'
- template: ./variables/build.yml
- template: ./variables/test.yml
@@ -106,14 +107,10 @@ stages:
inputs:
artifact: 'Build'
path: '$(Build.SourcesDirectory)'
- - template: 'templates/download-hashicorp-vault.yml'
- parameters:
- targetFolder: '$(Build.SourcesDirectory)'
- version: $(HashiCorp.Vault.Version)
- vaultBinVariableName: 'Arcus.HashiCorp.VaultBin'
- template: templates/run-integration-tests.yml
parameters:
dockerProjectName: '$(Project).Tests.Runtimes.AzureFunctions'
+ azureServiceConnection: '${{ parameters.azureServiceConnection }}'
- stage: ReleaseToMyget
displayName: 'Release to MyGet'
diff --git a/build/deploy-test-resources.yml b/build/deploy-test-resources.yml
new file mode 100644
index 00000000..89584bb6
--- /dev/null
+++ b/build/deploy-test-resources.yml
@@ -0,0 +1,54 @@
+name: Arcus Security - Deploy test resources
+
+trigger: none
+pr: none
+
+parameters:
+ - name: azureServiceConnection
+ displayName: 'Azure service connection'
+ type: string
+ default: 'Azure Codit-Arcus Service Principal'
+ - name: resourceGroupName
+ displayName: 'Resource group name'
+ default: arcus-security-dev-we-rg
+
+variables:
+ - template: ./variables/build.yml
+ - template: ./variables/test.yml
+
+resources:
+ repositories:
+ - repository: templates
+ type: github
+ name: arcus-azure/azure-devops-templates
+ endpoint: arcus-azure
+
+stages:
+ - stage: Deploy
+ jobs:
+ - job: DeployBicep
+ displayName: 'Deploy test resources'
+ pool:
+ vmImage: '$(Vm.Image)'
+ steps:
+ - task: AzureCLI@2
+ inputs:
+ azureSubscription: '${{ parameters.azureServiceConnection }}'
+ addSpnToEnvironment: true
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ $secretName = $env:ARCUS_SECURITY_KEYVAULT_TESTSECRETNAME
+ $secretValue = [System.Guid]::NewGuid().ToString()
+ $objectId = (az ad sp show --id $env:servicePrincipalId | ConvertFrom-Json).id
+
+ az deployment sub create `
+ --location westeurope `
+ --template-file ./build/templates/deploy-test-resources.bicep `
+ --parameters location=westeurope `
+ --parameters resourceGroupName=${{ parameters.resourceGroupName }} `
+ --parameters keyVaultName=$env:ARCUS_SECURITY_KEYVAULT_NAME `
+ --parameters secretName=$secretName `
+ --parameters secretValue=$secretValue `
+ --parameters servicePrincipal_objectId=$objectId `
+ | ConvertFrom-Json
diff --git a/build/nuget-release.yml b/build/nuget-release.yml
index c3d656a9..164c041f 100644
--- a/build/nuget-release.yml
+++ b/build/nuget-release.yml
@@ -15,8 +15,6 @@ resources:
endpoint: arcus-azure
variables:
- - group: 'Arcus Security - Integration Testing'
- - group: 'Arcus - GitHub Package Registry'
- group: 'Build Configuration'
- template: ./variables/build.yml
- template: ./variables/test.yml
@@ -92,11 +90,6 @@ stages:
inputs:
artifact: 'Build'
path: '$(Build.SourcesDirectory)'
- - template: 'templates/download-hashicorp-vault.yml'
- parameters:
- targetFolder: '$(Build.SourcesDirectory)'
- version: $(HashiCorp.Vault.Version)
- vaultBinVariableName: 'Arcus.HashiCorp.VaultBin'
- template: templates/run-integration-tests.yml
parameters:
dockerProjectName: '$(Project).Tests.Runtimes.AzureFunctions'
diff --git a/build/templates/deploy-test-resources.bicep b/build/templates/deploy-test-resources.bicep
new file mode 100644
index 00000000..dbc56a58
--- /dev/null
+++ b/build/templates/deploy-test-resources.bicep
@@ -0,0 +1,56 @@
+// Define the location for the deployment of the components.
+param location string
+
+// Define the name of the resource group where the components will be deployed.
+param resourceGroupName string
+
+// Define the name of the Key vault.
+param keyVaultName string
+
+// Define the name of the secret that will be added to the Key vault.
+param secretName string
+
+// Define the secret value that will be by default added to the Key vault.
+@secure()
+param secretValue string
+
+// Define the Service Principal ID that needs access full access to the deployed resource group.
+param servicePrincipal_objectId string
+
+targetScope='subscription'
+
+module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = {
+ name: 'resourceGroupDeployment'
+ params: {
+ name: resourceGroupName
+ location: location
+ }
+}
+
+resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' existing = {
+ name: resourceGroupName
+}
+
+module vault 'br/public:avm/res/key-vault/vault:0.6.1' = {
+ name: 'vaultDeployment'
+ dependsOn: [
+ resourceGroup
+ ]
+ scope: rg
+ params: {
+ name: keyVaultName
+ location: location
+ roleAssignments: [
+ {
+ principalId: servicePrincipal_objectId
+ roleDefinitionIdOrName: 'Key Vault Secrets officer'
+ }
+ ]
+ secrets: [
+ {
+ name: secretName
+ value: secretValue
+ }
+ ]
+ }
+}
diff --git a/build/templates/run-integration-tests.yml b/build/templates/run-integration-tests.yml
index b12ba655..01225d55 100644
--- a/build/templates/run-integration-tests.yml
+++ b/build/templates/run-integration-tests.yml
@@ -1,5 +1,6 @@
parameters:
dockerProjectName: ''
+ azureServiceConnection: ''
steps:
- bash: |
@@ -9,6 +10,38 @@ steps:
fi
env:
PROJECT_NAME: ${{ parameters.dockerProjectName }}
+ - task: AzureCLI@2
+ displayName: 'Import secrets from Azure Key Vault'
+ inputs:
+ azureSubscription: '${{ parameters.azureServiceConnection }}'
+ addSpnToEnvironment: true
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
+ Install-Module -Name Arcus.Scripting.DevOps -AllowClobber
+
+ Set-AzDevOpsVariable 'Arcus.Security.TenantId' -Value $env:tenantId -AsSecret
+ Set-AzDevOpsVariable 'Arcus.Security.ServicePrincipal.ClientId' -Value $env:servicePrincipalId -AsSecret
+ Set-AzDevOpsVariable 'Arcus.Security.ServicePrincipal.ClientSecret' -Value $env:servicePrincipalKey -AsSecret
+
+ $unauthorizedClientId = az keyvault secret show --name $env:ARCUS_GENERAL_UNAUTHORIZED_SERVICEPRINCIPAL_CLIENTID_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json
+ $unauthorizedClientSecret = az keyvault secret show --name $env:ARCUS_GENERAL_UNAUTHORIZED_SERVICEPRINCIPAL_CLIENTSECRET_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json
+ Set-AzDevOpsVariable 'Arcus.Security.Unauthorized.ServicePrincipal.ClientId' -Value $unauthorizedClientId.value -AsSecret
+ Set-AzDevOpsVariable 'Arcus.Security.Unauthorized.ServicePrincipal.ClientSecret' -Value $unauthorizedClientSecret.value -AsSecret
+
+ $testSecret = az keyvault secret show --name $env:ARCUS_SECURITY_KEYVAULT_TESTSECRETNAME --vault-name $env:ARCUS_SECURITY_KEYVAULT_NAME | ConvertFrom-Json
+ $testSecretVersion = $testSecret.id.Split('/') | Select-Object -Last 1
+ Write-Host "Test secret '$($testSecret.name)' version is '$testSecretVersion'"
+ $testSecretValue = $testSecret.value
+
+ Set-AzDevOpsVariable -AsSecret -Name 'Arcus.Security.KeyVault.TestSecretValue' -Value $testSecretValue
+ Set-AzDevOpsVariable -AsSecret -Name 'Arcus.Security.KeyVault.TestSecretVersion' -Value $testSecretVersion
+ - template: 'download-hashicorp-vault.yml'
+ parameters:
+ targetFolder: '$(Build.SourcesDirectory)'
+ version: $(HashiCorp.Vault.Version)
+ vaultBinVariableName: 'Arcus.HashiCorp.VaultBin'
- task: UseDotNet@2
displayName: 'Import .NET Core SDK ($(DotNet.Sdk.VersionBC))'
inputs:
diff --git a/build/variables/test.yml b/build/variables/test.yml
index 77b73775..d6920bcb 100644
--- a/build/variables/test.yml
+++ b/build/variables/test.yml
@@ -1,5 +1,8 @@
variables:
- Arcus.KeyVault.TestKeyName: "ArcusTestSecret"
- Arcus.KeyVault.TestKeyVersion: "8bde7a16366849e28b7abe26732e12e3"
- HashiCorp.Vault.Version: 1.5.0
- Arcus.AzureFunctions.HttpPort: "5000"
\ No newline at end of file
+ Arcus.Security.KeyVault.Name: 'arcus-security-kv'
+ Arcus.Security.KeyVault.TestSecretName: 'ArcusTestSecret'
+ Arcus.General.KeyVault.Name: 'arcus-kv'
+ Arcus.General.Unauthorized.ServicePrincipal.ClientId.SecretName: 'Arcus-Unauthorized-ServicePrincipal-ClientId'
+ Arcus.General.Unauthorized.ServicePrincipal.ClientSecret.SecretName: 'Arcus-Unauthorized-ServicePrincipal-ClientSecret'
+ Arcus.AzureFunctions.HttpPort: '5000'
+ HashiCorp.Vault.Version: 1.5.0
\ No newline at end of file
diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Arcus.Security.Providers.AzureKeyVault.csproj b/src/Arcus.Security.Providers.AzureKeyVault/Arcus.Security.Providers.AzureKeyVault.csproj
index 3cc88b84..8f216d5d 100644
--- a/src/Arcus.Security.Providers.AzureKeyVault/Arcus.Security.Providers.AzureKeyVault.csproj
+++ b/src/Arcus.Security.Providers.AzureKeyVault/Arcus.Security.Providers.AzureKeyVault.csproj
@@ -24,7 +24,7 @@
-
+
@@ -34,4 +34,4 @@
-
\ No newline at end of file
+
diff --git a/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj b/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj
index 05a4be2f..e47afac1 100644
--- a/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj
+++ b/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj
@@ -1,13 +1,13 @@
- netstandard2.1
+ net6.0;net8.0
-
-
-
+
+
+
diff --git a/src/Arcus.Security.Tests.Core/Stubs/SpyLogger.cs b/src/Arcus.Security.Tests.Core/Stubs/SpyLogger.cs
deleted file mode 100644
index c46761ae..00000000
--- a/src/Arcus.Security.Tests.Core/Stubs/SpyLogger.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using Microsoft.Extensions.Logging;
-
-namespace Arcus.Security.Tests.Core.Stubs
-{
- ///
- /// Represents an instance that spies on the send log messages.
- ///
- public class SpyLogger : ILogger
- {
- ///
- /// Gets the flag indicating the logger instance was called.
- ///
- public bool IsCalled { get; private set; }
-
- /// Writes a log entry.
- /// Entry will be written on this level.
- /// Id of the event.
- /// The entry to be written. Can be also an object.
- /// The exception related to this entry.
- /// Function to create a string message of the and .
- public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
- {
- IsCalled = true;
- }
-
- ///
- /// Checks if the given is enabled.
- ///
- /// level to be checked.
- /// true if enabled.
- public bool IsEnabled(LogLevel logLevel)
- {
- return true;
- }
-
- /// Begins a logical operation scope.
- /// The identifier for the scope.
- /// An IDisposable that ends the logical operation scope on dispose.
- public IDisposable BeginScope(TState state)
- {
- return null;
- }
- }
-}
diff --git a/src/Arcus.Security.Tests.Core/Stubs/TestLoggerProvider.cs b/src/Arcus.Security.Tests.Core/Stubs/TestLoggerProvider.cs
deleted file mode 100644
index bdf0728e..00000000
--- a/src/Arcus.Security.Tests.Core/Stubs/TestLoggerProvider.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace Arcus.Security.Tests.Core.Stubs
-{
- ///
- /// Represents an that delegates the logger creation to an fixed instance.
- ///
- public class TestLoggerProvider : ILoggerProvider
- {
- private readonly ILogger _logger;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public TestLoggerProvider(ILogger logger)
- {
- _logger = logger;
- }
-
- ///
- /// Creates a new instance.
- ///
- /// The category name for messages produced by the logger.
- public ILogger CreateLogger(string categoryName)
- {
- return _logger;
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- public void Dispose()
- {
- }
- }
-}
diff --git a/src/Arcus.Security.Tests.Integration/Arcus.Security.Tests.Integration.csproj b/src/Arcus.Security.Tests.Integration/Arcus.Security.Tests.Integration.csproj
index f2b97b96..8c8e9eca 100644
--- a/src/Arcus.Security.Tests.Integration/Arcus.Security.Tests.Integration.csproj
+++ b/src/Arcus.Security.Tests.Integration/Arcus.Security.Tests.Integration.csproj
@@ -8,6 +8,7 @@
+
diff --git a/src/Arcus.Security.Tests.Integration/AzureFunctions/SecretStoreBuilderTests.cs b/src/Arcus.Security.Tests.Integration/AzureFunctions/SecretStoreBuilderTests.cs
index 1d6a79aa..30d8a48d 100644
--- a/src/Arcus.Security.Tests.Integration/AzureFunctions/SecretStoreBuilderTests.cs
+++ b/src/Arcus.Security.Tests.Integration/AzureFunctions/SecretStoreBuilderTests.cs
@@ -1,7 +1,5 @@
using System.Net.Http;
using System.Threading.Tasks;
-using Arcus.Security.Tests.Integration.Fixture;
-using Arcus.Testing.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Xunit;
@@ -10,34 +8,30 @@
namespace Arcus.Security.Tests.Integration.AzureFunctions
{
[Collection("Azure Functions")]
- public class SecretStoreBuilderTests
+ public class SecretStoreBuilderTests : IntegrationTest
{
private readonly string _defaultRoute;
- private readonly ILogger _logger;
private static readonly HttpClient HttpClient = new HttpClient();
///
/// Initializes a new instance of the class.
///
- public SecretStoreBuilderTests(ITestOutputHelper outputWriter)
+ public SecretStoreBuilderTests(ITestOutputHelper outputWriter) : base(outputWriter)
{
- var config = TestConfig.Create();
- var httpPort = config.GetValue("Arcus:AzureFunctions:HttpPort");
+ var httpPort = Configuration.GetValue("Arcus:AzureFunctions:HttpPort");
_defaultRoute = $"http://localhost:{httpPort}/api/order";
-
- _logger = new XunitTestLogger(outputWriter);
}
[Fact]
public async Task ConfigureSecretStore_WithConfiguration_ReturnsConfigurationSecret()
{
// Act
- _logger.LogInformation("GET -> '{Uri}'", _defaultRoute);
+ Logger.LogInformation("GET -> '{Uri}'", _defaultRoute);
using (HttpResponseMessage response = await HttpClient.GetAsync(_defaultRoute))
{
// Assert
- _logger.LogInformation("{StatusCode} <- {Uri}", response.StatusCode, _defaultRoute);
+ Logger.LogInformation("{StatusCode} <- {Uri}", response.StatusCode, _defaultRoute);
string contents = await response.Content.ReadAsStringAsync();
Assert.Equal("TestSecret", contents);
}
diff --git a/src/Arcus.Security.Tests.Integration/Fixture/TestConfig.cs b/src/Arcus.Security.Tests.Integration/Fixture/TestConfig.cs
deleted file mode 100644
index 10647750..00000000
--- a/src/Arcus.Security.Tests.Integration/Fixture/TestConfig.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using GuardNet;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Primitives;
-
-namespace Arcus.Security.Tests.Integration.Fixture
-{
- ///
- /// Represents the configuration used in the integration test suite.
- ///
- public class TestConfig : IConfiguration
- {
- private readonly IConfiguration _configuration;
-
- ///
- /// Prevents a new instance of the class from being created.
- ///
- private TestConfig(IConfiguration configuration)
- {
- Guard.NotNull(configuration, nameof(configuration), $"Requires an {nameof(IConfiguration)} instance to initialize the test config");
-
- _configuration = configuration;
- }
-
- ///
- /// Creates a new instance of the class.
- ///
- public static TestConfig Create()
- {
- IConfiguration configuration = new ConfigurationBuilder()
- .AddJsonFile("appsettings.json", optional: false)
- .AddJsonFile("appsettings.local.json", optional: true)
- .Build();
-
- return new TestConfig(configuration);
- }
-
- ///
- /// Gets the configured tenant ID from the application configuration.
- ///
- /// Thrown when there's no tenant ID found in the application configuration.
- public string GetTenantId()
- {
- string tenantId = GetRequiredValue("Arcus:Tenant");
- return tenantId;
- }
-
- ///
- /// Gets the configured client ID of the service principal from the application configuration.
- ///
- /// Thrown when there's no application ID found in the application configuration.
- public string GetServicePrincipalClientId()
- {
- string clientId = GetRequiredValue("Arcus:ServicePrincipal:ApplicationId");
- return clientId;
- }
-
- ///
- /// Gets the configured client secret of the service principal from the application configuration.
- ///
- /// Thrown when there's no application secret found in the application configuration.
- public string GetServicePrincipalClientSecret()
- {
- string clientSecret = GetRequiredValue("Arcus:ServicePrincipal:AccessKey");
- return clientSecret;
- }
-
- ///
- /// Gets the configured HashiCorp Vault execution file.
- ///
- /// Thrown when no installation file path was found in the configuration app settings.
- /// Thrown when the installation file path doesn't point to a valid HashiCorp Vault execution file.
- public FileInfo GetHashiCorpVaultBin()
- {
- const string key = "Arcus:HashiCorp:VaultBin";
- string vaultBin = _configuration[key];
-
- if (string.IsNullOrWhiteSpace(vaultBin))
- {
- throw new KeyNotFoundException(
- "Could not find the installation file path of the HashiCorp Vault in the local app settings"
- + "please install the HashiCorp Vault on this machine (https://releases.hashicorp.com/vault/) "
- + $"and add the installation folder as configuration key '{key}' to your local app settings");
- }
-
- FileInfo vaultFile;
- try
- {
- vaultFile = new FileInfo(vaultBin);
- }
- catch (Exception exception)
- {
- throw new FileNotFoundException(
- $"Could not find file path returned for key '{key}' because it doesn't point to valid HashiCorp vault execution file, "
- + "please install the HashiCorp Vault on this machine (https://releases.hashicorp.com/vault/) "
- + $"and add the installation folder as configuration key '{key}' to your local app settings", exception);
- }
-
- if (!vaultFile.Exists || !vaultFile.Name.StartsWith("vault"))
- {
- throw new FileNotFoundException(
- $"Could not find file path returned for key '{key}' because it doesn't point to valid HashiCorp vault execution file ('vault'), "
- + "please install the HashiCorp Vault on this machine (https://releases.hashicorp.com/vault/) "
- + $"and add the installation folder as configuration key '{key}' to your local app settings");
- }
-
- return vaultFile;
- }
-
- public string GetRequiredValue(string key)
- {
- string value = _configuration[key];
- if (string.IsNullOrWhiteSpace(value))
- {
- throw new KeyNotFoundException(
- $"Could not find configuration value for key: '{key}', was blank");
- }
-
- return value;
- }
-
- ///
- /// Gets a configuration sub-section with the specified key.
- ///
- /// The key of the configuration section.
- /// The .
- ///
- /// This method will never return null. If no matching sub-section is found with the specified key,
- /// an empty will be returned.
- ///
- public IConfigurationSection GetSection(string key)
- {
- return _configuration.GetSection(key);
- }
-
- ///
- /// Gets the immediate descendant configuration sub-sections.
- ///
- /// The configuration sub-sections.
- public IEnumerable GetChildren()
- {
- return _configuration.GetChildren();
- }
-
- ///
- /// Returns a that can be used to observe when this configuration is reloaded.
- ///
- /// A .
- public IChangeToken GetReloadToken()
- {
- return _configuration.GetReloadToken();
- }
-
- /// Gets or sets a configuration value.
- /// The configuration key.
- /// The configuration value.
- public string this[string key]
- {
- get => _configuration[key];
- set => _configuration[key] = value;
- }
- }
-}
diff --git a/src/Arcus.Security.Tests.Integration/Fixture/TestConfigExtensions.cs b/src/Arcus.Security.Tests.Integration/Fixture/TestConfigExtensions.cs
new file mode 100644
index 00000000..dbe05282
--- /dev/null
+++ b/src/Arcus.Security.Tests.Integration/Fixture/TestConfigExtensions.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+// ReSharper disable once CheckNamespace
+namespace Arcus.Testing
+{
+ ///
+ /// Represents the configuration used in the integration test suite.
+ ///
+ public static class TestConfigExtensions
+ {
+ ///
+ /// Gets the configured tenant ID from the application configuration.
+ ///
+ /// Thrown when there's no tenant ID found in the application configuration.
+ public static string GetTenantId(this TestConfig config)
+ {
+ return config["Arcus:Tenant"];
+ }
+
+ ///
+ /// Gets the configured client ID of the service principal from the application configuration.
+ ///
+ /// Thrown when there's no application ID found in the application configuration.
+ public static string GetServicePrincipalClientId(this TestConfig config)
+ {
+ return config["Arcus:ServicePrincipal:ApplicationId"];
+ }
+
+ ///
+ /// Gets the configured client secret of the service principal from the application configuration.
+ ///
+ /// Thrown when there's no application secret found in the application configuration.
+ public static string GetServicePrincipalClientSecret(this TestConfig config)
+ {
+ string clientSecret = config["Arcus:ServicePrincipal:AccessKey"];
+ return clientSecret;
+ }
+
+ ///
+ /// Gets the configured client ID of the service principal that is not authenticated.
+ ///
+ public static string GetUnauthorizedServicePrincipalClientId(this TestConfig config)
+ {
+ return config["Arcus:UnauthorizedServicePrincipal:ApplicationId"];
+ }
+
+ ///
+ /// Gets the configured client secret of the service principal that is not authenticated.
+ ///
+ ///
+ public static string GetUnauthorizedServicePrincipalClientSecret(this TestConfig config)
+ {
+ return config["Arcus:UnauthorizedServicePrincipal:AccessKey"];
+ }
+
+ ///
+ /// Gets the name of the expected secret present in the Azure Key vault.
+ ///
+ public static string GetSecretName(this TestConfig config)
+ {
+ return config["Arcus:KeyVault:TestSecretName"];
+ }
+
+ ///
+ /// Gets the value of the expected secret present in the Azure Key vault.
+ ///
+ public static string GetSecretValue(this TestConfig config)
+ {
+ return config["Arcus:KeyVault:TestSecretValue"];
+ }
+
+ ///
+ /// Gets the version of the expected secret present in the Azure Key vault.
+ ///
+ public static string GetSecretVersion(this TestConfig config)
+ {
+ return config["Arcus:KeyVault:TestSecretVersion"];
+ }
+
+ ///
+ /// Gets the configured HashiCorp Vault execution file.
+ ///
+ /// Thrown when no installation file path was found in the configuration app settings.
+ /// Thrown when the installation file path doesn't point to a valid HashiCorp Vault execution file.
+ public static FileInfo GetHashiCorpVaultBin(this TestConfig config)
+ {
+ const string key = "Arcus:HashiCorp:VaultBin";
+ string vaultBin = config[key];
+
+ FileInfo vaultFile;
+ try
+ {
+ vaultFile = new FileInfo(vaultBin);
+ }
+ catch (Exception exception)
+ {
+ throw new FileNotFoundException(
+ $"Could not find file path returned for key '{key}' because it doesn't point to valid HashiCorp vault execution file, "
+ + "please install the HashiCorp Vault on this machine (https://releases.hashicorp.com/vault/) "
+ + $"and add the installation folder as configuration key '{key}' to your local app settings", exception);
+ }
+
+ if (!vaultFile.Exists || !vaultFile.Name.StartsWith("vault"))
+ {
+ throw new FileNotFoundException(
+ $"Could not find file path returned for key '{key}' because it doesn't point to valid HashiCorp vault execution file ('vault'), "
+ + "please install the HashiCorp Vault on this machine (https://releases.hashicorp.com/vault/) "
+ + $"and add the installation folder as configuration key '{key}' to your local app settings");
+ }
+
+ return vaultFile;
+ }
+
+ public static string GetRequiredValue(this TestConfig config, string key)
+ {
+ return config[key];
+ }
+ }
+}
diff --git a/src/Arcus.Security.Tests.Integration/Fixture/XunitTestLogSink.cs b/src/Arcus.Security.Tests.Integration/Fixture/XunitTestLogSink.cs
deleted file mode 100644
index 41ca62ac..00000000
--- a/src/Arcus.Security.Tests.Integration/Fixture/XunitTestLogSink.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using GuardNet;
-using Serilog.Core;
-using Serilog.Events;
-using Xunit.Abstractions;
-
-namespace Arcus.Security.Tests.Integration.Fixture
-{
- ///
- /// xUnit test implementation of an Serilog to delegate Serilog events to the xUnit .
- ///
- public class XunitTestLogSink : ILogEventSink
- {
- private readonly ITestOutputHelper _outputWriter;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The xUnit test output helper to delegate the Serilog log events to.
- /// Thrown when the is null.
- public XunitTestLogSink(ITestOutputHelper outputWriter)
- {
- Guard.NotNull(outputWriter, nameof(outputWriter), "Requires a xUnit test output helper to write Serilog log events to the xUnit test output");
- _outputWriter = outputWriter;
- }
-
- ///
- /// Emit the provided log event to the sink.
- ///
- /// The log event to write.
- public void Emit(LogEvent logEvent)
- {
- string message = logEvent.RenderMessage();
- _outputWriter.WriteLine(message);
- }
- }
-}
diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/HashiCorpSecretProviderTests.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/HashiCorpSecretProviderTests.cs
index a59a71ce..0e5b3075 100644
--- a/src/Arcus.Security.Tests.Integration/HashiCorp/HashiCorpSecretProviderTests.cs
+++ b/src/Arcus.Security.Tests.Integration/HashiCorp/HashiCorpSecretProviderTests.cs
@@ -4,12 +4,9 @@
using Arcus.Security.Providers.HashiCorp;
using Arcus.Security.Providers.HashiCorp.Configuration;
using Arcus.Security.Providers.HashiCorp.Extensions;
-using Arcus.Security.Tests.Integration.Fixture;
using Arcus.Security.Tests.Integration.HashiCorp.Hosting;
-using Arcus.Testing.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using VaultSharp;
using VaultSharp.V1.AuthMethods;
@@ -20,22 +17,20 @@
namespace Arcus.Security.Tests.Integration.HashiCorp
{
[Trait(name: "Category", value: "Integration")]
- public class HashiCorpSecretProviderTests
+ public partial class HashiCorpSecretProviderTests : IntegrationTest
{
private const string DefaultDevMountPoint = "secret";
- private readonly TestConfig _config;
- private readonly ILogger _logger;
-
///
/// Initializes a new instance of the class.
///
- public HashiCorpSecretProviderTests(ITestOutputHelper outputWriter)
+ public HashiCorpSecretProviderTests(ITestOutputHelper outputWriter) : base(outputWriter)
{
- _config = TestConfig.Create();
- _logger = new XunitTestLogger(outputWriter);
}
+ private string UserPassUserName => Configuration["Arcus:HashiCorp:UserPass:UserName"];
+ private string UserPassPassword => Configuration["Arcus:HashiCorp:UserPass:Password"];
+
[Fact]
public async Task AuthenticateWithUserPassKeyValueV2_GetSecret_Succeeds()
{
@@ -44,17 +39,14 @@ public async Task AuthenticateWithUserPassKeyValueV2_GetSecret_Succeeds()
string secretName = "my-value";
string expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
-
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, DefaultDevMountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(DefaultDevMountPoint))
{
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
path: secretPath,
data: new Dictionary { [secretName] = expected });
- var authentication = new UserPassAuthMethodInfo(userName, password);
+ var authentication = new UserPassAuthMethodInfo(UserPassUserName, UserPassPassword);
var settings = new VaultClientSettings(server.ListenAddress.ToString(), authentication);
var provider = new HashiCorpSecretProvider(settings, secretPath, new HashiCorpVaultOptions
{
@@ -78,17 +70,14 @@ public async Task AuthenticateWithUserPassKeyValueV2_GetNotFoundSecret_Fails()
string secretName = "my-value";
string expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
-
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, DefaultDevMountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(DefaultDevMountPoint))
{
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
path: secretPath,
data: new Dictionary { ["unknown-prefix-" + secretName] = expected });
- var authentication = new UserPassAuthMethodInfo(userName, password);
+ var authentication = new UserPassAuthMethodInfo(UserPassUserName, UserPassPassword);
var settings = new VaultClientSettings(server.ListenAddress.ToString(), authentication);
var provider = new HashiCorpSecretProvider(settings, secretPath, new HashiCorpVaultOptions
{
@@ -110,13 +99,11 @@ public async Task AddHashiCorpVaultWithUserPass_WithMutationToRemovePrefix_Succe
// Arrange
string secretPath = "secretpath";
string secretKey = "my-value", expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
const string secretNamePrefix = "Test-";
var builder = new HostBuilder();
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, DefaultDevMountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(DefaultDevMountPoint))
{
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
@@ -127,7 +114,7 @@ await server.KeyValueV2.WriteSecretAsync(
builder.ConfigureSecretStore((config, stores) =>
{
stores.AddHashiCorpVaultWithUserPass(
- server.ListenAddress.ToString(), userName, password, secretPath,
+ server.ListenAddress.ToString(), UserPassUserName, UserPassPassword, secretPath,
configureOptions: options => options.KeyValueMountPoint = DefaultDevMountPoint,
mutateSecretName: secretName => secretName.Remove(0, secretNamePrefix.Length),
name: null);
@@ -148,12 +135,10 @@ public async Task AddHashiCorpVaultWithUserPass_WithWrongMutation_Fails()
// Arrange
string secretPath = "secretpath";
string secretKey = "my-value", expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
var builder = new HostBuilder();
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, DefaultDevMountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(DefaultDevMountPoint))
{
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
@@ -164,7 +149,7 @@ await server.KeyValueV2.WriteSecretAsync(
builder.ConfigureSecretStore((config, stores) =>
{
stores.AddHashiCorpVaultWithUserPass(
- server.ListenAddress.ToString(), userName, password, secretPath,
+ server.ListenAddress.ToString(), UserPassUserName, UserPassPassword, secretPath,
configureOptions: options => options.KeyValueMountPoint = DefaultDevMountPoint,
mutateSecretName: secretName => "Test-" + secretName,
name: null);
@@ -183,20 +168,18 @@ public async Task AddHashiCorpVault_WithMutationToRemovePrefix_Succeeds()
// Arrange
string secretPath = "secretpath";
string secretKey = "my-value", expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
const string secretNamePrefix = "Test-";
var builder = new HostBuilder();
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, DefaultDevMountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(DefaultDevMountPoint))
{
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
path: secretPath,
data: new Dictionary { [secretKey] = expected });
- var authentication = new UserPassAuthMethodInfo(userName, password);
+ var authentication = new UserPassAuthMethodInfo(UserPassUserName, UserPassPassword);
var settings = new VaultClientSettings(server.ListenAddress.ToString(), authentication);
// Act
@@ -223,19 +206,17 @@ public async Task AddHashiCorpVault_WithWrongMutation_Fails()
// Arrange
string secretPath = "secretpath";
string secretKey = "my-value", expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
var builder = new HostBuilder();
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, DefaultDevMountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(DefaultDevMountPoint))
{
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
path: secretPath,
data: new Dictionary { [secretKey] = expected });
- var authentication = new UserPassAuthMethodInfo(userName, password);
+ var authentication = new UserPassAuthMethodInfo(UserPassUserName, UserPassPassword);
var settings = new VaultClientSettings(server.ListenAddress.ToString(), authentication);
// Act
@@ -262,13 +243,10 @@ public async Task AuthenticateWithUserPassKeyValueV1_GetSecret_Succeeds()
string secretName = "my-value";
string expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
-
const string mountPoint = "secret-v1";
const VaultKeyValueSecretEngineVersion keyValueVersion = VaultKeyValueSecretEngineVersion.V1;
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, mountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(mountPoint))
{
await server.MountKeyValueAsync(mountPoint, keyValueVersion);
await server.KeyValueV1.WriteSecretAsync(
@@ -276,7 +254,7 @@ await server.KeyValueV1.WriteSecretAsync(
path: secretPath,
values: new Dictionary { [secretName] = expected });
- var authentication = new UserPassAuthMethodInfo(userName, password);
+ var authentication = new UserPassAuthMethodInfo(UserPassUserName, UserPassPassword);
var settings = new VaultClientSettings(server.ListenAddress.ToString(), authentication);
var provider = new HashiCorpSecretProvider(settings, secretPath, new HashiCorpVaultOptions
{
@@ -300,13 +278,10 @@ public async Task AuthenticateWithUserPassKeyValueV1_GetNotFoundSecret_Fails()
string secretName = "my-value";
string expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
-
const string mountPoint = "secret-v1";
const VaultKeyValueSecretEngineVersion keyValueVersion = VaultKeyValueSecretEngineVersion.V1;
- using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(userName, password, mountPoint))
+ using (HashiCorpVaultTestServer server = await StartServerWithUserPassAsync(mountPoint))
{
await server.MountKeyValueAsync(mountPoint, keyValueVersion);
await server.KeyValueV1.WriteSecretAsync(
@@ -314,7 +289,7 @@ await server.KeyValueV1.WriteSecretAsync(
path: secretPath,
values: new Dictionary { ["unknown-prefix-" + secretName] = expected });
- var authentication = new UserPassAuthMethodInfo(userName, password);
+ var authentication = new UserPassAuthMethodInfo(UserPassUserName, UserPassPassword);
var settings = new VaultClientSettings(server.ListenAddress.ToString(), authentication);
var provider = new HashiCorpSecretProvider(settings, secretPath, new HashiCorpVaultOptions{
KeyValueMountPoint = mountPoint,
@@ -329,16 +304,18 @@ await server.KeyValueV1.WriteSecretAsync(
}
}
- private async Task StartServerWithUserPassAsync(string userName, string password, string availableSecretMountPoint)
+ private async Task StartServerWithUserPassAsync(string availableSecretMountPoint)
{
const string policyName = "my-policy";
- var server = await HashiCorpVaultTestServer.StartServerAsync(_config, _logger);
+ var server = await HashiCorpVaultTestServer.StartServerAsync(Configuration, Logger);
await server.AddPolicyAsync(policyName, availableSecretMountPoint, new[] { "read" });
await server.EnableAuthenticationTypeAsync(AuthMethodDefaultPaths.UserPass, "Authenticating with username and password");
- await server.AddUserPassUserAsync(userName, password, policyName);
+ await server.AddUserPassUserAsync(UserPassUserName, UserPassPassword, policyName);
return server;
}
+
+
}
}
diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs
index 0f24dcfb..435a0ddd 100644
--- a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs
+++ b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs
@@ -8,8 +8,8 @@
using System.Threading;
using System.Threading.Tasks;
using Arcus.Security.Providers.HashiCorp;
-using Arcus.Security.Tests.Integration.Fixture;
using Arcus.Security.Tests.Integration.HashiCorp.Mounting;
+using Arcus.Testing;
using GuardNet;
using Microsoft.Extensions.Logging;
using Polly;
@@ -21,8 +21,6 @@
using VaultSharp.V1.AuthMethods.Token;
using VaultSharp.V1.SecretsEngines.KeyValue.V1;
using VaultSharp.V1.SecretsEngines.KeyValue.V2;
-using VaultSharp.V1.SystemBackend;
-using IVaultClient = VaultSharp.IVaultClient;
using MountInfo = Arcus.Security.Tests.Integration.HashiCorp.Mounting.MountInfo;
using Policy = Polly.Policy;
using VaultClient = Vault.VaultClient;
diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/SecretStoreBuilderExtensionsTests.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/SecretStoreBuilderExtensionsTests.cs
index 1a2a0bf4..40b12171 100644
--- a/src/Arcus.Security.Tests.Integration/HashiCorp/SecretStoreBuilderExtensionsTests.cs
+++ b/src/Arcus.Security.Tests.Integration/HashiCorp/SecretStoreBuilderExtensionsTests.cs
@@ -5,36 +5,18 @@
using System.Threading.Tasks;
using Arcus.Security.Core;
using Arcus.Security.Providers.HashiCorp.Extensions;
-using Arcus.Security.Tests.Integration.Fixture;
using Arcus.Security.Tests.Integration.HashiCorp.Hosting;
-using Arcus.Testing.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using VaultSharp.Core;
using VaultSharp.V1.AuthMethods;
using Xunit;
-using Xunit.Abstractions;
namespace Arcus.Security.Tests.Integration.HashiCorp
{
- [Trait(name: "Category", value: "Integration")]
- public class SecretStoreBuilderExtensionsTests : IntegrationTest
+ public partial class HashiCorpSecretProviderTests
{
- private const string DefaultDevMountPoint = "secret";
-
- private readonly TestConfig _config;
- private readonly XunitTestLogger _logger;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SecretStoreBuilderExtensionsTests(ITestOutputHelper outputWriter) : base(outputWriter)
- {
- _config = TestConfig.Create();
- _logger = new XunitTestLogger(outputWriter);
- }
-
[Theory]
[InlineData(false, 0)]
[InlineData(true, 2)]
@@ -45,20 +27,18 @@ public async Task AuthenticateWithInvalidUserPassPasswordKeyValue_GetSecret_Fail
string secretName = "my-value";
string expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
string invalidPassword = Guid.NewGuid().ToString();
const string policyName = "my-policy";
var builder = new HostBuilder();
- builder.UseSerilog(Logger);
+ builder.UseSerilog(SerilogLogger);
- using (var server = await HashiCorpVaultTestServer.StartServerAsync(_config, _logger))
+ using (var server = await HashiCorpVaultTestServer.StartServerAsync(Configuration, Logger))
{
await server.AddPolicyAsync(policyName, DefaultDevMountPoint, new[] { "read" });
await server.EnableAuthenticationTypeAsync(AuthMethodDefaultPaths.UserPass, "Authenticating with username and password");
- await server.AddUserPassUserAsync(userName, password, policyName);
+ await server.AddUserPassUserAsync(UserPassUserName, UserPassPassword, policyName);
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
path: secretPath,
@@ -67,7 +47,7 @@ await server.KeyValueV2.WriteSecretAsync(
// Act
builder.ConfigureSecretStore((config, stores) =>
{
- stores.AddHashiCorpVaultWithUserPass(server.ListenAddress.ToString(), userName, invalidPassword, secretPath, options =>
+ stores.AddHashiCorpVaultWithUserPass(server.ListenAddress.ToString(), UserPassUserName, invalidPassword, secretPath, options =>
{
options.KeyValueMountPoint = secretPath;
options.TrackDependency = trackDependency;
@@ -98,18 +78,15 @@ public async Task AuthenticateWithUnauthorizedUserPassUserKeyValue_GetSecret_Fai
string secretName = "my-value";
string expected = "s3cr3t";
- string userName = _config["Arcus:HashiCorp:UserPass:UserName"];
- string password = _config["Arcus:HashiCorp:UserPass:Password"];
-
const string policyName = "my-policy";
var builder = new HostBuilder();
- builder.UseSerilog(Logger);
+ builder.UseSerilog(SerilogLogger);
- using (var server = await HashiCorpVaultTestServer.StartServerAsync(_config, _logger))
+ using (var server = await HashiCorpVaultTestServer.StartServerAsync(Configuration, Logger))
{
await server.EnableAuthenticationTypeAsync(AuthMethodDefaultPaths.UserPass, "Authenticating with username and password");
- await server.AddUserPassUserAsync(userName, password, policyName);
+ await server.AddUserPassUserAsync(UserPassUserName, UserPassPassword, policyName);
await server.KeyValueV2.WriteSecretAsync(
mountPoint: DefaultDevMountPoint,
path: secretPath,
@@ -118,7 +95,7 @@ await server.KeyValueV2.WriteSecretAsync(
// Act
builder.ConfigureSecretStore((config, stores) =>
{
- stores.AddHashiCorpVaultWithUserPass(server.ListenAddress.ToString(), userName, password, secretPath, options =>
+ stores.AddHashiCorpVaultWithUserPass(server.ListenAddress.ToString(), UserPassUserName, UserPassPassword, secretPath, options =>
{
options.KeyValueMountPoint = secretPath;
options.TrackDependency = trackDependency;
diff --git a/src/Arcus.Security.Tests.Integration/IntegrationTest.cs b/src/Arcus.Security.Tests.Integration/IntegrationTest.cs
index 1adf35a8..b6a7a088 100644
--- a/src/Arcus.Security.Tests.Integration/IntegrationTest.cs
+++ b/src/Arcus.Security.Tests.Integration/IntegrationTest.cs
@@ -1,37 +1,36 @@
using System;
-using Arcus.Security.Tests.Integration.Fixture;
-using Arcus.Testing.Logging.Extensions;
-using Arcus.Testing.Logging;
-using Microsoft.Extensions.Configuration;
+using Arcus.Testing;
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Xunit.Abstractions;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Arcus.Security.Tests.Integration
{
public class IntegrationTest : IDisposable
{
private bool _disposed;
-
- protected TestConfig Configuration { get; }
- protected Logger Logger { get; }
- protected InMemoryLogSink InMemoryLogSink { get; }
- public IntegrationTest(ITestOutputHelper testOutput)
+ protected IntegrationTest(ITestOutputHelper testOutput)
{
- // The appsettings.local.json allows users to override (gitignored) settings locally for testing purposes
Configuration = TestConfig.Create();
+ Logger = new XunitTestLogger(testOutput);
+
InMemoryLogSink = new InMemoryLogSink();
-
+
var configuration = new LoggerConfiguration()
.WriteTo.XunitTestLogging(testOutput)
- .WriteTo.Sink(InMemoryLogSink)
- .WriteTo.AzureApplicationInsightsWithInstrumentationKey(Configuration.GetValue("Arcus:ApplicationInsights:InstrumentationKey"));
+ .WriteTo.Sink(InMemoryLogSink);
- Logger = configuration.CreateLogger();
+ SerilogLogger = configuration.CreateLogger();
}
+ protected TestConfig Configuration { get; }
+ protected ILogger Logger { get; }
+ protected Logger SerilogLogger { get; }
+ protected InMemoryLogSink InMemoryLogSink { get; }
+
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
@@ -53,7 +52,7 @@ public void Dispose()
///
protected virtual void Dispose(bool disposing)
{
- Logger.Dispose();
+ SerilogLogger.Dispose();
}
}
}
\ No newline at end of file
diff --git a/src/Arcus.Security.Tests.Integration/KeyVault/Fixture/TemporaryManagedIdentityConnection.cs b/src/Arcus.Security.Tests.Integration/KeyVault/Fixture/TemporaryManagedIdentityConnection.cs
new file mode 100644
index 00000000..23567ef6
--- /dev/null
+++ b/src/Arcus.Security.Tests.Integration/KeyVault/Fixture/TemporaryManagedIdentityConnection.cs
@@ -0,0 +1,36 @@
+using System;
+using Arcus.Security.Tests.Core.Fixture;
+using Xunit;
+
+namespace Arcus.Security.Tests.Integration.KeyVault.Fixture
+{
+ public class TemporaryManagedIdentityConnection : IDisposable
+ {
+ private readonly TemporaryEnvironmentVariable[] _variables;
+
+ private TemporaryManagedIdentityConnection(string clientId, params TemporaryEnvironmentVariable[] variables)
+ {
+ _variables = variables;
+ ClientId = clientId;
+ }
+
+ public string ClientId { get; }
+
+ public static TemporaryManagedIdentityConnection Create(string tenantId, string clientId, string clientSecret)
+ {
+ return new TemporaryManagedIdentityConnection(
+ clientId,
+ TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, tenantId),
+ TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, clientId),
+ TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, clientSecret));
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ Assert.All(_variables, var => var.Dispose());
+ }
+ }
+}
diff --git a/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ManagedIdentityTests.cs b/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ManagedIdentityTests.cs
index 0e31aa26..c7ef7491 100644
--- a/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ManagedIdentityTests.cs
+++ b/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ManagedIdentityTests.cs
@@ -5,9 +5,9 @@
using Arcus.Security.Providers.AzureKeyVault.Configuration;
using Arcus.Security.Tests.Core.Fixture;
using Arcus.Security.Tests.Integration.Fixture;
+using Arcus.Security.Tests.Integration.KeyVault.Fixture;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
@@ -22,9 +22,7 @@ public partial class KeyVaultSecretProviderTests
public async Task KeyVaultSecretProvider_WithUserAssignedManagedIdentity_GetSecret_Succeeds()
{
// Arrange
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
var keyVaultSecretProvider = new KeyVaultSecretProvider(
tokenCredential: new ChainedTokenCredential(new ManagedIdentityCredential(ClientId), new EnvironmentCredential()),
@@ -42,9 +40,7 @@ public async Task KeyVaultSecretProvider_WithUserAssignedManagedIdentity_GetSecr
public async Task KeyVaultSecretProvider_WithUserAssignedManagedIdentity_GetSecret_NonExistingSecret_ThrowsSecretNotFoundException()
{
// Arrange
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
var notExistingSecretName = $"secret-{Guid.NewGuid():N}";
var keyVaultSecretProvider = new KeyVaultSecretProvider(
@@ -67,11 +63,9 @@ public async Task KeyVaultSecretProvider_StoreSecret_Succeeds()
var secretName = $"Test-Secret-{Guid.NewGuid()}";
var secretValue = Guid.NewGuid().ToString();
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using TemporaryManagedIdentityConnection connection = UseTemporaryManagedIdentityConnection();
{
- var tokenCredential = new ChainedTokenCredential(new ManagedIdentityCredential(ClientId), new EnvironmentCredential());
+ var tokenCredential = new ChainedTokenCredential(new ManagedIdentityCredential(connection.ClientId), new EnvironmentCredential());
try
{
var keyVaultSecretProvider = new KeyVaultSecretProvider(
@@ -106,9 +100,7 @@ public async Task AddAzureKeyVault_WithManagedIdentity_GetSecretSucceeds()
builder.ConfigureSecretStore((config, stores) => stores.AddAzureKeyVaultWithManagedIdentity(VaultUri, cacheConfiguration: null, ClientId));
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -141,9 +133,7 @@ public async Task AddAzureKeyVaultSimple_WithManagedIdentity_GetSecretSucceeds()
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -163,7 +153,7 @@ public async Task AddAzureKeyVaultWithDependencyTracking_WithManagedIdentity_Get
{
// Arrange
var builder = new HostBuilder();
- builder.UseSerilog(Logger, dispose: true);
+ builder.UseSerilog(SerilogLogger, dispose: true);
// Act
builder.ConfigureSecretStore((config, stores) =>
@@ -175,9 +165,7 @@ public async Task AddAzureKeyVaultWithDependencyTracking_WithManagedIdentity_Get
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
using (IHost host = builder.Build())
{
var provider = host.Services.GetRequiredService();
@@ -206,9 +194,7 @@ public async Task AddAzureKeyVault_WithManagedIdentityRemovesPrefix_GetsSecretSu
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -238,9 +224,7 @@ public async Task AddAzureKeyVault_WithManagedIdentityWrongMutation_GetsSecretFa
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -259,7 +243,7 @@ public async Task AddAzureKeyVaultWithDependencyTracking_WithManagedIdentityWron
{
// Arrange
var builder = new HostBuilder();
- builder.UseSerilog(Logger, dispose: true);
+ builder.UseSerilog(SerilogLogger, dispose: true);
// Act
builder.ConfigureSecretStore((config, stores) =>
@@ -272,9 +256,7 @@ public async Task AddAzureKeyVaultWithDependencyTracking_WithManagedIdentityWron
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using (IHost host = builder.Build())
{
@@ -301,9 +283,7 @@ public async Task AddAzureKeyVault_WithCachedManagedIdentity_GetSecretSucceeds()
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -332,9 +312,7 @@ public async Task AddAzureKeyVault_WithCachedManagedIdentity_GetSecretFails()
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -364,9 +342,7 @@ public async Task AddAzureKeyVault_WithCachedManagedIdentityRemovesPrefix_GetsSe
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -398,9 +374,7 @@ public async Task AddAzureKeyVault_WithCachedManagedIdentityWrongMutation_GetsSe
});
// Assert
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, TenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, ClientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, ClientSecret))
+ using var _ = UseTemporaryManagedIdentityConnection();
{
using IHost host = builder.Build();
var provider = host.Services.GetRequiredService();
@@ -416,22 +390,16 @@ public async Task AddAzureKeyVault_WithCachedManagedIdentityWrongMutation_GetsSe
public async Task CachedKeyVaultSecretProvider_StoreSecret_Succeeds()
{
// Arrange
- var keyVaultUri = Configuration.GetValue("Arcus:KeyVault:Uri");
- string tenantId = Configuration.GetTenantId();
- string clientId = Configuration.GetServicePrincipalClientId();
- string clientKey = Configuration.GetServicePrincipalClientSecret();
-
+
var secretName = $"Test-Secret-{Guid.NewGuid()}";
var secretValue = Guid.NewGuid().ToString();
-
- using (TemporaryEnvironmentVariable.Create(Constants.AzureTenantIdEnvironmentVariable, tenantId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientIdVariable, clientId))
- using (TemporaryEnvironmentVariable.Create(Constants.AzureServicePrincipalClientSecretVariable, clientKey))
+
+ using TemporaryManagedIdentityConnection connection = UseTemporaryManagedIdentityConnection();
{
- var tokenCredential = new ChainedTokenCredential(new ManagedIdentityCredential(clientId), new EnvironmentCredential());
+ var tokenCredential = new ChainedTokenCredential(new ManagedIdentityCredential(connection.ClientId), new EnvironmentCredential());
var keyVaultSecretProvider = new KeyVaultSecretProvider(
tokenCredential: tokenCredential,
- vaultConfiguration: new KeyVaultConfiguration(keyVaultUri));
+ vaultConfiguration: new KeyVaultConfiguration(VaultUri));
var cachedSecretProvider = new KeyVaultCachedSecretProvider(keyVaultSecretProvider);
try
@@ -450,7 +418,7 @@ public async Task CachedKeyVaultSecretProvider_StoreSecret_Succeeds()
}
finally
{
- var client = new SecretClient(new Uri(keyVaultUri), tokenCredential);
+ var client = new SecretClient(new Uri(VaultUri), tokenCredential);
await client.StartDeleteSecretAsync(secretName);
}
}
diff --git a/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ServicePrincipalTests.cs b/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ServicePrincipalTests.cs
index 173ac3cd..40531e49 100644
--- a/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ServicePrincipalTests.cs
+++ b/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProvider.ServicePrincipalTests.cs
@@ -7,9 +7,9 @@
using Arcus.Security.Core.Caching.Configuration;
using Arcus.Security.Providers.AzureKeyVault;
using Arcus.Security.Providers.AzureKeyVault.Configuration;
+using Arcus.Testing;
using Azure;
using Azure.Identity;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
@@ -84,7 +84,7 @@ public async Task AddAzureKeyVaultWithDependencyTracking_WithServicePrincipal_Ge
var keyName = "UnknownSecretName";
var builder = new HostBuilder();
- builder.UseSerilog(Logger, dispose: true);
+ builder.UseSerilog(SerilogLogger, dispose: true);
// Act
builder.ConfigureSecretStore((config, stores) =>
@@ -268,8 +268,8 @@ public async Task AddAzureKeyVault_WithWrongServicePrincipalCredentials_Throws()
public async Task AddAzureKeyVault_WithWrongUnauthorizedServicePrincipal_Throws()
{
// Arrange
- string applicationId = Configuration.GetValue("Arcus:UnauthorizedServicePrincipal:ApplicationId");
- var clientKey = Configuration.GetValue("Arcus:UnauthorizedServicePrincipal:AccessKey");
+ string applicationId = Configuration.GetUnauthorizedServicePrincipalClientId();
+ string clientKey = Configuration.GetUnauthorizedServicePrincipalClientSecret();
string keyName = TestSecretName;
var builder = new HostBuilder();
@@ -302,7 +302,7 @@ public async Task NewKeyVaultSecretProvider_ReturnsManySecrets_Succeeds()
IEnumerable secrets = await keyVaultSecretProvider.GetSecretsAsync(TestSecretName, amountOfVersions: 2);
// Assert
- Assert.Equal(2, secrets.Count());
+ Assert.True(10 >= secrets.Count(), "should only retrieve 10 or less versioned secrets");
Assert.Equal(TestSecretVersion, secrets.ElementAt(0).Version);
}
@@ -318,7 +318,7 @@ public async Task NewKeyVaultSecretProvider_ReturnsOnlyAvailableSecrets_Succeeds
IEnumerable secrets = await keyVaultSecretProvider.GetSecretsAsync(TestSecretName, amountOfVersions: 10);
// Assert
- Assert.Equal(2, secrets.Count());
+ Assert.True(10 >= secrets.Count(), "should only retrieve 10 or less versioned secrets");
Assert.Equal(TestSecretVersion, secrets.ElementAt(0).Version);
}
}
diff --git a/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProviderTests.cs b/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProviderTests.cs
index 230af9f8..2a5af1ce 100644
--- a/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProviderTests.cs
+++ b/src/Arcus.Security.Tests.Integration/KeyVault/KeyVaultSecretProviderTests.cs
@@ -1,6 +1,7 @@
using System.Linq;
using Arcus.Security.Core;
-using Microsoft.Extensions.Configuration;
+using Arcus.Security.Tests.Integration.KeyVault.Fixture;
+using Arcus.Testing;
using Xunit;
using Xunit.Abstractions;
@@ -14,13 +15,17 @@ public KeyVaultSecretProviderTests(ITestOutputHelper testOutput) : base(testOutp
}
private string TenantId => Configuration.GetTenantId();
- private string ClientId => Configuration.GetValue("Arcus:ServicePrincipal:ApplicationId");
- private string ClientSecret => Configuration.GetValue("Arcus:ServicePrincipal:AccessKey");
- private string VaultUri => Configuration.GetValue("Arcus:KeyVault:Uri");
- private string TestSecretName => Configuration.GetValue("Arcus:KeyVault:TestKeyName");
- private string TestSecretValue => Configuration.GetValue("Arcus:KeyVault:TestKeyValue");
- private string TestSecretVersion => Configuration.GetRequiredValue("Arcus:KeyVault:TestKeyVersion");
-
+ private string ClientId => Configuration.GetServicePrincipalClientId();
+ private string ClientSecret => Configuration.GetServicePrincipalClientSecret();
+ private string VaultUri => $"https://{Configuration.GetRequiredValue("Arcus:KeyVault:Name")}.vault.azure.net/";
+ private string TestSecretName => Configuration.GetSecretName();
+ private string TestSecretValue => Configuration.GetSecretValue();
+ private string TestSecretVersion => Configuration.GetSecretVersion();
+
+ private TemporaryManagedIdentityConnection UseTemporaryManagedIdentityConnection()
+ {
+ return TemporaryManagedIdentityConnection.Create(TenantId, ClientId, ClientSecret);
+ }
private void AssertTrackedAzureKeyVaultDependency(int expectedTrackedDependencyCount)
{
diff --git a/src/Arcus.Security.Tests.Integration/appsettings.json b/src/Arcus.Security.Tests.Integration/appsettings.json
index 29447f82..07a5c688 100644
--- a/src/Arcus.Security.Tests.Integration/appsettings.json
+++ b/src/Arcus.Security.Tests.Integration/appsettings.json
@@ -1,24 +1,19 @@
{
"Arcus": {
- "Tenant": "#{Arcus.Tenant}#",
+ "Tenant": "#{Arcus.Security.TenantId}#",
"KeyVault": {
- "Uri": "#{Arcus_KeyVault_Uri}#",
- "TestKeyName": "#{Arcus.KeyVault.TestKeyName}#",
- "TestKeyValue": "#{Arcus.KeyVault.TestKeyValue}#",
- "TestKeyVersion": "#{Arcus.KeyVault.TestKeyVersion}#"
+ "Name": "#{Arcus.Security.KeyVault.Name}#",
+ "TestSecretName": "#{Arcus.Security.KeyVault.TestSecretName}#",
+ "TestSecretValue": "#{Arcus.Security.KeyVault.TestSecretValue}#",
+ "TestSecretVersion": "#{Arcus.Security.KeyVault.TestSecretVersion}#"
},
"ServicePrincipal": {
- "ApplicationId": "#{Arcus_ServicePrincipal_ApplicationId}#",
- "AccessKey": "#{Arcus_ServicePrincipal_AccessKey}#"
+ "ApplicationId": "#{Arcus.Security.ServicePrincipal.ClientId}#",
+ "AccessKey": "#{Arcus.Security.ServicePrincipal.ClientSecret}#"
},
"UnauthorizedServicePrincipal": {
- "ApplicationId": "#{Arcus.UnauthorizedServicePrincipal.ApplicationId}#",
- "AccessKey": "#{Arcus.UnauthorizedServicePrincipal.AccessKey}#"
- },
- "MSI": {
- "AzureServicesAuth": {
- "ConnectionString": "#{Arcus_MSI_AzureServicesAuth_ConnectionString}#"
- }
+ "ApplicationId": "#{Arcus.Security.Unauthorized.ServicePrincipal.ClientId}#",
+ "AccessKey": "#{Arcus.Security.Unauthorized.ServicePrincipal.ClientSecret}#"
},
"HashiCorp": {
"VaultBin": "#{Arcus.HashiCorp.VaultBin}#",
@@ -27,9 +22,6 @@
"Password": "123"
}
},
- "ApplicationInsights": {
- "InstrumentationKey": "#{Arcus.ApplicationInsights.InstrumentationKey}#"
- },
"AzureFunctions": {
"HttpPort": "#{Arcus.AzureFunctions.HttpPort}#"
}
diff --git a/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs
index 3b56dabd..24e9fd8b 100644
--- a/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs
@@ -8,9 +8,8 @@
using Arcus.Security.Core;
using Arcus.Security.Core.Caching;
using Arcus.Security.Providers.HashiCorp.Extensions;
-using Arcus.Security.Tests.Core.Stubs;
using Arcus.Security.Tests.Unit.Core.Stubs;
-using Arcus.Testing.Logging;
+using Arcus.Testing;
using Arcus.Testing.Security.Providers.InMemory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -418,7 +417,7 @@ public async Task ConfigureSecretStore_WithDefaultAuditing_DoesntLogsSecurityEve
var stubProvider = new InMemorySecretProvider(new Dictionary { [secretName] = $"secret-{Guid.NewGuid()}" });
var spyLogger = new InMemoryLogger();
var builder = new HostBuilder();
- builder.ConfigureLogging(logging => logging.AddProvider(new TestLoggerProvider(spyLogger)));
+ builder.ConfigureLogging(logging => logging.AddProvider(new CustomLoggerProvider(spyLogger)));
// Act
builder.ConfigureSecretStore((config, stores) =>
@@ -443,7 +442,7 @@ public async Task ConfigureSecretStore_WithAuditing_LogsSecurityEvent(bool emitS
var stubProvider = new InMemorySecretProvider(new Dictionary { [secretName] = $"secret-{Guid.NewGuid()}" });
var spyLogger = new InMemoryLogger();
var builder = new HostBuilder();
- builder.ConfigureLogging(logging => logging.AddProvider(new TestLoggerProvider(spyLogger)));
+ builder.ConfigureLogging(logging => logging.AddProvider(new CustomLoggerProvider(spyLogger)));
// Act
builder.ConfigureSecretStore((config, stores) =>
@@ -467,7 +466,7 @@ public async Task ConfigureSecretStore_WithAuditingIncrement_LogsSecurityEvent()
var stubProvider = new InMemorySecretProvider(new Dictionary { [secretName] = $"secret-{Guid.NewGuid()}" });
var spyLogger = new InMemoryLogger();
var builder = new HostBuilder();
- builder.ConfigureLogging(logging => logging.AddProvider(new TestLoggerProvider(spyLogger)));
+ builder.ConfigureLogging(logging => logging.AddProvider(new CustomLoggerProvider(spyLogger)));
// Act
builder.ConfigureSecretStore((config, stores) =>
diff --git a/src/Arcus.Security.Tests.Unit/Core/Extensions/IServiceCollectionExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/Extensions/IServiceCollectionExtensionsTests.cs
index b3d705ce..723f6290 100644
--- a/src/Arcus.Security.Tests.Unit/Core/Extensions/IServiceCollectionExtensionsTests.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/Extensions/IServiceCollectionExtensionsTests.cs
@@ -5,8 +5,8 @@
using System.Threading.Tasks;
using Arcus.Security.Core;
using Arcus.Security.Core.Caching;
-using Arcus.Security.Tests.Core.Stubs;
using Arcus.Security.Tests.Unit.Core.Stubs;
+using Arcus.Testing;
using Arcus.Testing.Security.Providers.InMemory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -184,9 +184,9 @@ public async Task AddSecretStore_WithLogger_UsesLogger()
{
// Arrange
var services = new ServiceCollection();
- var spyLogger = new SpyLogger();
+ var spyLogger = new InMemoryLogger();
services.AddLogging(logging => logging.SetMinimumLevel(LogLevel.Trace)
- .AddProvider(new TestLoggerProvider(spyLogger)));
+ .AddProvider(new CustomLoggerProvider(spyLogger)));
const string secretName = "MySecret";
var stubProvider = new InMemorySecretProvider(new Dictionary { [secretName] = $"secret-{Guid.NewGuid()}" });
@@ -198,7 +198,7 @@ public async Task AddSecretStore_WithLogger_UsesLogger()
IServiceProvider serviceProvider = services.BuildServiceProvider();
var secretProvider = serviceProvider.GetRequiredService();
await secretProvider.GetRawSecretAsync(secretName);
- Assert.True(spyLogger.IsCalled);
+ Assert.NotEmpty(spyLogger.Messages);
}
[Fact]