Skip to content

Commit cbf7c00

Browse files
authored
Add a console/worker app for certificate auth (#391)
1 parent 85ab6cf commit cbf7c00

35 files changed

+391
-66
lines changed

Security/src/AuthApi/Program.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using Microsoft.AspNetCore.Authentication.JwtBearer;
21
using Steeltoe.Common.Certificates;
32
using Steeltoe.Configuration.CloudFoundry;
43
using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
@@ -27,7 +26,7 @@
2726
builder.Configuration.AddAppInstanceIdentityCertificate(new Guid(orgId), new Guid(spaceId));
2827

2928
// Steeltoe: Register Microsoft's JWT Bearer and Certificate libraries for authentication, configure JWT to work with UAA/Cloud Foundry.
30-
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer().ConfigureJwtBearerForCloudFoundry().AddCertificate();
29+
builder.Services.AddAuthentication().AddJwtBearer().ConfigureJwtBearerForCloudFoundry().AddCertificate();
3130

3231
// Steeltoe: Register Microsoft authorization services.
3332
builder.Services.AddAuthorizationBuilder()

Security/src/AuthApi/Steeltoe.Samples.AuthApi.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
5-
<Nullable>enable</Nullable>
65
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

99
<ItemGroup>

Security/src/AuthApi/manifest-windows.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
---
1+
---
22
applications:
33
- name: auth-server-sample
44
buildpacks:
55
- binary_buildpack
66
command: cmd /c .\Steeltoe.Samples.AuthApi --urls=http://0.0.0.0:%PORT%
7-
memory: 128M
7+
memory: 256M
88
stack: windows
99
env:
1010
DOTNET_CLI_TELEMETRY_OPTOUT: "true"

Security/src/AuthApi/manifest.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
---
1+
---
22
applications:
33
- name: auth-server-sample
44
buildpacks:
55
- dotnet_core_buildpack
6-
memory: 128M
6+
memory: 256M
77
stack: cflinuxfs4
88
env:
99
DOTNET_CLI_TELEMETRY_OPTOUT: "true"

Security/src/AuthConsole/.cfignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# DotNet
2+
bin/
3+
obj/
4+
publish/
5+
6+
# user-specific state
7+
*.user
8+
9+
# VS Code
10+
.vscode/
11+
*.code-workspace
12+
13+
# Visual Studio
14+
.vs/
15+
16+
# JetBrains
17+
.idea/
18+
*.iws
19+
*.iml
20+
*.ipr
21+
22+
# Test framework files
23+
scaffold/
24+
*.feature
25+
26+
# Common files that don't need to be pushed
27+
config/
28+
*.http
29+
manifest*.yml
30+
*.md
31+
launchSettings.json
32+
33+
# files specific this sample
34+
GeneratedCertificates
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Steeltoe.Samples.AuthConsole.Models;
2+
3+
namespace Steeltoe.Samples.AuthConsole.ApiClients;
4+
5+
public sealed class CertificateAuthorizationApiClient(HttpClient httpClient)
6+
: StringApiClient(httpClient)
7+
{
8+
public async Task<AuthApiResponseModel> GetSameOrgAsync(CancellationToken cancellationToken)
9+
{
10+
return await GetAsync("api/certificate/SameOrg", cancellationToken);
11+
}
12+
13+
public async Task<AuthApiResponseModel> GetSameSpaceAsync(CancellationToken cancellationToken)
14+
{
15+
return await GetAsync("api/certificate/SameSpace", cancellationToken);
16+
}
17+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Steeltoe.Samples.AuthConsole.Models;
2+
3+
namespace Steeltoe.Samples.AuthConsole.ApiClients;
4+
5+
public abstract class StringApiClient(HttpClient httpClient)
6+
{
7+
protected HttpClient HttpClient => httpClient;
8+
9+
protected async Task<AuthApiResponseModel> GetAsync(string requestUri, CancellationToken cancellationToken)
10+
{
11+
string fullRequestUri = httpClient.BaseAddress + requestUri;
12+
13+
try
14+
{
15+
using HttpResponseMessage response = await httpClient.GetAsync(requestUri, cancellationToken);
16+
string responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
17+
18+
if (response.IsSuccessStatusCode)
19+
{
20+
return new AuthApiResponseModel
21+
{
22+
RequestUri = fullRequestUri,
23+
Message = responseBody
24+
};
25+
}
26+
27+
throw new HttpRequestException($"Request failed with status {(int)response.StatusCode}:{Environment.NewLine}{responseBody}");
28+
}
29+
catch (Exception exception)
30+
{
31+
return new AuthApiResponseModel
32+
{
33+
RequestUri = fullRequestUri,
34+
Error = exception
35+
};
36+
}
37+
}
38+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Steeltoe.Samples.AuthConsole;
2+
3+
internal sealed class CloudFoundryConventions
4+
{
5+
public const string ConfigurationPrefix = "CloudFoundryConventions";
6+
7+
public string ApiUriSegment { get; set; } = "";
8+
9+
public string AppsUriSegment { get; set; } = "";
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project>
2+
<PropertyGroup>
3+
<SteeltoeVersion>4.0.*-*</SteeltoeVersion>
4+
</PropertyGroup>
5+
<PropertyGroup>
6+
<AspNetCoreVersion>8.0.*</AspNetCoreVersion>
7+
</PropertyGroup>
8+
</Project>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Microsoft.Extensions.DependencyInjection.Extensions;
2+
using Microsoft.Extensions.Http.Logging;
3+
4+
namespace Steeltoe.Samples.AuthConsole;
5+
6+
/// <summary>
7+
/// Provides simplified logging of outgoing HTTP requests.
8+
/// </summary>
9+
/// <remarks>
10+
/// Based on https://josef.codes/customize-the-httpclient-logging-dotnet-core/.
11+
/// </remarks>
12+
public static class HttpClientBuilderExtensions
13+
{
14+
public static IHttpClientBuilder ConfigureLogging(this IHttpClientBuilder builder)
15+
{
16+
builder.Services.TryAddScoped<HttpLogger>();
17+
return builder.RemoveAllLoggers().AddLogger<HttpLogger>(true);
18+
}
19+
20+
private sealed class HttpLogger(ILogger<HttpLogger> logger) : IHttpClientLogger
21+
{
22+
private readonly ILogger<HttpLogger> _logger = logger;
23+
24+
public object? LogRequestStart(HttpRequestMessage request)
25+
{
26+
_logger.LogInformation("Sending '{Request.Method}' to '{Request.Host}{Request.Path}'", request.Method,
27+
request.RequestUri?.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped), request.RequestUri?.PathAndQuery);
28+
29+
return null;
30+
}
31+
32+
public void LogRequestStop(object? context, HttpRequestMessage request, HttpResponseMessage response, TimeSpan elapsed)
33+
{
34+
_logger.LogInformation("Received '{Response.StatusCodeInt} {Response.StatusCodeString}' after {Response.ElapsedMilliseconds}ms",
35+
(int)response.StatusCode, response.StatusCode, elapsed.TotalMilliseconds.ToString("F1"));
36+
}
37+
38+
public void LogRequestFailed(object? context, HttpRequestMessage request, HttpResponseMessage? response, Exception exception, TimeSpan elapsed)
39+
{
40+
_logger.LogError(exception, "Request towards '{Request.Host}{Request.Path}' failed after {Response.ElapsedMilliseconds}ms",
41+
request.RequestUri?.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped), request.RequestUri!.PathAndQuery,
42+
elapsed.TotalMilliseconds.ToString("F1"));
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)