using System.Security.Claims; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using ZB.MOM.WW.OtOpcUa.Security.Jwt; using ZB.MOM.WW.OtOpcUa.Security.Ldap; namespace ZB.MOM.WW.OtOpcUa.Security.Endpoints; public static class AuthEndpoints { public sealed record LoginRequest(string Username, string Password); public sealed record TokenResponse(string Token); public static IEndpointRouteBuilder MapOtOpcUaAuth(this IEndpointRouteBuilder app) { app.MapPost("/auth/login", (Delegate)LoginAsync).AllowAnonymous(); app.MapGet("/auth/ping", (Delegate)Ping).AllowAnonymous(); app.MapPost("/auth/token", (Delegate)IssueToken).RequireAuthorization(); app.MapPost("/auth/logout", (Delegate)LogoutAsync).RequireAuthorization(); return app; } private static async Task LoginAsync( LoginRequest request, HttpContext http, ILdapAuthService ldap, CancellationToken ct) { LdapAuthResult result; try { result = await ldap.AuthenticateAsync(request.Username, request.Password, ct); } catch (Exception) { return Results.StatusCode(StatusCodes.Status503ServiceUnavailable); } if (!result.Success) return Results.Unauthorized(); var claims = new List { new(ClaimTypes.NameIdentifier, result.Username ?? request.Username), new(JwtTokenService.UsernameClaimType, result.Username ?? request.Username), new(JwtTokenService.DisplayNameClaimType, result.DisplayName ?? request.Username), }; foreach (var role in result.Roles) claims.Add(new Claim(ClaimTypes.Role, role)); var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var principal = new ClaimsPrincipal(identity); await http.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); return Results.NoContent(); } private static IResult Ping(HttpContext http) => http.User.Identity?.IsAuthenticated == true ? Results.Ok() : Results.Unauthorized(); private static IResult IssueToken(HttpContext http, JwtTokenService jwt) { var user = http.User; var username = user.FindFirst(JwtTokenService.UsernameClaimType)?.Value ?? user.Identity?.Name ?? string.Empty; var displayName = user.FindFirst(JwtTokenService.DisplayNameClaimType)?.Value ?? username; var roles = user.FindAll(ClaimTypes.Role).Select(c => c.Value).ToArray(); return Results.Ok(new TokenResponse(jwt.Issue(displayName, username, roles))); } private static async Task LogoutAsync(HttpContext http) { await http.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Results.NoContent(); } }