From 2a26e23001e134942f6947c8fd98398c7c1fc624 Mon Sep 17 00:00:00 2001 From: BenceV95 Date: Tue, 25 Feb 2025 17:13:13 +0100 Subject: [PATCH] Fixed auth token blacklisting, enabled authorized endpoints in the data controller and modified the integration test to reflect the change. also reverted the frontend to use the dev enviroment instead of docker --- SolarWatch/Controllers/AuthController.cs | 1 + .../Controllers/SolarWatchController.cs | 4 +- .../Services/Authentication/AuthService.cs | 7 ++- SolarWatch/SolarWatch.csproj.user | 2 +- SolarWatch/SolarWatch.sln.DotSettings.user | 1 + SolarWatchTests/IntegrationTests.cs | 53 +++++++++++++++++-- SolarWatch_Frontend/vite.config.js | 2 +- 7 files changed, 61 insertions(+), 9 deletions(-) diff --git a/SolarWatch/Controllers/AuthController.cs b/SolarWatch/Controllers/AuthController.cs index de68dda..de513df 100644 --- a/SolarWatch/Controllers/AuthController.cs +++ b/SolarWatch/Controllers/AuthController.cs @@ -24,6 +24,7 @@ public AuthController(IAuthService authenticationService) public async Task> RenewToken() { var token = Request.Headers["Authorization"].ToString().Replace("Bearer ", ""); + // do a validation for a valid / not blacklisted token var result = await _authenticationService.RenewTokenAsync(token); if (!result.Success) diff --git a/SolarWatch/Controllers/SolarWatchController.cs b/SolarWatch/Controllers/SolarWatchController.cs index c269ec9..a277dbe 100644 --- a/SolarWatch/Controllers/SolarWatchController.cs +++ b/SolarWatch/Controllers/SolarWatchController.cs @@ -19,7 +19,7 @@ public SolarWatchController(ILogger logger, ISolarDataServ _solarDataService = solarDataService; } - [HttpGet("GeocodingData"), /*Authorize(Roles = "User, Admin")*/] + [HttpGet("GeocodingData"), Authorize(Roles = "User, Admin")] public async Task> GetGeocodingData([Required] string location) { try @@ -35,7 +35,7 @@ public async Task> GetGeocodingData([Required] strin } - [HttpGet("SolarData"), /*Authorize(Roles = "User, Admin")*/] + [HttpGet("SolarData"), Authorize(Roles = "User, Admin")] public async Task> GetSolarData([Required] DateOnly date, [Required] string location) { try diff --git a/SolarWatch/Services/Authentication/AuthService.cs b/SolarWatch/Services/Authentication/AuthService.cs index 8511c70..dbd33a6 100644 --- a/SolarWatch/Services/Authentication/AuthService.cs +++ b/SolarWatch/Services/Authentication/AuthService.cs @@ -7,11 +7,13 @@ public class AuthService : IAuthService { private readonly UserManager _userManager; private readonly ITokenService _tokenService; + private readonly ITokenBlacklistService _tokenBlacklistService; - public AuthService(UserManager userManager, ITokenService tokenService) + public AuthService(UserManager userManager, ITokenService tokenService, ITokenBlacklistService tokenBlacklistService) { _userManager = userManager; _tokenService = tokenService; + _tokenBlacklistService = tokenBlacklistService; } public async Task RegisterAsync(string email, string username, string password, string role) @@ -92,6 +94,7 @@ private static AuthResult FailedRegistration(IdentityResult result, string email public async Task RenewTokenAsync(string token) { + var principal = _tokenService.GetPrincipalFromExpiredToken(token); if (principal == null) { @@ -111,6 +114,8 @@ public async Task RenewTokenAsync(string token) return NoRolesAssigned(user.Email, user.UserName); } + _tokenBlacklistService.AddTokenToBlacklist(token); + var newToken = _tokenService.CreateToken(user, roles[0]); // roles[0] might fail if there are more roles / user return new AuthResult(true, user.Email, user.UserName, newToken); } diff --git a/SolarWatch/SolarWatch.csproj.user b/SolarWatch/SolarWatch.csproj.user index c404400..983ecfc 100644 --- a/SolarWatch/SolarWatch.csproj.user +++ b/SolarWatch/SolarWatch.csproj.user @@ -1,7 +1,7 @@  - https + http ProjectDebugger diff --git a/SolarWatch/SolarWatch.sln.DotSettings.user b/SolarWatch/SolarWatch.sln.DotSettings.user index a310cbe..76bda7d 100644 --- a/SolarWatch/SolarWatch.sln.DotSettings.user +++ b/SolarWatch/SolarWatch.sln.DotSettings.user @@ -3,5 +3,6 @@ <TestAncestor> <TestId>NUnit3x::799DCF59-930B-4FF3-BF8D-EDF88B1AAEB7::net9.0::SolarWatchTests.SolarWatchControllerTests</TestId> <TestId>xUnit::799DCF59-930B-4FF3-BF8D-EDF88B1AAEB7::net9.0::SolarWatchTests.IntegrationTests</TestId> + <TestId>xUnit::799DCF59-930B-4FF3-BF8D-EDF88B1AAEB7::net9.0::SolarWatchTests.IntegrationTestForAuth</TestId> </TestAncestor> </SessionState> \ No newline at end of file diff --git a/SolarWatchTests/IntegrationTests.cs b/SolarWatchTests/IntegrationTests.cs index 77db92c..e15c533 100644 --- a/SolarWatchTests/IntegrationTests.cs +++ b/SolarWatchTests/IntegrationTests.cs @@ -1,6 +1,9 @@ using System; using System.Linq; +using System.Net; using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; using System.Threading.Tasks; using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; @@ -10,17 +13,23 @@ using SolarWatch; using Microsoft.AspNetCore.Hosting; using SolarWatch.Context; +using SolarWatch.Contracts; +using SolarWatch.Controllers; +using Assert = Xunit.Assert; namespace SolarWatchTests { [Collection("IntegrationTests")] - public class IntegrationTests : IClassFixture> + public class IntegrationTestForAuth : IDisposable { private readonly string _dbName = Guid.NewGuid().ToString(); - private readonly HttpClient _client; + public HttpClient Client { get; } + public string Token { get; private set; } - public IntegrationTests(WebApplicationFactory factory) + public IntegrationTestForAuth() { + var factory = new WebApplicationFactory(); + var webAppFactory = factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Test"); @@ -52,9 +61,45 @@ public IntegrationTests(WebApplicationFactory factory) }); }); - _client = webAppFactory.CreateClient(); + Client = webAppFactory.CreateClient(); + RegisterTestUser().GetAwaiter().GetResult(); // register a new user before tests for [Authorize] to work + } + + private async Task RegisterTestUser() + { + var newUser = new RegistrationRequest("testuser@test.com", "testuser", "testuser"); + var response = await Client.PostAsJsonAsync("/Auth/Register", newUser); + response.EnsureSuccessStatusCode(); + + var login = await Client.PostAsJsonAsync("/Auth/Login", new AuthController.AuthRequest("testuser@test.com", "testuser")); + var token = await login.Content.ReadFromJsonAsync(); + Token = token.Token; + + Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token); + } + + public void Dispose() => Client.Dispose(); + } + + public class IntegrationTests : IClassFixture + { + + private readonly HttpClient _client; + + public IntegrationTests(IntegrationTestForAuth setupAuth) + { + _client = setupAuth.Client; + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", setupAuth.Token); } + [Fact] + public async Task LoginTest() + { + + var testEndpoint = await _client.GetAsync("/Auth/testUser"); + + Assert.Equal(HttpStatusCode.OK, testEndpoint.StatusCode); + } [Fact] public async Task GetGeocodingData_ValidLocation_ReturnsOk() diff --git a/SolarWatch_Frontend/vite.config.js b/SolarWatch_Frontend/vite.config.js index b9261d1..699c028 100644 --- a/SolarWatch_Frontend/vite.config.js +++ b/SolarWatch_Frontend/vite.config.js @@ -8,7 +8,7 @@ export default defineConfig({ port: 3000, proxy: { '/api': { - target: process.env.VITE_API_BASE_URL,// || 'https://localhost:7119', // remove .env file and it will work + target: /* process.env.VITE_API_BASE_URL */ 'http://localhost:5158', // remove .env file and it will work changeOrigin: true, secure: false, // DO NOT USE IN PRODUCTION. GET A VALID SSL CERTIFICATE rewrite: (path) => path.replace(/^\/api/, '')