-
Notifications
You must be signed in to change notification settings - Fork 496
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Unless unsecured, the app host will generate an API key and pass it to the dashboard via an environment variable. The dashboard then includes this key in a header for all gRPC calls. The app host's resource service validates that the expected key is received and rejects requests where the key is omitted.
- Loading branch information
1 parent
0fdfcd5
commit cf1276f
Showing
17 changed files
with
228 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
namespace Aspire.Dashboard.Configuration; | ||
|
||
public enum ResourceClientAuthMode | ||
{ | ||
Unsecured, | ||
ApiKey, | ||
Certificate | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Security.Claims; | ||
using System.Text.Encodings.Web; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Aspire.Hosting.Dashboard; | ||
|
||
internal static class ResourceServiceAuthorization | ||
{ | ||
public const string PolicyName = "ResourceServicePolicy"; | ||
} | ||
|
||
internal static class ResourceServiceAuthenticationDefaults | ||
{ | ||
public const string AuthenticationScheme = "ResourceService"; | ||
} | ||
|
||
internal sealed class ResourceServiceApiKeyAuthenticationOptions : AuthenticationSchemeOptions | ||
{ | ||
} | ||
|
||
internal sealed class ResourceServiceApiKeyAuthenticationHandler( | ||
IOptionsMonitor<ResourceServiceOptions> resourceServiceOptions, | ||
IOptionsMonitor<ResourceServiceApiKeyAuthenticationOptions> options, | ||
ILoggerFactory logger, | ||
UrlEncoder encoder) | ||
: AuthenticationHandler<ResourceServiceApiKeyAuthenticationOptions>(options, logger, encoder) | ||
{ | ||
private const string ApiKeyHeaderName = "x-resource-service-api-key"; | ||
|
||
protected override Task<AuthenticateResult> HandleAuthenticateAsync() | ||
{ | ||
var options = resourceServiceOptions.CurrentValue; | ||
|
||
if (options.AuthMode is ResourceServiceAuthMode.ApiKey) | ||
{ | ||
if (!Request.Headers.TryGetValue(ApiKeyHeaderName, out var headerValues)) | ||
{ | ||
return Task.FromResult(AuthenticateResult.Fail($"'{ApiKeyHeaderName}' header not found")); | ||
} | ||
|
||
if (headerValues.Count != 1) | ||
{ | ||
return Task.FromResult(AuthenticateResult.Fail($"Expecting only a single '{ApiKeyHeaderName}' header.")); | ||
} | ||
|
||
if (!CompareHelpers.CompareKey(expectedKeyBytes: options.GetApiKeyBytes(), requestKey: headerValues.ToString())) | ||
{ | ||
return Task.FromResult(AuthenticateResult.Fail($"Invalid '{ApiKeyHeaderName}' header value.")); | ||
} | ||
} | ||
|
||
return Task.FromResult( | ||
AuthenticateResult.Success( | ||
new AuthenticationTicket( | ||
principal: new ClaimsPrincipal(new ClaimsIdentity()), | ||
authenticationScheme: Scheme.Name))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Text; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Aspire.Hosting.Dashboard; | ||
|
||
internal enum ResourceServiceAuthMode | ||
{ | ||
// NOTE unlike ResourceClientAuthMode, there's no 'Certificate' option here. | ||
// The AppHost's implementation of the resource service does not support | ||
// certificate-based auth. | ||
|
||
Unsecured, | ||
ApiKey | ||
} | ||
|
||
internal sealed class ResourceServiceOptions | ||
{ | ||
private string? _apiKey; | ||
private byte[]? _apiKeyBytes; | ||
|
||
public ResourceServiceAuthMode? AuthMode { get; set; } | ||
|
||
public string? ApiKey | ||
{ | ||
get => _apiKey; | ||
set | ||
{ | ||
_apiKey = value; | ||
_apiKeyBytes = value is null ? null : Encoding.UTF8.GetBytes(value); | ||
} | ||
} | ||
|
||
internal byte[] GetApiKeyBytes() | ||
{ | ||
return _apiKeyBytes ?? throw new InvalidOperationException($"{nameof(ApiKey)} not specified in configuration."); | ||
} | ||
} | ||
|
||
internal sealed class ValidateResourceServiceOptions : IValidateOptions<ResourceServiceOptions> | ||
{ | ||
public ValidateOptionsResult Validate(string? name, ResourceServiceOptions options) | ||
{ | ||
List<string>? errorMessages = null; | ||
|
||
if (options.AuthMode is ResourceServiceAuthMode.ApiKey) | ||
{ | ||
if (string.IsNullOrWhiteSpace(options.ApiKey)) | ||
{ | ||
AddError($"{nameof(ResourceServiceOptions.ApiKey)} value is required when AuthMode is {nameof(ResourceServiceAuthMode.ApiKey)}."); | ||
} | ||
} | ||
|
||
return errorMessages is { Count: > 0 } | ||
? ValidateOptionsResult.Fail(errorMessages) | ||
: ValidateOptionsResult.Success; | ||
|
||
void AddError(string message) => (errorMessages ??= []).Add(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.