using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using IdentityModel.Client; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; using xCommons.Constants; using xCommons.Extensions; using xExceptions.Constants; using xExceptions.Models; using xIdentityModels.Models; using xIdentityService.Interfaces; public static partial class XTokenExtensions { /// /// Retrieve Tokens From Headers /// /// /// public static XLoginResponse RetrieveTokens (this HttpRequest source) { // var accessToken = source.Headers[XAuthorization.Header].ToString (); var refreshToken = source.Headers[XAuthorization.RefreshToken].ToString (); // var expiresAtStr = source.Headers[XAuthorization.ExpiresAt].ToString (); long expiresAt = expiresAtStr.ConvertTo (); // if (accessToken .ToNormalString () .Contains (XAuthorization.TokenIdentifier.ToNormalString ())) { accessToken = accessToken.Remove (0, XAuthorization.TokenIdentifier.Length); } // return new XLoginResponse { AccessToken = accessToken, RefreshToken = refreshToken, ExpiresAt = expiresAt }; } /// /// Retrieve Tokens From HttpContext /// /// /// public static async Task RetrieveTokens (this HttpContext source) { // var accessToken = await source.GetTokenAsync (XAuthorization.AccessToken); if (accessToken .ToNormalString () .Contains (XAuthorization.TokenIdentifier.ToNormalString ())) { accessToken = accessToken.Remove (0, XAuthorization.TokenIdentifier.Length); } var refreshToken = await source.GetTokenAsync (XAuthorization.RefreshToken); var expiresAtStr = await source.GetTokenAsync (XAuthorization.ExpiresAt); long expiresAt = expiresAtStr.ConvertTo (); // var headerRequestTokens = source.Request.RetrieveTokens (); // var result = new XLoginResponse { AccessToken = accessToken ?? headerRequestTokens.AccessToken, RefreshToken = refreshToken ?? headerRequestTokens.RefreshToken, ExpiresAt = expiresAt != 0 ? expiresAt : headerRequestTokens.ExpiresAt }; // return result; } /// /// Retrieve Tokens From ActionExecutingContext /// /// /// public static async Task RetrieveTokens (this ActionExecutingContext source) { // var result = await source.HttpContext.RetrieveTokens (); return result; } /// /// Retrieve Tokens From XUserInfo instance /// /// /// public static XTokenResponse RetrieveTokens (this XUserClaimsInfoDto source) { // var result = new XLoginResponse { AccessToken = source.AccessToken, RefreshToken = source.RefreshToken, ExpiresAt = source.ExpiresAt }; // return result; } /// /// Retrieve Tokens From IHeader Dictionary /// /// /// public static XLoginResponse RetrieveTokens (this IHeaderDictionary source) { // var accessToken = source[XAuthorization.Header].ToString () ?? ""; if (accessToken .ToNormalString () .Contains (XAuthorization.TokenIdentifier.ToNormalString ())) { accessToken = accessToken.Remove (0, XAuthorization.TokenIdentifier.Length); } // var refreshToken = source[XAuthorization.RefreshToken].ToString () ?? ""; // var expiresAtStr = source[XAuthorization.ExpiresAt].ToString () ?? ""; var expiresAt = expiresAtStr.ConvertTo (); // var result = new XLoginResponse { AccessToken = accessToken, RefreshToken = refreshToken, ExpiresAt = expiresAt }; // return result; } /// /// Retrieve IXIdentityProvider from HttpContext /// /// /// public static IXIdentityProvider GetXApiIdentityProvider (this FilterContext source) { // var services = source.HttpContext.RequestServices; return (IXIdentityProvider) services .GetService (typeof (IXIdentityProvider)); } /// /// Generate XLoginResponse instance based on TokenResponse /// /// /// public static XLoginResponse CreateXLoginResponse (this TokenResponse source) { // if (source.IsNull () || source.IsError) { XException.InvalidToken.Throw (); } // var expiresAt = new DateTimeOffset (DateTime.UtcNow) .ToUnixTimeSeconds () + source.ExpiresIn; // var result = new XLoginResponse { AccessToken = source.AccessToken, RefreshToken = source.RefreshToken, ExpiresAt = expiresAt }; // return result; } /// /// Add Authorization Tokens in Headers of /// Specific IHeaderDictionary instance /// /// /// public static void SetXAuthenticationTokens (this IHeaderDictionary source, XLoginResponse model, string secret = null) { // source.Remove (XAuthorization.Header); source.Remove (XAuthorization.RefreshToken); source.Remove (XAuthorization.ExpiresAt); source.Remove (XAuthorization.RevisionChecksum); // source.Add (XAuthorization.Header, $"{XAuthorization.TokenIdentifier}{model.AccessToken}"); source.Add (XAuthorization.RefreshToken, $"{model.RefreshToken}"); source.Add (XAuthorization.ExpiresAt, $"{model.ExpiresAt}"); // if (!secret.IsNullOrEmpty ()) { var revisionChecksum = model.GetRevisionChecksum (secret); source.Add (XAuthorization.RevisionChecksum, revisionChecksum); } } /// /// Add Authorization Tokens in Headers of /// Specific IHeaderDictionary instance /// /// /// public static void SetXAuthenticationTokens (this HttpRequestHeaders source, XLoginResponse model) { // source.Remove (XAuthorization.Header); source.Remove (XAuthorization.RefreshToken); source.Remove (XAuthorization.ExpiresAt); source.Remove (XAuthorization.RevisionChecksum); // source.Add (XAuthorization.Header, $"{XAuthorization.TokenIdentifier}{model.AccessToken}"); source.Add (XAuthorization.RefreshToken, $"{model.RefreshToken}"); source.Add (XAuthorization.ExpiresAt, $"{model.ExpiresAt}"); } /// /// Add Authorization Tokens in Headers of /// Specific HttpRequest instance /// /// /// public static void SetXAuthenticationTokens (this HttpRequest source, XLoginResponse model) { source.Headers.SetXAuthenticationTokens (model); } /// /// Add Authorization Tokens in Headers of /// Specific HttpRequest instance /// /// /// public static void SetXAuthenticationTokens (this HttpRequestMessage source, XLoginResponse model) { source.Headers.SetXAuthenticationTokens (model); } /// /// Add ReNewed Authorization Tokens in Headers of /// Specific Response. /// Later in HttpInterceptors we can Look for AccessToken-ReNewed /// header Value and Renew User Tokens based on it /// /// /// public static void SetXAuthenticationTokens (this HttpResponse source, XLoginResponse model, string secret) { source.Headers.SetXAuthenticationTokens (model, secret); } /// /// Determines a Token Can Refrsh or not /// /// /// public static bool IsRefreshable (this XLoginResponse source) { // var containsTokenData = !source.IsNull () && !source.AccessToken.IsNullOrEmpty () && !source.RefreshToken.IsNullOrEmpty (); if (!containsTokenData) { return false; } // var current = new DateTimeOffset (DateTime.UtcNow) .ToUnixTimeSeconds (); // // var result = current > source.ExpiresAt || current > source.ExpiresAt - XAuthorization.ThresholdBeforeTokenExpiration; var result = current > source.ExpiresAt - XAuthorization.ThresholdBeforeTokenExpiration; // return result; } /// /// Generate a Revision Checksum for new Tokens /// /// /// /// public static string GetRevisionChecksum (this XLoginResponse source, string secret) { return (source.AccessToken + secret + source.RefreshToken + secret + source.ExpiresAt.ToString () ) .ToMd5String (); } /// /// Generate a Revision Checksum for new Tokens /// /// /// /// public static string GetRevisionChecksum (this XTokenResponse source, string secret) { return (source.AccessToken + secret + source.RefreshToken + secret + source.ExpiresAt.ToString () ) .ToMd5String (); } /// /// Check an XLoginResponse instance is Valid with it's revision /// /// /// /// /// public static bool ValidateRevisionChecksum (this XLoginResponse source, string checksum, string secret) { // var xChecksum = source.GetRevisionChecksum (secret); return checksum == xChecksum; } /// /// Check an XTokenResponse instance is Valid with it's revision /// /// /// /// /// public static bool ValidateRevisionChecksum (this XTokenResponse source, string checksum, string secret) { // var xChecksum = source.GetRevisionChecksum (secret); return checksum == xChecksum; } /// /// Retrieve Exception Details if Fails /// /// /// public static Exception GetException (this TokenResponse source) { // // Validate Args ... if (source.IsNull () || !source.IsError) { return XException.ActionFailed.ToException (); } // XError error = source.ErrorDescription.FromJSON (); return error.ToException (); } /// /// Convert XTokenResponse to Header Dictionary /// /// /// public static IDictionary ToHeaderDictionary (this XTokenResponse source) { // var result = new Dictionary { { XAuthorization.RefreshToken, source.RefreshToken }, { XAuthorization.ExpiresAt, source.ExpiresAt.ToString () } }; // return result; } }