using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Identity.Web; using Shogi.Api.Extensions; using Shogi.Api.Models; using Shogi.Api.Repositories; using System.Security.Claims; namespace Shogi.Api; /// /// Standardizes the claims from third party issuers. Also registers new msal users in the database. /// public class ShogiUserClaimsTransformer : IShogiUserClaimsTransformer { private readonly IUserRepository userRepository; public ShogiUserClaimsTransformer(IUserRepository userRepository) { this.userRepository = userRepository; } public async Task TransformAsync(ClaimsPrincipal principal) { var newPrincipal = principal.IsMicrosoft() ? await CreateClaimsFromMicrosoftPrincipal(principal) : await CreateClaimsFromGuestPrincipal(principal); return newPrincipal; } public async Task CreateClaimsFromGuestPrincipal(ClaimsPrincipal principal) { var id = principal.GetGuestUserId(); if (string.IsNullOrWhiteSpace(id)) { var newUser = User.CreateGuestUser(Guid.NewGuid().ToString()); await this.userRepository.CreateUser(newUser); return new ClaimsPrincipal(CreateClaimsIdentity(newUser)); } var user = await this.userRepository.ReadUser(id); if (user == null) throw new UnauthorizedAccessException("Guest account does not exist."); return new ClaimsPrincipal(CreateClaimsIdentity(user)); } private async Task CreateClaimsFromMicrosoftPrincipal(ClaimsPrincipal principal) { var id = principal.GetMsalAccountId(); if (string.IsNullOrWhiteSpace(id)) { throw new UnauthorizedAccessException("Found MSAL claims but no preferred_username."); } var user = await this.userRepository.ReadUser(id); if (user == null) { user = User.CreateMsalUser(id); await this.userRepository.CreateUser(user); } return new ClaimsPrincipal(CreateClaimsIdentity(user)); } private static ClaimsIdentity CreateClaimsIdentity(User user) { var claims = new List(4) { new Claim(ClaimTypes.NameIdentifier, user.Id), new Claim(ClaimTypes.Name, user.DisplayName), }; if (user.LoginPlatform == WhichLoginPlatform.Guest) { claims.Add(new Claim(ClaimTypes.Role, "Guest")); return new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); } else { return new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme); } } } public interface IShogiUserClaimsTransformer : IClaimsTransformation { Task CreateClaimsFromGuestPrincipal(ClaimsPrincipal principal); }