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);
}