using FluentResults; using IdentityShroud.Api.Mappers; using IdentityShroud.Api.Validation; using IdentityShroud.Core.Messages; using IdentityShroud.Core.Messages.Realm; using IdentityShroud.Core.Model; using IdentityShroud.Core.Services; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; namespace IdentityShroud.Api; public static class HttpContextExtensions { public static Realm GetValidatedRealm(this HttpContext context) => (Realm)context.Items["RealmEntity"]!; } public static class RealmApi { public static void MapRealmEndpoints(this IEndpointRouteBuilder app) { var realmsGroup = app.MapGroup("/realms"); realmsGroup.MapPost("", RealmCreate) .Validate() .WithName("Create Realm") .Produces(StatusCodes.Status201Created); var realmSlugGroup = realmsGroup.MapGroup("{slug}") .AddEndpointFilter(); realmSlugGroup.MapGet(".well-known/openid-configuration", GetOpenIdConfiguration); var openidConnect = realmSlugGroup.MapGroup("openid-connect"); openidConnect.MapPost("auth", OpenIdConnectAuth); openidConnect.MapPost("token", OpenIdConnectToken); openidConnect.MapGet("jwks", OpenIdConnectJwks); } private static async Task, InternalServerError>> RealmCreate(RealmCreateRequest request, [FromServices] IRealmService service) { var response = await service.Create(request); if (response.IsSuccess) return TypedResults.Created($"/realms/{response.Value.Slug}", response.Value); // TODO make helper to convert failure response to a proper HTTP result. return TypedResults.InternalServerError(); } private static async Task, BadRequest>> OpenIdConnectJwks( string slug, [FromServices]IRealmService realmService, [FromServices]KeyMapper keyMapper, HttpContext context) { Realm realm = context.GetValidatedRealm(); await realmService.LoadActiveKeys(realm); return TypedResults.Ok(keyMapper.KeyListToJsonWebKeySet(realm.Keys)); } private static Task OpenIdConnectToken(HttpContext context) { throw new NotImplementedException(); } private static Task OpenIdConnectAuth(HttpContext context) { throw new NotImplementedException(); } private static async Task> GetOpenIdConfiguration( string slug, [FromServices]IRealmService realmService, HttpContext context) { Realm realm = context.GetValidatedRealm(); var s = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}"; var searchString = $"realms/{slug}"; int index = s.IndexOf(searchString, StringComparison.OrdinalIgnoreCase); string baseUri = s.Substring(0, index + searchString.Length); return TypedResults.Json(new OpenIdConfiguration() { AuthorizationEndpoint = baseUri + "/openid-connect/auth", TokenEndpoint = baseUri + "/openid-connect/token", Issuer = baseUri, JwksUri = baseUri + "/openid-connect/jwks", }, AppJsonSerializerContext.Default.OpenIdConfiguration); } }