Skip to content

Commit

Permalink
fix(authentication): sign in after sign up and sign out after deletin…
Browse files Browse the repository at this point in the history
…g own user profile
  • Loading branch information
undrcrxwn committed Jul 25, 2024
1 parent 2498848 commit 0057db0
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 18 deletions.
29 changes: 22 additions & 7 deletions src/CrowdParlay.Users.Api/v1/Controllers/UsersController.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
using System.Net;
using System.Net.Mime;
using System.Security.Claims;
using System.Text.Json;
using CrowdParlay.Users.Api.Extensions;
using CrowdParlay.Users.Api.v1.DTOs;
using CrowdParlay.Users.Application;
using CrowdParlay.Users.Application.Exceptions;
using CrowdParlay.Users.Application.Extensions;
using CrowdParlay.Users.Application.Features.Users.Commands;
using CrowdParlay.Users.Application.Features.Users.Queries;
using CrowdParlay.Users.Application.Models;
using Dodo.Primitives;
using Mapster;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -41,18 +45,28 @@ public UsersController(IDataProtectionProvider dataProtectionProvider)
throw new ForbiddenException();

var command = request.Adapt<Register.Command>();
Register.Response response;

var encryptedTicketJson = Request.Cookies[ExternalLoginTicketDefaults.CookieKey];
if (encryptedTicketJson is null)
return await Mediator.Send(command);
response = await Mediator.Send(command);
else
{
var ticketJson = _externalLoginTicketProtector.Unprotect(encryptedTicketJson);
command.ExternalLoginTicket = JsonSerializer.Deserialize<ExternalLoginTicket>(ticketJson, GlobalSerializerOptions.SnakeCase)!;

if (command.ExternalLoginTicket.ProviderId == GoogleAuthenticationDefaults.ExternalLoginProviderId)
command.Email = command.ExternalLoginTicket.Identity;

var ticketJson = _externalLoginTicketProtector.Unprotect(encryptedTicketJson);
command.ExternalLoginTicket = JsonSerializer.Deserialize<ExternalLoginTicket>(ticketJson, GlobalSerializerOptions.SnakeCase)!;
Response.Cookies.Delete(ExternalLoginTicketDefaults.CookieKey);
response = await Mediator.Send(command);
}

if (command.ExternalLoginTicket.ProviderId == GoogleAuthenticationDefaults.ExternalLoginProviderId)
command.Email = command.ExternalLoginTicket.Identity;
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity.AddUserClaims(response));
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

Response.Cookies.Delete(ExternalLoginTicketDefaults.CookieKey);
return await Mediator.Send(command);
return response;
}

/// <summary>
Expand Down Expand Up @@ -124,6 +138,7 @@ public async Task Delete([FromRoute] Uuid userId)
if (userId != HttpContext.GetUserId())
throw new ForbiddenException();

await HttpContext.SignOutAsync();
await Mediator.Send(new Delete.Command(userId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,23 @@ public async Task Authenticate_Cookie_Positive()
var registerResponseMessage = await _client.PostAsJsonAsync("/api/v1/users/register", registerRequest, GlobalSerializerOptions.SnakeCase);
var registerResponse = await registerResponseMessage.Content.ReadFromJsonAsync<Register.Response>();

await _client.PostAsync("/api/v1/authentication/sign-out", content: null);

var beforeSignInResponse = await _client.DeleteAsync($"/api/v1/users/{registerResponse!.Id}");
beforeSignInResponse.Should().HaveStatusCode(HttpStatusCode.Unauthorized);

var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["usernameOrEmail"] = registerRequest.Username,
["password"] = registerRequest.Password!
});

var beforeSignInResponse = await _client.DeleteAsync($"/api/v1/users/{registerResponse!.Id}");
beforeSignInResponse.Should().HaveStatusCode(HttpStatusCode.Unauthorized);

var signInResponse = await _client.PostAsync("/api/v1/authentication/sign-in", content);
signInResponse.Should().BeSuccessful();

var afterSignInResponse = await _client.DeleteAsync($"/api/v1/users/{registerResponse.Id}");
afterSignInResponse.Should().BeSuccessful();

var signOutResponse = await _client.PostAsync("/api/v1/authentication/sign-out", content: null);
signOutResponse.Should().BeSuccessful();

var afterSignOutResponse = await _client.DeleteAsync($"/api/v1/users/{registerResponse.Id}");
afterSignOutResponse.Should().HaveStatusCode(HttpStatusCode.Unauthorized);
}
Expand Down Expand Up @@ -96,8 +95,6 @@ public async Task Authenticate_Google_Positive()
_cookies.GetAllCookies().Should().Contain(cookie => cookie.Name == ".CrowdParlay.Authentication");

await _client.DeleteAsync($"/api/v1/users/{registerResponse!.Id}");
var signOutResponse = await _client.PostAsync("/api/v1/authentication/sign-out", content: null);
signOutResponse.Should().BeSuccessful();
}

[Fact(DisplayName = "Double sign in with Google is allowed")]
Expand All @@ -122,8 +119,6 @@ public async Task DoubleSignInWithGoogle_Positive()
signInResponseB.Should().BeRedirection();

await _client.DeleteAsync($"/api/v1/users/{registerResponse!.Id}");
var signOutResponse = await _client.PostAsync("/api/v1/authentication/sign-out", content: null);
signOutResponse.Should().BeSuccessful();
}

[Fact(DisplayName = "Sign up with Google preserves external login ticket")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class UsersControllerTests : IAssemblyFixture<WebApplicationFixture>

public UsersControllerTests(WebApplicationFixture fixture)
{
_client = fixture.WebApplicationFactory.CreateClient();
_client = fixture.WebApplicationFactory.CreateDefaultClient();
_harness = fixture.Services.GetTestHarness();
}

Expand Down

0 comments on commit 0057db0

Please sign in to comment.