Saving changes
Using asymmetric validation
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user