From 79c17f75cdab4ccc0806d376b972799f2fc3313a Mon Sep 17 00:00:00 2001 From: Robert Marshall Date: Sun, 12 Apr 2020 14:25:16 +0100 Subject: [PATCH] Use new Auth API --- .../Data/AuthenticationProviderTests.cs | 55 +++++++++++++++++++ .../Data/MySQLDatabaseProviderTests.cs | 32 ----------- Website.Tests/Models/UserTests.cs | 17 ------ Website.Tests/Website.Tests.csproj | 3 +- Website/Controllers/AccountController.cs | 8 +-- Website/Data/AuthenticationProvider.cs | 19 +++++++ Website/Data/IAuthenticationProvider.cs | 8 +++ Website/Data/IDatabaseProvider.cs | 9 --- Website/Data/MySQLDatabaseProvider.cs | 17 ------ Website/Data/States/UserState.cs | 10 ---- Website/Data/UserRepository.cs | 25 --------- Website/Models/User.cs | 28 +--------- Website/Startup.cs | 6 +- Website/Website.csproj | 3 - Website/appsettings.Development.json | 3 +- Website/appsettings.json | 1 + 16 files changed, 94 insertions(+), 150 deletions(-) create mode 100644 Website.Tests/Data/AuthenticationProviderTests.cs delete mode 100644 Website.Tests/Data/MySQLDatabaseProviderTests.cs delete mode 100644 Website.Tests/Models/UserTests.cs create mode 100644 Website/Data/AuthenticationProvider.cs create mode 100644 Website/Data/IAuthenticationProvider.cs delete mode 100644 Website/Data/IDatabaseProvider.cs delete mode 100644 Website/Data/MySQLDatabaseProvider.cs delete mode 100644 Website/Data/States/UserState.cs delete mode 100644 Website/Data/UserRepository.cs diff --git a/Website.Tests/Data/AuthenticationProviderTests.cs b/Website.Tests/Data/AuthenticationProviderTests.cs new file mode 100644 index 0000000..5d3eb83 --- /dev/null +++ b/Website.Tests/Data/AuthenticationProviderTests.cs @@ -0,0 +1,55 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using FluentAssertions; +using Website.Data; +using Website.Models; +using Xunit; + +namespace Website.Tests.Data { + public class AuthenticationProviderTests { + [Fact] + public async Task Authenticate_WithSuccessfulLoginRequest_ReturnsUser() { + const string json = @"{""username"":""username"",""password"":""password""}"; + var httpClient = new HttpClientBuilder() + .WithMethod(HttpMethod.Post) + .WithUrl("/authenticate") + .WithPostBody(@"{""Username"":""username"",""Password"":""password"",""ReturnUrl"":null}") + .WithResponse(json) + .Build(); + + var request = new LoginRequest { + Username = "username", + Password = "password" + }; + + var expectedUser = new User { + Username = "username", + Password = "password" + }; + + var provider = new AuthenticationProvider(httpClient); + (await provider.Authenticate(request)).Should().BeEquivalentTo(expectedUser); + } + + [Fact] + public async Task Authenticate_WithFailedLoginRequest_ReturnsNull() { + const string json = @"{""username"":""username"",""password"":""password""}"; + var httpClient = new HttpClientBuilder() + .WithMethod(HttpMethod.Post) + .WithUrl("/authenticate") + .WithPostBody(@"{""Username"":""username"",""Password"":""password"",""ReturnUrl"":null}") + .WithErrorStatus(HttpStatusCode.Unauthorized) + .WithResponse(json) + .Build(); + + var request = new LoginRequest { + Username = "username", + Password = "wrong" + }; + + var provider = new AuthenticationProvider(httpClient); + (await provider.Authenticate(request)).Should().BeNull(); + } + } +} \ No newline at end of file diff --git a/Website.Tests/Data/MySQLDatabaseProviderTests.cs b/Website.Tests/Data/MySQLDatabaseProviderTests.cs deleted file mode 100644 index b4c4967..0000000 --- a/Website.Tests/Data/MySQLDatabaseProviderTests.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Website.Data; -using Xunit; -using FluentAssertions; -using MySql.Data.MySqlClient; -using NSubstitute; -using Microsoft.Extensions.Configuration; - -namespace Website.Tests.Data -{ - public class MySQLDatabaseProviderTests - { - const string ConnectionString = "Server=host;User ID=username;Password=password;Database=database"; - - [Fact] - public void NewConnection_WithStringConstructor_ReturnsMySQLConnection() { - var provider = new MySQLDatabaseProvider(ConnectionString); - var connection = provider.NewConnection(); - connection.Should().BeOfType(); - (connection as MySqlConnection).ConnectionString.Should().Be(ConnectionString); - } - - [Fact] - public void NewConnection_WithConfigConstructor_ReturnsMySQLConnection() { - var config = Substitute.For(); - config.GetConnectionString("database").Returns(ConnectionString); - var provider = new MySQLDatabaseProvider(ConnectionString); - var connection = provider.NewConnection(); - connection.Should().BeOfType(); - (connection as MySqlConnection).ConnectionString.Should().Be(ConnectionString); - } - } -} \ No newline at end of file diff --git a/Website.Tests/Models/UserTests.cs b/Website.Tests/Models/UserTests.cs deleted file mode 100644 index 6a3a76d..0000000 --- a/Website.Tests/Models/UserTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -using FluentAssertions; -using Website.Models; -using Xunit; - -namespace Website.Tests.Models { - public class UserTests { - [Fact] - public void ValidatePassword_WithValidSHA256Input_ReturnsTrue() { - var user = new User { - Password= "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" - }; - - - user.ValidatePassword("password").Should().BeTrue(); - } - } -} \ No newline at end of file diff --git a/Website.Tests/Website.Tests.csproj b/Website.Tests/Website.Tests.csproj index 3a4ffb3..d74d9bc 100644 --- a/Website.Tests/Website.Tests.csproj +++ b/Website.Tests/Website.Tests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 @@ -14,7 +14,6 @@ - diff --git a/Website/Controllers/AccountController.cs b/Website/Controllers/AccountController.cs index 5fb5740..a4ad69b 100644 --- a/Website/Controllers/AccountController.cs +++ b/Website/Controllers/AccountController.cs @@ -10,9 +10,9 @@ using Website.ViewModels; namespace Website.Controllers { public class AccountController:Controller { - private readonly UserRepository _repo; + private readonly IAuthenticationProvider _authenticationProvider; - public AccountController(UserRepository repo) => _repo = repo; + public AccountController(IAuthenticationProvider authenticationProvider) => _authenticationProvider = authenticationProvider; [Authorize] public IActionResult Index() => View(); @@ -29,8 +29,8 @@ namespace Website.Controllers { [HttpPost] public async Task Login(LoginRequest request) { try { - var user = await _repo.GetUserByEmail(request.Username); - return user.ValidatePassword(request.Password) + var user = await _authenticationProvider.Authenticate(request); + return user != null ? await SetIdentityAndRedirect(request.ReturnUrl, user) : Login(request.ReturnUrl, true); } diff --git a/Website/Data/AuthenticationProvider.cs b/Website/Data/AuthenticationProvider.cs new file mode 100644 index 0000000..dbaeeb1 --- /dev/null +++ b/Website/Data/AuthenticationProvider.cs @@ -0,0 +1,19 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Website.Models; + +namespace Website.Data { + public class AuthenticationProvider:ApiClient, IAuthenticationProvider { + public AuthenticationProvider(HttpClient client) : base(client) { + } + + public async Task Authenticate(LoginRequest request) { + try { + return await Post("authenticate", request); + } + catch (ApiCallException) { + return null; + } + } + } +} \ No newline at end of file diff --git a/Website/Data/IAuthenticationProvider.cs b/Website/Data/IAuthenticationProvider.cs new file mode 100644 index 0000000..40e431c --- /dev/null +++ b/Website/Data/IAuthenticationProvider.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; +using Website.Models; + +namespace Website.Data { + public interface IAuthenticationProvider { + Task Authenticate(LoginRequest request); + } +} \ No newline at end of file diff --git a/Website/Data/IDatabaseProvider.cs b/Website/Data/IDatabaseProvider.cs deleted file mode 100644 index 7423ac0..0000000 --- a/Website/Data/IDatabaseProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Data; - -namespace Website.Data -{ - public interface IDatabaseProvider - { - IDbConnection NewConnection(); - } -} \ No newline at end of file diff --git a/Website/Data/MySQLDatabaseProvider.cs b/Website/Data/MySQLDatabaseProvider.cs deleted file mode 100644 index e9155a0..0000000 --- a/Website/Data/MySQLDatabaseProvider.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Data; -using Microsoft.Extensions.Configuration; -using MySql.Data.MySqlClient; - -namespace Website.Data -{ - public class MySQLDatabaseProvider:IDatabaseProvider - { - private readonly string _connectionString; - - public MySQLDatabaseProvider(IConfiguration config) => _connectionString = config.GetConnectionString("database"); - - public MySQLDatabaseProvider(string connectionString) => _connectionString = connectionString; - - public IDbConnection NewConnection() => new MySqlConnection(_connectionString); - } -} \ No newline at end of file diff --git a/Website/Data/States/UserState.cs b/Website/Data/States/UserState.cs deleted file mode 100644 index 1b699dd..0000000 --- a/Website/Data/States/UserState.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Website.Data.States { - public class UserState { - public string User_Id { get; set; } - public string User_Email { get; set; } - public string User_Password { get; set; } - public string User_Created { get; set; } - public string User_Deleted { get; set; } - public string Group_Id { get; set; } - } -} \ No newline at end of file diff --git a/Website/Data/UserRepository.cs b/Website/Data/UserRepository.cs deleted file mode 100644 index 6e91b56..0000000 --- a/Website/Data/UserRepository.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Dapper; -using Website.Data.States; -using Website.Models; - -namespace Website.Data { - public class UserRepository { - private readonly IDatabaseProvider _dbProvider; - - public UserRepository(IDatabaseProvider dbProvider) { - _dbProvider = dbProvider; - } - - public async Task GetUserByEmail(string email) { - const string query = "SELECT * FROM users WHERE user_email=@email"; - - using (var connection = _dbProvider.NewConnection()) { - connection.Open(); - var result = await connection.QueryAsync(query, new {email}); - return new User(result.Single()); - } - } - } -} \ No newline at end of file diff --git a/Website/Models/User.cs b/Website/Models/User.cs index 67a9fb6..fb3f670 100644 --- a/Website/Models/User.cs +++ b/Website/Models/User.cs @@ -1,31 +1,5 @@ -using System.Security.Cryptography; -using System.Text; -using Website.Data.States; - -namespace Website.Models { +namespace Website.Models { public class User { - public User() { - } - - public User(UserState state) { - Username = state.User_Email; - Password = state.User_Password; - } - - public bool ValidatePassword(string password) { - using (var sha256 = SHA256.Create()) { - var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(password)); - - var builder = new StringBuilder(); - foreach (var b in hash) - builder.Append(b.ToString("x2")); - var hashString = builder.ToString(); - - return hashString == Password; - } - } - - public string Username { get; set; } public string Password { get; set; } } diff --git a/Website/Startup.cs b/Website/Startup.cs index 2151cd3..977d386 100644 --- a/Website/Startup.cs +++ b/Website/Startup.cs @@ -1,5 +1,4 @@ using System; -using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; @@ -32,8 +31,6 @@ namespace Website }); services.AddSingleton(Configuration); - services.AddSingleton() - .AddSingleton(); services.AddHttpClient(client => client.BaseAddress = new Uri(Configuration["gitApiEndpoint"])) .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler {ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true}); @@ -41,6 +38,9 @@ namespace Website services.AddHttpClient(client => client.BaseAddress = new Uri(Configuration["blogApiEndpoint"])) .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler {ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true}); + services.AddHttpClient(client => client.BaseAddress = new Uri(Configuration["authApiEndpoint"])) + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler {ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true}); + services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); services.AddMvc(options => options.EnableEndpointRouting = false) diff --git a/Website/Website.csproj b/Website/Website.csproj index 02f1db5..a354948 100644 --- a/Website/Website.csproj +++ b/Website/Website.csproj @@ -8,11 +8,8 @@ - - - diff --git a/Website/appsettings.Development.json b/Website/appsettings.Development.json index ff63028..78368ec 100644 --- a/Website/appsettings.Development.json +++ b/Website/appsettings.Development.json @@ -10,5 +10,6 @@ "database": "Server=localhost;User ID=user;Password=pass;Database=db" }, "blogApiEndpoint": "", - "gitApiEndpoint": "" + "gitApiEndpoint": "", + "authApiEndpoint": "" } \ No newline at end of file diff --git a/Website/appsettings.json b/Website/appsettings.json index afd4a11..9a16c5c 100644 --- a/Website/appsettings.json +++ b/Website/appsettings.json @@ -9,6 +9,7 @@ }, "blogApiEndpoint": "", "gitApiEndpoint": "", + "authApiEndpoint": "", "AllowedHosts": "*", "Kestrel": { "EndPoints": {