Saving changes

Using asymmetric validation
This commit is contained in:
Kun Deng
2022-08-13 18:23:03 -04:00
parent f0551a4801
commit 467a9d7e0f
12 changed files with 528 additions and 1 deletions
+180
View File
@@ -1,9 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using JWT;
using JWT.Serializers;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using RestSharp;
using Icarus.Models;
@@ -15,6 +25,8 @@ namespace Icarus.Controllers.Managers
#region Fields
private string _clientId;
private string _clientSecret;
private string _privateKeyPath;
private string _publicKeyPath;
private string _audience;
private string _grantType;
private string _url;
@@ -68,6 +80,172 @@ namespace Icarus.Controllers.Managers
Message = "Successfully retrieved token"
};
}
public LoginResult LogIn(User user)
{
var tokenResult = new Token();
tokenResult.TokenType = "Jwt";
var privateKey = ReadKeyContent(_privateKeyPath).Result;
var publicKey = ReadKeyContent(_publicKeyPath).Result;
var payload = Payload();
var token = CreateToken(payload, privateKey);
tokenResult.AccessToken = token;
var expClaim = payload.FirstOrDefault(cl =>
{
return cl.Type.Equals("exp");
});
tokenResult.Expiration = System.Convert.ToInt32(expClaim.Value);
return new LoginResult
{
UserID = user.UserID, Username = user.Username, Token = tokenResult.AccessToken,
TokenType = tokenResult.TokenType, Expiration = tokenResult.Expiration,
Message = "Successfully retrieved token"
};
}
private string AllScopes()
{
var allScopes = new List<String>()
{
"download:songs",
"read:song_details",
"upload:songs",
"delete:songs",
"read:albums",
"read:artists",
"update:songs",
"stream:songs",
"read:genre",
"read:year",
"download:cover_art"
};
var scopes = string.Empty;
for (var i = 0; i < allScopes.Count; i++)
{
if (i == allScopes.Count - 1)
{
scopes += allScopes[i];
}
else
{
scopes += allScopes[i] + " ";
}
}
return scopes;
}
private List<Claim> Payload()
{
const int expLimit = 24;
var currentDate = DateTime.Now;
var expiredDate = currentDate.AddHours(expLimit);
var issued = Math.Floor((currentDate - DateTime.UnixEpoch).TotalSeconds);
var expires = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds);
var issuer = "https://soaricarus.auth0.com";
issuer = "http://localhost:5002";
var audience = "https://icarus/api";
audience = "http://localhost:5002";
var claim = new List<System.Security.Claims.Claim>()
{
new System.Security.Claims.Claim("scope", AllScopes(), "string"),
new System.Security.Claims.Claim("exp", $"{expires}", "integer"),
new System.Security.Claims.Claim("aud", $"{audience}", "string"),
new System.Security.Claims.Claim("iss", $"{issuer}", "string"),
new System.Security.Claims.Claim("iat", $"{issued}", "integer")
};
return claim;
}
private string CreateToken(List<Claim> claims, string privateKey)
{
var token = string.Empty;
if (string.IsNullOrEmpty(privateKey))
{
privateKey = ReadKeyContent(_privateKeyPath).Result;
}
RSAParameters rsaParams;
using (var tr = new System.IO.StringReader(privateKey))
{
var pemReader = new PemReader(tr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
if (keyPair == null)
{
throw new Exception("Could not read RSA private key");
}
var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
var rsaParamsPublic = GetRSAPublic(ReadKeyContent(_publicKeyPath).Result);
var rsaPublic = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParams);
rsaPublic.ImportParameters(rsaParamsPublic);
Dictionary<string, object> payload = new Dictionary<string, object>();
foreach (var claim in claims)
{
var type = claim.Type;
var val = Int32.TryParse(claim.Value, out _);
if (val)
{
payload.Add(type, Convert.ToInt32(claim.Value));
}
else
{
payload.Add(type, claim.Value);
}
}
var algorithm = new JWT.Algorithms.RS256Algorithm(rsaPublic, rsa);
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
token = encoder.Encode(payload, privateKey);
}
return token;
}
private RSAParameters GetRSAPublic(string publicKey)
{
using (var tr = new System.IO.StringReader(publicKey))
{
var pemReader = new PemReader(tr);
var publicKeyParams = pemReader.ReadObject() as RsaKeyParameters;
if (publicKeyParams == null)
{
throw new Exception("Could not read RSA public key");
}
return DotNetUtilities.ToRSAParameters(publicKeyParams);
}
}
private async Task<string> ReadKeyContent(string filepath)
{
return await System.IO.File.ReadAllTextAsync(filepath);
}
private TokenRequest RetrieveTokenRequest()
{
@@ -89,6 +267,8 @@ namespace Icarus.Controllers.Managers
_audience = _config["Auth0:ApiIdentifier"];
_grantType = "client_credentials";
_url = $"https://{_config["Auth0:Domain"]}";
_privateKeyPath = _config["RSAKeys:PrivateKeyPath"];
_publicKeyPath = _config["RSAKeys:PublicKeyPath"];
PrintCredentials();
}
+1 -1
View File
@@ -73,7 +73,7 @@ namespace Icarus.Controllers.V1
TokenManager tk = new TokenManager(_config);
loginRes = tk.RetrieveLoginResult(user);
loginRes = tk.LogIn(user);
return Ok(loginRes);
}