Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SecurityService.BusinessLogic/Oidc/OidcCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ public sealed record VerifyGetQuery(HttpContext HttpContext) : IRequest<Result<V
public sealed record VerifyPostCommand(HttpContext HttpContext, string Action, string UserCode) : IRequest<Result<VerifyPostCommandResult>>;
public sealed record ConsentGetQuery(HttpContext HttpContext, string ReturnUrl) : IRequest<Result<ConsentGetQueryResult>>;
public sealed record ConsentPostCommand(string ReturnUrl, string Button, IReadOnlyCollection<string> SelectedScopes) : IRequest<Result<ConsentPostCommandResult>>;
public sealed record DiagnosticsQuery(HttpContext HttpContext) : IRequest<Result<DiagnosticsQueryResult>>;
}
14 changes: 14 additions & 0 deletions SecurityService.BusinessLogic/Oidc/OidcResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,17 @@ public abstract record ConsentPostCommandResult;
public sealed record ConsentPostRedirectResult(string Url) : ConsentPostCommandResult;

public sealed record ConsentPostPageResult(string ModelError) : ConsentPostCommandResult;

// ---- Diagnostics endpoint ----

public abstract record DiagnosticsQueryResult;

public sealed record DiagnosticsPageResult(
IReadOnlyCollection<DiagnosticItem> Claims,
IReadOnlyCollection<DiagnosticItem> Properties) : DiagnosticsQueryResult;

public sealed record DiagnosticsNotFoundResult : DiagnosticsQueryResult;

public sealed record DiagnosticsChallengeResult(string AuthenticationScheme) : DiagnosticsQueryResult;

public sealed record DiagnosticItem(string Type, string Value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Net;
using MediatR;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using SecurityService.BusinessLogic.Oidc;
using SimpleResults;

namespace SecurityService.BusinessLogic.RequestHandlers;

public sealed class DiagnosticsRequestHandler :
IRequestHandler<OidcCommands.DiagnosticsQuery, Result<DiagnosticsQueryResult>>
{
public async Task<Result<DiagnosticsQueryResult>> Handle(OidcCommands.DiagnosticsQuery query, CancellationToken cancellationToken)
{
var context = query.HttpContext;

if (context.Connection.RemoteIpAddress is { } remoteIpAddress &&
IPAddress.IsLoopback(remoteIpAddress) == false)
{
return Result.Success<DiagnosticsQueryResult>(new DiagnosticsNotFoundResult());
}

var result = await context.AuthenticateAsync(IdentityConstants.ApplicationScheme);
if (result.Succeeded == false || result.Principal is null)
{
return Result.Success<DiagnosticsQueryResult>(new DiagnosticsChallengeResult(IdentityConstants.ApplicationScheme));
}

var claims = result.Principal.Claims
.Select(claim => new DiagnosticItem(claim.Type, claim.Value))
.OrderBy(item => item.Type, StringComparer.OrdinalIgnoreCase)
.ToArray();

var properties = result.Properties?.Items
.OrderBy(item => item.Key, StringComparer.OrdinalIgnoreCase)
.Select(item => new DiagnosticItem(item.Key, item.Value ?? string.Empty))
.ToArray() ?? Array.Empty<DiagnosticItem>();

return Result.Success<DiagnosticsQueryResult>(new DiagnosticsPageResult(claims, properties));
}
}
46 changes: 22 additions & 24 deletions SecurityService/Pages/Diagnostics/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
using System.Net;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using SecurityService.BusinessLogic.Oidc;

namespace SecurityService.Pages.Diagnostics;

public sealed class IndexModel : PageModel
{
private readonly IMediator _mediator;

public IndexModel(IMediator mediator)
{
this._mediator = mediator;
}

public IReadOnlyCollection<DiagnosticItem> Claims { get; private set; } = Array.Empty<DiagnosticItem>();

public IReadOnlyCollection<DiagnosticItem> Properties { get; private set; } = Array.Empty<DiagnosticItem>();

public async Task<IActionResult> OnGetAsync()
public async Task<IActionResult> OnGetAsync(CancellationToken cancellationToken)
{
if (this.Request.HttpContext.Connection.RemoteIpAddress is { } remoteIpAddress &&
IPAddress.IsLoopback(remoteIpAddress) == false)
{
return this.NotFound();
}
var result = await this._mediator.Send(new OidcCommands.DiagnosticsQuery(this.HttpContext), cancellationToken);

var result = await this.HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
if (result.Succeeded == false || result.Principal is null)
return result.Data switch
{
return this.Challenge(IdentityConstants.ApplicationScheme);
}

this.Claims = result.Principal.Claims
.Select(claim => new DiagnosticItem(claim.Type, claim.Value))
.OrderBy(item => item.Type, StringComparer.OrdinalIgnoreCase)
.ToArray();

this.Properties = result.Properties?.Items
.OrderBy(item => item.Key, StringComparer.OrdinalIgnoreCase)
.Select(item => new DiagnosticItem(item.Key, item.Value ?? string.Empty))
.ToArray() ?? Array.Empty<DiagnosticItem>();
DiagnosticsNotFoundResult => this.NotFound(),
DiagnosticsChallengeResult challenge => this.Challenge(challenge.AuthenticationScheme),
DiagnosticsPageResult page => this.ApplyPageResult(page),
_ => this.Page()
};
}

private IActionResult ApplyPageResult(DiagnosticsPageResult page)
{
this.Claims = page.Claims;
this.Properties = page.Properties;
return this.Page();
}
}

public sealed record DiagnosticItem(string Type, string Value);
Loading