Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
TimHess committed Jun 3, 2024
1 parent cf5d7ec commit 9bbeed0
Show file tree
Hide file tree
Showing 34 changed files with 219 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

using System.Reflection;
using FluentAssertions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
Expand Down Expand Up @@ -227,7 +226,7 @@ public void Tracing_IsAutowired()
}

[Fact]
public void CloudFoundryContainerSecurity_IsAutowired()
public void ContainerIdentityCertificate_IsAutowired()
{
using IHost host = GetHostForOnly(SteeltoeAssemblyNames.CommonSecurity);
var configuration = host.Services.GetRequiredService<IConfiguration>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Net;
using System.Reflection;
using FluentAssertions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
Expand Down Expand Up @@ -228,7 +227,7 @@ public void Tracing_IsAutowired()
}

[Fact]
public void CloudFoundryContainerSecurity_IsAutowired()
public void ContainerIdentityCertificate_IsAutowired()
{
using WebApplication host = GetWebApplicationForOnly(SteeltoeAssemblyNames.CommonSecurity);
var configuration = host.Services.GetRequiredService<IConfiguration>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Reflection;
using FluentAssertions;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
Expand Down Expand Up @@ -228,7 +227,7 @@ public void Tracing_IsAutowired()
}

[Fact]
public void CloudFoundryContainerSecurity_IsAutowired()
public void ContainerIdentityCertificate_IsAutowired()
{
using IWebHost host = GetWebHostForOnly(SteeltoeAssemblyNames.CommonSecurity);
var configuration = host.Services.GetRequiredService<IConfiguration>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,50 +49,50 @@ public static IConfigurationBuilder AddCertificate(this IConfigurationBuilder bu
}

/// <summary>
/// Adds PEM files representing application identity to application configuration. When running outside of Cloud Foundry based platforms,
/// will create certificates resembling those found on the platform.
/// Adds PEM files representing application identity to application configuration. When running outside of Cloud Foundry based platforms, will create
/// certificates resembling those found on the platform.
/// </summary>
/// <param name="builder">
/// Your <see cref="IConfigurationBuilder" />.
/// </param>
/// <remarks>
/// Outside of Cloud Foundry, CA and Intermediate certificates will be created a directory above the current project so that they can
/// be shared between different projects operating in the same solution context.
/// Outside of Cloud Foundry, CA and Intermediate certificates will be created a directory above the current project so that they can be shared between
/// different projects operating in the same solution context.
/// </remarks>
public static IConfigurationBuilder AddContainerIdentityCertificate(this IConfigurationBuilder builder)
{
return builder.AddContainerIdentityCertificate(null, null);
}

/// <summary>
/// Adds PEM files representing application identity to application configuration. When running outside of Cloud Foundry based platforms,
/// will create certificates resembling those found on the platform.
/// Adds PEM files representing application identity to application configuration. When running outside of Cloud Foundry based platforms, will create
/// certificates resembling those found on the platform.
/// </summary>
/// <param name="builder">
/// Your <see cref="IConfigurationBuilder" />.
/// </param>
/// <param name="organizationId">
/// (Optional) A GUID representing an organization, for use with Cloud Foundry certificate-based authorization
/// policy.
/// (Optional) A GUID representing an organization, for use with Cloud Foundry certificate-based authorization policy.
/// </param>
/// <param name="spaceId">
/// (Optional) A GUID representing a space, for use with Cloud Foundry certificate-based authorization policy.
/// </param>
/// <remarks>
/// Outside of Cloud Foundry, CA and Intermediate certificates will be created a directory above the current project so that they can
/// be shared between different projects operating in the same solution context.
/// Outside of Cloud Foundry, CA and Intermediate certificates will be created a directory above the current project so that they can be shared between
/// different projects operating in the same solution context.
/// </remarks>
public static IConfigurationBuilder AddContainerIdentityCertificate(this IConfigurationBuilder builder, Guid? organizationId, Guid? spaceId)
{
if (!Platform.IsCloudFoundry)
{
organizationId ??= Guid.NewGuid();
spaceId ??= Guid.NewGuid();
spaceId ??= Guid.NewGuid();

var task = new LocalCertificateWriter();
task.Write((Guid)organizationId, (Guid)spaceId);

Environment.SetEnvironmentVariable("CF_SYSTEM_CERT_PATH", Path.Combine(Directory.GetParent(LocalCertificateWriter.ApplicationBasePath)!.ToString(), "GeneratedCertificates"));
Environment.SetEnvironmentVariable("CF_SYSTEM_CERT_PATH",
Path.Combine(Directory.GetParent(LocalCertificateWriter.ApplicationBasePath)!.ToString(), "GeneratedCertificates"));

Environment.SetEnvironmentVariable("CF_INSTANCE_CERT",
Path.Combine(LocalCertificateWriter.ApplicationBasePath, "GeneratedCertificates", "SteeltoeInstanceCert.pem"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Steeltoe.Common.Security;
public static class CertificateServiceCollectionExtensions
{
/// <summary>
/// Configure <see cref="CertificateOptions"/> for use with client certificates.
/// Configure <see cref="CertificateOptions" /> for use with client certificates.
/// </summary>
/// <param name="services">
/// The <see cref="IServiceCollection" /> to add services to.
Expand All @@ -25,7 +25,8 @@ public static class CertificateServiceCollectionExtensions
/// <param name="fileProvider">
/// Provides access to the file system.
/// </param>
public static IServiceCollection ConfigureCertificateOptions(this IServiceCollection services, IConfiguration configuration, IFileProvider? fileProvider = null)
public static IServiceCollection ConfigureCertificateOptions(this IServiceCollection services, IConfiguration configuration,
IFileProvider? fileProvider = null)
{
fileProvider ??= new PhysicalFileProvider(Environment.CurrentDirectory);
IConfigurationSection[] childSections = configuration.GetSection(CertificateOptions.ConfigurationKeyPrefix).GetChildren().ToArray();
Expand Down
38 changes: 18 additions & 20 deletions src/Common/src/Common.Security/LocalCertificateWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ internal sealed class LocalCertificateWriter

internal string CertificateFilenamePrefix { get; set; } = "SteeltoeInstance";

public string RootCertificateAuthorityPfxPath { get; set; } = Path.Combine(Directory.GetParent(ApplicationBasePath)!.ToString(), "GeneratedCertificates", "SteeltoeCA.pfx");
public string RootCertificateAuthorityPfxPath { get; set; } =
Path.Combine(Directory.GetParent(ApplicationBasePath)!.ToString(), "GeneratedCertificates", "SteeltoeCA.pfx");

public string IntermediatePfxPath { get; set; } =
Path.Combine(Directory.GetParent(ApplicationBasePath)!.ToString(), "GeneratedCertificates", "SteeltoeIntermediate.pfx");
Expand Down Expand Up @@ -52,6 +53,7 @@ public void Write(Guid orgId, Guid spaceId)

// Create the intermediate certificate if it doesn't already exist (can be shared by multiple applications)
X509Certificate2 intermediateCertificate;

if (!File.Exists(IntermediatePfxPath))
{
intermediateCertificate = CreateIntermediateCertificate("CN=SteeltoeGeneratedIntermediate", rootAuthorityCertificate);
Expand All @@ -73,23 +75,15 @@ public void Write(Guid orgId, Guid spaceId)
}

#if NET8_0_OR_GREATER
string chainedCertificateContents = clientCertificate.ExportCertificatePem() + "\r\n" +
intermediateCertificate.ExportCertificatePem() + "\r\n" +
string chainedCertificateContents = clientCertificate.ExportCertificatePem() + "\r\n" + intermediateCertificate.ExportCertificatePem() + "\r\n" +
rootAuthorityCertificate.ExportCertificatePem();

string keyContents = clientCertificate.GetRSAPrivateKey()!.ExportRSAPrivateKeyPem();

#else
string chainedCertificateContents = "-----BEGIN CERTIFICATE-----\r\n" +
Convert.ToBase64String(clientCertificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) +
"\r\n-----END CERTIFICATE-----\r\n" + "-----BEGIN CERTIFICATE-----\r\n" +
Convert.ToBase64String(intermediateCertificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) +
"\r\n-----END CERTIFICATE-----\r\n" + "-----BEGIN CERTIFICATE-----\r\n" +
Convert.ToBase64String(rootAuthorityCertificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) +
"\r\n-----END CERTIFICATE-----\r\n";

string keyContents = "-----BEGIN RSA PRIVATE KEY-----\r\n" +
Convert.ToBase64String(clientCertificate.GetRSAPrivateKey()!.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks) +
"\r\n-----END RSA PRIVATE KEY-----";
string chainedCertificateContents = "-----BEGIN CERTIFICATE-----\r\n" + Convert.ToBase64String(clientCertificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) + "\r\n-----END CERTIFICATE-----\r\n" + "-----BEGIN CERTIFICATE-----\r\n" + Convert.ToBase64String(intermediateCertificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) + "\r\n-----END CERTIFICATE-----\r\n" + "-----BEGIN CERTIFICATE-----\r\n" + Convert.ToBase64String(rootAuthorityCertificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) + "\r\n-----END CERTIFICATE-----\r\n";

string keyContents = "-----BEGIN RSA PRIVATE KEY-----\r\n" + Convert.ToBase64String(clientCertificate.GetRSAPrivateKey()!.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks) + "\r\n-----END RSA PRIVATE KEY-----";

#endif

Expand All @@ -100,7 +94,9 @@ public void Write(Guid orgId, Guid spaceId)
private static X509Certificate2 CreateRootCertificate(string distinguishedName)
{
using var privateKey = RSA.Create();
var certificateRequest = new CertificateRequest(new X500DistinguishedName(distinguishedName), privateKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

var certificateRequest =
new CertificateRequest(new X500DistinguishedName(distinguishedName), privateKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));

Expand All @@ -120,17 +116,18 @@ private static X509Certificate2 CreateIntermediateCertificate(string subjectName
return certificateRequest.Create(issuerCertificate, DateTimeOffset.UtcNow, issuerCertificate.NotAfter, serialNumber).CopyWithPrivateKey(privateKey);
}

private static X509Certificate2 CreateClientCertificate(string subjectName, X509Certificate2 issuerCertificate, SubjectAlternativeNameBuilder alternativeNames, DateTimeOffset? notAfter = null)
private static X509Certificate2 CreateClientCertificate(string subjectName, X509Certificate2 issuerCertificate,
SubjectAlternativeNameBuilder alternativeNames, DateTimeOffset? notAfter = null)
{
using var privateKey = RSA.Create();
var request = new CertificateRequest(subjectName, privateKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(
[

request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension([
new Oid("1.3.6.1.5.5.7.3.1"), // serverAuth
new Oid("1.3.6.1.5.5.7.3.2") // clientAuth
new Oid("1.3.6.1.5.5.7.3.2") // clientAuth
], false));

if (alternativeNames != null)
Expand All @@ -145,7 +142,8 @@ private static X509Certificate2 CreateClientCertificate(string subjectName, X509
randomNumberGenerator.GetBytes(serialNumber);
}

X509Certificate2 signedCertificate = request.Create(issuerCertificate, DateTimeOffset.UtcNow, notAfter ?? DateTimeOffset.UtcNow.AddDays(1), serialNumber);
X509Certificate2 signedCertificate =
request.Create(issuerCertificate, DateTimeOffset.UtcNow, notAfter ?? DateTimeOffset.UtcNow.AddDays(1), serialNumber);

return signedCertificate.CopyWithPrivateKey(privateKey);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public async Task CertificateOptionsUpdateOnFileChange()

IConfigurationRoot configuration = new ConfigurationBuilder().AddCertificate(CertificateName, certificateFilePath, privateKeyFilePath).Build();

ServiceProvider serviceProvider = new ServiceCollection().AddSingleton<IConfiguration>(configuration).ConfigureCertificateOptions(configuration, null)
ServiceProvider serviceProvider = new ServiceCollection().AddSingleton<IConfiguration>(configuration).ConfigureCertificateOptions(configuration)
.BuildServiceProvider();

var optionsMonitor = serviceProvider.GetRequiredService<IOptionsMonitor<CertificateOptions>>();
Expand Down Expand Up @@ -116,7 +116,7 @@ public async Task CertificateOptionsNotifyOnChange()

IConfigurationRoot configuration = new ConfigurationBuilder().AddCertificate(CertificateName, certificateFilePath, privateKeyFilePath).Build();

ServiceProvider serviceProvider = new ServiceCollection().AddSingleton<IConfiguration>(configuration).ConfigureCertificateOptions(configuration, null)
ServiceProvider serviceProvider = new ServiceCollection().AddSingleton<IConfiguration>(configuration).ConfigureCertificateOptions(configuration)
.BuildServiceProvider();

var optionsMonitor = serviceProvider.GetRequiredService<IOptionsMonitor<CertificateOptions>>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public void CertificatesIncludeParams()
rsa.ImportFromPem(File.ReadAllText(Path.Combine(LocalCertificateWriter.ApplicationBasePath, "GeneratedCertificates", "SteeltoeInstanceKey.pem")));

X509Certificate2 clientCert =
new X509Certificate2(File.ReadAllBytes(Path.Combine(LocalCertificateWriter.ApplicationBasePath, "GeneratedCertificates", "SteeltoeInstanceCert.pem")))
new X509Certificate2(
File.ReadAllBytes(Path.Combine(LocalCertificateWriter.ApplicationBasePath, "GeneratedCertificates", "SteeltoeInstanceCert.pem")))
.CopyWithPrivateKey(rsa);

rootCertificate.Should().NotBeNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace Steeltoe.Configuration.CloudFoundry.ServiceBinding.PostProcessors;

internal abstract class CloudFoundryPostProcessor : IConfigurationPostProcessor
{
private static readonly Regex TagsConfigurationKeyRegex = new("^vcap:services:[^:]+:[0-9]+:tags:[0-9]+", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex LabelConfigurationKeyRegex = new("^vcap:services:[^:]+:[0-9]+:label+", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex TagsConfigurationKeyRegex = new("^vcap:services:[^:]+:[0-9]+:tags:[0-9]+", RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));
private static readonly Regex LabelConfigurationKeyRegex = new("^vcap:services:[^:]+:[0-9]+:label+", RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));

public abstract void PostProcessConfiguration(PostProcessorConfigurationProvider provider, IDictionary<string, string?> configurationData);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ internal sealed class IdentityCloudFoundryPostProcessor : CloudFoundryPostProces
{
internal const string BindingType = "p-identity";
internal const string AuthenticationConfigurationKeyPrefix = "Authentication:Schemes";
internal static readonly string[] AuthenticationSchemes = ["OpenIdConnect", "Bearer"];

internal static readonly string[] AuthenticationSchemes =
[
"OpenIdConnect",
"Bearer"
];

private readonly ILogger<IdentityCloudFoundryPostProcessor> _logger;

public IdentityCloudFoundryPostProcessor(ILogger<IdentityCloudFoundryPostProcessor> logger)
Expand All @@ -34,14 +40,14 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
}

var mapper = ServiceBindingMapper.Create(configurationData, key, BindingType, AuthenticationConfigurationKeyPrefix);
foreach (var scheme in AuthenticationSchemes)

foreach (string scheme in AuthenticationSchemes)
{
mapper.MapFromTo("credentials:auth_domain", $"{scheme}:Authority");
mapper.MapFromTo("credentials:client_id", $"{scheme}:ClientId");
mapper.MapFromTo("credentials:client_secret", $"{scheme}:ClientSecret");
}


hasMapped = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,25 @@ namespace Steeltoe.Security.Authentication.JwtBearer;
public static class JwtBearerServiceCollectionExtensions
{
/// <summary>
/// Configure <see cref="JwtBearerOptions"/> for compatibility with UAA-based systems, including Single Sign-On for VMware Tanzu Platform.
/// Configure <see cref="JwtBearerOptions" /> for compatibility with UAA-based systems, including Single Sign-On for VMware Tanzu Platform.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="services">
/// The <see cref="IServiceCollection" /> to add services to.
/// </param>
public static IServiceCollection ConfigureJwtBearerForCloudFoundry(this IServiceCollection services)
{
return ConfigureJwtBearerForCloudFoundry(services, null);
}

/// <summary>
/// Configure <see cref="JwtBearerOptions"/> for compatibility with UAA-based systems, including Single Sign-On for VMware Tanzu Platform.
/// Configure <see cref="JwtBearerOptions" /> for compatibility with UAA-based systems, including Single Sign-On for VMware Tanzu Platform.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="configureHttpClient">Configure the HttpClient used to interact with the identity server.</param>
/// <param name="services">
/// The <see cref="IServiceCollection" /> to add services to.
/// </param>
/// <param name="configureHttpClient">
/// Configure the HttpClient used to interact with the identity server.
/// </param>
public static IServiceCollection ConfigureJwtBearerForCloudFoundry(this IServiceCollection services, Action<HttpClient>? configureHttpClient)
{
ArgumentGuard.NotNull(services);
Expand Down
Loading

0 comments on commit 9bbeed0

Please sign in to comment.