Initial curated itworx-knowledge-hub source from 3b1751d0d9dee551aa6994eee0093704dc334817
This commit is contained in:
commit
ad8ad252a9
825 files changed
+124216
No files matched your search
+134
@@ -0,0 +1,134 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using ItWorx.KnowledgeHub.Contracts.Admin;
|
||||
using ItWorx.KnowledgeHub.Contracts.Auth;
|
||||
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
|
||||
|
||||
namespace ItWorx.KnowledgeHub.IntegrationTests.Authorization;
|
||||
|
||||
[Collection(PostgresTestGroup.Name)]
|
||||
public sealed class RoleAuthorizationTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
|
||||
{
|
||||
[Fact]
|
||||
public async Task Unauthenticated_requests_to_admin_endpoints_are_rejected()
|
||||
{
|
||||
using var client = Factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync("/api/v1/admin/users");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Reader_role_cannot_reach_administrator_only_endpoints()
|
||||
{
|
||||
using var adminClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(adminClient, OwnerEmail, OwnerPassword);
|
||||
|
||||
const string readerEmail = "lezer@itworx.test";
|
||||
const string readerPassword = "reader-strong-password";
|
||||
await CreateUserAsync(adminClient, readerEmail, readerPassword, "Reader");
|
||||
|
||||
using var readerClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(readerClient, readerEmail, readerPassword);
|
||||
|
||||
using var response = await readerClient.GetAsync("/api/v1/admin/users");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Editor_role_cannot_reach_administrator_only_endpoints()
|
||||
{
|
||||
using var adminClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(adminClient, OwnerEmail, OwnerPassword);
|
||||
|
||||
const string editorEmail = "redacteur@itworx.test";
|
||||
const string editorPassword = "editor-strong-password";
|
||||
await CreateUserAsync(adminClient, editorEmail, editorPassword, "Editor");
|
||||
|
||||
using var editorClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(editorClient, editorEmail, editorPassword);
|
||||
|
||||
using var response = await editorClient.GetAsync("/api/v1/admin/users");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Administrator_role_can_reach_administrator_only_endpoints()
|
||||
{
|
||||
using var adminClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(adminClient, OwnerEmail, OwnerPassword);
|
||||
|
||||
using var response = await adminClient.GetAsync("/api/v1/admin/users");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Disabling_a_user_immediately_invalidates_their_existing_session_not_only_future_logins()
|
||||
{
|
||||
using var adminClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(adminClient, OwnerEmail, OwnerPassword);
|
||||
|
||||
const string email = "tijdelijk@itworx.test";
|
||||
const string password = "temporary-strong-password";
|
||||
var created = await CreateUserAsync(adminClient, email, password, "Editor");
|
||||
|
||||
using var targetClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(targetClient, email, password);
|
||||
|
||||
var whileEnabled = await targetClient.GetAsync("/api/v1/auth/session");
|
||||
Assert.Equal(HttpStatusCode.OK, whileEnabled.StatusCode);
|
||||
|
||||
var disableResponse = await SetupHelper.PatchWithCsrfAsync(
|
||||
adminClient,
|
||||
$"/api/v1/admin/users/{created.Id}",
|
||||
new UpdateUserRequest(Role: null, Enabled: false));
|
||||
Assert.Equal(HttpStatusCode.OK, disableResponse.StatusCode);
|
||||
|
||||
// The already-issued session cookie must stop working immediately — this is
|
||||
// checked on the very next request, not after any polling delay, because the
|
||||
// security-stamp validation happens on every request (ValidationInterval =
|
||||
// TimeSpan.Zero).
|
||||
var afterDisable = await targetClient.GetFromJsonAsync<SessionResponse>("/api/v1/auth/session");
|
||||
Assert.NotNull(afterDisable);
|
||||
Assert.False(afterDisable.Authenticated);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Administrator_cannot_demote_the_last_enabled_administrator()
|
||||
{
|
||||
using var adminClient = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(adminClient, OwnerEmail, OwnerPassword);
|
||||
|
||||
var session = await adminClient.GetFromJsonAsync<SessionResponse>("/api/v1/auth/session");
|
||||
Assert.NotNull(session);
|
||||
|
||||
var response = await SetupHelper.PatchWithCsrfAsync(
|
||||
adminClient,
|
||||
$"/api/v1/admin/users/{session.UserId}",
|
||||
new UpdateUserRequest(Role: "Reader", Enabled: null));
|
||||
|
||||
Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);
|
||||
}
|
||||
|
||||
private static async Task<UserSummaryResponse> CreateUserAsync(
|
||||
HttpClient adminClient,
|
||||
string email,
|
||||
string password,
|
||||
string role)
|
||||
{
|
||||
var response = await SetupHelper.PostWithCsrfAsync(
|
||||
adminClient,
|
||||
"/api/v1/admin/users",
|
||||
new CreateUserRequest($"Test {role}", email, password, role));
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<UserSummaryResponse>();
|
||||
Assert.NotNull(payload);
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user