Files
Aaru.Server/Aaru.Server.New/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs

126 lines
6.9 KiB
C#
Raw Normal View History

2024-05-03 03:24:40 +01:00
using System.Reflection;
2024-05-02 07:43:47 +01:00
using System.Security.Claims;
using System.Text.Json;
2024-05-03 03:24:40 +01:00
using Aaru.Server.New.Components.Account.Pages;
using Aaru.Server.New.Components.Account.Pages.Manage;
using Aaru.Server.New.Data;
2024-05-02 07:43:47 +01:00
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Routing;
2024-05-03 03:24:40 +01:00
static class IdentityComponentsEndpointRouteBuilderExtensions
2024-05-02 07:43:47 +01:00
{
// These endpoints are required by the Identity Razor components defined in the /Components/Account/Pages directory of this project.
public static IEndpointConventionBuilder MapAdditionalIdentityEndpoints(this IEndpointRouteBuilder endpoints)
{
ArgumentNullException.ThrowIfNull(endpoints);
2024-05-03 03:24:40 +01:00
RouteGroupBuilder accountGroup = endpoints.MapGroup("/Account");
2024-05-02 07:43:47 +01:00
accountGroup.MapPost("/PerformExternalLogin",
(HttpContext context, [FromServices] SignInManager<ApplicationUser> signInManager,
[FromForm] string provider, [FromForm] string returnUrl) =>
{
IEnumerable<KeyValuePair<string, StringValues>> query =
[
2024-05-03 03:24:40 +01:00
new KeyValuePair<string, StringValues>("ReturnUrl", returnUrl),
new KeyValuePair<string, StringValues>("Action",
ExternalLogin.LoginCallbackAction)
2024-05-02 07:43:47 +01:00
];
2024-05-03 03:24:40 +01:00
string redirectUrl = UriHelper.BuildRelative(context.Request.PathBase,
"/Account/ExternalLogin",
QueryString.Create(query));
2024-05-02 07:43:47 +01:00
2024-05-03 03:24:40 +01:00
AuthenticationProperties properties =
2024-05-02 07:43:47 +01:00
signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return TypedResults.Challenge(properties, [provider]);
});
accountGroup.MapPost("/Logout",
async (ClaimsPrincipal user, SignInManager<ApplicationUser> signInManager,
[FromForm] string returnUrl) =>
{
await signInManager.SignOutAsync();
return TypedResults.LocalRedirect($"~/{returnUrl}");
});
2024-05-03 03:24:40 +01:00
RouteGroupBuilder manageGroup = accountGroup.MapGroup("/Manage").RequireAuthorization();
2024-05-02 07:43:47 +01:00
manageGroup.MapPost("/LinkExternalLogin",
async (HttpContext context, [FromServices] SignInManager<ApplicationUser> signInManager,
[FromForm] string provider) =>
{
// Clear the existing external cookie to ensure a clean login process
await context.SignOutAsync(IdentityConstants.ExternalScheme);
2024-05-03 03:24:40 +01:00
string redirectUrl = UriHelper.BuildRelative(context.Request.PathBase,
"/Account/Manage/ExternalLogins",
QueryString.Create("Action",
ExternalLogins
.LinkLoginCallbackAction));
2024-05-02 07:43:47 +01:00
2024-05-03 03:24:40 +01:00
AuthenticationProperties properties =
2024-05-02 07:43:47 +01:00
signInManager.ConfigureExternalAuthenticationProperties(provider,
redirectUrl,
signInManager.UserManager.GetUserId(context.User));
return TypedResults.Challenge(properties, [provider]);
});
2024-05-03 03:24:40 +01:00
ILoggerFactory loggerFactory = endpoints.ServiceProvider.GetRequiredService<ILoggerFactory>();
ILogger downloadLogger = loggerFactory.CreateLogger("DownloadPersonalData");
2024-05-02 07:43:47 +01:00
manageGroup.MapPost("/DownloadPersonalData",
async (HttpContext context, [FromServices] UserManager<ApplicationUser> userManager,
[FromServices] AuthenticationStateProvider authenticationStateProvider) =>
{
2024-05-03 03:24:40 +01:00
ApplicationUser? user = await userManager.GetUserAsync(context.User);
2024-05-02 07:43:47 +01:00
if(user is null)
{
return
Results
.NotFound($"Unable to load user with ID '{userManager.GetUserId(context.User)}'.");
}
2024-05-03 03:24:40 +01:00
string userId = await userManager.GetUserIdAsync(user);
2024-05-02 07:43:47 +01:00
downloadLogger.LogInformation("User with ID '{UserId}' asked for their personal data.",
userId);
// Only include personal data for download
var personalData = new Dictionary<string, string>();
2024-05-03 03:24:40 +01:00
IEnumerable<PropertyInfo> personalDataProps = typeof(ApplicationUser).GetProperties()
2024-05-02 07:43:47 +01:00
.Where(prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));
2024-05-03 03:24:40 +01:00
foreach(PropertyInfo p in personalDataProps)
2024-05-02 07:43:47 +01:00
personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
2024-05-03 03:24:40 +01:00
IList<UserLoginInfo> logins = await userManager.GetLoginsAsync(user);
2024-05-02 07:43:47 +01:00
2024-05-03 03:24:40 +01:00
foreach(UserLoginInfo l in logins)
2024-05-02 07:43:47 +01:00
personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey);
personalData.Add("Authenticator Key",
(await userManager.GetAuthenticatorKeyAsync(user))!);
2024-05-03 03:24:40 +01:00
byte[] fileBytes = JsonSerializer.SerializeToUtf8Bytes(personalData);
2024-05-02 07:43:47 +01:00
context.Response.Headers.TryAdd("Content-Disposition",
"attachment; filename=PersonalData.json");
2024-05-03 03:24:40 +01:00
return TypedResults.File(fileBytes, "application/json", "PersonalData.json");
2024-05-02 07:43:47 +01:00
});
return accountGroup;
}
}