< Summary

Information
Class: Elsa.ExternalAuthentication.Endpoints.Connections.ConnectionObservationResponse
Assembly: Elsa.ExternalAuthentication
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.ExternalAuthentication/Endpoints/Connections/ConnectionManagementModels.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 224
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Status()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.ExternalAuthentication/Endpoints/Connections/ConnectionManagementModels.cs

#LineLine coverage
 1using System.Text.Json;
 2using System.Text.Json.Serialization;
 3using Elsa.ExternalAuthentication.Contracts;
 4using Elsa.ExternalAuthentication.Models;
 5using Elsa.ExternalAuthentication.Services;
 6
 7namespace Elsa.ExternalAuthentication.Endpoints.Connections;
 8
 9internal sealed class ConnectionScopeRequest
 10{
 11    public string? Kind { get; set; }
 12    public string? TenantId { get; set; }
 13}
 14
 15internal sealed class ConnectionRequest
 16{
 17    public string? Key { get; set; }
 18    public ConnectionScopeRequest? Scope { get; set; }
 19    public string? AdapterType { get; set; }
 20    public int AdapterSettingsVersion { get; set; }
 21    public JsonElement AdapterSettings { get; set; }
 22    // Accepted only to return a precise error for clients attempting to mutate
 23    // secret references through the general connection document.
 24    public Dictionary<string, SecretBinding>? SecretBindings { get; set; }
 25    public string? DisplayName { get; set; }
 26    public string? IconId { get; set; }
 27    public int Order { get; set; }
 28    public bool IsPreferred { get; set; }
 29    public bool OverridesConfigurationConnection { get; set; }
 30    public PolicySelection? UnlinkedPolicy { get; set; }
 31    public List<GrantSourceSelection>? PermissionGrantSources { get; set; }
 32    public ClaimProjectionRequest? ClaimProjection { get; set; }
 33    [JsonConverter(typeof(UpstreamLogoutModeJsonConverter))]
 34    public UpstreamLogoutMode UpstreamLogoutMode { get; set; }
 35    public bool ConfirmUnsafeSettings { get; set; }
 36    public bool ConfirmFinalLoginPathOverride { get; set; }
 37
 38    public bool HasOnlyHostScope() => Scope is null ||
 39        (string.IsNullOrWhiteSpace(Scope.TenantId) && (string.IsNullOrWhiteSpace(Scope.Kind) || string.Equals(Scope.Kind
 40
 41    public IdentityProviderConnection ToConnection() => new()
 42    {
 43        TenantId = ConnectionScope.HostTenantId,
 44        Key = Key ?? string.Empty,
 45        AdapterType = AdapterType ?? string.Empty,
 46        AdapterSettingsVersion = AdapterSettingsVersion,
 47        AdapterSettings = AdapterSettings.ValueKind == JsonValueKind.Undefined ? default : AdapterSettings.Clone(),
 48        SecretBindings = new Dictionary<string, SecretBinding>(StringComparer.Ordinal),
 49        DisplayName = DisplayName ?? string.Empty,
 50        IconId = IconId,
 51        DisplayOrder = Order,
 52        IsPreferred = IsPreferred,
 53        OverridesConfigurationConnection = OverridesConfigurationConnection,
 54        UnlinkedPolicy = UnlinkedPolicy,
 55        PermissionGrantSources = PermissionGrantSources?.Select(x => new GrantSourceSelection(x.Type, x.SettingsVersion,
 56        ClaimProjection = ClaimProjection?.ToProjection() ?? Elsa.ExternalAuthentication.Models.ClaimProjection.Empty,
 57        UpstreamLogoutMode = UpstreamLogoutMode
 58    };
 59}
 60
 61internal sealed class ClaimProjectionRequest
 62{
 63    public ICollection<string>? AllowedClaimTypes { get; set; }
 64    public ICollection<string>? RedactedClaimTypes { get; set; }
 65    public int MaximumClaimCount { get; set; }
 66    public int MaximumValueLength { get; set; }
 67    public int MaximumTotalBytes { get; set; }
 68
 69    public ClaimProjection ToProjection() => new(
 70        new HashSet<string>(AllowedClaimTypes ?? [], StringComparer.Ordinal),
 71        new HashSet<string>(RedactedClaimTypes ?? [], StringComparer.Ordinal),
 72        MaximumClaimCount,
 73        MaximumValueLength,
 74        MaximumTotalBytes);
 75}
 76
 77internal sealed record ConnectionSecretBindingResponse(string Ownership, string? ResolverType, string? Reference, bool I
 78
 79internal sealed class ManagedSecretBindingRequest
 80{
 81    public string? ResolverType { get; set; }
 82    public string? Value { get; set; }
 83}
 84
 85internal sealed record ConnectionScopeResponse(string Kind, string TenantId);
 86
 87internal sealed class ConnectionResponse
 88{
 89    public string Id { get; init; } = null!;
 90    public string Key { get; init; } = null!;
 91    public string Source { get; init; } = null!;
 92    public ConnectionScopeResponse Scope { get; init; } = null!;
 93    public string AdapterType { get; init; } = null!;
 94    public Uri? CallbackUri { get; init; }
 95    public Uri? PreviewCallbackUri { get; init; }
 96    public int AdapterSettingsVersion { get; init; }
 97    public JsonElement AdapterSettings { get; init; }
 98    public IReadOnlyDictionary<string, ConnectionSecretBindingResponse> SecretBindings { get; init; } = null!;
 99    public string DisplayName { get; init; } = null!;
 100    public string? IconId { get; init; }
 101    public int Order { get; init; }
 102    public bool IsPreferred { get; init; }
 103    public bool OverridesConfigurationConnection { get; init; }
 104    public bool CanCreateOverride { get; init; }
 105    public bool CanPromoteToConfigurationOverride { get; init; }
 106    public bool EnabledIntent { get; init; }
 107    public bool EffectivelyEnabled { get; init; }
 108    public string Validity { get; init; } = null!;
 109    public bool Shadowed { get; init; }
 110    public ConnectionReferenceResponse? ShadowedBy { get; init; }
 111    public IReadOnlyCollection<ConnectionReferenceResponse> Shadows { get; init; } = [];
 112    public bool Archived { get; init; }
 113    public PolicySelection? UnlinkedPolicy { get; init; }
 114    public IReadOnlyCollection<GrantSourceSelection> PermissionGrantSources { get; init; } = [];
 115    public ClaimProjection ClaimProjection { get; init; } = ClaimProjection.Empty;
 116    [JsonConverter(typeof(UpstreamLogoutModeJsonConverter))]
 117    public UpstreamLogoutMode UpstreamLogoutMode { get; init; }
 118    public long Revision { get; init; }
 119    public string MaterialRevision { get; init; } = null!;
 120    public ConnectionObservationResponse? LatestObservation { get; init; }
 121
 122    public static async ValueTask<ConnectionResponse> FromAsync(EffectiveIdentityProviderConnection effective, Services.
 123    {
 124        var states = await management.GetSecretBindingStatesAsync(effective.Connection, cancellationToken);
 125        var adapterSettings = effective.Connection.AdapterSettings.ValueKind == JsonValueKind.Undefined
 126            ? default
 127            : adapters.TryGet(effective.Connection.AdapterType, out var adapter)
 128                ? AdapterSettingsSecretFieldGuard.RedactDeclaredSecrets(effective.Connection.AdapterSettings, adapter.De
 129                : JsonSerializer.SerializeToElement(new Dictionary<string, object?>());
 130        return new ConnectionResponse
 131        {
 132            Id = effective.Connection.Id,
 133            Key = effective.Connection.Key,
 134            Source = effective.Ownership == ConnectionSourceOwnership.Configuration ? "configuration" : "database",
 135            Scope = new ConnectionScopeResponse(effective.Scope.Kind switch { ConnectionScopeKind.Host => "host", Connec
 136            AdapterType = effective.Connection.AdapterType,
 137            CallbackUri = management.GetProviderCallbackUri(effective.Connection),
 138            PreviewCallbackUri = management.GetProviderPreviewCallbackUri(effective.Connection),
 139            AdapterSettingsVersion = effective.Connection.AdapterSettingsVersion,
 140            AdapterSettings = adapterSettings,
 141            SecretBindings = effective.Connection.SecretBindings.ToDictionary(x => x.Key, x =>
 142            {
 143                states.TryGetValue(x.Key, out var state);
 144                var presentation = management.PresentSecretBinding(x.Value, state);
 145                return new ConnectionSecretBindingResponse(
 146                    presentation.Ownership,
 147                    x.Value.Ownership == SecretBindingOwnership.External ? x.Value.ResolverType : null,
 148                    x.Value.Ownership == SecretBindingOwnership.External ? x.Value.Reference : null,
 149                    presentation.IsConfigured,
 150                    presentation.IsResolvable);
 151            }, StringComparer.Ordinal),
 152            DisplayName = effective.Connection.DisplayName,
 153            IconId = effective.Connection.IconId,
 154            Order = effective.Connection.DisplayOrder,
 155            IsPreferred = effective.Connection.IsPreferred,
 156            OverridesConfigurationConnection = effective.Connection.OverridesConfigurationConnection,
 157            CanCreateOverride = effective.Ownership == ConnectionSourceOwnership.Configuration && management.CanCreateCo
 158            CanPromoteToConfigurationOverride = management.CanPromoteToConfigurationOverride(effective),
 159            EnabledIntent = effective.Connection.IsEnabled,
 160            EffectivelyEnabled = effective.Connection.IsEnabled && !effective.Connection.ArchivedAt.HasValue && !effecti
 161            Validity = effective.Validity.ToString().ToLowerInvariant(),
 162            Shadowed = effective.IsShadowed,
 163            ShadowedBy = effective.ShadowedBy is null ? null : ConnectionReferenceResponse.From(effective.ShadowedBy),
 164            Shadows = effective.Shadows.Select(ConnectionReferenceResponse.From).ToArray(),
 165            Archived = effective.Connection.ArchivedAt.HasValue,
 166            UnlinkedPolicy = effective.Connection.UnlinkedPolicy,
 167            PermissionGrantSources = effective.Connection.PermissionGrantSources.ToArray(),
 168            ClaimProjection = effective.Connection.ClaimProjection,
 169            UpstreamLogoutMode = effective.Connection.UpstreamLogoutMode,
 170            Revision = effective.Connection.Revision,
 171            MaterialRevision = effective.Connection.MaterialRevision,
 172            LatestObservation = observation is null
 173                ? null
 174                : new ConnectionObservationResponse(
 175                    observation.Status.ToString().ToLowerInvariant(),
 176                    observation.ObservedAt,
 177                    observation.TestedMaterialRevision,
 178                    !string.Equals(observation.TestedMaterialRevision, effective.Connection.MaterialRevision, StringComp
 179                    observation.Category,
 180                    observation.Summary)
 181        };
 182    }
 183
 184}
 185
 186internal sealed class UpstreamLogoutModeJsonConverter : JsonConverter<UpstreamLogoutMode>
 187{
 188    public override UpstreamLogoutMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options
 189    {
 190        if (reader.TokenType != JsonTokenType.String)
 191            throw new JsonException("The upstream logout mode must be a string.");
 192
 193        return reader.GetString()?.ToLowerInvariant() switch
 194        {
 195            "disabled" => UpstreamLogoutMode.Disabled,
 196            "userchoice" or "user-choice" or "user_choice" => UpstreamLogoutMode.UserChoice,
 197            "always" => UpstreamLogoutMode.Always,
 198            _ => throw new JsonException("The upstream logout mode is not supported.")
 199        };
 200    }
 201
 202    public override void Write(Utf8JsonWriter writer, UpstreamLogoutMode value, JsonSerializerOptions options) =>
 203        writer.WriteStringValue(value switch
 204        {
 205            UpstreamLogoutMode.Disabled => "disabled",
 206            UpstreamLogoutMode.UserChoice => "user-choice",
 207            UpstreamLogoutMode.Always => "always",
 208            _ => throw new JsonException("The upstream logout mode is not supported.")
 209        });
 210}
 211
 212internal sealed record ConnectionReferenceResponse(string Id, string DisplayName, string Source)
 213{
 214    public static ConnectionReferenceResponse From(IdentityProviderConnectionReference reference) =>
 215        new(
 216            reference.Id,
 217            reference.DisplayName,
 218            reference.Ownership == ConnectionSourceOwnership.Configuration ? "configuration" : "database");
 219}
 220
 14221internal sealed record ConnectionObservationResponse(string Status, DateTimeOffset ObservedAt, string TestedMaterialRevi
 222internal sealed record ConnectionValidationResponse(bool Valid, IReadOnlyCollection<ConnectionValidationError> Errors, I
 223internal sealed record ConnectionListResponse(IReadOnlyCollection<ConnectionResponse> Items, string? NextCursor);
 224internal sealed record ManagementErrorResponse(string Error, string Message, object? Details, string CorrelationId);

Methods/Properties

get_Status()