[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:
parent
1ace285d35
commit
e5e66e8a3d
3 changed files with 59 additions and 21 deletions
|
@ -29,11 +29,28 @@
|
||||||
<input type="checkbox" name="autoDetectQuotes" id="autoDetectQuotes" value="1"/>
|
<input type="checkbox" name="autoDetectQuotes" id="autoDetectQuotes" value="1"/>
|
||||||
<label for="autoDetectQuotes">Automatically detect quotes</label>
|
<label for="autoDetectQuotes">Automatically detect quotes</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="margin-bottom-5px margin-top-10px">
|
@if (Model.AuthenticatedUsers.Count > 0)
|
||||||
Log in below to confirm this:
|
{
|
||||||
|
<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>
|
</div>
|
||||||
<input type="text" placeholder="Username" name="username"/>
|
<input type="text" placeholder="Username" name="username"/>
|
||||||
<input type="password" placeholder="Password" name="password"/>
|
<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>
|
<button type="submit">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,6 +16,7 @@ public class AuthorizeModel(DatabaseContext db) : PageModel
|
||||||
|
|
||||||
public List<string> Scopes = [];
|
public List<string> Scopes = [];
|
||||||
public OauthToken? Token;
|
public OauthToken? Token;
|
||||||
|
public List<User> AuthenticatedUsers = [];
|
||||||
[FromQuery(Name = "response_type")] public string ResponseType { get; set; } = null!;
|
[FromQuery(Name = "response_type")] public string ResponseType { get; set; } = null!;
|
||||||
[FromQuery(Name = "client_id")] public string ClientId { 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 = "redirect_uri")] public string RedirectUri { get; set; } = null!;
|
||||||
|
@ -41,25 +42,41 @@ public class AuthorizeModel(DatabaseContext db) : PageModel
|
||||||
throw GracefulException.BadRequest("Invalid response_type");
|
throw GracefulException.BadRequest("Invalid response_type");
|
||||||
if (!App.RedirectUris.Contains(RedirectUri))
|
if (!App.RedirectUris.Contains(RedirectUri))
|
||||||
throw GracefulException.BadRequest("Cannot request redirect_uri not sent during app registration");
|
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(
|
public async Task OnPost(
|
||||||
[FromForm] string username, [FromForm] string password, [FromForm] bool supportsHtmlFormatting,
|
[FromForm] string? username, [FromForm] string? password, [FromForm] string? userId,
|
||||||
[FromForm] bool autoDetectQuotes
|
[FromForm] bool supportsHtmlFormatting, [FromForm] bool autoDetectQuotes
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Validate query parameters first
|
// Validate query parameters & populate model first
|
||||||
await OnGet();
|
await OnGet();
|
||||||
|
|
||||||
var user = await db.Users.FirstOrDefaultAsync(p => p.IsLocalUser &&
|
var user = AuthenticatedUsers.FirstOrDefault(p => p.Id == userId);
|
||||||
p.UsernameLower == username.ToLowerInvariant());
|
|
||||||
if (user == null)
|
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);
|
var userSettings = await db.UserSettings.FirstOrDefaultAsync(p => p.User == user);
|
||||||
if (userSettings?.Password == null)
|
if (userSettings?.Password == null)
|
||||||
throw GracefulException.Forbidden("Invalid username or password");
|
throw Forbidden();
|
||||||
if (AuthHelpers.ComparePassword(password, userSettings.Password) == false)
|
if (AuthHelpers.ComparePassword(password, userSettings.Password) == false)
|
||||||
throw GracefulException.Forbidden("Invalid username or password");
|
throw Forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
var token = new OauthToken
|
var token = new OauthToken
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.margin-top-5px {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.margin-top-10px {
|
.margin-top-10px {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue