Added OpenID authentication method

This commit is contained in:
2024-12-21 22:35:04 +01:00
parent df89450745
commit ba7584c771
17 changed files with 345 additions and 15 deletions

View File

@@ -0,0 +1,10 @@
using HopFrame.Security.Authentication.OpenID.Models;
namespace HopFrame.Security.Authentication.OpenID;
public interface IOpenIdAccessor {
Task<OpenIdConfiguration> LoadConfiguration();
Task<OpenIdToken> RequestToken(string code);
Task<string> ConstructAuthUri(string state = null);
Task<OpenIdIntrospection> InspectToken(string token);
}

View File

@@ -0,0 +1,64 @@
using System.Text.Json;
using HopFrame.Security.Authentication.OpenID.Models;
using HopFrame.Security.Authentication.OpenID.Options;
using Microsoft.Extensions.Options;
namespace HopFrame.Security.Authentication.OpenID.Implementation;
internal class OpenIdAccessor(IHttpClientFactory clientFactory, IOptions<OpenIdOptions> options) : IOpenIdAccessor {
public async Task<OpenIdConfiguration> LoadConfiguration() {
var client = clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, Path.Combine(options.Value.Issuer, ".well-known/openid-configuration"));
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
return null;
return await JsonSerializer.DeserializeAsync<OpenIdConfiguration>(await response.Content.ReadAsStreamAsync());
}
public async Task<OpenIdToken> RequestToken(string code) {
var configuration = await LoadConfiguration();
var client = clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, configuration.TokenEndpoint) {
Content = new FormUrlEncodedContent(new Dictionary<string, string> {
{ "grant_type", "authorization_code" },
{ "code", code },
{ "redirect_uri", options.Value.Callback },
{ "client_id", options.Value.ClientId },
{ "client_secret", options.Value.ClientSecret }
})
};
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
return null;
return await JsonSerializer.DeserializeAsync<OpenIdToken>(await response.Content.ReadAsStreamAsync());
}
public async Task<string> ConstructAuthUri(string state = null) {
var configuration = await LoadConfiguration();
return $"{configuration.AuthorizationEndpoint}?response_type=code&client_id={options.Value.ClientId}&redirect_uri={options.Value.Callback}&scope=openid%20profile%20email&state={state}";
}
public async Task<OpenIdIntrospection> InspectToken(string token) {
var configuration = await LoadConfiguration();
var client = clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, configuration.IntrospectionEndpoint) {
Content = new FormUrlEncodedContent(new Dictionary<string, string> {
{ "token", token },
{ "client_id", options.Value.ClientId },
{ "client_secret", options.Value.ClientSecret }
})
};
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
return null;
return await JsonSerializer.DeserializeAsync<OpenIdIntrospection>(await response.Content.ReadAsStreamAsync());
}
}

View File

@@ -0,0 +1,68 @@
using System.Text.Json.Serialization;
namespace HopFrame.Security.Authentication.OpenID.Models;
public sealed class OpenIdConfiguration {
[JsonPropertyName("issuer")]
public string Issuer { get; set; }
[JsonPropertyName("authorization_endpoint")]
public string AuthorizationEndpoint { get; set; }
[JsonPropertyName("token_endpoint")]
public string TokenEndpoint { get; set; }
[JsonPropertyName("userinfo_endpoint")]
public string UserinfoEndpoint { get; set; }
[JsonPropertyName("end_session_endpoint")]
public string EndSessionEndpoint { get; set; }
[JsonPropertyName("introspection_endpoint")]
public string IntrospectionEndpoint { get; set; }
[JsonPropertyName("revocation_endpoint")]
public string RevocationEndpoint { get; set; }
[JsonPropertyName("device_authorization_endpoint")]
public string DeviceAuthorizationEndpoint { get; set; }
[JsonPropertyName("response_types_supported")]
public List<string> ResponseTypesSupported { get; set; }
[JsonPropertyName("response_modes_supported")]
public List<string> ResponseModesSupported { get; set; }
[JsonPropertyName("jwks_uri")]
public string JwksUri { get; set; }
[JsonPropertyName("grant_types_supported")]
public List<string> GrantTypesSupported { get; set; }
[JsonPropertyName("id_token_signing_alg_values_supported")]
public List<string> IdTokenSigningAlgValuesSupported { get; set; }
[JsonPropertyName("subject_types_supported")]
public List<string> SubjectTypesSupported { get; set; }
[JsonPropertyName("token_endpoint_auth_methods_supported")]
public List<string> TokenEndpointAuthMethodsSupported { get; set; }
[JsonPropertyName("acr_values_supported")]
public List<string> AcrValuesSupported { get; set; }
[JsonPropertyName("scopes_supported")]
public List<string> ScopesSupported { get; set; }
[JsonPropertyName("request_parameter_supported")]
public bool RequestParameterSupported { get; set; }
[JsonPropertyName("claims_supported")]
public List<string> ClaimsSupported { get; set; }
[JsonPropertyName("claims_parameter_supported")]
public bool ClaimsParameterSupported { get; set; }
[JsonPropertyName("code_challenge_methods_supported")]
public List<string> CodeChallengeMethodsSupported { get; set; }
}

View File

@@ -0,0 +1,62 @@
using System.Text.Json.Serialization;
namespace HopFrame.Security.Authentication.OpenID.Models;
public sealed class OpenIdIntrospection {
[JsonPropertyName("iss")]
public string Issuer { get; set; }
[JsonPropertyName("sub")]
public string Subject { get; set; }
[JsonPropertyName("aud")]
public string Audience { get; set; }
[JsonPropertyName("exp")]
public long Expiration { get; set; }
[JsonPropertyName("iat")]
public long IssuedAt { get; set; }
[JsonPropertyName("auth_time")]
public long AuthTime { get; set; }
[JsonPropertyName("acr")]
public string Acr { get; set; }
[JsonPropertyName("amr")]
public List<string> AuthenticationMethods { get; set; }
[JsonPropertyName("sid")]
public string SessionId { get; set; }
[JsonPropertyName("email")]
public string Email { get; set; }
[JsonPropertyName("email_verified")]
public bool EmailVerified { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("given_name")]
public string GivenName { get; set; }
[JsonPropertyName("preferred_username")]
public string PreferredUsername { get; set; }
[JsonPropertyName("nickname")]
public string Nickname { get; set; }
[JsonPropertyName("groups")]
public List<string> Groups { get; set; }
[JsonPropertyName("active")]
public bool Active { get; set; }
[JsonPropertyName("scope")]
public string Scope { get; set; }
[JsonPropertyName("client_id")]
public string ClientId { get; set; }
}

View File

@@ -0,0 +1,17 @@
using System.Text.Json.Serialization;
namespace HopFrame.Security.Authentication.OpenID.Models;
public sealed class OpenIdToken {
[JsonPropertyName("access_token")]
public string AccessToken { get; set; }
[JsonPropertyName("token_type")]
public string TokenType { get; set; }
[JsonPropertyName("expires_in")]
public int ExpiresIn { get; set; }
[JsonPropertyName("id_token")]
public string IdToken { get; set; }
}

View File

@@ -0,0 +1,15 @@
using HopFrame.Security.Options;
namespace HopFrame.Security.Authentication.OpenID.Options;
public sealed class OpenIdOptions : OptionsFromConfiguration {
public override string Position { get; } = "HopFrame:Authentication:OpenID";
public bool Enabled { get; set; } = false;
public bool GenerateUsers { get; set; } = true;
public string Issuer { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string Callback { get; set; }
}