DamageAssessment_Backend/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs

470 lines
20 KiB
C#

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 Newtonsoft.Json;
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<UsersAccessProvider> 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<JwtSettings> options, ITokenServiceProvider tokenServiceProvider, IHttpContextAccessor httpContextAccessor, UsersAccessDbContext userAccessDbContext, IEmployeeServiceProvider employeeServiceProvider, ILogger<UsersAccessProvider> 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 { EmployeeId = 1, EmployeeCode = "Emp1", RoleId = 1, IsActive = true, CreateDate = DateTime.Now });
userAccessDbContext.Users.Add(new Db.User { EmployeeId = 2, EmployeeCode = "Emp2", RoleId = 2, IsActive = true, CreateDate = DateTime.Now });
//userAccessDbContext.Users.Add(new Db.User { EmployeeId = 3, EmployeeCode = "Emp3", RoleId = 3, IsActive = true, CreateDate = DateTime.Now });
userAccessDbContext.SaveChanges();
}
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.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<object> Users, string ErrorMessage)> GetUsersAsync()
{
try
{
logger?.LogInformation("Gell all Users from DB");
var users = await userAccessDbContext.Users.ToListAsync();
List<object> userslist = new List<object>();
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);
string FirstName = null, LastName = null, EmployeeName = null;
if (employee != null)
{
string[] names = employee.Name.Split(' ');
EmployeeName = employee.Name;
FirstName = names[0];
LastName = EmployeeName.Replace(FirstName + " ", "");
}
userslist.Add(new
{
Id = user.Id,
EmployeeId = user.EmployeeId,
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
});
}
logger?.LogInformation($"{users.Count} Items(s) found");
// var result = mapper.Map<IEnumerable<Db.User>, IEnumerable<Models.User>>(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);
string FirstName = null, LastName = null, EmployeeName = null;
if (employee != null)
{
string[] names = employee.Name.Split(' ');
EmployeeName = employee.Name;
FirstName = names[0];
LastName = EmployeeName.Replace(FirstName + " ", "");
}
var data = new
{
Id = user.Id,
EmployeeId = user.EmployeeId,
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
};
logger?.LogInformation($"User Id: {Id} found");
var result = mapper.Map<Db.User, Models.User>(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<Models.User, Db.User>(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)
{
Db.User vUsers = mapper.Map<Models.User, Db.User>(user);
vUsers.UpdateDate = DateTime.Now;
userAccessDbContext.Users.Update(vUsers);
userAccessDbContext.SaveChanges();
user.Id = Id;
return (true, user, "Successful");
}
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<Db.User, Models.User>(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, DadeSchoolToken TokenResponse, string ErrorMessage)> AuthenticateAsync(string username, string password)
{
var mode = configuration.GetValue<string>("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
{
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, configuration.GetValue<string>("Dadeschools:TokenUrl"));
var collection = new List<KeyValuePair<string, string>>();
collection.Add(new("client_id", configuration.GetValue<string>("Dadeschools:TokenClientId")));
collection.Add(new("client_secret", configuration.GetValue<string>("Dadeschools:TokenClientSecret")));
collection.Add(new("scope", configuration.GetValue<string>("Dadeschools:scope")));
collection.Add(new("grant_type", configuration.GetValue<string>("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<DadeSchoolToken>(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<string>("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)
{
return (false, null, ex.Message);
}
}
private string DecodeJwtToken(string token)
{
try
{
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(token);
var tokenS = handler.ReadToken(token) as JwtSecurityToken;
if (tokenS == null)
return null;
var payload = tokenS.Payload.SerializeToJson();
return payload;
}
catch
{
return null;
}
}
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.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<Db.User, Models.User>(user)) };
return (true, response, "Authentication success and token issued.");
}
else
{
return (false, null, "user inactive or not exist.");
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.Role> 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<Db.Role>, IEnumerable<Models.Role>>(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<Db.User, Models.User>(user);
var response = tokenServiceProvider.TokenAuthenticate(_user, principal.Claims.ToArray()).Result;
return (true, response, "Token authenticated and refreshed.");
}
}
}