Implemented Auth0 functionality to handler authentication. Not complete, will add to it some more. #15
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
using Icarus.Authorization;
|
||||
|
||||
namespace Icarus.Authorization.Handlers
|
||||
{
|
||||
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
|
||||
{
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
|
||||
HasScopeRequirement requirement)
|
||||
{
|
||||
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var scopes = context.User.FindFirst(c => c.Type == "scope" &&
|
||||
c.Issuer == requirement.Issuer).Value.Split(' ');
|
||||
|
||||
if (scopes.Any(s => s == requirement.Scope))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Icarus.Authorization
|
||||
{
|
||||
public class HasScopeRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public string Issuer { get; }
|
||||
public string Scope { get; }
|
||||
|
||||
|
||||
public HasScopeRequirement(string scope, string issuer)
|
||||
{
|
||||
Scope = scope ?? throw new ArgumentNullException(nameof(scope));
|
||||
Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
using Icarus.Controllers.Managers;
|
||||
using Icarus.Controllers.Utilities;
|
||||
using Icarus.Models;
|
||||
using Icarus.Models.Context;
|
||||
|
||||
namespace Icarus.Controllers
|
||||
{
|
||||
[Route("api/register")]
|
||||
[ApiController]
|
||||
public class RegisterController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
private IConfiguration _config;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructor
|
||||
public RegisterController(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public void Post([FromBody] User user)
|
||||
{
|
||||
Console.WriteLine($"Username: {user.Username}");
|
||||
Console.WriteLine($"Password: {user.Password}");
|
||||
|
||||
PasswordEncryption pe = new PasswordEncryption();
|
||||
user = pe.HashPassword(user);
|
||||
Console.WriteLine($"Hashed Password: {user.Password}");
|
||||
|
||||
UserStoreContext context = HttpContext.RequestServices
|
||||
.GetService(typeof(UserStoreContext))
|
||||
as UserStoreContext;
|
||||
context.SaveUser(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,8 @@ namespace Icarus.Controllers
|
||||
|
||||
|
||||
[HttpGet("{id}")]
|
||||
//[Route("private-scoped")]
|
||||
//[Authorize("download:songs")]
|
||||
public async Task<IActionResult> Get(int id)
|
||||
{
|
||||
MusicStoreContext context = HttpContext.RequestServices
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||
|
||||
using Icarus.Models;
|
||||
|
||||
namespace Icarus.Controllers.Utilities
|
||||
{
|
||||
public class PasswordEncryption
|
||||
{
|
||||
#region Fields
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructor
|
||||
#endregion
|
||||
|
||||
|
||||
#region Methods
|
||||
public User HashPassword(User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userSalt = GenerateSalt();
|
||||
var userHash = GenerateHash(user.Password, userSalt);
|
||||
|
||||
user.Password = userHash;
|
||||
user.Salt = userSalt;
|
||||
|
||||
return user;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var exMsg = ex.Message;
|
||||
Console.WriteLine($"An error occurred {exMsg}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
string GenerateHash(string password, byte[] salt)
|
||||
{
|
||||
|
||||
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
||||
password: password,
|
||||
salt: salt,
|
||||
prf: KeyDerivationPrf.HMACSHA1,
|
||||
iterationCount: 10000,
|
||||
numBytesRequested: 256/8));
|
||||
|
||||
return hashed;
|
||||
}
|
||||
|
||||
byte[] GenerateSalt()
|
||||
{
|
||||
byte[] salt = new byte[128/8];
|
||||
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
rng.GetBytes(salt);
|
||||
}
|
||||
|
||||
|
||||
return salt;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Icarus.Models.Context
|
||||
{
|
||||
public class BaseStoreContext
|
||||
{
|
||||
#region Fields
|
||||
protected string _connectionString;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Methods
|
||||
protected MySqlConnection GetConnection()
|
||||
{
|
||||
return new MySqlConnection(_connectionString);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,6 @@ namespace Icarus.Models.Context
|
||||
this.ConnectionString = connectionString;
|
||||
}
|
||||
|
||||
public void InsertSongDetails()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void SaveSong(Song song)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
using Icarus.Models;
|
||||
|
||||
namespace Icarus.Models.Context
|
||||
{
|
||||
public class UserStoreContext: BaseStoreContext
|
||||
{
|
||||
#region Fields
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructor
|
||||
public UserStoreContext(string connectionString)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Methods
|
||||
public void SaveUser(User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (MySqlConnection conn = GetConnection())
|
||||
{
|
||||
conn.Open();
|
||||
string query = "INSERT INTO Users(Username, Password, Salt, " +
|
||||
"Email, PhoneNumber, Firstname, Lastname, " +
|
||||
"DateCreated, LastLogin) VALUES(@Username, " +
|
||||
"@Password, @Salt, @Email, @PhoneNumber, " +
|
||||
"@Firstname, @Lastname, @DateCreated, @LastLogin)";
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Username", user.Username);
|
||||
cmd.Parameters.AddWithValue("@Password", user.Password);
|
||||
cmd.Parameters.AddWithValue("@Salt", user.Salt);
|
||||
cmd.Parameters.AddWithValue("@Email", user.Email);
|
||||
cmd.Parameters.AddWithValue("@PhoneNumber", user.PhoneNumber);
|
||||
cmd.Parameters.AddWithValue("@Firstname", user.Firstname);
|
||||
cmd.Parameters.AddWithValue("@Lastname", user.Lastname);
|
||||
cmd.Parameters.AddWithValue("@DateCreated", DateTime.Now);
|
||||
cmd.Parameters.AddWithValue("@LastLogin", DateTime.Now);
|
||||
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var exMsg = ex.Message;
|
||||
Console.WriteLine($"An error occurred:\n{exMsg}");
|
||||
}
|
||||
}
|
||||
|
||||
public User RetrieveUser(User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (MySqlConnection conn = GetConnection())
|
||||
{
|
||||
conn.Open();
|
||||
var query = "SELECT * FROM Users WHERE Username=@Username";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Username", user.Username);
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
user.Id = Convert.ToInt32(reader["Id"]);
|
||||
user.Email = reader["Email"].ToString();
|
||||
user.PhoneNumber = reader["PhoneNumber"].ToString();
|
||||
user.Firstname = reader["Firstname"].ToString();
|
||||
user.Lastname = reader["Lastname"].ToString();
|
||||
user.DateCreated = DateTime.ParseExact(reader["DateCreated"].ToString(), "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
|
||||
user.LastLogin = DateTime.ParseExact(reader["LastLogin"].ToString(), "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var exMsg = ex.Message;
|
||||
Console.WriteLine($"An error occurred:\n{exMsg}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,10 @@ namespace Icarus.Models
|
||||
public int Id { get; set; }
|
||||
[JsonProperty("username")]
|
||||
public string Username { get; set; }
|
||||
[JsonProperty("password")]
|
||||
public string Password { get; set; }
|
||||
[JsonIgnore]
|
||||
public byte[] Salt { get; set; }
|
||||
[JsonProperty("email")]
|
||||
public string Email { get; set; }
|
||||
[JsonProperty("phone_number")]
|
||||
|
||||
+34
-1
@@ -2,7 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
@@ -16,7 +19,8 @@ using MySql.Data;
|
||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
using Icarus.Models;
|
||||
using Icarus.Authorization;
|
||||
using Icarus.Authorization.Handlers;
|
||||
using Icarus.Models.Context;
|
||||
|
||||
namespace Icarus
|
||||
@@ -35,13 +39,40 @@ namespace Icarus
|
||||
{
|
||||
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
services.AddSingleton<IConfiguration>(Configuration);
|
||||
|
||||
string domain = $"https://{Configuration["Auth0:Domain"]}/";
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
}).AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = domain;
|
||||
options.Audience = Configuration["Auth0:ApiIdentifier"];
|
||||
});
|
||||
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("download:songs", policy =>
|
||||
policy.Requirements.Add(new HasScopeRequirement
|
||||
("download:songs", domain)));
|
||||
});
|
||||
|
||||
|
||||
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
|
||||
|
||||
var connString = Configuration.GetConnectionString("DefaultConnection");
|
||||
|
||||
services.Add(new ServiceDescriptor(typeof(MusicStoreContext),
|
||||
new MusicStoreContext(Configuration
|
||||
.GetConnectionString("DefaultConnection"))));
|
||||
services.Add(new ServiceDescriptor(typeof(UserStoreContext),
|
||||
new UserStoreContext(Configuration
|
||||
.GetConnectionString("DefaultConnection"))));
|
||||
|
||||
services.AddDbContext<SongContext>(options => options.UseMySQL(connString));
|
||||
services.AddDbContext<UserContext>(options => options.UseMySQL(connString));
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
@@ -57,6 +88,8 @@ namespace Icarus
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseMvc();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"Auth0": {
|
||||
"Domain": "[domain].auth0.com",
|
||||
"ApiIdentifier": "https://[identifier]/api"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection":"Server=;Database=;Uid=;Pwd=;"
|
||||
},
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Auth0": {
|
||||
"Domain": "[domain].auth0.com",
|
||||
"ApiIdentifier": "https://[identifier]/api"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection":"Server=;Database=;Uid=;Pwd=;"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user