using System; using System.Configuration; using System.IdentityModel.Tokens; using System.Linq; using System.Net; using System.Net.Http; using System.Security.Claims; using System.ServiceModel.Security.Tokens; using System.Threading; using System.Threading.Tasks; using iiie.Authentication.DBO; using iiie.Logs.DataAccess; using iiie.Logs.DBO; using Newtonsoft.Json; namespace iiie.Authentication.Business.JWT { /// /// Handler for token authentication /// public abstract class TokenValidationHandler : DelegatingHandler { /// /// Gets the token from the HTTP AUthorization header /// /// The HTTP request /// The variable to store the token /// True if the token has been found, false otherwise private static bool TryRetrieveToken(HttpRequestMessage request, out string token) { token = null; var auth = request.Headers.Authorization; if (auth == null || auth.Scheme != "Bearer") return false; token = auth.Parameter; return true; } /// /// Contructs a user dbo from the specified username and salt /// /// The username of the verified token /// The salt in the token /// The user dbo, or null if user is not valid protected abstract BasicUserDbo GetUserDbo(string username, string salt); /// /// Attempts to verify user token /// /// The HTTP request /// Token used for cancelation /// The HTTP response protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { OpResult error; string token; if (!TryRetrieveToken(request, out token)) { return base.SendAsync(request, cancellationToken); } try { var claim = TokenManager.ParseToken(token); Thread.CurrentPrincipal = claim; var name = ((ClaimsIdentity)claim.Identity).Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name); var salt = ((ClaimsIdentity)claim.Identity).Claims.FirstOrDefault(x => x.Type == ClaimTypes.Authentication); var data = ((ClaimsIdentity)claim.Identity).Claims.FirstOrDefault(x => x.Type == ClaimTypes.UserData); if (name == null || salt == null) { error = OpResult.Error(ResultStatus.LoginError, string.Format("Incomplete token; username is present: {0}; salt is present {1}", name != null, salt != null), "Incomplete token").Log(); } else { var user = GetUserDbo(name.Value, salt.Value); if (user == null) { error = OpResult.Error(ResultStatus.LoginError, string.Format("Username {0} not found", name.Value), "").Log(); } else { if (data != null) { user.TokenData = JsonConvert.DeserializeObject(data.Value); } UserStorage.BasicUserDbo = user; return base.SendAsync(request, cancellationToken); } } } catch (Exception e) { error = OpResult.Error(ResultStatus.LoginError, e, "Failed to validate token").Log(); } var resp = request.CreateErrorResponse(HttpStatusCode.Unauthorized, error.PublicDetails); return Task.Factory.StartNew(() => resp, cancellationToken); } } }