using MyCore.Framework.Business; using MyCore.Interfaces.DTO; using MyCore.Interfaces.Models; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; using System.Security.Cryptography; namespace MyCore.Service.Services { /// /// Tokens service /// public class TokensService { private readonly ILogger _logger; private readonly TokensSettings _tokenSettings; private readonly ProfileLogic _profileLogic; private readonly SigningCredentials _signingCredentials; /// /// Constructor /// /// Logger /// Tokens settings /// Database context /// Profile logic /// Email client public TokensService(ILogger logger, IOptions tokenSettings, ProfileLogic profileLogic) { _logger = logger; _tokenSettings = tokenSettings.Value; _profileLogic = profileLogic; var key = Encoding.UTF8.GetBytes(_tokenSettings.Secret); _signingCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature); } /// /// Authenticate /// /// Email /// Password /// Token DTO in case of success public TokenDTO Authenticate(string email, string password) { try { var claims = new List(); var expiration = DateTime.UtcNow.AddMinutes(_tokenSettings.AccessTokenExpiration); // Todo nothing good here.. var profile = _profileLogic.Authenticate(email, password); claims.Add(new Claim(ClaimTypes.Email, email)); // TODO: add refresh token support var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor() { Subject = new ClaimsIdentity(claims), Expires = expiration, SigningCredentials = _signingCredentials }; var token = tokenHandler.CreateToken(tokenDescriptor); return new TokenDTO() { access_token = tokenHandler.WriteToken(token), expires_in = _tokenSettings.AccessTokenExpiration * 60, expiration = new DateTimeOffset(token.ValidTo), token_type = "Bearer", scope = Security.Scope }; } /*catch (UnauthorizedAccessException ex) { _logger?.LogError(ex, $"Authenticate error for user '{email}': unauthorized access"); throw; }*/ catch (Exception ex) { _logger?.LogError(ex, $"Authenticate error for user '{email}': {ex.Message}"); throw; } } public object GenerateToken(string username) { var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("%G2YZ=\tgN7fC9M$FXDt#q*a&]Z")); // Put the secret in a file or something var claims = new Claim[] { new Claim(ClaimTypes.Name, username), new Claim(JwtRegisteredClaimNames.Email, "john.doe@blinkingcaret.com"), new Claim(ClaimTypes.Role, "Admin") }; var token = new JwtSecurityToken( issuer: "MyCore App", audience: "Miotecher", claims: claims, notBefore: DateTime.Now, expires: DateTime.Now.AddDays(28), signingCredentials: new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256) ); string jwtToken = new JwtSecurityTokenHandler().WriteToken(token); return jwtToken; } public static string GenerateSHA256String(string inputString) { SHA256 sha256 = SHA256Managed.Create(); byte[] bytes = Encoding.UTF8.GetBytes(inputString); byte[] hash = sha256.ComputeHash(bytes); return GetStringFromHash(hash); } public static string GetStringFromHash(byte[] hash) { StringBuilder result = new StringBuilder(); for (int i = 0; i < hash.Length; i++) { result.Append(hash[i].ToString("X2")); } return result.ToString(); } } }