using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using GZTW.Pecklist.Models; using GZTW.Pecklist.Util; using System.Linq; using System; //required to inject configuration in constructor using Microsoft.Extensions.Configuration; namespace GZTW.Pecklist.Controllers { //Authentication controller public class AuthController : Controller { private readonly PecklistContext _context; private readonly IConfiguration _configuration; public AuthController(PecklistContext context, IConfiguration configuration)//these two are injected, see startup.cs { _context = context; //_configuration = configuration; //guard clause _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); } //AUTHENTICATE CREDS //RETURN JWT [HttpPost("/authenticate")] public JsonResult PostCreds(string login, string password) { int nFailedAuthDelay = 10000; if (string.IsNullOrWhiteSpace(login) || string.IsNullOrWhiteSpace(password)) { //Make a failed pw wait System.Threading.Thread.Sleep(nFailedAuthDelay); return Json(new { msg = "authentication failed", error = 1 }); } var user = _context.User.SingleOrDefault(m => m.Login == login); if (user == null) { //Make a failed pw wait System.Threading.Thread.Sleep(nFailedAuthDelay); return Json(new { msg = "authentication failed", error = 1 }); } //TODO: do a test login from postman, login as john, then copy pw into db //string pwnewJohn=Hasher.hash(user.Salt,"XXX"); //then login as Joyce and copy pw into db // string pwnewJoyce=Hasher.hash(user.Salt,"XXX"); string hashed = Hasher.hash(user.Salt, password); if (hashed == user.Password) { //get teh secret from appsettings.json var secret = _configuration.GetSection("JWT").GetValue("secret"); byte[] secretKey = System.Text.Encoding.ASCII.GetBytes(secret); var iat = new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds(); //NOTE: pecklist is appropriate for a really long expiry var exp = new DateTimeOffset(DateTime.Now.AddDays(365)).ToUnixTimeSeconds(); //Generate a download token and store it with the user account and return it for the client Guid g = Guid.NewGuid(); string dlkey = Convert.ToBase64String(g.ToByteArray()); dlkey = dlkey.Replace("=", ""); dlkey = dlkey.Replace("+", ""); user.DlKey = dlkey; user.DlKeyExp = exp; _context.User.Update(user); _context.SaveChanges(); var payload = new Dictionary() { { "iat", iat.ToString() }, { "exp", exp.ToString() }, { "iss", "GZTW_Pecklist" }, { "id", user.Id.ToString() } }; //NOTE: probably don't need Jose.JWT as am using Microsoft jwt stuff to validate routes so it should also be able to //issue tokens as well, but it looked cmplex and this works so unless need to remove in future keeping it. string token = Jose.JWT.Encode(payload, secretKey, Jose.JwsAlgorithm.HS256); //string jsonDecoded = Jose.JWT.Decode(token, secretKey); return Json(new { ok = 1, issued = iat, expires = exp, token = token, dlkey = dlkey, name = user.Name, id = user.Id }); } else { //Make a failed pw wait System.Threading.Thread.Sleep(nFailedAuthDelay); return Json(new { msg = "authentication failed", error = 1 }); } } //------------------------------------------------------ }//eoc }//eons