Implemented Auth0 functionality to handler authentication. Not complete, will add to it some more. #15

This commit is contained in:
amazing-username
2019-04-21 21:07:13 -04:00
parent 4ba342b625
commit a161d2277a
14 changed files with 351 additions and 5 deletions
+32
View File
@@ -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;
}
}
}
+19
View File
@@ -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));
}
}
}
View File
View File
+54
View File
@@ -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);
}
}
}
+2
View File
@@ -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
}
}
+21
View File
@@ -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
}
}
-4
View File
@@ -14,10 +14,6 @@ namespace Icarus.Models.Context
this.ConnectionString = connectionString;
}
public void InsertSongDetails()
{
}
public void SaveSong(Song song)
{
+104
View File
@@ -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
}
}
+4
View File
@@ -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
View File
@@ -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();
}
+4
View File
@@ -6,6 +6,10 @@
"Microsoft": "Information"
}
},
"Auth0": {
"Domain": "[domain].auth0.com",
"ApiIdentifier": "https://[identifier]/api"
},
"ConnectionStrings": {
"DefaultConnection":"Server=;Database=;Uid=;Pwd=;"
},
+4
View File
@@ -5,6 +5,10 @@
}
},
"AllowedHosts": "*",
"Auth0": {
"Domain": "[domain].auth0.com",
"ApiIdentifier": "https://[identifier]/api"
},
"ConnectionStrings": {
"DefaultConnection":"Server=;Database=;Uid=;Pwd=;"
},