From 61df26b6678a567333d3c9d145e3bd9229249c5e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 3 Aug 2023 11:48:59 -0400 Subject: [PATCH] fix #3082 - handle username claim as "unique_name" with "name" as fallback, improve validation logic and logging --- .../Middleware/JwtMiddleware.cs | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/Oqtane.Server/Infrastructure/Middleware/JwtMiddleware.cs b/Oqtane.Server/Infrastructure/Middleware/JwtMiddleware.cs index f0e65998..40a43841 100644 --- a/Oqtane.Server/Infrastructure/Middleware/JwtMiddleware.cs +++ b/Oqtane.Server/Infrastructure/Middleware/JwtMiddleware.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Oqtane.Extensions; using Oqtane.Models; +using Oqtane.Modules.Admin.Roles; using Oqtane.Repository; using Oqtane.Security; using Oqtane.Shared; @@ -37,20 +38,46 @@ namespace Oqtane.Infrastructure var identity = jwtManager.ValidateToken(token, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", "")); if (identity != null && identity.Claims.Any()) { - // create user identity using jwt claims (note the difference in claimtype names) - var user = new User + var idclaim = "nameid"; + var nameclaim = "unique_name"; + var legacynameclaim = "name"; // this was a breaking change in System.IdentityModel.Tokens.Jwt in .NET 7 + + // get jwt claims for userid and username + var userid = identity.Claims.FirstOrDefault(item => item.Type == idclaim)?.Value; + if (userid != null) { - UserId = int.Parse(identity.Claims.FirstOrDefault(item => item.Type == "nameid")?.Value), - Username = identity.Claims.FirstOrDefault(item => item.Type == "name")?.Value - }; - // jwt already contains the roles - we are reloading to ensure most accurate permissions - var _userRoles = context.RequestServices.GetService(typeof(IUserRoleRepository)) as IUserRoleRepository; + if (!int.TryParse(userid, out _)) + { + userid = null; + } + } + var username = identity.Claims.FirstOrDefault(item => item.Type == nameclaim)?.Value; + if (username == null) + { + // fallback for legacy clients + username = identity.Claims.FirstOrDefault(item => item.Type == legacynameclaim)?.Value; + } - // set claims identity - var claimsidentity = UserSecurity.CreateClaimsIdentity(alias, user, _userRoles.GetUserRoles(user.UserId, alias.SiteId).ToList()); - context.User = new ClaimsPrincipal(claimsidentity); + if (userid != null && username != null) + { + // create user identity + var user = new User + { + UserId = int.Parse(userid), + Username = username + }; - logger.Log(alias.SiteId, LogLevel.Information, "TokenValidation", Enums.LogFunction.Security, "Token Validated For User {Username}", user.Username); + // set claims identity (note jwt already contains the roles - we are reloading to ensure most accurate permissions) + var _userRoles = context.RequestServices.GetService(typeof(IUserRoleRepository)) as IUserRoleRepository; + var claimsidentity = UserSecurity.CreateClaimsIdentity(alias, user, _userRoles.GetUserRoles(user.UserId, alias.SiteId).ToList()); + context.User = new ClaimsPrincipal(claimsidentity); + + logger.Log(alias.SiteId, LogLevel.Information, "TokenValidation", Enums.LogFunction.Security, "Token Validated For UserId {UserId} And Username {Username}", user.UserId, user.Username); + } + else + { + logger.Log(alias.SiteId, LogLevel.Error, "TokenValidation", Enums.LogFunction.Security, "Token Validated But Could Not Locate UserId Or Username In Claims {Claims}", identity.Claims.ToString()); + } } else {