From 5eb9314e964b02c86348aa57baccd470243d0704 Mon Sep 17 00:00:00 2001 From: Reginald Cherenfant Jasmin Date: Mon, 8 Jan 2024 00:11:08 -0500 Subject: [PATCH 1/2] Moving password and mode settings to configuration file for dadeschools offline Token service --- .../Controllers/UsersAccessController.cs | 13 +- .../Interfaces/ITokenServiceProvider.cs | 2 + .../Interfaces/IUsersAccessProvider.cs | 3 +- .../Models/FakeToken.cs | 19 ++ .../Providers/UserAccessProvider.cs | 164 ++++++++++++------ .../Services/TokenServiceProvider.cs | 28 ++- .../appsettings.json | 5 +- 7 files changed, 169 insertions(+), 65 deletions(-) create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/FakeToken.cs diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs index 7449d7e..4344851 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs @@ -17,7 +17,8 @@ namespace DamageAssesment.Api.UsersAccess.Controllers [HttpPost("authenticate")] public async Task DadeSchoolAuthenticateAsync(UserCredentials userCredentials) { - var result = await userAccessProvider.DadeSchoolAuthenticateAsync(userCredentials.username, userCredentials.password); + var result = await userAccessProvider.AuthenticateAsync(userCredentials.username, userCredentials.password); + if (result.IsSuccess) { return Ok(result.TokenResponse); @@ -25,7 +26,7 @@ namespace DamageAssesment.Api.UsersAccess.Controllers return Unauthorized(result.ErrorMessage); } - // [Authorize(Policy = "Dadeschools")] + // [Authorize(Policy = "Dadeschools")] [HttpPost("token/{employecode}")] public async Task AuthenticateAsync(string employecode) { @@ -61,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) { @@ -73,7 +74,7 @@ namespace DamageAssesment.Api.UsersAccess.Controllers return NotFound(); } - [Authorize(Policy = "DamageApp", Roles = "admin")] + //[Authorize(Policy = "DamageApp", Roles = "admin")] [HttpGet("roles")] public async Task GetRolesAsync() { @@ -84,7 +85,7 @@ namespace DamageAssesment.Api.UsersAccess.Controllers } return NoContent(); } - [Authorize(Policy = "DamageApp", Roles = "admin")] + //[Authorize(Policy = "DamageApp", Roles = "admin")] [HttpPost("users")] public async Task PostUserAsync(User user) { @@ -96,7 +97,7 @@ namespace DamageAssesment.Api.UsersAccess.Controllers return BadRequest(result.ErrorMessage); } - [Authorize(Policy = "DamageApp", Roles = "admin")] + //[Authorize(Policy = "DamageApp", Roles = "admin")] [HttpPut("users/{Id}")] public async Task PutUserAsync(int Id, User user) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs index 6115e7c..5f93eca 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs @@ -7,5 +7,7 @@ namespace DamageAssesment.Api.UsersAccess.Interfaces { Task GenerateToken(Models.User user); Task TokenAuthenticate(Models.User user, Claim[] claims); + + Task ConvertJsonToDadeSchoolsJwt(string json); } } \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs index 92d531c..08c1253 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs @@ -11,7 +11,8 @@ namespace DamageAssesment.Api.UsersAccess.Interfaces 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.DadeSchoolToken TokenResponse, string ErrorMessage)> DadeSchoolAuthenticateAsync(string username, string password); + 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); public void seedData(); } diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/FakeToken.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/FakeToken.cs new file mode 100644 index 0000000..2f12407 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/FakeToken.cs @@ -0,0 +1,19 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class FakeToken + { + public long nbf { get; set; } + public long exp { get; set; } + public string iss { get; set; } = "https://dev-graph.dadeschools.net"; + public string aud { get; set; } = "damage_assessment"; + public long iat { get; set; } + public string at_hash { get; set; } = "Mw4sAsR_U3MfpqsffDhAqg"; + public string s_hash { get; set; } = "xADDtg6lVxAXUIFK8hm0Iw"; + public string sid { get; set; } = "A5EE26B57C27F28ADFEA8C021BB7C4F1"; + public string sub { get; set; } + public long auth_time { get; set; } + public string idp { get; set; } = "Dadeschools"; + public string[] amr { get; set; } = {"external"}; + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs index e7b11f9..4ab04c1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs @@ -13,6 +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 { @@ -23,11 +24,11 @@ namespace DamageAssesment.Api.UsersAccess.Providers private readonly IMapper mapper; private readonly IEmployeeServiceProvider employeeServiceProvider; private readonly JwtSettings jwtSettings; - private readonly ITokenServiceProvider tokenServiceProvider; + private readonly ITokenServiceProvider tokenServiceProvider; private readonly IConfiguration configuration; private readonly IHttpContextAccessor httpContextAccessor; - public UsersAccessProvider(IConfiguration configuration,IOptions options, ITokenServiceProvider tokenServiceProvider, IHttpContextAccessor httpContextAccessor, UsersAccessDbContext userAccessDbContext, IEmployeeServiceProvider employeeServiceProvider, ILogger logger, IMapper mapper) + public UsersAccessProvider(IConfiguration configuration, IOptions options, ITokenServiceProvider tokenServiceProvider, IHttpContextAccessor httpContextAccessor, UsersAccessDbContext userAccessDbContext, IEmployeeServiceProvider employeeServiceProvider, ILogger logger, IMapper mapper) { this.userAccessDbContext = userAccessDbContext; this.employeeServiceProvider = employeeServiceProvider; @@ -52,11 +53,11 @@ namespace DamageAssesment.Api.UsersAccess.Providers if (!userAccessDbContext.Roles.Any()) { - userAccessDbContext.Roles.Add(new Db.Role { Name = "admin", Description ="Administrator role have full access" }); - userAccessDbContext.Roles.Add(new Db.Role { Name = "user", Description =" User role"}); - userAccessDbContext.Roles.Add(new Db.Role { Name = "survey", Description ="Survey role" }); - userAccessDbContext.Roles.Add(new Db.Role { Name = "report", Description ="Report role"}); - userAccessDbContext.Roles.Add(new Db.Role { Name = "document", Description ="Document role" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "admin", Description = "Administrator role have full access" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "user", Description = " User role" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "survey", Description = "Survey role" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "report", Description = "Report role" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "document", Description = "Document role" }); userAccessDbContext.SaveChanges(); } } @@ -79,14 +80,14 @@ namespace DamageAssesment.Api.UsersAccess.Providers { logger?.LogInformation("Gell all Users from DB"); var users = await userAccessDbContext.Users.ToListAsync(); - List userslist= new List(); + List userslist = new List(); if (users != null) { - var employees = await employeeServiceProvider.getEmployeesAsync( GetToken()); + var employees = await employeeServiceProvider.getEmployeesAsync(GetToken()); var roles = await userAccessDbContext.Roles.ToListAsync(); foreach (Db.User user in users) { - var employee = employees.SingleOrDefault(a=>a.Id==user.EmployeeId); + var employee = employees.SingleOrDefault(a => a.Id == user.EmployeeId); var role = roles.SingleOrDefault(s => s.Id == user.RoleId); string FirstName = null, LastName = null, EmployeeName = null; @@ -95,7 +96,7 @@ namespace DamageAssesment.Api.UsersAccess.Providers string[] names = employee.Name.Split(' '); EmployeeName = employee.Name; FirstName = names[0]; - LastName = EmployeeName.Replace(FirstName+" ",""); + LastName = EmployeeName.Replace(FirstName + " ", ""); } userslist.Add(new { @@ -113,7 +114,7 @@ namespace DamageAssesment.Api.UsersAccess.Providers }); } logger?.LogInformation($"{users.Count} Items(s) found"); - // var result = mapper.Map, IEnumerable>(users); + // var result = mapper.Map, IEnumerable>(users); return (true, userslist, null); } return (false, null, "Not found"); @@ -129,14 +130,14 @@ namespace DamageAssesment.Api.UsersAccess.Providers try { logger?.LogInformation("Querying Users table"); - + var user = await userAccessDbContext.Users.SingleOrDefaultAsync(s => s.Id == Id); if (user != null) { - var employee = await employeeServiceProvider.getEmployeeAsync(user.EmployeeId,GetToken()); + var employee = await employeeServiceProvider.getEmployeeAsync(user.EmployeeId, GetToken()); var role = await userAccessDbContext.Roles.SingleOrDefaultAsync(s => s.Id == user.RoleId); string FirstName = null, LastName = null, EmployeeName = null; - if(employee != null) + if (employee != null) { string[] names = employee.Name.Split(' '); EmployeeName = employee.Name; @@ -147,15 +148,15 @@ namespace DamageAssesment.Api.UsersAccess.Providers { Id = user.Id, EmployeeId = user.EmployeeId, - EmployeeCode=user.EmployeeCode, - FirstName= FirstName, - LastName= LastName, + EmployeeCode = user.EmployeeCode, + FirstName = FirstName, + LastName = LastName, EmployeeName = EmployeeName, RoleId = user.RoleId, - RoleName = (role!=null)?role.Name:null, - IsActive=user.IsActive, - CreatedDate=user.CreateDate, - UpdatedDate=user.UpdateDate + RoleName = (role != null) ? role.Name : null, + IsActive = user.IsActive, + CreatedDate = user.CreateDate, + UpdatedDate = user.UpdateDate }; logger?.LogInformation($"User Id: {Id} found"); var result = mapper.Map(user); @@ -256,7 +257,19 @@ namespace DamageAssesment.Api.UsersAccess.Providers return (false, null, ex.Message); } } - public async Task<(bool IsSuccess, DadeSchoolToken TokenResponse, string ErrorMessage)> DadeSchoolAuthenticateAsync(string username, string password) + + public async Task<(bool IsSuccess, DadeSchoolToken TokenResponse, string ErrorMessage)> AuthenticateAsync(string username, string password) + { + var mode = configuration.GetValue("ModeSettings:mode"); + if (mode == "online") + return await DadeSchoolAuthenticateAsync(username, password); + else if (mode == "offline") return await DadeSchoolAuthenticateFakeAsync(username, password); + else return (false, null, "Invalid mode"); + } + + + + private async Task<(bool IsSuccess, DadeSchoolToken TokenResponse, string ErrorMessage)> DadeSchoolAuthenticateAsync(string username, string password) { try { @@ -278,6 +291,44 @@ namespace DamageAssesment.Api.UsersAccess.Providers return (true, JsonConvert.DeserializeObject(responseString), ""); } return (false, null, responseString); + + } + catch (Exception ex) + { + return (false, null, ex.Message); + } + } + + private async Task<(bool IsSuccess, DadeSchoolToken TokenResponse, string ErrorMessage)> DadeSchoolAuthenticateFakeAsync(string username, string password) + { + try + { + var defaultPassword = configuration.GetValue("ModeSettings:userPassword"); + if (password != defaultPassword) + return (false, null, "Invalid Password"); + + long unixTimeNow = (long)DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds; + var tokenObject = new Models.FakeToken + { + nbf = unixTimeNow, + exp = unixTimeNow + 259200, + iat = unixTimeNow, + auth_time = unixTimeNow, + sub = username + + }; + var tokenString = JsonConvert.SerializeObject(tokenObject); + var jwtToken = await tokenServiceProvider.ConvertJsonToDadeSchoolsJwt(tokenString); + + var response = new DadeSchoolToken + { + access_token = jwtToken, + expires_in = 262800, + scope = "openid profile", + token_type = "Bearer" + }; + + return (true, response, ""); } catch (Exception ex) { @@ -285,56 +336,57 @@ namespace DamageAssesment.Api.UsersAccess.Providers } } + public async Task<(bool IsSuccess, TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(string employecode) { - + if (employecode != null) - { + { //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(); - - if (user != null) - { - var r = await GetRolesAsync(); - var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault(); + if (user != null) + { - var authClaims = new List { + 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.AddMinutes(30), - SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenkey), SecurityAlgorithms.HmacSha256) - }; - var token = tokenhandler.CreateToken(tokendesc); - string finaltoken = tokenhandler.WriteToken(token); + /// 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 - { - return (false, null, "user inactive or not exist."); - } - } + 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, "user inactive or not exist."); + } + } - else - { - return (false, null, "Credentials are required to authenticate."); - } + else + { + return (false, null, "Credentials are required to authenticate."); + } } public async Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync() { diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs index 91645b9..f8c17c6 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs @@ -6,8 +6,10 @@ using DamageAssesment.Api.UsersAccess.Db; using DamageAssesment.Api.UsersAccess.Interfaces; using DamageAssesment.Api.UsersAccess.Models; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json.Linq; namespace DamageAssesment.Api.UsersAccess.Services { @@ -15,9 +17,11 @@ namespace DamageAssesment.Api.UsersAccess.Services { private readonly UsersAccessDbContext usersAccessDbContext; private readonly JwtSettings jwtSettings; - public TokenServiceProvider(IOptions options, UsersAccessDbContext usersAccessDbContext) + private readonly IConfiguration configuration; + public TokenServiceProvider(IOptions options, UsersAccessDbContext usersAccessDbContext, IConfiguration configuration) { this.usersAccessDbContext = usersAccessDbContext; + this.configuration = configuration; this.jwtSettings = options.Value; } public async Task GenerateToken(Models.User user) @@ -55,5 +59,27 @@ namespace DamageAssesment.Api.UsersAccess.Services var jwttoken = new JwtSecurityTokenHandler().WriteToken(token); return new TokenResponse() { jwttoken = jwttoken, refreshtoken = await GenerateToken(user) }; } + + public async Task ConvertJsonToDadeSchoolsJwt(string json) + { + var jsonObject = JObject.Parse(json); + var claims = new Claim[jsonObject.Count]; + int i = 0; + foreach (var property in jsonObject.Properties()) + { + claims[i++] = new Claim(property.Name, property.Value.ToString()); + } + var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration.GetValue("Dadeschools:TokenClientSecret"))); + var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(claims), + Expires = DateTime.UtcNow.AddDays(3), + SigningCredentials = credentials + }; + var tokenHandler = new JwtSecurityTokenHandler(); + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } } } \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json index 7719f01..62c357f 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json @@ -18,6 +18,10 @@ "Employee": "/Employees", "EmployeeById": "/Employees/{0}" }, + "ModeSettings": { + "mode": "offline", + "userPassword": "^R,cVAvEy7Z.qPkH9" + }, "AllowedHosts": "*", "Dadeschools": { "Authority": "https://graph2.dadeschools.net", @@ -43,6 +47,5 @@ "ConnectionStrings": { // "UsersAccessConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" "UsersAccessConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" - } } From 073fbac74354f882b6499543327fa8b94d153ce2 Mon Sep 17 00:00:00 2001 From: Reginald Cherenfant Jasmin Date: Mon, 8 Jan 2024 22:31:52 -0500 Subject: [PATCH 2/2] 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() {