using System.Net.Http.Headers; using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.WebUtilities; using w4c_workflows.Models.Credentials; namespace w4c_workflows.Services.Credentials; /// /// Applies a resolved credential to an outbound HTTP request according to its /// type's injection strategy. Returns a human-readable error when the credential /// cannot be injected (unknown type, missing field, unsupported strategy). /// public static class CredentialInjector { public static string? Apply(CredentialData credential, CredentialTypeCatalog catalog, HttpRequestMessage request) { var type = catalog.Get(credential.Type); if (type == null) return $"unknown credential type '{credential.Type}'"; var injection = type.Injection; return injection.Kind switch { CredentialInjectionKind.Basic => ApplyBasic(credential.Data, injection, request), CredentialInjectionKind.Bearer => ApplyBearer(credential.Data, injection, request), CredentialInjectionKind.Header => ApplyHeader(credential.Data, injection, request), CredentialInjectionKind.Query => ApplyQuery(credential.Data, injection, request), CredentialInjectionKind.None => null, _ => $"credential type '{credential.Type}' has an unsupported injection strategy '{injection.Kind}'", }; } private static string? ApplyBasic(JsonObject data, CredentialInjection injection, HttpRequestMessage request) { var username = Read(data, injection.UsernameField); if (string.IsNullOrEmpty(username)) return $"credential is missing '{injection.UsernameField}'"; var password = Read(data, injection.PasswordField) ?? string.Empty; var token = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token); return null; } private static string? ApplyBearer(JsonObject data, CredentialInjection injection, HttpRequestMessage request) { var token = Read(data, injection.TokenField); if (string.IsNullOrEmpty(token)) return $"credential is missing '{injection.TokenField}'"; request.Headers.Authorization = new AuthenticationHeaderValue(injection.Prefix, token); return null; } private static string? ApplyHeader(JsonObject data, CredentialInjection injection, HttpRequestMessage request) { var name = Read(data, injection.NameField); var value = Read(data, injection.ValueField); if (string.IsNullOrEmpty(name) || value == null) return "credential is missing its header name or value"; request.Headers.TryAddWithoutValidation(name, value); return null; } private static string? ApplyQuery(JsonObject data, CredentialInjection injection, HttpRequestMessage request) { var name = Read(data, injection.NameField); var value = Read(data, injection.ValueField); if (string.IsNullOrEmpty(name) || value == null) return "credential is missing its query parameter name or value"; if (request.RequestUri == null) return "cannot inject a query credential without a request URI"; var query = QueryHelpers.AddQueryString(request.RequestUri.ToString(), name, value); request.RequestUri = new Uri(query); return null; } private static string? Read(JsonObject data, string? field) => field != null && data[field] is JsonValue value && value.TryGetValue(out var text) ? text : null; }