namespace EntKube.Web.Components.Provisioning; /// /// BFF proxy endpoints for Keycloak realm management. The Blazor frontend calls these /// endpoints, and the BFF forwards requests to the Provisioning microservice. /// public static class KeycloakRealmProxyEndpoints { public static void Map(IEndpointRouteBuilder app) { RouteGroupBuilder group = app.MapGroup("/api/keycloak-realms") .RequireAuthorization() .DisableAntiforgery(); // GET /api/keycloak-realms/cluster/{clusterId} — list realms for a cluster. group.MapGet("cluster/{clusterId:guid}", async (Guid clusterId, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); HttpResponseMessage response = await client.GetAsync($"/api/keycloak-realms/cluster/{clusterId}", ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // GET /api/keycloak-realms/{id} — get a single realm. group.MapGet("{id:guid}", async (Guid id, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); HttpResponseMessage response = await client.GetAsync($"/api/keycloak-realms/{id}", ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // POST /api/keycloak-realms — create a new realm. group.MapPost("", async (HttpContext httpContext, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); StreamContent content = new(httpContext.Request.Body); content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse( httpContext.Request.ContentType ?? "application/json"); HttpResponseMessage response = await client.PostAsync("/api/keycloak-realms", content, ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // DELETE /api/keycloak-realms/{id} — delete a realm. group.MapDelete("{id:guid}", async (Guid id, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); HttpResponseMessage response = await client.DeleteAsync($"/api/keycloak-realms/{id}", ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // PUT /api/keycloak-realms/{id}/branding — update realm branding. group.MapPut("{id:guid}/branding", async (Guid id, HttpContext httpContext, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); StreamContent content = new(httpContext.Request.Body); content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse( httpContext.Request.ContentType ?? "application/json"); HttpResponseMessage response = await client.PutAsync($"/api/keycloak-realms/{id}/branding", content, ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // PUT /api/keycloak-realms/{id}/pages — update realm pages config. group.MapPut("{id:guid}/pages", async (Guid id, HttpContext httpContext, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); StreamContent content = new(httpContext.Request.Body); content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse( httpContext.Request.ContentType ?? "application/json"); HttpResponseMessage response = await client.PutAsync($"/api/keycloak-realms/{id}/pages", content, ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // POST /api/keycloak-realms/{id}/identity-providers — add identity provider. group.MapPost("{id:guid}/identity-providers", async (Guid id, HttpContext httpContext, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); StreamContent content = new(httpContext.Request.Body); content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse( httpContext.Request.ContentType ?? "application/json"); HttpResponseMessage response = await client.PostAsync($"/api/keycloak-realms/{id}/identity-providers", content, ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // DELETE /api/keycloak-realms/{id}/identity-providers/{alias} — remove identity provider. group.MapDelete("{id:guid}/identity-providers/{alias}", async (Guid id, string alias, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); HttpResponseMessage response = await client.DeleteAsync($"/api/keycloak-realms/{id}/identity-providers/{alias}", ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // POST /api/keycloak-realms/{id}/organizations — add organization. group.MapPost("{id:guid}/organizations", async (Guid id, HttpContext httpContext, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); StreamContent content = new(httpContext.Request.Body); content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse( httpContext.Request.ContentType ?? "application/json"); HttpResponseMessage response = await client.PostAsync($"/api/keycloak-realms/{id}/organizations", content, ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); // DELETE /api/keycloak-realms/{id}/organizations/{name} — remove organization. group.MapDelete("{id:guid}/organizations/{name}", async (Guid id, string name, IHttpClientFactory httpClientFactory, CancellationToken ct) => { HttpClient client = httpClientFactory.CreateClient("ProvisioningApi"); HttpResponseMessage response = await client.DeleteAsync($"/api/keycloak-realms/{id}/organizations/{name}", ct); string body = await response.Content.ReadAsStringAsync(ct); return Results.Text(body, "application/json", statusCode: (int)response.StatusCode); }); } }