[backend/razor] Allow logging in as users that the frontend has already authenticated (ISH-406)

This reduces friction when logging in to multiple apps.
This commit is contained in:
Laura Hausmann 2024-07-16 20:34:10 +02:00
parent 1ace285d35
commit e5e66e8a3d
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
3 changed files with 59 additions and 21 deletions

View file

@ -29,11 +29,28 @@
<input type="checkbox" name="autoDetectQuotes" id="autoDetectQuotes" value="1"/>
<label for="autoDetectQuotes">Automatically detect quotes</label>
</div>
<div class="margin-bottom-5px margin-top-10px">
Log in below to confirm this:
@if (Model.AuthenticatedUsers.Count > 0)
{
<div class="margin-top-5px">
@foreach (var user in Model.AuthenticatedUsers)
{
<button type="submit" name="userId" value="@user.Id">Log in as @@@user.Username</button>
}
</div>
<div class="margin-bottom-5px margin-top-5px">
Alternatively, sign in with to a different account below:
</div>
<input type="text" placeholder="Username" name="username"/>
<input type="password" placeholder="Password" name="password"/>
}
else
{
<div class="margin-bottom-5px margin-top-10px">
Log in below to confirm this:
</div>
<input type="text" placeholder="Username" name="username" required/>
<input type="password" placeholder="Password" name="password" required/>
}
<button type="submit">Submit</button>
</form>
</div>

View file

@ -16,6 +16,7 @@ public class AuthorizeModel(DatabaseContext db) : PageModel
public List<string> Scopes = [];
public OauthToken? Token;
public List<User> 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!;
@ -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");
{
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 GracefulException.Forbidden("Invalid username or password");
throw Forbidden();
if (AuthHelpers.ComparePassword(password, userSettings.Password) == false)
throw GracefulException.Forbidden("Invalid username or password");
throw Forbidden();
}
var token = new OauthToken
{

View file

@ -6,6 +6,10 @@
margin-bottom: 5px;
}
.margin-top-5px {
margin-top: 5px;
}
.margin-top-10px {
margin-top: 10px;
}