Update UserAccess microservice to read Employee Code from token when retreiving App token. Update dadeschools Authorization policy to work offline

This commit is contained in:
Reginald Cherenfant Jasmin 2024-01-08 22:31:52 -05:00
parent 5eb9314e96
commit 073fbac743
6 changed files with 81 additions and 59 deletions

View File

@ -18,9 +18,9 @@ namespace DamageAssesment.Api.UsersAccess.Test
public async Task GetTokenAsync_ShouldReturnStatusCode200() public async Task GetTokenAsync_ShouldReturnStatusCode200()
{ {
var response = await MockData.getTokenResponse(true,null); 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 controller = new UsersAccessController(mockService.Object);
var result = (OkObjectResult)await controller.AuthenticateAsync("Emp1"); var result = (OkObjectResult)await controller.AuthenticateAsync();
Assert.Equal(200, result.StatusCode); Assert.Equal(200, result.StatusCode);
} }
@ -28,9 +28,9 @@ namespace DamageAssesment.Api.UsersAccess.Test
public async Task GetTokenAsync_ShouldReturnStatusCode401() public async Task GetTokenAsync_ShouldReturnStatusCode401()
{ {
var response = await MockData.getTokenResponse(false, null); 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 controller = new UsersAccessController(mockService.Object);
var result = (UnauthorizedObjectResult)await controller.AuthenticateAsync("Emp1"); var result = (UnauthorizedObjectResult)await controller.AuthenticateAsync();
Assert.Equal(401, result.StatusCode); Assert.Equal(401, result.StatusCode);
} }

View File

@ -8,17 +8,17 @@ namespace DamageAssesment.Api.UsersAccess.Controllers
[ApiController] [ApiController]
public class UsersAccessController : ControllerBase public class UsersAccessController : ControllerBase
{ {
private IUsersAccessProvider userAccessProvider; private readonly IUsersAccessProvider userAccessProvider;
public UsersAccessController(IUsersAccessProvider userAccessProvider) public UsersAccessController(IUsersAccessProvider userAccessProvider)
{ {
this.userAccessProvider = userAccessProvider; this.userAccessProvider = userAccessProvider;
} }
[HttpPost("authenticate")] [HttpPost("dadeschools/token")]
public async Task<ActionResult> DadeSchoolAuthenticateAsync(UserCredentials userCredentials) public async Task<ActionResult> DadeSchoolAuthenticateAsync(UserCredentials userCredentials)
{ {
var result = await userAccessProvider.AuthenticateAsync(userCredentials.username, userCredentials.password); var result = await userAccessProvider.AuthenticateAsync(userCredentials.username, userCredentials.password);
if (result.IsSuccess) if (result.IsSuccess)
{ {
return Ok(result.TokenResponse); return Ok(result.TokenResponse);
@ -26,20 +26,20 @@ namespace DamageAssesment.Api.UsersAccess.Controllers
return Unauthorized(result.ErrorMessage); return Unauthorized(result.ErrorMessage);
} }
// [Authorize(Policy = "Dadeschools")] [Authorize(Policy = "Dadeschools")]
[HttpPost("token/{employecode}")] [HttpGet("damageapp/token")]
public async Task<ActionResult> AuthenticateAsync(string employecode) public async Task<ActionResult> AuthenticateAsync()
{ {
var result = await userAccessProvider.AuthenticateAsync(employecode); var result = await userAccessProvider.AuthenticateAsync();
if (result.IsSuccess) if (result.IsSuccess)
{ {
return Ok(result.TokenResponse); return Ok(result.TokenResponse);
} }
return Unauthorized(result.ErrorMessage); return Unauthorized(result.ErrorMessage);
} }
// [Authorize(Policy = "Dadeschools")] [Authorize(Policy = "Dadeschools")]
[HttpPost("refreshtoken")] [HttpPost("damageapp/refreshtoken")]
public async Task<ActionResult> RefreshTokenAsync(TokenResponse tokenResponse) public async Task<ActionResult> RefreshTokenAsync(TokenResponse tokenResponse)
{ {
var result = await userAccessProvider.RefreshTokenAsync(tokenResponse); var result = await userAccessProvider.RefreshTokenAsync(tokenResponse);
@ -62,7 +62,7 @@ namespace DamageAssesment.Api.UsersAccess.Controllers
return NoContent(); return NoContent();
} }
//[Authorize(Policy = "DamageApp", Roles = "admin")] // [Authorize(Policy = "DamageApp", Roles = "admin")]
[HttpGet("users/{Id}")] [HttpGet("users/{Id}")]
public async Task<ActionResult> GetUsersAsync(int Id) public async Task<ActionResult> GetUsersAsync(int Id)
{ {

View File

@ -27,6 +27,7 @@
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.21.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -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)> PutUserAsync(int Id,Models.User User);
public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id); public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id);
public Task<(bool IsSuccess, IEnumerable<Models.Role> Roles, string ErrorMessage)> GetRolesAsync(); public Task<(bool IsSuccess, IEnumerable<Models.Role> 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, DadeSchoolToken TokenResponse, string ErrorMessage)> AuthenticateAsync(string username, string password);
public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)>RefreshTokenAsync(TokenResponse tokenResponse); public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)>RefreshTokenAsync(TokenResponse tokenResponse);

View File

@ -17,11 +17,13 @@ const int maxRetryForCircuitBraker = 5;
const int intervalForCircuitBraker = 5; //5 seconds const int intervalForCircuitBraker = 5; //5 seconds
var builder = WebApplication.CreateBuilder(args); 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(); build.WithOrigins("*").AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin();
})); }));
// Add services to the container. // Add services to the container.
var authkey = builder.Configuration.GetValue<string>("JwtSettings:securitykey"); var authkey = builder.Configuration.GetValue<string>("JwtSettings:securitykey");
var mode = builder.Configuration.GetValue<string>("ModeSettings:mode");
builder.Services.AddAuthentication(). builder.Services.AddAuthentication().
@ -52,16 +54,20 @@ builder.Services.AddAuthorization(options =>
.RequireAuthenticatedUser() .RequireAuthenticatedUser()
.AddAuthenticationSchemes("DamageApp") .AddAuthenticationSchemes("DamageApp")
.Build(); .Build();
var DadeschoolsPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser() var DadeschoolsPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
.AddAuthenticationSchemes("Dadeschools") .AddAuthenticationSchemes("Dadeschools")
.Build(); .Build();
var DadeschoolsPolicyOffline = new AuthorizationPolicyBuilder().RequireAssertion(_ => true)
.Build();
var allPolicy = new AuthorizationPolicyBuilder() var allPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser() .RequireAuthenticatedUser()
.AddAuthenticationSchemes("DamageApp", "Dadeschools") .AddAuthenticationSchemes("DamageApp", "Dadeschools")
.Build(); .Build();
options.AddPolicy("DamageApp", DamageAppPolicy); options.AddPolicy("DamageApp", DamageAppPolicy);
options.AddPolicy("Dadeschools", DadeschoolsPolicy); options.AddPolicy("Dadeschools", mode == "online" ? DadeschoolsPolicy : DadeschoolsPolicyOffline);
options.AddPolicy("AllPolicies", allPolicy); options.AddPolicy("AllPolicies", allPolicy);
options.DefaultPolicy = options.GetPolicy("DamageApp")!; options.DefaultPolicy = options.GetPolicy("DamageApp")!;
}); });

View File

@ -13,7 +13,7 @@ using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using DamageAssesment.Api.UsersAccess.Services;
namespace DamageAssesment.Api.UsersAccess.Providers 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)
{ {
try
if (employecode != null)
{ {
//implementation for dadeschools authentication var handler = new JwtSecurityTokenHandler();
// var employees = await employeeServiceProvider.getEmployeesAsync(); var jsonToken = handler.ReadToken(token);
// var employee = employees.Where(e=> e.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); var tokenS = handler.ReadToken(token) as JwtSecurityToken;
var user = userAccessDbContext.Users.Where(x => x.IsActive == true && x.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault();
if (user != null) if (tokenS == null)
{ return null;
var r = await GetRolesAsync(); var payload = tokenS.Payload.SerializeToJson();
var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault(); return payload;
}
catch
{
return null;
}
}
var authClaims = new List<Claim> { 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<Claim> {
new Claim(ClaimTypes.Name, user.EmployeeCode), new Claim(ClaimTypes.Name, user.EmployeeCode),
new Claim(ClaimTypes.Role, role.Name), new Claim(ClaimTypes.Role, role.Name),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()) new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
}; };
/// Generate Token /// Generate Token
var tokenhandler = new JwtSecurityTokenHandler(); var tokenhandler = new JwtSecurityTokenHandler();
var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey); var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey);
var tokendesc = new SecurityTokenDescriptor 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<Db.User, Models.User>(user)) };
return (true, response, "Authentication success and token issued.");
}
else
{ {
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<Db.User, Models.User>(user)) };
return (true, response, "Authentication success and token issued.");
}
else else
{ {
return (false, null, "Credentials are required to authenticate."); return (false, null, "user inactive or not exist.");
} }
} }
public async Task<(bool IsSuccess, IEnumerable<Models.Role> Roles, string ErrorMessage)> GetRolesAsync() public async Task<(bool IsSuccess, IEnumerable<Models.Role> Roles, string ErrorMessage)> GetRolesAsync()
{ {