Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions Dan.Common/Config/PluginKeyVault.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Security.Cryptography.X509Certificates;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;

namespace Dan.Common.Config;

/// <summary>
/// Keyvault config class
/// </summary>
public class PluginKeyVault
{
private SecretClient SecretClient { get; }

/// <summary>
/// Keyvault config class
/// </summary>
/// <param name="vaultName">Name of the Key Vault</param>
public PluginKeyVault(string? vaultName)
{
if (string.IsNullOrEmpty(vaultName))
{
throw new ArgumentNullException(nameof(vaultName), $"{nameof(vaultName)} cannot be null or empty.");
}
SecretClient = new SecretClient(new Uri($"https://{vaultName}.vault.azure.net/"), new DefaultAzureCredential());
}

/// <summary>
/// Get a secret from the key vault
/// </summary>
/// <param name="key">Secret name</param>
/// <returns>The secret value</returns>
public async Task<string?> Get(string? key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException(nameof(key), $"{nameof(key)} cannot be null or empty.");
}

var secret = await SecretClient.GetSecretAsync(key);
return secret?.Value?.Value;
}

/// <summary>
/// Get a X509 certificate from the key vault
/// </summary>
/// <param name="key">Certificate name</param>
/// <returns>The certificate</returns>
public async Task<X509Certificate2?> GetCertificate(string key)
{
var base64Certificate = await Get(key);
if (base64Certificate == null)
{
return default;
}
var certBytes = Convert.FromBase64String(base64Certificate);

var cert = new X509Certificate2(certBytes, string.Empty, X509KeyStorageFlags.MachineKeySet);

return await Task.FromResult(cert);
}
}
1 change: 1 addition & 0 deletions Dan.Common/Dan.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

<ItemGroup>
<PackageReference Include="AsyncKeyedLock" Version="7.1.4" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.7.0" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.Azure.Core.NewtonsoftJson" Version="2.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.23.0" />
Expand Down
1 change: 1 addition & 0 deletions Dan.PluginTest/Config/PluginConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ public static class PluginConstants
public const string DatasetTwo = "DatasetTwo";

public const string PluginForward = "PluginForward";
public const string PluginSettingsTest = "PluginSettingsTest";
}
16 changes: 14 additions & 2 deletions Dan.PluginTest/Config/Settings.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
namespace Dan.PluginTest.Config;
using Dan.Common.Config;

namespace Dan.PluginTest.Config;

public class Settings
{
public string PluginCode { get; set; }
public string? PluginCode { get; set; }
public string? KeyVaultName { get; set; }
public string? CertName { get; set; }


private string? _cert;
public string? Certificate
{
get => _cert ?? new PluginKeyVault(KeyVaultName).Get(CertName).Result;
set => _cert = value;
}
}
14 changes: 14 additions & 0 deletions Dan.PluginTest/Metadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ public List<EvidenceCode> GetEvidenceCodes()
ValueType = EvidenceValueType.JsonSchema
}
]
},
new EvidenceCode
{
EvidenceCodeName = PluginConstants.PluginSettingsTest,
EvidenceSource = PluginConstants.Source,
ServiceContext = DanTest,
Values =
[
new EvidenceValue
{
EvidenceValueName = "certSuccessfullyFetched",
ValueType = EvidenceValueType.Boolean
}
]
}
];
}
Expand Down
35 changes: 35 additions & 0 deletions Dan.PluginTest/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,30 @@
() => FetchPluginValue(evidenceHarvesterRequest));
}

// Used to test app settings - particularly getting settings from keyvault
[Function(PluginConstants.PluginSettingsTest)]
public async Task<HttpResponseData> PluginSettingsTest(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestData req,
FunctionContext context)
{
EvidenceHarvesterRequest? evidenceHarvesterRequest;
try
{
evidenceHarvesterRequest = await req.ReadFromJsonAsync<EvidenceHarvesterRequest>();
}
catch (Exception e)
{
_logger.LogError(e,
"Exception while attempting to parse request into EvidenceHarvesterRequest: {exceptionType}: {exceptionMessage}",
e.GetType().Name, e.Message);
throw new EvidenceSourcePermanentClientException(PluginConstants.ErrorInvalidInput,
"Unable to parse request", e);
}

return await EvidenceSourceResponse.CreateResponse(req,
() => EvidenceValuesPluginSettings(evidenceHarvesterRequest));
}

private async Task<List<EvidenceValue>> GetEvidenceValuesDatasetOne(
EvidenceHarvesterRequest? evidenceHarvesterRequest)
{
Expand Down Expand Up @@ -127,7 +151,7 @@

var response = await danPluginClientService.GetPluginDataSetAsync<dynamic>(
request: enovaRequest,
code: _settings.PluginCode,

Check warning on line 154 in Dan.PluginTest/Plugin.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Possible null reference argument for parameter 'code' in 'Task<dynamic?> IDanPluginClientService.GetPluginDataSetAsync<dynamic>(EvidenceHarvesterRequest request, string code, string env, bool isDefaultJson, string url = "", string source = "")'.

Check warning on line 154 in Dan.PluginTest/Plugin.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Possible null reference argument for parameter 'code' in 'Task<dynamic?> IDanPluginClientService.GetPluginDataSetAsync<dynamic>(EvidenceHarvesterRequest request, string code, string env, bool isDefaultJson, string url = "", string source = "")'.

Check warning on line 154 in Dan.PluginTest/Plugin.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Possible null reference argument for parameter 'code' in 'Task<dynamic?> IDanPluginClientService.GetPluginDataSetAsync<dynamic>(EvidenceHarvesterRequest request, string code, string env, bool isDefaultJson, string url = "", string source = "")'.

Check warning on line 154 in Dan.PluginTest/Plugin.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Possible null reference argument for parameter 'code' in 'Task<dynamic?> IDanPluginClientService.GetPluginDataSetAsync<dynamic>(EvidenceHarvesterRequest request, string code, string env, bool isDefaultJson, string url = "", string source = "")'.
env: "dev",
isDefaultJson: true,
source: "enova");
Expand All @@ -136,4 +160,15 @@

return ecb.GetEvidenceValues();
}

private async Task<List<EvidenceValue>> EvidenceValuesPluginSettings(
EvidenceHarvesterRequest? evidenceHarvesterRequest)
{
var ecb = new EvidenceBuilder(evidenceSourceMetadata, PluginConstants.PluginSettingsTest);
var certFetched = !string.IsNullOrWhiteSpace(_settings.Certificate);
ecb.AddEvidenceValue("certSuccessfullyFetched", certFetched, PluginConstants.Source);

await Task.CompletedTask;
return ecb.GetEvidenceValues();
}
}
3 changes: 0 additions & 3 deletions Dan.PluginTest/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Dan.Common.Extensions;
using Dan.PluginTest.Config;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

var host = new HostBuilder()
.ConfigureDanPluginDefaults()
Expand All @@ -13,8 +12,6 @@
{
var configurationRoot = context.Configuration;
services.Configure<Settings>(configurationRoot);

var applicationSettings = services.BuildServiceProvider().GetRequiredService<IOptions<Settings>>().Value;
})
.Build();

Expand Down
Loading