/// <summary>Validates the JWT token.</summary> /// <param name="jwtTokenString"></param> /// <param name="subject"></param> /// <returns> /// <c>true</c> if XXXX, <c>false</c> otherwise.</returns> /// <remarks>This would be used server side</remarks> public static (bool isTokenValid, string validatedUsername, JwtSecurityToken jwtToken) ValidateJWTToken(string jwtTokenString, string audience) { // determine who the caller claims to be (as identified by the private key they used) // the private key they used is identified by the kid parameter in the JWT header JwtSecurityToken jwtToken = new JwtSecurityToken(jwtTokenString); //string signingKeyThumbprint = jwtToken.Header.Kid; // find the user that should be associated with the supplied thumbprint //var userInfo = UserController.GetUserWithKeyThumbprint(signingKeyThumbprint); string clientID = jwtToken.GetPayloadValue(CLIENT_ID_CLAIM_NAME); var userInfo = UserController.GetUserWithClientID(clientID); if (userInfo == null) { // fail if thumbprint is not associated with a user in our user repo return(false, string.Empty, null); } if (!userInfo.IsEnabled) { // fail if user is marked disabled in the User Repo return(false, string.Empty, null); } if (jwtToken.Payload.Sub.ToLower() != userInfo.Company.ToLower()) { // fail if sub(ject) value in token payload does not match the value on the user record return(false, string.Empty, null); } if (!jwtToken.Payload.ContainsKey(CLIENT_ID_CLAIM_NAME) || ((string)jwtToken.Payload[CLIENT_ID_CLAIM_NAME] != userInfo.ClientID.ToLower())) { // fail if Client id value in token payload does not match the value on the user record return(false, string.Empty, null); } // create a security key from the certificate SecurityKey key = null; if (!_valdiateCache.TryGetValue(userInfo.KeyThumbprint, out key)) { // load the cert we want to use to validate the JWT var certificate = CertificateController.GetCertificateWithThumbprint(userInfo.KeyThumbprint); key = new X509SecurityKey(certificate); _valdiateCache.Add(userInfo.KeyThumbprint, key); } // setup the token validation parameters TokenValidationParameters validationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = true, ValidAudiences = new[] { audience }, IssuerSigningKeys = new List <SecurityKey>() { key } }; // try and validate the token // if we can validate the JWT using the cert... we use that as a surrogate method for authentication SecurityToken validatedToken; JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); try { handler.ValidateToken(jwtTokenString, validationParameters, out validatedToken); // validation succeeded return(true, userInfo.User, jwtToken); } catch { // validation fails return(false, string.Empty, null); } }
/// <summary>Creates the JWT token.</summary> /// <param name="userName"></param> /// <param name="subject">The subject.</param> /// <param name="audience">The audience.</param> /// <param name="ttlMinutes">The ttlMinutes.</param> /// <param name="httpBody">The httpBody.</param> /// <returns>System.String.</returns> /// <remarks>This would be used on the client side</remarks> public static string CreateJWTToken(string userName, string subject, string audience, int ttlMinutes, string httpBody) { JwtHeader header = null; var userInfo = UserController.GetUserInfo(userName); if (!_createCache.TryGetValue(userName, out header)) { if (ttlMinutes < 1 || ttlMinutes > 30) { throw new ArgumentException($"ttlMinutes paramter value of: [{ttlMinutes}] must be from 1 to 30"); } // Load the Certificate var certificate = CertificateController.GetCertificateWithThumbprint(userInfo.KeyThumbprint); // Represents the cryptographic key and security algorithms that are used to generate a digital signature. var credentials = new SigningCredentials(new X509SecurityKey(certificate), "RS256"); // Create a header class that will use the supplied credentials header = new JwtHeader(credentials); // add to the cache _createCache.Add(userName, header); } // Define the JWT Payload // Note: the specifc content required for this use case (Purchase Auth) needs to be determined JwtPayload payload = null; if (!string.IsNullOrEmpty(httpBody)) { payload = new JwtPayload { { "sub", subject }, { "aud", audience }, { "exp", DateTime.UtcNow.AddMinutes(ttlMinutes).ToEpochSeconds() }, { CLIENT_ID_CLAIM_NAME, userInfo.ClientID }, { BODYHASH_CLAIM_NAME, httpBody.SHA256Hash() }, { HASHTYPE_CLAIM_NAME, @"sha256" } }; } else { payload = new JwtPayload { { "sub", subject }, { "aud", audience }, { "exp", DateTime.UtcNow.AddMinutes(15).ToEpochSeconds() }, }; } // create the JWT var secToken = new JwtSecurityToken(header, payload); var handler = new JwtSecurityTokenHandler(); // convert the Token to a String handler.TokenLifetimeInMinutes = ttlMinutes; var tokenString = handler.WriteToken(secToken); /* * Sample JWT generated * eyJhbGciOiJSUzI1NiIsImtpZCI6IjFERTJERjQ2NkQyMTg4RDMyRjc0ODdCMjlCQzc2OTExNURDNTM0NzIiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJodHRwczovL3d3dy5kYXRhY2Fwc3lzdGVtcy5jb20vIiwiYXVkIjoiaHR0cHM6Ly93d3cud29ybGRwYXkuY29tLyIsImV4cCI6MTU2NTAzNjcyMCwiYm9keWhhc2giOiI4NTFkOTNkMjMwYmE0ZThiMzVkNWE1ZjUwYWY3N2Q2MDgxNmJiY2ZjZGM4NWE4ODUwODZkMzhiZDVjMzM5NjViIiwiaGFzaHR5cGUiOiJzaGEyNTYifQ.bD_Aw72U9niNcy_SWdmmSyb_bcpWe6itbni5D0TunC3lf3_SkGWwnWKRlWViwp59VtC6Vj0B3M5ouXvQ1aI4ehsB6R03uAMkh4zW5HQKhccbInhtpNSeOmGh2IsjZfBK2w8_gs7z3Wsqhvio9N2PTWq9wtAuVUdNCeaBBhtsr_WP8QQjLpm0GswqGLARZc07Rw6bxOIHASsF-4Doy-huDLmydBggjO5YS2y2Wp2_MFmCIawCYvnnrSnhxzvZ1iz7bIwHX614VPlDHc2PlspLp7Lal5oJTOBoh284njuOgVlxwKaW2YjZS0W3dmUgNrro3_JDEvWeJvvgiRXk58bXdw * * using https://jwt.io/ * Header * { * "alg": "RS256", * "kid": "1DE2DF466D2188D32F7487B29BC769115DC53472", * "typ": "JWT" * } * * Payload * { * "sub": "https://www.datacapsystems.com/", * "aud": "https://www.worldpay.com/", * "exp": 1565036720, * "bodyhash": "851d93d230ba4e8b35d5a5f50af77d60816bbcfcdc85a885086d38bd5c33965b", * "hashtype": "sha256" * } */ return(tokenString); }
public static string CreateDownstreamJWTToken(string userName, string subject, string audience, int ttlMinutes, string upstreamjwt) { var userInfo = UserController.GetUserInfo(userName); if (ttlMinutes < 1 || ttlMinutes > 10) { throw new ArgumentException($"ttlMinutes paramter value of: [{ttlMinutes}] must be from 1 to 10"); } // Load the Certificate var certificate = CertificateController.GetCertificateForDP(); #region Experimenting with Pubic Key string publicKey = certificate.GetPublicKeyString(); byte[] bytes = new byte[publicKey.Length * sizeof(char)]; System.Buffer.BlockCopy(publicKey.ToCharArray(), 0, bytes, 0, bytes.Length); // =================== //Create a new instance of RSACryptoServiceProvider. RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); //Get an instance of RSAParameters from ExportParameters function. RSAParameters RSAKeyInfo = RSA.ExportParameters(false); //Set RSAKeyInfo to the public key values. RSAKeyInfo.Modulus = bytes; //Import key parameters into RSA. RSA.ImportParameters(RSAKeyInfo); // =================== #endregion // Represents the cryptographic key and security algorithms that are used to generate a digital signature. var credentials = new SigningCredentials(new X509SecurityKey(certificate), "RS256"); // Create a header class that will use the supplied credentials var header = new JwtHeader(credentials); // Define the JWT Payload // Note: the specifc content required for this use case (Purchase Auth) needs to be determined JwtPayload payload = new JwtPayload { { "sub", subject }, { "aud", audience }, { "exp", DateTime.UtcNow.AddMinutes(15).ToEpochSeconds() }, { "ujwt", upstreamjwt }, }; // create the JWT var secToken = new JwtSecurityToken(header, payload); var handler = new JwtSecurityTokenHandler(); // convert the Token to a String var tokenString = handler.WriteToken(secToken); /* * Sample JWT generated * eyJhbGciOiJSUzI1NiIsImtpZCI6IjFERTJERjQ2NkQyMTg4RDMyRjc0ODdCMjlCQzc2OTExNURDNTM0NzIiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJodHRwczovL3d3dy5kYXRhY2Fwc3lzdGVtcy5jb20vIiwiYXVkIjoiaHR0cHM6Ly93d3cud29ybGRwYXkuY29tLyIsImV4cCI6MTU2NTAzNjcyMCwiYm9keWhhc2giOiI4NTFkOTNkMjMwYmE0ZThiMzVkNWE1ZjUwYWY3N2Q2MDgxNmJiY2ZjZGM4NWE4ODUwODZkMzhiZDVjMzM5NjViIiwiaGFzaHR5cGUiOiJzaGEyNTYifQ.bD_Aw72U9niNcy_SWdmmSyb_bcpWe6itbni5D0TunC3lf3_SkGWwnWKRlWViwp59VtC6Vj0B3M5ouXvQ1aI4ehsB6R03uAMkh4zW5HQKhccbInhtpNSeOmGh2IsjZfBK2w8_gs7z3Wsqhvio9N2PTWq9wtAuVUdNCeaBBhtsr_WP8QQjLpm0GswqGLARZc07Rw6bxOIHASsF-4Doy-huDLmydBggjO5YS2y2Wp2_MFmCIawCYvnnrSnhxzvZ1iz7bIwHX614VPlDHc2PlspLp7Lal5oJTOBoh284njuOgVlxwKaW2YjZS0W3dmUgNrro3_JDEvWeJvvgiRXk58bXdw * * using https://jwt.io/ * Header * { * "alg": "RS256", * "kid": "1DE2DF466D2188D32F7487B29BC769115DC53472", * "typ": "JWT" * } * * Payload * { * "sub": "https://www.datacapsystems.com/", * "aud": "https://www.worldpay.com/", * "exp": 1565036720, * "bodyhash": "851d93d230ba4e8b35d5a5f50af77d60816bbcfcdc85a885086d38bd5c33965b", * "hashtype": "sha256" * } */ return(tokenString); }