From e5e66e8a3df0263c1f1e722e1051625634d4d04e Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Tue, 16 Jul 2024 20:34:10 +0200 Subject: [PATCH] [backend/razor] Allow logging in as users that the frontend has already authenticated (ISH-406) This reduces friction when logging in to multiple apps. --- .../Pages/OAuth/Authorize.cshtml | 27 ++++++++-- .../Pages/OAuth/Authorize.cshtml.cs | 49 +++++++++++++------ .../Pages/OAuth/Authorize.cshtml.css | 4 ++ 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml b/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml index d543590f..d9e28aa4 100644 --- a/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml +++ b/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml @@ -29,11 +29,28 @@ -
- Log in below to confirm this: -
- - + @if (Model.AuthenticatedUsers.Count > 0) + { +
+ @foreach (var user in Model.AuthenticatedUsers) + { + + } +
+
+ Alternatively, sign in with to a different account below: +
+ + + } + else + { +
+ Log in below to confirm this: +
+ + + } diff --git a/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.cs b/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.cs index dbc25a3c..67b74015 100644 --- a/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.cs +++ b/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.cs @@ -16,11 +16,12 @@ public class AuthorizeModel(DatabaseContext db) : PageModel public List Scopes = []; public OauthToken? Token; - [FromQuery(Name = "response_type")] public string ResponseType { get; set; } = null!; - [FromQuery(Name = "client_id")] public string ClientId { get; set; } = null!; - [FromQuery(Name = "redirect_uri")] public string RedirectUri { get; set; } = null!; - [FromQuery(Name = "force_login")] public bool ForceLogin { get; set; } = false; - [FromQuery(Name = "lang")] public string? Language { get; set; } + public List AuthenticatedUsers = []; + [FromQuery(Name = "response_type")] public string ResponseType { get; set; } = null!; + [FromQuery(Name = "client_id")] public string ClientId { get; set; } = null!; + [FromQuery(Name = "redirect_uri")] public string RedirectUri { get; set; } = null!; + [FromQuery(Name = "force_login")] public bool ForceLogin { get; set; } = false; + [FromQuery(Name = "lang")] public string? Language { get; set; } [FromQuery(Name = "scope")] public string Scope @@ -41,25 +42,41 @@ public class AuthorizeModel(DatabaseContext db) : PageModel throw GracefulException.BadRequest("Invalid response_type"); if (!App.RedirectUris.Contains(RedirectUri)) throw GracefulException.BadRequest("Cannot request redirect_uri not sent during app registration"); + if (Request.Cookies.TryGetValue("sessions", out var sessions)) + { + var tokens = sessions.Split(','); + AuthenticatedUsers = await db.Sessions + .Where(p => tokens.Contains(p.Token) && p.Active) + .Select(p => p.User) + .ToListAsync(); + } } public async Task OnPost( - [FromForm] string username, [FromForm] string password, [FromForm] bool supportsHtmlFormatting, - [FromForm] bool autoDetectQuotes + [FromForm] string? username, [FromForm] string? password, [FromForm] string? userId, + [FromForm] bool supportsHtmlFormatting, [FromForm] bool autoDetectQuotes ) { - // Validate query parameters first + // Validate query parameters & populate model first await OnGet(); - var user = await db.Users.FirstOrDefaultAsync(p => p.IsLocalUser && - p.UsernameLower == username.ToLowerInvariant()); + var user = AuthenticatedUsers.FirstOrDefault(p => p.Id == userId); + if (user == null) - throw GracefulException.Forbidden("Invalid username or password"); - var userSettings = await db.UserSettings.FirstOrDefaultAsync(p => p.User == user); - if (userSettings?.Password == null) - throw GracefulException.Forbidden("Invalid username or password"); - if (AuthHelpers.ComparePassword(password, userSettings.Password) == false) - throw GracefulException.Forbidden("Invalid username or password"); + { + Exception Forbidden() => GracefulException.Forbidden("Invalid username or password"); + if (username == null || password == null) + throw Forbidden(); + + user = await db.Users.FirstOrDefaultAsync(p => p.IsLocalUser && + p.UsernameLower == username.ToLowerInvariant()) ?? + throw Forbidden(); + var userSettings = await db.UserSettings.FirstOrDefaultAsync(p => p.User == user); + if (userSettings?.Password == null) + throw Forbidden(); + if (AuthHelpers.ComparePassword(password, userSettings.Password) == false) + throw Forbidden(); + } var token = new OauthToken { diff --git a/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.css b/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.css index 1a12982f..656e0dc2 100644 --- a/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.css +++ b/Iceshrimp.Backend/Pages/OAuth/Authorize.cshtml.css @@ -6,6 +6,10 @@ margin-bottom: 5px; } +.margin-top-5px { + margin-top: 5px; +} + .margin-top-10px { margin-top: 10px; } \ No newline at end of file