147 lines
6.6 KiB
C#
147 lines
6.6 KiB
C#
|
|
using Refit;
|
||
|
|
|
||
|
|
namespace OTSSignsOrchestrator.Server.Clients;
|
||
|
|
|
||
|
|
// ── Configuration ───────────────────────────────────────────────────────────
|
||
|
|
public sealed class AuthentikOptions
|
||
|
|
{
|
||
|
|
public const string Section = "Authentik";
|
||
|
|
|
||
|
|
public string BaseUrl { get; set; } = string.Empty;
|
||
|
|
public string ApiToken { get; set; } = string.Empty;
|
||
|
|
|
||
|
|
/// <summary>UUID of the OTS signing certificate-key pair used for all SAML sources.</summary>
|
||
|
|
public string OtsSigningKpId { get; set; } = string.Empty;
|
||
|
|
|
||
|
|
/// <summary>Authentik pre-authentication flow slug for SAML sources (e.g. "default-source-pre-authentication").</summary>
|
||
|
|
public string SourcePreAuthFlowSlug { get; set; } = "default-source-pre-authentication";
|
||
|
|
|
||
|
|
/// <summary>Authentik authentication flow slug for SAML sources (e.g. "default-source-authentication").</summary>
|
||
|
|
public string SourceAuthFlowSlug { get; set; } = "default-source-authentication";
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Request DTOs ────────────────────────────────────────────────────────────
|
||
|
|
public record CreateSamlProviderRequest(
|
||
|
|
string Name,
|
||
|
|
string AuthorizationFlow,
|
||
|
|
string AcsUrl,
|
||
|
|
string Issuer,
|
||
|
|
string SpBinding,
|
||
|
|
string Audience,
|
||
|
|
string? SigningKp);
|
||
|
|
|
||
|
|
public record CreateAuthentikApplicationRequest(
|
||
|
|
string Name,
|
||
|
|
string Slug,
|
||
|
|
string Provider,
|
||
|
|
string? MetaLaunchUrl);
|
||
|
|
|
||
|
|
public record CreateAuthentikGroupRequest(
|
||
|
|
string Name,
|
||
|
|
bool? IsSuperuser,
|
||
|
|
string? Parent);
|
||
|
|
|
||
|
|
public record CreateFlowRequest(
|
||
|
|
string Name,
|
||
|
|
bool? SingleUse,
|
||
|
|
DateTimeOffset? Expires);
|
||
|
|
|
||
|
|
public record CreateAuthentikUserRequest(
|
||
|
|
string Username,
|
||
|
|
string Name,
|
||
|
|
string Email,
|
||
|
|
string[] Groups);
|
||
|
|
|
||
|
|
public record ImportCertRequest(
|
||
|
|
string Name,
|
||
|
|
string CertificateData,
|
||
|
|
string? KeyData);
|
||
|
|
|
||
|
|
public record CreateSamlSourceRequest(
|
||
|
|
string Name,
|
||
|
|
string Slug,
|
||
|
|
string SsoUrl,
|
||
|
|
string? SloUrl,
|
||
|
|
string Issuer,
|
||
|
|
string? SigningKp,
|
||
|
|
string? VerificationKp,
|
||
|
|
string BindingType,
|
||
|
|
string NameIdPolicy,
|
||
|
|
string PreAuthenticationFlow,
|
||
|
|
string AuthenticationFlow,
|
||
|
|
bool AllowIdpInitiated);
|
||
|
|
|
||
|
|
// ── Response DTOs ───────────────────────────────────────────────────────────
|
||
|
|
/// <summary>Authentik paginated list response. Results contain dictionaries with entity fields.</summary>
|
||
|
|
public record AuthentikPagedResult(
|
||
|
|
List<Dictionary<string, object>> Results);
|
||
|
|
|
||
|
|
// ── Authentik Refit Interface ───────────────────────────────────────────────
|
||
|
|
// One global Authentik instance serves all tenants.
|
||
|
|
[Headers("Authorization: Bearer")]
|
||
|
|
public interface IAuthentikClient
|
||
|
|
{
|
||
|
|
// ── SAML Providers ──────────────────────────────────────────────────────
|
||
|
|
[Post("/api/v3/providers/saml/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateSamlProviderAsync(
|
||
|
|
[Body] CreateSamlProviderRequest body);
|
||
|
|
|
||
|
|
[Get("/api/v3/providers/saml/{id}/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> GetSamlProviderAsync(int id);
|
||
|
|
|
||
|
|
[Delete("/api/v3/providers/saml/{id}/")]
|
||
|
|
Task DeleteSamlProviderAsync(int id);
|
||
|
|
|
||
|
|
// ── Applications ────────────────────────────────────────────────────────
|
||
|
|
[Post("/api/v3/core/applications/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateApplicationAsync(
|
||
|
|
[Body] CreateAuthentikApplicationRequest body);
|
||
|
|
|
||
|
|
[Delete("/api/v3/core/applications/{slug}/")]
|
||
|
|
Task DeleteApplicationAsync(string slug);
|
||
|
|
|
||
|
|
// ── Groups ──────────────────────────────────────────────────────────────
|
||
|
|
[Get("/api/v3/core/groups/")]
|
||
|
|
Task<ApiResponse<AuthentikPagedResult>> ListGroupsAsync([AliasAs("search")] string? search = null);
|
||
|
|
|
||
|
|
[Post("/api/v3/core/groups/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateGroupAsync(
|
||
|
|
[Body] CreateAuthentikGroupRequest body);
|
||
|
|
|
||
|
|
[Delete("/api/v3/core/groups/{id}/")]
|
||
|
|
Task DeleteGroupAsync(string id);
|
||
|
|
|
||
|
|
// ── Invitations ─────────────────────────────────────────────────────────
|
||
|
|
[Post("/api/v3/stages/invitation/invitations/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateInvitationAsync(
|
||
|
|
[Body] CreateFlowRequest body);
|
||
|
|
|
||
|
|
// ── Users ───────────────────────────────────────────────────────────────
|
||
|
|
[Post("/api/v3/core/users/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateUserAsync(
|
||
|
|
[Body] CreateAuthentikUserRequest body);
|
||
|
|
|
||
|
|
// ── Health ──────────────────────────────────────────────────────────────
|
||
|
|
[Get("/api/v3/-/health/ready/")]
|
||
|
|
Task<ApiResponse<object>> CheckHealthAsync();
|
||
|
|
|
||
|
|
// ── Certificates ────────────────────────────────────────────────────────
|
||
|
|
[Get("/api/v3/crypto/certificatekeypairs/{kpId}/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> GetCertificateKeyPairAsync(string kpId);
|
||
|
|
|
||
|
|
[Post("/api/v3/crypto/certificatekeypairs/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> ImportCertificateAsync(
|
||
|
|
[Body] ImportCertRequest body);
|
||
|
|
|
||
|
|
// ── SAML Sources ────────────────────────────────────────────────────────
|
||
|
|
[Post("/api/v3/sources/saml/")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateSamlSourceAsync(
|
||
|
|
[Body] CreateSamlSourceRequest body);
|
||
|
|
|
||
|
|
[Get("/api/v3/sources/saml/{slug}/metadata/")]
|
||
|
|
Task<ApiResponse<string>> GetSamlSourceMetadataAsync(string slug);
|
||
|
|
|
||
|
|
[Delete("/api/v3/sources/saml/{slug}/")]
|
||
|
|
Task DeleteSamlSourceAsync(string slug);
|
||
|
|
}
|