From 073fbac74354f882b6499543327fa8b94d153ce2 Mon Sep 17 00:00:00 2001 From: Reginald Cherenfant Jasmin Date: Mon, 8 Jan 2024 22:31:52 -0500 Subject: [PATCH] Update UserAccess microservice to read Employee Code from token when retreiving App token. Update dadeschools Authorization policy to work offline --- .../UsersAccessTest.cs | 8 +- .../Controllers/UsersAccessController.cs | 30 +++---- .../DamageAssesment.Api.UsersAccess.csproj | 1 + .../Interfaces/IUsersAccessProvider.cs | 2 +- .../Program.cs | 14 ++- .../Providers/UserAccessProvider.cs | 85 +++++++++++-------- 6 files changed, 81 insertions(+), 59 deletions(-) diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs index 46165f3..567a35a 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs @@ -18,9 +18,9 @@ namespace DamageAssesment.Api.UsersAccess.Test public async Task GetTokenAsync_ShouldReturnStatusCode200() { var response = await MockData.getTokenResponse(true,null); - mockService.Setup(service => service.AuthenticateAsync("Emp1")).ReturnsAsync(response); + mockService.Setup(service => service.AuthenticateAsync()).ReturnsAsync(response); var controller = new UsersAccessController(mockService.Object); - var result = (OkObjectResult)await controller.AuthenticateAsync("Emp1"); + var result = (OkObjectResult)await controller.AuthenticateAsync(); Assert.Equal(200, result.StatusCode); } @@ -28,9 +28,9 @@ namespace DamageAssesment.Api.UsersAccess.Test public async Task GetTokenAsync_ShouldReturnStatusCode401() { var response = await MockData.getTokenResponse(false, null); - mockService.Setup(service => service.AuthenticateAsync("Emp1")).ReturnsAsync(response); + mockService.Setup(service => service.AuthenticateAsync()).ReturnsAsync(response); var controller = new UsersAccessController(mockService.Object); - var result = (UnauthorizedObjectResult)await controller.AuthenticateAsync("Emp1"); + var result = (UnauthorizedObjectResult)await controller.AuthenticateAsync(); Assert.Equal(401, result.StatusCode); } diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs index 4344851..050e690 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs @@ -8,17 +8,17 @@ namespace DamageAssesment.Api.UsersAccess.Controllers [ApiController] public class UsersAccessController : ControllerBase { - private IUsersAccessProvider userAccessProvider; + private readonly IUsersAccessProvider userAccessProvider; public UsersAccessController(IUsersAccessProvider userAccessProvider) { this.userAccessProvider = userAccessProvider; } - [HttpPost("authenticate")] + [HttpPost("dadeschools/token")] public async Task DadeSchoolAuthenticateAsync(UserCredentials userCredentials) { var result = await userAccessProvider.AuthenticateAsync(userCredentials.username, userCredentials.password); - + if (result.IsSuccess) { return Ok(result.TokenResponse); @@ -26,20 +26,20 @@ namespace DamageAssesment.Api.UsersAccess.Controllers return Unauthorized(result.ErrorMessage); } - // [Authorize(Policy = "Dadeschools")] - [HttpPost("token/{employecode}")] - public async Task AuthenticateAsync(string employecode) + [Authorize(Policy = "Dadeschools")] + [HttpGet("damageapp/token")] + public async Task AuthenticateAsync() { - var result = await userAccessProvider.AuthenticateAsync(employecode); - if (result.IsSuccess) - { - return Ok(result.TokenResponse); - } - return Unauthorized(result.ErrorMessage); + var result = await userAccessProvider.AuthenticateAsync(); + if (result.IsSuccess) + { + return Ok(result.TokenResponse); + } + return Unauthorized(result.ErrorMessage); } - // [Authorize(Policy = "Dadeschools")] - [HttpPost("refreshtoken")] + [Authorize(Policy = "Dadeschools")] + [HttpPost("damageapp/refreshtoken")] public async Task RefreshTokenAsync(TokenResponse tokenResponse) { var result = await userAccessProvider.RefreshTokenAsync(tokenResponse); @@ -62,7 +62,7 @@ namespace DamageAssesment.Api.UsersAccess.Controllers return NoContent(); } - //[Authorize(Policy = "DamageApp", Roles = "admin")] + // [Authorize(Policy = "DamageApp", Roles = "admin")] [HttpGet("users/{Id}")] public async Task GetUsersAsync(int Id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj index 264aea4..ecde420 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj @@ -27,6 +27,7 @@ + diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs index 08c1253..5d6a7ea 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs @@ -10,7 +10,7 @@ namespace DamageAssesment.Api.UsersAccess.Interfaces public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id,Models.User User); public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id); public Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync(); - public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(string employeCode); + public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(); public Task<(bool IsSuccess, DadeSchoolToken TokenResponse, string ErrorMessage)> AuthenticateAsync(string username, string password); public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)>RefreshTokenAsync(TokenResponse tokenResponse); diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs index 3c9d869..be2170e 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs @@ -17,11 +17,13 @@ const int maxRetryForCircuitBraker = 5; const int intervalForCircuitBraker = 5; //5 seconds var builder = WebApplication.CreateBuilder(args); -builder.Services.AddCors(p => p.AddPolicy("DamageAppCorsPolicy", build => { +builder.Services.AddCors(p => p.AddPolicy("DamageAppCorsPolicy", build => +{ build.WithOrigins("*").AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin(); })); // Add services to the container. var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +var mode = builder.Configuration.GetValue("ModeSettings:mode"); builder.Services.AddAuthentication(). @@ -52,16 +54,20 @@ builder.Services.AddAuthorization(options => .RequireAuthenticatedUser() .AddAuthenticationSchemes("DamageApp") .Build(); - var DadeschoolsPolicy = new AuthorizationPolicyBuilder() - .RequireAuthenticatedUser() + + var DadeschoolsPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser() .AddAuthenticationSchemes("Dadeschools") .Build(); + + var DadeschoolsPolicyOffline = new AuthorizationPolicyBuilder().RequireAssertion(_ => true) + .Build(); + var allPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes("DamageApp", "Dadeschools") .Build(); options.AddPolicy("DamageApp", DamageAppPolicy); - options.AddPolicy("Dadeschools", DadeschoolsPolicy); + options.AddPolicy("Dadeschools", mode == "online" ? DadeschoolsPolicy : DadeschoolsPolicyOffline); options.AddPolicy("AllPolicies", allPolicy); options.DefaultPolicy = options.GetPolicy("DamageApp")!; }); diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs index 4ab04c1..b5e8071 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs @@ -13,7 +13,7 @@ using Newtonsoft.Json; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; -using DamageAssesment.Api.UsersAccess.Services; + namespace DamageAssesment.Api.UsersAccess.Providers { @@ -337,56 +337,71 @@ namespace DamageAssesment.Api.UsersAccess.Providers } - public async Task<(bool IsSuccess, TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(string employecode) + private string DecodeJwtToken(string token) { - - if (employecode != null) + try { - //implementation for dadeschools authentication - // var employees = await employeeServiceProvider.getEmployeesAsync(); - // var employee = employees.Where(e=> e.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); - var user = userAccessDbContext.Users.Where(x => x.IsActive == true && x.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); + var handler = new JwtSecurityTokenHandler(); + var jsonToken = handler.ReadToken(token); + var tokenS = handler.ReadToken(token) as JwtSecurityToken; - if (user != null) - { + if (tokenS == null) + return null; - var r = await GetRolesAsync(); - var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault(); + var payload = tokenS.Payload.SerializeToJson(); + return payload; + } + catch + { + return null; + } + } - var authClaims = new List { + public async Task<(bool IsSuccess, TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync() + { + var dadeschoolsToken = GetToken(); + var decodedToken = DecodeJwtToken(dadeschoolsToken); + var tokenObject = decodedToken == null ? null : JObject.Parse(decodedToken); + + if (tokenObject == null) + return (false, null, "JWT authentication is required"); + + var employecode = (string)tokenObject["sub"]; + var user = userAccessDbContext.Users.Where(x => x.IsActive == true && x.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); + if (user != null) + { + var r = await GetRolesAsync(); + var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault(); + + var authClaims = new List { new Claim(ClaimTypes.Name, user.EmployeeCode), new Claim(ClaimTypes.Role, role.Name), new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()) }; - /// Generate Token - var tokenhandler = new JwtSecurityTokenHandler(); - var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey); - var tokendesc = new SecurityTokenDescriptor - { - Audience = "", - NotBefore = DateTime.Now, - Subject = new ClaimsIdentity(authClaims), - Expires = DateTime.Now.AddDays(3), - SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenkey), SecurityAlgorithms.HmacSha256) - }; - var token = tokenhandler.CreateToken(tokendesc); - string finaltoken = tokenhandler.WriteToken(token); - - var response = new TokenResponse() { jwttoken = finaltoken, refreshtoken = await tokenServiceProvider.GenerateToken(mapper.Map(user)) }; - return (true, response, "Authentication success and token issued."); - } - else + /// Generate Token + var tokenhandler = new JwtSecurityTokenHandler(); + var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey); + var tokendesc = new SecurityTokenDescriptor { - return (false, null, "user inactive or not exist."); - } - } + Audience = "", + NotBefore = DateTime.Now, + Subject = new ClaimsIdentity(authClaims), + Expires = DateTime.Now.AddDays(3), + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenkey), SecurityAlgorithms.HmacSha256) + }; + var token = tokenhandler.CreateToken(tokendesc); + string finaltoken = tokenhandler.WriteToken(token); + var response = new TokenResponse() { jwttoken = finaltoken, refreshtoken = await tokenServiceProvider.GenerateToken(mapper.Map(user)) }; + return (true, response, "Authentication success and token issued."); + } else { - return (false, null, "Credentials are required to authenticate."); + return (false, null, "user inactive or not exist."); } + } public async Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync() {