Skip to content

Commit

Permalink
add identity sessions page
Browse files Browse the repository at this point in the history
lists active and inactive sessions
  • Loading branch information
josxha committed Jan 5, 2024
1 parent d05ff7f commit f720348
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 51 deletions.
207 changes: 207 additions & 0 deletions OryAdmin/Components/Pages/Identities/Users/Sessions.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
@page "/identities/users/{UserId}/sessions"
@rendermode InteractiveServer
@inject NavigationManager nav

<PageTitle>View Identity | OryAdmin</PageTitle>

<h1 class="title">Identity Sessions</h1>
@if (_isLoading)
{
<p>Loading data...</p>
}
else
{
<div class="box">
<h1 class="title">Active Sessions</h1>
@if (_activeSessions!.Count == 0)
{
<p>This user has no active sessions.</p>
}
else
{
<table class="table is-fullwidth">
<thead>
<tr>
<td>ID</td>
<td>Authentication Methods</td>
<td>Authenticator Assurance Level</td>
<td>Devices</td>
<td>Timestamps</td>
<td></td>
</tr>
</thead>
<tbody>
@foreach (var session in _activeSessions!)
{
<tr>
<td>@session.Id</td>
<td>@string.Join(", ", session.AuthenticationMethods.Select(method => method.Method.ToString()))</td>
<td>@session.AuthenticatorAssuranceLevel</td>
<td>
@foreach (var device in session.Devices)
{
<p>@device.Id (@device.IpAddress)</p>
}
</td>
<td>
<p>Authenticated: @session.AuthenticatedAt</p>
<p>Issued: @session.IssuedAt</p>
<p>Expires: @session.ExpiresAt</p>
</td>
<td>
<button class="button is-warning is-small"
@onclick="() => _sessionToInvoke = session">
Invoke
</button>
</td>
</tr>
}
</tbody>
</table>

@if (_sessionToInvoke != null)
{
<div id="delete-identity-modal" class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Confirm Invoke Session</p>
<button class="delete" aria-label="close"
@onclick="() => _sessionToInvoke = null">
</button>
</header>
<section class="modal-card-body">
<p>Are you sure to invoke the identity session?</p>
</section>
<footer class="modal-card-foot">
<button class="button" data-target="delete-identity-modal"
type="button" @onclick="() => _sessionToInvoke = null">
Cancel
</button>
<div class="button is-warning"
@onclick="() => InvokeSession(_sessionToInvoke.Id)">
Yes
</div>
</footer>
</div>
</div>
}
}
</div>

<div class="box">
<h1 class="title">Inactive Sessions</h1>
@if (_inactiveSessions!.Count == 0)
{
<p>This user has no inactive sessions.</p>
}
else
{
<table class="table is-fullwidth">
<thead>
<tr>
<td>ID</td>
<td>Authentication Methods</td>
<td>Authenticator Assurance Level</td>
<td>Devices</td>
<td>Timestamps</td>
<td></td>
</tr>
</thead>
<tbody>
@foreach (var session in _inactiveSessions!)
{
<tr>
<td>@session.Id</td>
<td>@string.Join(", ", session.AuthenticationMethods.Select(method => method.Method.ToString()))</td>
<td>@session.AuthenticatorAssuranceLevel</td>
<td>
@foreach (var device in session.Devices)
{
<p>@device.Id (@device.IpAddress)</p>
}
</td>
<td>
<p>Authenticated: @session.AuthenticatedAt</p>
<p>Issued: @session.IssuedAt</p>
<p>Expires: @session.ExpiresAt</p>
</td>
<td>
<!--<button class="button is-warning is-small"
@onclick="() => _sessionToExtend = session">
Extend
</button>-->
</td>
</tr>
}
</tbody>
</table>

@if (_sessionToExtend != null)
{
<div id="delete-identity-modal" class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Confirm Extend Session</p>
<button class="delete" aria-label="close"
@onclick="() => _sessionToExtend = null">
</button>
</header>
<section class="modal-card-body">
<p>Are you sure to extend the identity session?</p>
</section>
<footer class="modal-card-foot">
<button class="button" data-target="delete-identity-modal"
type="button" @onclick="() => _sessionToExtend = null">
Cancel
</button>
<div class="button is-warning"
@onclick="() => ExtendSession(_sessionToExtend.Id)">
Yes
</div>
</footer>
</div>
</div>
}
}
</div>
}

<div class="box p-5">
<div class="buttons">
<a class="button is-dark" href="/identities/users/@UserId">Back</a>
<button class="js-modal-trigger button is-danger" data-target="delete-identity-modal"
type="button" @onclick="() => _showDeleteSessionsModal = true">
Delete Sessions
</button>
</div>
</div>

@if (_showDeleteSessionsModal)
{
<div id="delete-identity-modal" class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Confirm Delete User Sessions</p>
<button class="delete" aria-label="close"
@onclick="() => _showDeleteSessionsModal = false">
</button>
</header>
<section class="modal-card-body">
<p>Are you sure to delete every session for this identity?</p>
<p>Be aware that this cannot be undone.</p>
</section>
<footer class="modal-card-foot">
<button class="button" data-target="delete-identity-modal"
type="button" @onclick="() => _showDeleteSessionsModal = false">
Cancel
</button>
<div class="button is-danger" @onclick="DeleteIdentitySessions">
Yes
</div>
</footer>
</div>
</div>
}
63 changes: 63 additions & 0 deletions OryAdmin/Components/Pages/Identities/Users/Sessions.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Components;
using Ory.Kratos.Client.Model;
using OryAdmin.Services;

namespace OryAdmin.Components.Pages.Identities.Users;

public partial class Sessions
{
private List<KratosSession>? _activeSessions;
private List<KratosSession>? _inactiveSessions;
private bool _isLoading = true;
private KratosSession? _sessionToExtend;
private KratosSession? _sessionToInvoke;
private bool _showDeleteSessionsModal;
[Parameter] public string? UserId { get; set; }
[Inject] private ApiService ApiService { get; set; } = default!;
[Inject] private EnvService EnvService { get; set; } = default!;

protected override async Task OnInitializedAsync()
{
await ReloadSessions();
_isLoading = false;
}

private async Task ReloadSessions()
{
var tasks = new List<Task>
{
Task.Run(async () =>
{
_activeSessions = await ApiService.KratosIdentity.ListIdentitySessionsAsync(UserId, active: true);
}),
Task.Run(async () =>
{
_inactiveSessions =
await ApiService.KratosIdentity.ListIdentitySessionsAsync(UserId, active: false);
})
};

await Task.WhenAll(tasks);
}

private async Task DeleteIdentitySessions()
{
await ApiService.KratosIdentity.DeleteIdentitySessionsAsync(UserId);
_showDeleteSessionsModal = false;
await ReloadSessions();
}

private async Task InvokeSession(string sessionId)
{
await ApiService.KratosIdentity.DisableSessionAsync(sessionId);
_sessionToInvoke = null;
await ReloadSessions();
}

private async Task ExtendSession(string sessionId)
{
await ApiService.KratosIdentity.ExtendSessionAsync(sessionId);
_sessionToExtend = null;
await ReloadSessions();
}
}
56 changes: 14 additions & 42 deletions OryAdmin/Components/Pages/Identities/Users/View.razor
Original file line number Diff line number Diff line change
Expand Up @@ -135,79 +135,51 @@ else
</td>
<td>
<button class="button is-warning is-small"
@onclick="() => _identitySessionToInvoke = session">
Disable
@onclick="() => _sessionToInvoke = session">
Invoke
</button>
</td>
</tr>
}
</tbody>
</table>
<div class="buttons">
<button class="js-modal-trigger button is-danger" data-target="delete-identity-modal"
type="button" @onclick="() => _showDeleteSessionsModal = true">
Delete Sessions
</button>
</div>

@if (_identitySessionToInvoke != null)

@if (_sessionToInvoke != null)
{
<div id="delete-identity-modal" class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Confirm Invoke Session</p>
<button class="delete" aria-label="close"
@onclick="() => _identitySessionToInvoke = null">
@onclick="() => _sessionToInvoke = null">
</button>
</header>
<section class="modal-card-body">
<p>Are you sure to invoke the identity session?</p>
<p></p>
<p>Be aware that this cannot be undone.</p>
</section>
<footer class="modal-card-foot">
<button class="button" data-target="delete-identity-modal"
type="button" @onclick="() => _identitySessionToInvoke = null">
type="button" @onclick="() => _sessionToInvoke = null">
Cancel
</button>
<div class="button is-danger"
@onclick="() => DisableIdentitySession(_identitySessionToInvoke.Id)">
Yes
</div>
</footer>
</div>
</div>
}

@if (_showDeleteSessionsModal)
{
<div id="delete-identity-modal" class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Confirm Delete User Sessions</p>
<button class="delete" aria-label="close"
@onclick="() => _showDeleteSessionsModal = false">
</button>
</header>
<section class="modal-card-body">
<p>Are you sure to delete every session for this identity?</p>
<p>Be aware that this cannot be undone.</p>
</section>
<footer class="modal-card-foot">
<button class="button" data-target="delete-identity-modal"
type="button" @onclick="() => _showDeleteSessionsModal = false">
Cancel
</button>
<div class="button is-danger" @onclick="DeleteIdentitySessions">
@onclick="() => DisableIdentitySession(_sessionToInvoke.Id)">
Yes
</div>
</footer>
</div>
</div>
}
}

<div class="buttons pt-3">
<a class="button is-info"
href="/identities/users/@UserId/sessions">
View All Sessions
</a>
</div>
</div>

@if (_oauth2Sessions != null)
Expand Down
10 changes: 1 addition & 9 deletions OryAdmin/Components/Pages/Identities/Users/View.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ public partial class View
{
private List<KratosSession>? _activeSessions;
private KratosIdentity? _identity;
private KratosSession? _identitySessionToInvoke;
private bool _isLoading = true;
private List<HydraOAuth2ConsentSession>? _oauth2Sessions;
private HydraOAuth2ConsentSession? _oauth2SessionToShowDetailsFor;
private KratosSession? _sessionToInvoke;
private bool _showDeleteIdentityModal;
private bool _showDeleteSessionsModal;
private bool _showRevokeOAuth2SessionsModal;
[Parameter] public string? UserId { get; set; }
[Inject] private ApiService ApiService { get; set; } = default!;
Expand Down Expand Up @@ -61,13 +60,6 @@ private async Task RevokeOAuth2ConsentSessions()
_oauth2Sessions = await ApiService.HydraOAuth2.ListOAuth2ConsentSessionsAsync(UserId);
}

private async Task DeleteIdentitySessions()
{
await ApiService.KratosIdentity.DeleteIdentitySessionsAsync(UserId);
_showDeleteSessionsModal = false;
_activeSessions = await ApiService.KratosIdentity.ListIdentitySessionsAsync(UserId, active: true);
}

private async Task DisableIdentitySession(string sessionId)
{
await ApiService.KratosIdentity.DisableSessionAsync(sessionId);
Expand Down

0 comments on commit f720348

Please sign in to comment.