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;" - } }