using AutoMapper; using DamageAssesment.Api.UsersAccess.Db; using DamageAssesment.Api.UsersAccess.Interfaces; using DamageAssesment.Api.UsersAccess.Models; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Data; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace DamageAssesment.Api.UsersAccess.Providers { public class UsersAccessProvider : IUsersAccessProvider { private readonly UsersAccessDbContext userAccessDbContext; private readonly ILogger logger; private readonly IMapper mapper; private readonly IEmployeeServiceProvider employeeServiceProvider; private readonly JwtSettings jwtSettings; 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) { this.userAccessDbContext = userAccessDbContext; this.employeeServiceProvider = employeeServiceProvider; this.logger = logger; this.mapper = mapper; jwtSettings = options.Value; this.tokenServiceProvider = tokenServiceProvider; this.httpContextAccessor = httpContextAccessor; this.configuration = configuration; seedData(); } public void seedData() { if (!userAccessDbContext.Users.Any()) { userAccessDbContext.Users.Add(new Db.User { Id = 1, EmployeeId = 1, EmployeeCode = "Emp1", RoleId = 1, IsActive = true, CreateDate = DateTime.Now }); userAccessDbContext.Users.Add(new Db.User { Id = 2, EmployeeId = 2, EmployeeCode = "Emp2", RoleId = 2, IsActive = true, CreateDate = DateTime.Now }); userAccessDbContext.Users.Add(new Db.User { Id = 3, EmployeeId = 3, EmployeeCode = "Emp3", RoleId = 3, IsActive = true, CreateDate = DateTime.Now }); userAccessDbContext.SaveChanges(); } if (!userAccessDbContext.Roles.Any()) { userAccessDbContext.Roles.Add(new Db.Role { Id = 1, Name = "admin", Description ="Administrator role have full access" }); userAccessDbContext.Roles.Add(new Db.Role { Id = 2, Name = "user", Description =" User role"}); userAccessDbContext.Roles.Add(new Db.Role { Id = 3, Name = "survey", Description ="Survey role" }); userAccessDbContext.Roles.Add(new Db.Role { Id = 4, Name = "report", Description ="Report role"}); userAccessDbContext.Roles.Add(new Db.Role { Id = 5, Name = "document", Description ="Document role" }); userAccessDbContext.SaveChanges(); } } private string GetToken() { string token = httpContextAccessor.HttpContext.Request.Headers.Authorization; if (token != null) { token = token.Replace("Bearer ", string.Empty); } else { token = ""; } return token; } public async Task<(bool IsSuccess, IEnumerable Users, string ErrorMessage)> GetUsersAsync() { try { logger?.LogInformation("Gell all Users from DB"); var users = await userAccessDbContext.Users.ToListAsync(); List userslist= new List(); if (users != null) { 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 role = roles.SingleOrDefault(s => s.Id == user.RoleId); userslist.Add(new { Id = user.Id, EmployeeId = user.EmployeeId, EmployeeCode = user.EmployeeCode, EmployeeName = (employee != null) ? employee.Name : null, RoleId = user.RoleId, RoleName = (role != null) ? role.Name : null }); } logger?.LogInformation($"{users.Count} Items(s) found"); // var result = mapper.Map, IEnumerable>(users); return (true, userslist, null); } return (false, null, "Not found"); } catch (Exception ex) { logger?.LogError(ex.ToString()); return (false, null, ex.Message); } } public async Task<(bool IsSuccess, object User, string ErrorMessage)> GetUsersAsync(int Id) { 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 role = await userAccessDbContext.Roles.SingleOrDefaultAsync(s => s.Id == user.RoleId); var data = new { Id = user.Id, EmployeeId = user.EmployeeId, EmployeeCode=user.EmployeeCode, EmployeeName = (employee != null) ? employee.Name : null, RoleId = user.RoleId, RoleName = (role!=null)?role.Name:null }; logger?.LogInformation($"User Id: {Id} found"); var result = mapper.Map(user); return (true, data, null); } return (false, null, "Not found"); } catch (Exception ex) { logger?.LogError(ex.ToString()); return (false, null, ex.Message); } } public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PostUserAsync(Models.User user) { try { if (user != null) { var _user = mapper.Map(user); userAccessDbContext.Users.Add(_user); user.Id = _user.Id; await userAccessDbContext.SaveChangesAsync(); return (true, user, "Successful"); } else { logger?.LogInformation($"null object cannot be added"); return (false, null, $"null object cannot be added"); } } catch (Exception ex) { logger?.LogError(ex.ToString()); return (false, null, ex.Message); } } public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id, Models.User user) { try { if (user != null) { var _user = await userAccessDbContext.Users.AsNoTracking().Where(s => s.Id == Id).SingleOrDefaultAsync(); if (_user != null) { int count = userAccessDbContext.Users.Where(u => u.Id != user.Id).Count(); if (count == 0) { await userAccessDbContext.SaveChangesAsync(); logger?.LogInformation($"Employee Id: {user.EmployeeId} updated successfuly"); return (true, mapper.Map(_user), $"Employee Id: {_user.EmployeeId} updated successfuly"); } else { logger?.LogInformation($"Employee Id: {user.EmployeeId} is already exist"); return (false, null, $"Employee Id: {user.EmployeeId} is already exist"); } } else { logger?.LogInformation($"User Id : {Id} Not found"); return (false, null, "Not Found"); } } else { logger?.LogInformation($"User Id: {Id} Bad Request"); return (false, null, "Bad request"); } } catch (Exception ex) { logger?.LogError(ex.ToString()); return (false, null, ex.Message); } } public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id) { try { var user = await userAccessDbContext.Users.Where(x => x.Id == Id).SingleOrDefaultAsync(); if (user != null) { userAccessDbContext.Users.Remove(user); await userAccessDbContext.SaveChangesAsync(); logger?.LogInformation($"User Id: {Id} deleted Successfuly"); return (true, mapper.Map(user), $"User Id: {Id} deleted Successfuly"); } else { logger?.LogInformation($"User Id : {Id} Not found"); return (false, null, "Not Found"); } } catch (Exception ex) { logger?.LogError(ex.ToString()); return (false, null, ex.Message); } } 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(); 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); 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."); } } public async Task<(bool IsSuccess, DadeSchoolToken TokenResponse, string ErrorMessage)> DadeSchoolAuthenticateAsync(string username, string password) { try { var client = new HttpClient(); var request = new HttpRequestMessage(HttpMethod.Post, configuration.GetValue("Dadeschools:TokenUrl")); var collection = new List>(); collection.Add(new("client_id", configuration.GetValue("Dadeschools:TokenClientId"))); collection.Add(new("client_secret", configuration.GetValue("Dadeschools:TokenClientSecret"))); collection.Add(new("scope", configuration.GetValue("Dadeschools:scope"))); collection.Add(new("grant_type", configuration.GetValue("Dadeschools:grant_type"))); collection.Add(new("username", username)); collection.Add(new("password", password)); var content = new FormUrlEncodedContent(collection); request.Content = content; var response = await client.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { return (true, JsonConvert.DeserializeObject(responseString), ""); } return (false, null, responseString); } catch (Exception ex) { return (false, null, ex.Message); } } public async Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync() { try { logger?.LogInformation("Gell all Roles from DB"); var roles = await userAccessDbContext.Roles.ToListAsync(); if (roles != null) { logger?.LogInformation($"{roles.Count} Items(s) found"); var result = mapper.Map, IEnumerable>(roles); return (true, result, null); } return (false, null, "Not found"); } catch (Exception ex) { logger?.LogError(ex.ToString()); return (false, null, ex.Message); } } public async Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> RefreshTokenAsync(TokenResponse tokenResponse) { //Generate token var tokenhandler = new JwtSecurityTokenHandler(); var tokenkey = Encoding.UTF8.GetBytes(this.jwtSettings.securitykey); SecurityToken securityToken; var principal = tokenhandler.ValidateToken(tokenResponse.jwttoken, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(tokenkey), ValidateIssuer = false, ValidateAudience = false, }, out securityToken); var token = securityToken as JwtSecurityToken; if (token != null && !token.Header.Alg.Equals(SecurityAlgorithms.HmacSha256)) { return (false, null, "Unauthorized"); } var username = principal.Identity?.Name; var tokens = await userAccessDbContext.Tokens.ToListAsync(); var users = await userAccessDbContext.Users.ToListAsync(); var user = (from u in users join t in tokens on u.Id equals t.UserId where u.EmployeeId == 1 && t.RefreshToken == tokenResponse.refreshtoken select u).FirstOrDefault(); if (user == null) return (false, null, "Invalid Token Response object provided"); var _user = mapper.Map(user); var response = tokenServiceProvider.TokenAuthenticate(_user, principal.Claims.ToArray()).Result; return (true, response, "Token authenticated and refreshed."); } } }