Saving changes
Using asymmetric validation
This commit is contained in:
@@ -3,6 +3,9 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
/.vs/Icarus
|
/.vs/Icarus
|
||||||
|
/bin/*
|
||||||
/bin/Debug/netcoreapp2.2
|
/bin/Debug/netcoreapp2.2
|
||||||
/Migrations
|
/Migrations
|
||||||
/obj
|
/obj
|
||||||
|
/obj/*
|
||||||
|
/Icarus.txt
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
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 Microsoft.Extensions.Configuration;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Org.BouncyCastle.Crypto;
|
||||||
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
using Org.BouncyCastle.OpenSsl;
|
||||||
|
using Org.BouncyCastle.Security;
|
||||||
|
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
using Icarus.Models;
|
using Icarus.Models;
|
||||||
@@ -15,6 +25,8 @@ namespace Icarus.Controllers.Managers
|
|||||||
#region Fields
|
#region Fields
|
||||||
private string _clientId;
|
private string _clientId;
|
||||||
private string _clientSecret;
|
private string _clientSecret;
|
||||||
|
private string _privateKeyPath;
|
||||||
|
private string _publicKeyPath;
|
||||||
private string _audience;
|
private string _audience;
|
||||||
private string _grantType;
|
private string _grantType;
|
||||||
private string _url;
|
private string _url;
|
||||||
@@ -69,6 +81,172 @@ namespace Icarus.Controllers.Managers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
private TokenRequest RetrieveTokenRequest()
|
||||||
{
|
{
|
||||||
_logger.Info("Retrieving token object");
|
_logger.Info("Retrieving token object");
|
||||||
@@ -89,6 +267,8 @@ namespace Icarus.Controllers.Managers
|
|||||||
_audience = _config["Auth0:ApiIdentifier"];
|
_audience = _config["Auth0:ApiIdentifier"];
|
||||||
_grantType = "client_credentials";
|
_grantType = "client_credentials";
|
||||||
_url = $"https://{_config["Auth0:Domain"]}";
|
_url = $"https://{_config["Auth0:Domain"]}";
|
||||||
|
_privateKeyPath = _config["RSAKeys:PrivateKeyPath"];
|
||||||
|
_publicKeyPath = _config["RSAKeys:PublicKeyPath"];
|
||||||
|
|
||||||
PrintCredentials();
|
PrintCredentials();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace Icarus.Controllers.V1
|
|||||||
|
|
||||||
TokenManager tk = new TokenManager(_config);
|
TokenManager tk = new TokenManager(_config);
|
||||||
|
|
||||||
loginRes = tk.RetrieveLoginResult(user);
|
loginRes = tk.LogIn(user);
|
||||||
|
|
||||||
return Ok(loginRes);
|
return Ok(loginRes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
// using MySql.Data.Entity;
|
// using MySql.Data.Entity;
|
||||||
// using MySql.Data.MySqlClient;
|
// using MySql.Data.MySqlClient;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
using Icarus.Models;
|
using Icarus.Models;
|
||||||
|
|
||||||
@@ -18,11 +19,15 @@ namespace Icarus.Database.Contexts
|
|||||||
public DbSet<User> Users { get; set; }
|
public DbSet<User> Users { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
public UserContext(DbContextOptions<UserContext> options) : base(options) { }
|
public UserContext(DbContextOptions<UserContext> options) : base(options) { }
|
||||||
|
[ActivatorUtilitiesConstructor]
|
||||||
public UserContext(string connString) : base(new DbContextOptionsBuilder<UserContext>()
|
public UserContext(string connString) : base(new DbContextOptionsBuilder<UserContext>()
|
||||||
.UseMySQL(connString).Options)
|
.UseMySQL(connString).Options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Icarus.Exceptions
|
||||||
|
{
|
||||||
|
public class InvalidCredentialsException : Exception
|
||||||
|
{
|
||||||
|
public InvalidCredentialsException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCredentialsException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCredentialsException(string message,
|
||||||
|
Exception exception) : base(message, exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Icarus.Models.Shared
|
||||||
|
{
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public IEnumerable<string> Roles { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<Claim> Claims()
|
||||||
|
{
|
||||||
|
var claims = new List<Claim> { new Claim(ClaimTypes.Name, Username) };
|
||||||
|
claims.AddRange(Roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
||||||
|
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ namespace Icarus.Models
|
|||||||
[Table("User")]
|
[Table("User")]
|
||||||
public class User
|
public class User
|
||||||
{
|
{
|
||||||
|
#region Properties
|
||||||
[JsonProperty("user_id")]
|
[JsonProperty("user_id")]
|
||||||
[Column("UserID")]
|
[Column("UserID")]
|
||||||
[Key]
|
[Key]
|
||||||
@@ -35,5 +37,21 @@ namespace Icarus.Models
|
|||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
[JsonProperty("last_login")]
|
[JsonProperty("last_login")]
|
||||||
public DateTime? LastLogin { get; set; }
|
public DateTime? LastLogin { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[NotMapped]
|
||||||
|
public System.Collections.Generic.IEnumerable<string> Roles { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> Claims()
|
||||||
|
{
|
||||||
|
var claims = new System.Collections.Generic.List<System.Security.Claims.Claim> { new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, Username) };
|
||||||
|
claims.AddRange(Roles.Select(role => new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, role)));
|
||||||
|
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// using JwtAuthentication.Shared.Models;
|
||||||
|
// using Icarus.Models.Shared;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Icarus.Repositories
|
||||||
|
{
|
||||||
|
// TODO: Replace this with the UserContext.
|
||||||
|
public class UserRepository
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<Icarus.Models.User> users;
|
||||||
|
|
||||||
|
public UserRepository()
|
||||||
|
{
|
||||||
|
users = new List<Icarus.Models.User>
|
||||||
|
{
|
||||||
|
new Icarus.Models.User
|
||||||
|
{
|
||||||
|
Username = "john.doe",
|
||||||
|
Password = "john.password",
|
||||||
|
Roles = new []{"User"}
|
||||||
|
},
|
||||||
|
new Icarus.Models.User
|
||||||
|
{
|
||||||
|
Username = "jane.doe",
|
||||||
|
Password = "jane.password",
|
||||||
|
Roles = new []{"User", "Admin"}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Icarus.Models.User GetUser(string username)
|
||||||
|
{
|
||||||
|
return users.SingleOrDefault(u => u.Username.Equals(username));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// using JwtAuthentication.Shared.Models;
|
||||||
|
// using JwtAuthentication.Shared.Services;
|
||||||
|
using Icarus;
|
||||||
|
using Icarus.Repositories;
|
||||||
|
using Icarus.Models.Shared;
|
||||||
|
using Icarus.Services;
|
||||||
|
|
||||||
|
namespace Icarus.Services
|
||||||
|
{
|
||||||
|
public class AuthenticationService
|
||||||
|
{
|
||||||
|
private Microsoft.Extensions.Configuration.IConfiguration _configuration;
|
||||||
|
private readonly UserService userService;
|
||||||
|
private readonly TokenService tokenService;
|
||||||
|
|
||||||
|
public AuthenticationService(UserService userService, TokenService tokenService, Microsoft.Extensions.Configuration.IConfiguration configuration)
|
||||||
|
{
|
||||||
|
this.userService = userService;
|
||||||
|
this.tokenService = tokenService;
|
||||||
|
this._configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Authenticate(UserCredentials userCredentials)
|
||||||
|
{
|
||||||
|
userService.ValidateCredentials(userCredentials);
|
||||||
|
string securityToken = tokenService.GetToken(userCredentials.Username);
|
||||||
|
|
||||||
|
return securityToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// using JwtAuthentication.AsymmetricEncryption.Certificates;
|
||||||
|
using Icarus;
|
||||||
|
using Icarus.Repositories;
|
||||||
|
using Icarus.Models.Shared;
|
||||||
|
// using JwtAuthentication.Shared;
|
||||||
|
// using JwtAuthentication.Shared.Models;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Icarus.Services
|
||||||
|
{
|
||||||
|
public class TokenService
|
||||||
|
{
|
||||||
|
private Microsoft.Extensions.Configuration.IConfiguration _configuration;
|
||||||
|
private readonly UserRepository userRepository;
|
||||||
|
private readonly SigningAudienceCertificate signingAudienceCertificate;
|
||||||
|
private string _publickKeyPath = string.Empty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
public TokenService(UserRepository userRepository)
|
||||||
|
{
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
signingAudienceCertificate = new SigningAudienceCertificate();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public TokenService(UserRepository userRepository, Microsoft.Extensions.Configuration.IConfiguration configuration)
|
||||||
|
{
|
||||||
|
this._configuration = configuration;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
signingAudienceCertificate = new SigningAudienceCertificate();
|
||||||
|
_publickKeyPath = configuration["RSAKeys:PublicKeyPath"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetToken(string username)
|
||||||
|
{
|
||||||
|
var user = userRepository.GetUser(username);
|
||||||
|
SecurityTokenDescriptor tokenDescriptor = GetTokenDescriptor(user);
|
||||||
|
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
|
||||||
|
string token = tokenHandler.WriteToken(securityToken);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecurityTokenDescriptor GetTokenDescriptor(Icarus.Models.User user)
|
||||||
|
{
|
||||||
|
const int expiringDays = 7;
|
||||||
|
|
||||||
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Subject = new ClaimsIdentity(user.Claims()),
|
||||||
|
Expires = DateTime.UtcNow.AddDays(expiringDays),
|
||||||
|
SigningCredentials = signingAudienceCertificate.GetAudienceSigningKey(_publickKeyPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
return tokenDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// using JwtAuthentication.Shared.Exceptions;
|
||||||
|
// using JwtAuthentication.Shared.Models;
|
||||||
|
using Icarus.Exceptions;
|
||||||
|
using Icarus.Models.Shared;
|
||||||
|
using Icarus.Services;
|
||||||
|
using Icarus.Repositories;
|
||||||
|
|
||||||
|
namespace Icarus.Services
|
||||||
|
{
|
||||||
|
public class UserService
|
||||||
|
{
|
||||||
|
private Microsoft.Extensions.Configuration.IConfiguration _configuration;
|
||||||
|
private readonly UserRepository userRepository;
|
||||||
|
|
||||||
|
public UserService(UserRepository userRepository, Microsoft.Extensions.Configuration.IConfiguration configuration)
|
||||||
|
{
|
||||||
|
this._configuration = configuration;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ValidateCredentials(UserCredentials userCredentials)
|
||||||
|
{
|
||||||
|
Icarus.Models.User user = userRepository.GetUser(userCredentials.Username);
|
||||||
|
bool isValid = user != null && AreValidCredentials(userCredentials, user);
|
||||||
|
|
||||||
|
if (!isValid)
|
||||||
|
{
|
||||||
|
throw new InvalidCredentialsException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AreValidCredentials(UserCredentials userCredentials, Icarus.Models.User user)
|
||||||
|
{
|
||||||
|
return user.Username == userCredentials.Username &&
|
||||||
|
user.Password == userCredentials.Password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
@@ -4,6 +4,8 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@@ -21,22 +23,113 @@ using Newtonsoft.Json;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Web;
|
using NLog.Web;
|
||||||
using NLog.Web.AspNetCore;
|
using NLog.Web.AspNetCore;
|
||||||
|
using Org.BouncyCastle.Crypto;
|
||||||
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
using Org.BouncyCastle.OpenSsl;
|
||||||
|
using Org.BouncyCastle.Security;
|
||||||
|
|
||||||
|
using Icarus.Services;
|
||||||
|
using Icarus.Repositories;
|
||||||
using Icarus.Authorization;
|
using Icarus.Authorization;
|
||||||
using Icarus.Authorization.Handlers;
|
using Icarus.Authorization.Handlers;
|
||||||
using Icarus.Database.Contexts;
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
namespace Icarus
|
namespace Icarus
|
||||||
{
|
{
|
||||||
|
#region Classes
|
||||||
|
public class SigningIssuerCertificate
|
||||||
|
{
|
||||||
|
public SigningIssuerCertificate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// public or private key?
|
||||||
|
public RsaSecurityKey GetIssuerSigningKey(string publicKeyPath)
|
||||||
|
{
|
||||||
|
var file = publicKeyPath;
|
||||||
|
var publicKey = System.IO.File.ReadAllText(file);
|
||||||
|
var rsa = new RSACryptoServiceProvider();
|
||||||
|
|
||||||
|
using (var reader = System.IO.File.OpenText(file))
|
||||||
|
{
|
||||||
|
var pem = new PemReader(reader);
|
||||||
|
var o = (RsaKeyParameters)pem.ReadObject();
|
||||||
|
var parameters = new RSAParameters();
|
||||||
|
parameters.Modulus = o.Modulus.ToByteArray();
|
||||||
|
parameters.Exponent = o.Exponent.ToByteArray();
|
||||||
|
rsa.ImportParameters(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RsaSecurityKey(rsa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SigningAudienceCertificate
|
||||||
|
{
|
||||||
|
// public or private key?
|
||||||
|
public SigningCredentials GetAudienceSigningKey(string keyPath)
|
||||||
|
{
|
||||||
|
// string privateXmlKey = System.IO.File.ReadAllText("./private_key.xml");
|
||||||
|
// rsa.FromXmlString(privateXmlKey);
|
||||||
|
|
||||||
|
var file = keyPath;
|
||||||
|
var publicKey = System.IO.File.ReadAllText(file);
|
||||||
|
var rsa = new RSACryptoServiceProvider();
|
||||||
|
|
||||||
|
using (var reader = System.IO.File.OpenText(file))
|
||||||
|
{
|
||||||
|
var pem = new PemReader(reader);
|
||||||
|
var o = (RsaKeyParameters)pem.ReadObject();
|
||||||
|
var parameters = new RSAParameters();
|
||||||
|
parameters.Modulus = o.Modulus.ToByteArray();
|
||||||
|
parameters.Exponent = o.Exponent.ToByteArray();
|
||||||
|
rsa.ImportParameters(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SigningCredentials(
|
||||||
|
key: new RsaSecurityKey(rsa),
|
||||||
|
algorithm: SecurityAlgorithms.RsaSha256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static class MyClass
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddAsymmetricAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
// public static IServiceCollection AddAsymmetricAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var issuerSigningCertificate = new SigningIssuerCertificate();
|
||||||
|
RsaSecurityKey issuerSigningKey = issuerSigningCertificate.GetIssuerSigningKey(configuration["RSAKeys:PublicKeyPath"]);
|
||||||
|
|
||||||
|
services.AddAuthentication(authOptions =>
|
||||||
|
{
|
||||||
|
})
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
IssuerSigningKey = issuerSigningKey,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
|
#region Constructors
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
@@ -45,6 +138,7 @@ namespace Icarus
|
|||||||
var auth_id = Configuration["Auth0:Domain"];
|
var auth_id = Configuration["Auth0:Domain"];
|
||||||
var domain = $"https://{auth_id}/";
|
var domain = $"https://{auth_id}/";
|
||||||
var audience = Configuration["Auth0:ApiIdentifier"];
|
var audience = Configuration["Auth0:ApiIdentifier"];
|
||||||
|
/**
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
@@ -103,6 +197,7 @@ namespace Icarus
|
|||||||
|
|
||||||
|
|
||||||
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
|
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
|
||||||
|
*/
|
||||||
|
|
||||||
var connString = Configuration.GetConnectionString("DefaultConnection");
|
var connString = Configuration.GetConnectionString("DefaultConnection");
|
||||||
|
|
||||||
@@ -114,6 +209,21 @@ namespace Icarus
|
|||||||
services.AddDbContext<GenreContext>(options => options.UseMySQL(connString));
|
services.AddDbContext<GenreContext>(options => options.UseMySQL(connString));
|
||||||
services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString));
|
services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString));
|
||||||
|
|
||||||
|
services.AddAsymmetricAuthentication(Configuration);
|
||||||
|
|
||||||
|
services.AddTransient<AuthenticationService>(au => new AuthenticationService(new UserService(new UserRepository(), Configuration), new TokenService(new UserRepository(), Configuration), Configuration));
|
||||||
|
services.AddTransient<UserService>(us => new UserService(new UserRepository(), Configuration));
|
||||||
|
services.AddTransient<TokenService>(tk => new TokenService(new UserRepository(), Configuration));
|
||||||
|
services.AddTransient<UserRepository>();
|
||||||
|
services.AddTransient<UserContext>(uc => new UserContext(connString));
|
||||||
|
/**
|
||||||
|
services.AddTransient<Func<string, UserContext>((providers) =>
|
||||||
|
{
|
||||||
|
return new Func<string, UserContext>((numParams) =>
|
||||||
|
new UserContext(providers.GetRequiredService<IConfiguration>, numParams));
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
services.AddControllers()
|
services.AddControllers()
|
||||||
.AddNewtonsoftJson();
|
.AddNewtonsoftJson();
|
||||||
}
|
}
|
||||||
@@ -131,5 +241,6 @@ namespace Icarus
|
|||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user