diff --git a/Gameboard.ShogiUI.Sockets/Controllers/GameController.cs b/Gameboard.ShogiUI.Sockets/Controllers/GameController.cs index 3a1618a..ef5f6e1 100644 --- a/Gameboard.ShogiUI.Sockets/Controllers/GameController.cs +++ b/Gameboard.ShogiUI.Sockets/Controllers/GameController.cs @@ -176,7 +176,7 @@ namespace Gameboard.ShogiUI.Sockets.Controllers } [HttpGet] - public async Task GetSessions() + public async Task> GetSessions() { var user = await ReadUserOrThrow(); var sessions = await gameboardRepository.ReadSessionMetadatas(); @@ -190,11 +190,11 @@ namespace Gameboard.ShogiUI.Sockets.Controllers .Select(s => mapper.Map(s)) .ToList(); - return new GetSessionsResponse + return Ok(new GetSessionsResponse { PlayerHasJoinedSessions = sessionsJoinedByUser, AllOtherSessions = sessionsNotJoinedByUser - }; + }); } [HttpPut("{gameName}")] diff --git a/Gameboard.ShogiUI.Sockets/Extensions/Extensions.cs b/Gameboard.ShogiUI.Sockets/Extensions/Extensions.cs index ca6dc5c..d687b10 100644 --- a/Gameboard.ShogiUI.Sockets/Extensions/Extensions.cs +++ b/Gameboard.ShogiUI.Sockets/Extensions/Extensions.cs @@ -1,28 +1,29 @@ -using System.Linq; -using System.Security.Claims; +using System.Security.Claims; namespace Gameboard.ShogiUI.Sockets.Extensions { - public static class Extensions - { - public static string? UserId(this ClaimsPrincipal self) - { - return self.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; - } + public static class Extensions + { + private static readonly string MsalUsernameClaim = "preferred_username"; - public static string? DisplayName(this ClaimsPrincipal self) - { - return self.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value; - } + public static string? UserId(this ClaimsPrincipal self) + { + return self.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; + } - public static bool IsGuest(this ClaimsPrincipal self) - { - return self.HasClaim(c => c.Type == ClaimTypes.Role && c.Value == "Guest"); - } + public static string? DisplayName(this ClaimsPrincipal self) + { + return self.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value; + } - public static string ToCamelCase(this string self) - { - return char.ToLowerInvariant(self[0]) + self[1..]; - } - } + public static bool IsMicrosoft(this ClaimsPrincipal self) + { + return self.HasClaim(c => c.Type == MsalUsernameClaim); + } + + public static string ChangeFirstCharacterToLowerCase(this string self) + { + return char.ToLowerInvariant(self[0]) + self[1..]; + } + } } diff --git a/Gameboard.ShogiUI.Sockets/Managers/GameboardManager.cs b/Gameboard.ShogiUI.Sockets/Managers/GameboardManager.cs index 9ca34c1..fe315f4 100644 --- a/Gameboard.ShogiUI.Sockets/Managers/GameboardManager.cs +++ b/Gameboard.ShogiUI.Sockets/Managers/GameboardManager.cs @@ -31,9 +31,9 @@ namespace Gameboard.ShogiUI.Sockets.Managers throw new InvalidOperationException("Cannot create user from given claims."); } - var user = principal.IsGuest() - ? User.CreateGuestUser(id) - : User.CreateMsalUser(id); + var user = principal.IsMicrosoft() + ? User.CreateMsalUser(id) + : User.CreateGuestUser(id); await repository.CreateUser(user); return user; diff --git a/Gameboard.ShogiUI.Sockets/Models/User.cs b/Gameboard.ShogiUI.Sockets/Models/User.cs index e633524..ebc2da0 100644 --- a/Gameboard.ShogiUI.Sockets/Models/User.cs +++ b/Gameboard.ShogiUI.Sockets/Models/User.cs @@ -1,8 +1,6 @@ using Gameboard.ShogiUI.Sockets.Repositories.CouchModels; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.JwtBearer; -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Security.Claims; @@ -62,7 +60,6 @@ namespace Gameboard.ShogiUI.Sockets.Models new Claim(ClaimTypes.NameIdentifier, Id), new Claim(ClaimTypes.Name, DisplayName), new Claim(ClaimTypes.Role, "Guest"), - new Claim(ClaimTypes.Role, "Shogi") // The Shogi role grants access to api controllers. }; return new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); } @@ -72,7 +69,6 @@ namespace Gameboard.ShogiUI.Sockets.Models { new Claim(ClaimTypes.NameIdentifier, Id), new Claim(ClaimTypes.Name, DisplayName), - new Claim(ClaimTypes.Role, "Shogi") // The Shogi role grants access to api controllers. }; return new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme); } diff --git a/Gameboard.ShogiUI.Sockets/Program.cs b/Gameboard.ShogiUI.Sockets/Program.cs index db0ad07..749546a 100644 --- a/Gameboard.ShogiUI.Sockets/Program.cs +++ b/Gameboard.ShogiUI.Sockets/Program.cs @@ -169,7 +169,7 @@ namespace Gameboard.ShogiUI.Sockets services.AddSingleton, JoinGameRequestValidator>(); services.AddSingleton(); services.AddTransient(); - services.AddSingleton(); + services.AddTransient(); services.AddHttpClient("couchdb", c => { var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes("admin:admin")); diff --git a/Gameboard.ShogiUI.Sockets/ShogiUserClaimsTransformer.cs b/Gameboard.ShogiUI.Sockets/ShogiUserClaimsTransformer.cs index 766efa6..c2b5977 100644 --- a/Gameboard.ShogiUI.Sockets/ShogiUserClaimsTransformer.cs +++ b/Gameboard.ShogiUI.Sockets/ShogiUserClaimsTransformer.cs @@ -1,43 +1,44 @@ -using Gameboard.ShogiUI.Sockets.Repositories; +using Gameboard.ShogiUI.Sockets.Extensions; +using Gameboard.ShogiUI.Sockets.Repositories; using Microsoft.AspNetCore.Authentication; -using System.Linq; using System.Security.Claims; -using System.Threading.Tasks; namespace Gameboard.ShogiUI.Sockets { - /// - /// Standardizes the claims from third party issuers. Also registers new msal users in the database. - /// - public class ShogiUserClaimsTransformer : IClaimsTransformation - { - private static readonly string MsalUsernameClaim = "preferred_username"; - private readonly IGameboardRepository gameboardRepository; + /// + /// Standardizes the claims from third party issuers. Also registers new msal users in the database. + /// + public class ShogiUserClaimsTransformer : IClaimsTransformation + { + private readonly IGameboardRepository gameboardRepository; - public ShogiUserClaimsTransformer(IGameboardRepository gameboardRepository) - { - this.gameboardRepository = gameboardRepository; - } + public ShogiUserClaimsTransformer(IGameboardRepository gameboardRepository) + { + this.gameboardRepository = gameboardRepository; + } - public async Task TransformAsync(ClaimsPrincipal principal) - { - var nameClaim = principal.Claims.FirstOrDefault(c => c.Type == MsalUsernameClaim); - if (nameClaim != default) - { - var user = await gameboardRepository.ReadUser(nameClaim.Value); - if (user == null) - { - var newUser = Models.User.CreateMsalUser(nameClaim.Value); - await gameboardRepository.CreateUser(newUser); - user = newUser; - } + public async Task TransformAsync(ClaimsPrincipal principal) + { + var id = principal.UserId(); + if (!string.IsNullOrWhiteSpace(id)) + { + var user = await gameboardRepository.ReadUser(id); + if (user == null) + { + var newUser = principal.IsMicrosoft() + ? Models.User.CreateMsalUser(id) + : Models.User.CreateGuestUser(id); - if (user != null) - { - return new ClaimsPrincipal(user.CreateClaimsIdentity()); - } - } - return principal; - } - } + await gameboardRepository.CreateUser(newUser); + user = newUser; + } + + if (user != null) + { + return new ClaimsPrincipal(user.CreateClaimsIdentity()); + } + } + return principal; + } + } } diff --git a/Shogi.AcceptanceTests/Shogi.AcceptanceTests.csproj b/Shogi.AcceptanceTests/Shogi.AcceptanceTests.csproj index 554316d..601141f 100644 --- a/Shogi.AcceptanceTests/Shogi.AcceptanceTests.csproj +++ b/Shogi.AcceptanceTests/Shogi.AcceptanceTests.csproj @@ -1,43 +1,44 @@  - - net6.0 - enable - enable + + net6.0 + enable + enable - false - 96d6281d-a75b-4181-b535-ea34b26dc8a2 - + false + 96d6281d-a75b-4181-b535-ea34b26dc8a2 + true + - - - + + + - - - PreserveNewest - - + + + PreserveNewest + + - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + diff --git a/Shogi.AcceptanceTests/TestSetup/AATFixture.cs b/Shogi.AcceptanceTests/TestSetup/AATFixture.cs index 719751c..5681b89 100644 --- a/Shogi.AcceptanceTests/TestSetup/AATFixture.cs +++ b/Shogi.AcceptanceTests/TestSetup/AATFixture.cs @@ -44,9 +44,6 @@ namespace Shogi.AcceptanceTests.TestSetup authResult.AccessToken.Should().NotBeNullOrEmpty(); Service.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); - - var response = await Service.GetAsync("Socket/Token"); - response.IsSuccessStatusCode.Should().BeTrue(because: "AAT client should create an account for tests."); } protected virtual void Dispose(bool disposing) diff --git a/Shogi.Domain.UnitTests/Shogi.Domain.UnitTests.csproj b/Shogi.Domain.UnitTests/Shogi.Domain.UnitTests.csproj index 724e08f..76e3c8e 100644 --- a/Shogi.Domain.UnitTests/Shogi.Domain.UnitTests.csproj +++ b/Shogi.Domain.UnitTests/Shogi.Domain.UnitTests.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive