From b0d77084e64fc32fb06f7e44b7453b08a9f18a94 Mon Sep 17 00:00:00 2001 From: minux Date: Tue, 10 Dec 2024 22:43:55 +0900 Subject: [PATCH] Rename Admin Role to SystemAdmin for Clarity (#1054) Motivation: The term "Admin" does not clearly convey its purpose as a system-wide administrator role, as discussed in [issue #1048](https://github.com/line/centraldogma/issues/1048). Renaming this role improves clarity for users and developers. Modifications: - Renamed all "Admin" to "SystemAdmin" across the codebase. - Updated `MetadataService.updateTokenLevel()` to avoid directly accessing the `admin` property. Result: - The role name "Admin" has been replaced with "SystemAdmin". - (Breaking) - `authentication.administrators` in dogma.json is now `authentication.systemAdministrators`. - (Deprecation) - Use `systemAdmin` property instead of `admin` when creating a token via REST API: ```json {"appId": "foo", "isSystemAdmin": true, ...} ``` - Use `SYSTEMADMIN` instead of `admin` when changing the token level: ```json {"level":"SYSTEMADMIN"} ``` --- .../client/armeria/xds/AuthUpstreamTest.java | 2 +- .../git/LegacyGitMirrorSettingsTest.java | 2 +- .../it/mirror/git/MirrorRunnerTest.java | 48 +++--- .../it/mirror/git/ZoneAwareMirrorTest.java | 2 +- .../centraldogma/it/NonRandomTokenTest.java | 12 +- .../it/ReplicationWriteQuotaTest.java | 2 +- .../it/StandaloneWriteQuotaTest.java | 2 +- .../centraldogma/it/WriteQuotaTestBase.java | 8 +- .../server/test/XdsMemberPermissionTest.java | 2 +- .../MirroringAndCredentialServiceV1Test.java | 42 ++--- .../centraldogma/server/CentralDogma.java | 8 +- .../server/CentralDogmaBuilder.java | 24 +-- .../centraldogma/server/auth/AuthConfig.java | 20 +-- .../command/AbstractCommandExecutor.java | 2 +- .../server/command/ForcePushCommand.java | 2 +- ....java => SystemAdministrativeCommand.java} | 6 +- .../command/UpdateServerStatusCommand.java | 2 +- .../admin/auth/CsrfTokenAuthorizer.java | 4 +- .../admin/auth/SessionTokenAuthorizer.java | 13 +- .../server/internal/api/ContentServiceV1.java | 8 +- .../internal/api/CredentialServiceV1.java | 4 +- .../server/internal/api/HttpApiUtil.java | 2 +- .../internal/api/MetadataApiService.java | 4 +- .../server/internal/api/ProjectServiceV1.java | 8 +- .../internal/api/RepositoryServiceV1.java | 2 +- ....java => SystemAdministrativeService.java} | 8 +- .../internal/api/TokenLevelRequest.java | 2 +- .../server/internal/api/TokenService.java | 44 +++--- .../api/auth/RequiresPermissionDecorator.java | 10 +- .../api/auth/RequiresRoleDecorator.java | 2 +- ....java => RequiresSystemAdministrator.java} | 8 +- ...RequiresSystemAdministratorDecorator.java} | 20 +-- .../converter/HttpApiRequestConverter.java | 5 +- .../storage/project/ProjectApiManager.java | 11 +- .../server/metadata/MetadataService.java | 43 +++--- .../centraldogma/server/metadata/Token.java | 32 ++-- .../centraldogma/server/metadata/User.java | 23 +-- .../server/metadata/UserWithToken.java | 4 +- .../server/storage/project/Project.java | 4 +- .../admin/model/SerializationTest.java | 4 +- .../api/ProjectServiceV1ListProjectTest.java | 40 ++--- .../internal/api/ProjectServiceV1Test.java | 38 ++--- ...a => SystemAdministrativeServiceTest.java} | 2 +- .../server/internal/api/TokenServiceTest.java | 146 ++++++++++-------- .../metadata/MetadataApiServiceTest.java | 19 +-- .../server/metadata/MetadataServiceTest.java | 6 +- .../server/metadata/TokenTest.java | 111 ++++++++++++- site/src/sphinx/auth.rst | 25 +-- .../CentralDogmaReplicationExtension.java | 2 +- .../common/components/ProjectSearchBox.tsx | 2 +- .../src/dogma/common/components/UserRole.tsx | 2 +- webapp/src/dogma/features/api/apiSlice.ts | 4 +- .../src/dogma/features/auth/ProjectRole.tsx | 2 +- webapp/src/dogma/features/auth/UserDto.ts | 2 +- webapp/src/dogma/features/auth/authSlice.ts | 2 +- .../src/dogma/features/project/Projects.tsx | 6 +- .../settings/credentials/CredentialView.tsx | 4 +- .../features/token/DisplaySecretModal.tsx | 4 +- webapp/src/dogma/features/token/NewToken.tsx | 10 +- webapp/src/dogma/features/token/TokenDto.ts | 2 +- webapp/src/pages/api/v0/users/me.ts | 2 +- webapp/src/pages/api/v1/tokens.ts | 2 +- webapp/src/pages/app/settings/tokens.tsx | 4 +- .../webapp/ShiroCentralDogmaTestServer.java | 2 +- 64 files changed, 511 insertions(+), 379 deletions(-) rename server/src/main/java/com/linecorp/centraldogma/server/command/{AdministrativeCommand.java => SystemAdministrativeCommand.java} (79%) rename server/src/main/java/com/linecorp/centraldogma/server/internal/api/{AdministrativeService.java => SystemAdministrativeService.java} (93%) rename server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/{RequiresAdministrator.java => RequiresSystemAdministrator.java} (82%) rename server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/{RequiresAdministratorDecorator.java => RequiresSystemAdministratorDecorator.java} (73%) rename server/src/test/java/com/linecorp/centraldogma/server/internal/api/{AdministrativeServiceTest.java => SystemAdministrativeServiceTest.java} (99%) diff --git a/client/java-armeria-xds/src/test/java/com/linecorp/centraldogma/client/armeria/xds/AuthUpstreamTest.java b/client/java-armeria-xds/src/test/java/com/linecorp/centraldogma/client/armeria/xds/AuthUpstreamTest.java index 3acdfb7e78..de50be2d62 100644 --- a/client/java-armeria-xds/src/test/java/com/linecorp/centraldogma/client/armeria/xds/AuthUpstreamTest.java +++ b/client/java-armeria-xds/src/test/java/com/linecorp/centraldogma/client/armeria/xds/AuthUpstreamTest.java @@ -65,7 +65,7 @@ class AuthUpstreamTest { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); } diff --git a/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/LegacyGitMirrorSettingsTest.java b/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/LegacyGitMirrorSettingsTest.java index 963ec8b992..d099316396 100644 --- a/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/LegacyGitMirrorSettingsTest.java +++ b/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/LegacyGitMirrorSettingsTest.java @@ -41,7 +41,7 @@ class LegacyGitMirrorSettingsTest { @Override protected void configure(CentralDogmaBuilder builder) { builder.authProviderFactory(new TestAuthProviderFactory()); - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); } }; diff --git a/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/MirrorRunnerTest.java b/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/MirrorRunnerTest.java index d33ce5c203..95e7bfe783 100644 --- a/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/MirrorRunnerTest.java +++ b/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/MirrorRunnerTest.java @@ -60,7 +60,7 @@ class MirrorRunnerTest { @Override protected void configure(CentralDogmaBuilder builder) { builder.authProviderFactory(new TestAuthProviderFactory()); - builder.administrators(USERNAME); + builder.systemAdministrators(USERNAME); } @Override @@ -82,15 +82,15 @@ protected void scaffold(CentralDogma client) { } }; - private BlockingWebClient adminClient; + private BlockingWebClient systemAdminClient; @BeforeEach void setUp() throws Exception { final String adminToken = getAccessToken(dogma.httpClient(), USERNAME, PASSWORD); - adminClient = WebClient.builder(dogma.httpClient().uri()) - .auth(AuthToken.ofOAuth2(adminToken)) - .build() - .blocking(); + systemAdminClient = WebClient.builder(dogma.httpClient().uri()) + .auth(AuthToken.ofOAuth2(adminToken)) + .build() + .blocking(); TestMirrorRunnerListener.reset(); } @@ -98,31 +98,31 @@ void setUp() throws Exception { void triggerMirroring() throws Exception { final PublicKeyCredential credential = getCredential(); ResponseEntity response = - adminClient.prepare() - .post("/api/v1/projects/{proj}/credentials") - .pathParam("proj", FOO_PROJ) - .contentJson(credential) - .asJson(PushResultDto.class) - .execute(); + systemAdminClient.prepare() + .post("/api/v1/projects/{proj}/credentials") + .pathParam("proj", FOO_PROJ) + .contentJson(credential) + .asJson(PushResultDto.class) + .execute(); assertThat(response.status()).isEqualTo(HttpStatus.CREATED); final MirrorDto newMirror = newMirror(); - response = adminClient.prepare() - .post("/api/v1/projects/{proj}/mirrors") - .pathParam("proj", FOO_PROJ) - .contentJson(newMirror) - .asJson(PushResultDto.class) - .execute(); + response = systemAdminClient.prepare() + .post("/api/v1/projects/{proj}/mirrors") + .pathParam("proj", FOO_PROJ) + .contentJson(newMirror) + .asJson(PushResultDto.class) + .execute(); assertThat(response.status()).isEqualTo(HttpStatus.CREATED); for (int i = 0; i < 3; i++) { final ResponseEntity mirrorResponse = - adminClient.prepare() - .post("/api/v1/projects/{proj}/mirrors/{mirrorId}/run") - .pathParam("proj", FOO_PROJ) - .pathParam("mirrorId", TEST_MIRROR_ID) - .asJson(MirrorResult.class) - .execute(); + systemAdminClient.prepare() + .post("/api/v1/projects/{proj}/mirrors/{mirrorId}/run") + .pathParam("proj", FOO_PROJ) + .pathParam("mirrorId", TEST_MIRROR_ID) + .asJson(MirrorResult.class) + .execute(); assertThat(mirrorResponse.status()).isEqualTo(HttpStatus.OK); if (i == 0) { diff --git a/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/ZoneAwareMirrorTest.java b/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/ZoneAwareMirrorTest.java index f1bd77cbba..37c89b63d7 100644 --- a/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/ZoneAwareMirrorTest.java +++ b/it/mirror/src/test/java/com/linecorp/centraldogma/it/mirror/git/ZoneAwareMirrorTest.java @@ -76,7 +76,7 @@ class ZoneAwareMirrorTest { @Override protected void configureEach(int serverId, CentralDogmaBuilder builder) { builder.authProviderFactory(new TestAuthProviderFactory()); - builder.administrators(USERNAME); + builder.systemAdministrators(USERNAME); builder.zone(new ZoneConfig(ZONES.get(serverId - 1), ZONES)); builder.pluginConfigs(new MirroringServicePluginConfig(true, null, null, null, true)); } diff --git a/it/server/src/test/java/com/linecorp/centraldogma/it/NonRandomTokenTest.java b/it/server/src/test/java/com/linecorp/centraldogma/it/NonRandomTokenTest.java index 32316af3bd..1caaf48fdd 100644 --- a/it/server/src/test/java/com/linecorp/centraldogma/it/NonRandomTokenTest.java +++ b/it/server/src/test/java/com/linecorp/centraldogma/it/NonRandomTokenTest.java @@ -41,7 +41,7 @@ class NonRandomTokenTest { static final CentralDogmaExtension dogma = new CentralDogmaExtension() { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); } }; @@ -56,17 +56,17 @@ void createNonRandomToken() throws Exception { assertThat(response.status()).isEqualTo(HttpStatus.OK); final String sessionId = Jackson.readValue(response.content().array(), AccessToken.class) .accessToken(); - final WebClient adminClient = WebClient.builder(client.uri()) - .auth(AuthToken.ofOAuth2(sessionId)).build(); + final WebClient systemAdminClient = WebClient.builder(client.uri()) + .auth(AuthToken.ofOAuth2(sessionId)).build(); final HttpRequest request = HttpRequest.builder() .post("/api/v1/tokens") .content(MediaType.FORM_DATA, - "secret=appToken-secret&isAdmin=true&appId=foo") + "secret=appToken-secret&isSystemAdmin=true&appId=foo") .build(); - AggregatedHttpResponse res = adminClient.execute(request).aggregate().join(); + AggregatedHttpResponse res = systemAdminClient.execute(request).aggregate().join(); assertThat(res.status()).isEqualTo(HttpStatus.CREATED); - res = adminClient.get("/api/v1/tokens").aggregate().join(); + res = systemAdminClient.get("/api/v1/tokens").aggregate().join(); assertThat(res.contentUtf8()).contains("\"secret\":\"appToken-secret\""); } } diff --git a/it/server/src/test/java/com/linecorp/centraldogma/it/ReplicationWriteQuotaTest.java b/it/server/src/test/java/com/linecorp/centraldogma/it/ReplicationWriteQuotaTest.java index b3dc35f5a6..bacf598aa4 100644 --- a/it/server/src/test/java/com/linecorp/centraldogma/it/ReplicationWriteQuotaTest.java +++ b/it/server/src/test/java/com/linecorp/centraldogma/it/ReplicationWriteQuotaTest.java @@ -130,7 +130,7 @@ private static CompletableFuture startNewReplica( int port, int serverId, Map servers) throws IOException { return new CentralDogmaBuilder(tempDir.newFolder().toFile()) .port(port, SessionProtocol.HTTP) - .administrators(TestAuthMessageUtil.USERNAME) + .systemAdministrators(TestAuthMessageUtil.USERNAME) .authProviderFactory(factory) .pluginConfigs(new MirroringServicePluginConfig(false)) .writeQuotaPerRepository(5, 1) diff --git a/it/server/src/test/java/com/linecorp/centraldogma/it/StandaloneWriteQuotaTest.java b/it/server/src/test/java/com/linecorp/centraldogma/it/StandaloneWriteQuotaTest.java index ec8c8db8de..8d46b20747 100644 --- a/it/server/src/test/java/com/linecorp/centraldogma/it/StandaloneWriteQuotaTest.java +++ b/it/server/src/test/java/com/linecorp/centraldogma/it/StandaloneWriteQuotaTest.java @@ -45,7 +45,7 @@ class StandaloneWriteQuotaTest extends WriteQuotaTestBase { static final CentralDogmaExtension dogma = new CentralDogmaExtension() { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); // Default write quota builder.writeQuotaPerRepository(5, 1); diff --git a/it/server/src/test/java/com/linecorp/centraldogma/it/WriteQuotaTestBase.java b/it/server/src/test/java/com/linecorp/centraldogma/it/WriteQuotaTestBase.java index 38c19b6608..a99a685ecf 100644 --- a/it/server/src/test/java/com/linecorp/centraldogma/it/WriteQuotaTestBase.java +++ b/it/server/src/test/java/com/linecorp/centraldogma/it/WriteQuotaTestBase.java @@ -94,14 +94,16 @@ void updateWriteQuota() throws Exception { assertThat(CompletableFutures.allAsList(futures4).join()).hasSize(8); } - private static QuotaConfig updateWriteQuota(WebClient adminClient, String repoName, QuotaConfig writeQuota) + private static QuotaConfig updateWriteQuota( + WebClient systemAdminClient, String repoName, QuotaConfig writeQuota) throws JsonProcessingException { final String updatePath = "/api/v1/metadata/test_prj/repos/" + repoName + "/quota/write"; final String content = mapper.writeValueAsString(writeQuota); final HttpRequest req = HttpRequest.of(HttpMethod.PATCH, updatePath, MediaType.JSON_PATCH, content); - assertThat(adminClient.execute(req).aggregate().join().status()).isEqualTo(HttpStatus.OK); + assertThat(systemAdminClient.execute(req).aggregate().join().status()).isEqualTo(HttpStatus.OK); - final AggregatedHttpResponse res = adminClient.get("/api/v1/projects/test_prj").aggregate().join(); + final AggregatedHttpResponse res = systemAdminClient.get("/api/v1/projects/test_prj") + .aggregate().join(); final ProjectMetadata meta = Jackson.readValue(res.contentUtf8(), ProjectMetadata.class); return meta.repo(repoName).writeQuota(); } diff --git a/it/xds-member-permission/src/test/java/com/linecorp/centraldogma/server/test/XdsMemberPermissionTest.java b/it/xds-member-permission/src/test/java/com/linecorp/centraldogma/server/test/XdsMemberPermissionTest.java index 0a0221985e..db80abf257 100644 --- a/it/xds-member-permission/src/test/java/com/linecorp/centraldogma/server/test/XdsMemberPermissionTest.java +++ b/it/xds-member-permission/src/test/java/com/linecorp/centraldogma/server/test/XdsMemberPermissionTest.java @@ -54,7 +54,7 @@ class XdsMemberPermissionTest { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(USERNAME) + builder.systemAdministrators(USERNAME) .cors("*") .authProviderFactory(new ShiroAuthProviderFactory(unused -> { final Ini iniConfig = new Ini(); diff --git a/server-mirror-git/src/test/java/com/linecorp/centraldogma/server/internal/mirror/MirroringAndCredentialServiceV1Test.java b/server-mirror-git/src/test/java/com/linecorp/centraldogma/server/internal/mirror/MirroringAndCredentialServiceV1Test.java index 9467d2c8f5..5cc4082eee 100644 --- a/server-mirror-git/src/test/java/com/linecorp/centraldogma/server/internal/mirror/MirroringAndCredentialServiceV1Test.java +++ b/server-mirror-git/src/test/java/com/linecorp/centraldogma/server/internal/mirror/MirroringAndCredentialServiceV1Test.java @@ -65,7 +65,7 @@ class MirroringAndCredentialServiceV1Test { @Override protected void configure(CentralDogmaBuilder builder) { builder.authProviderFactory(new TestAuthProviderFactory()); - builder.administrators(USERNAME); + builder.systemAdministrators(USERNAME); } @Override @@ -87,16 +87,16 @@ protected void scaffold(CentralDogma client) { } }; - private BlockingWebClient adminClient; + private BlockingWebClient systemAdminClient; private BlockingWebClient userClient; @BeforeEach void setUp() throws JsonProcessingException { - final String adminToken = getAccessToken(dogma.httpClient(), USERNAME, PASSWORD); - adminClient = WebClient.builder(dogma.httpClient().uri()) - .auth(AuthToken.ofOAuth2(adminToken)) - .build() - .blocking(); + final String systemAdminToken = getAccessToken(dogma.httpClient(), USERNAME, PASSWORD); + systemAdminClient = WebClient.builder(dogma.httpClient().uri()) + .auth(AuthToken.ofOAuth2(systemAdminToken)) + .build() + .blocking(); final String userToken = getAccessToken(dogma.httpClient(), USERNAME2, PASSWORD2); userClient = WebClient.builder(dogma.httpClient().uri()) @@ -146,12 +146,12 @@ private void rejectInvalidRepositoryUri() { private void setUpRole() { final ResponseEntity res = - adminClient.prepare() - .post("/api/v1/metadata/{proj}/members") - .pathParam("proj", FOO_PROJ) - .contentJson(ImmutableMap.of("id", USERNAME2, "role", "OWNER")) - .asJson(Revision.class) - .execute(); + systemAdminClient.prepare() + .post("/api/v1/metadata/{proj}/members") + .pathParam("proj", FOO_PROJ) + .contentJson(ImmutableMap.of("id", USERNAME2, "role", "OWNER")) + .asJson(Revision.class) + .execute(); assertThat(res.status()).isEqualTo(HttpStatus.OK); } @@ -181,8 +181,8 @@ private void createAndReadCredential() { assertThat(creationResponse.status()).isEqualTo(HttpStatus.CREATED); assertThat(creationResponse.content().revision().major()).isEqualTo(i + 2); - for (BlockingWebClient client : ImmutableList.of(adminClient, userClient)) { - final boolean isAdmin = client == adminClient; + for (BlockingWebClient client : ImmutableList.of(systemAdminClient, userClient)) { + final boolean isSystemAdmin = client == systemAdminClient; final ResponseEntity fetchResponse = client.prepare() .get("/api/v1/projects/{proj}/credentials/{id}") @@ -197,14 +197,14 @@ private void createAndReadCredential() { if ("password".equals(credentialType)) { final PasswordCredential actual = (PasswordCredential) credentialDto; assertThat(actual.username()).isEqualTo(credential.get("username")); - if (isAdmin) { + if (isSystemAdmin) { assertThat(actual.password()).isEqualTo(credential.get("password")); } else { assertThat(actual.password()).isEqualTo("****"); } } else if ("access_token".equals(credentialType)) { final AccessTokenCredential actual = (AccessTokenCredential) credentialDto; - if (isAdmin) { + if (isSystemAdmin) { assertThat(actual.accessToken()).isEqualTo(credential.get("accessToken")); } else { assertThat(actual.accessToken()).isEqualTo("****"); @@ -213,7 +213,7 @@ private void createAndReadCredential() { final PublicKeyCredential actual = (PublicKeyCredential) credentialDto; assertThat(actual.username()).isEqualTo(credential.get("username")); assertThat(actual.publicKey()).isEqualTo(credential.get("publicKey")); - if (isAdmin) { + if (isSystemAdmin) { assertThat(actual.rawPrivateKey()).isEqualTo(credential.get("privateKey")); assertThat(actual.rawPassphrase()).isEqualTo(credential.get("passphrase")); } else { @@ -248,8 +248,8 @@ private void updateCredential() { .execute(); assertThat(creationResponse.status()).isEqualTo(HttpStatus.OK); - for (BlockingWebClient client : ImmutableList.of(adminClient, userClient)) { - final boolean isAdmin = client == adminClient; + for (BlockingWebClient client : ImmutableList.of(systemAdminClient, userClient)) { + final boolean isSystemAdmin = client == systemAdminClient; final ResponseEntity fetchResponse = client.prepare() .get("/api/v1/projects/{proj}/credentials/{id}") @@ -261,7 +261,7 @@ private void updateCredential() { assertThat(actual.id()).isEqualTo((String) credential.get("id")); assertThat(actual.username()).isEqualTo(credential.get("username")); assertThat(actual.publicKey()).isEqualTo(credential.get("publicKey")); - if (isAdmin) { + if (isSystemAdmin) { assertThat(actual.rawPrivateKey()).isEqualTo(credential.get("privateKey")); assertThat(actual.rawPassphrase()).isEqualTo(credential.get("passphrase")); } else { diff --git a/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java b/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java index 35ea167fb3..fed302b6da 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java @@ -132,7 +132,6 @@ import com.linecorp.centraldogma.server.internal.admin.service.DefaultLogoutService; import com.linecorp.centraldogma.server.internal.admin.service.RepositoryService; import com.linecorp.centraldogma.server.internal.admin.service.UserService; -import com.linecorp.centraldogma.server.internal.api.AdministrativeService; import com.linecorp.centraldogma.server.internal.api.ContentServiceV1; import com.linecorp.centraldogma.server.internal.api.CredentialServiceV1; import com.linecorp.centraldogma.server.internal.api.GitHttpService; @@ -141,6 +140,7 @@ import com.linecorp.centraldogma.server.internal.api.MirroringServiceV1; import com.linecorp.centraldogma.server.internal.api.ProjectServiceV1; import com.linecorp.centraldogma.server.internal.api.RepositoryServiceV1; +import com.linecorp.centraldogma.server.internal.api.SystemAdministrativeService; import com.linecorp.centraldogma.server.internal.api.TokenService; import com.linecorp.centraldogma.server.internal.api.WatchService; import com.linecorp.centraldogma.server.internal.api.auth.ApplicationTokenAuthorizer; @@ -742,7 +742,7 @@ private AuthProvider createAuthProvider( final AuthProviderParameters parameters = new AuthProviderParameters( // Find application first, then find the session token. new ApplicationTokenAuthorizer(mds::findTokenBySecret).orElse( - new SessionTokenAuthorizer(sessionManager, authCfg.administrators())), + new SessionTokenAuthorizer(sessionManager, authCfg.systemAdministrators())), cfg, sessionManager::generateSessionId, // Propagate login and logout events to the other replicas. @@ -817,7 +817,7 @@ private Function authService( final Authorizer tokenAuthorizer = new ApplicationTokenAuthorizer(mds::findTokenBySecret) .orElse(new SessionTokenAuthorizer(sessionManager, - authCfg.administrators())); + authCfg.systemAdministrators())); return AuthService.builder() .add(tokenAuthorizer) .onFailure(new CentralDogmaAuthFailureHandler()) @@ -862,7 +862,7 @@ private void configureHttpApi(ServerBuilder sb, assert statusManager != null; final ContextPathServicesBuilder apiV1ServiceBuilder = sb.contextPath(API_V1_PATH_PREFIX); apiV1ServiceBuilder - .annotatedService(new AdministrativeService(executor, statusManager)) + .annotatedService(new SystemAdministrativeService(executor, statusManager)) .annotatedService(new ProjectServiceV1(projectApiManager, executor)) .annotatedService(new RepositoryServiceV1(executor, mds)) .annotatedService(new CredentialServiceV1(projectApiManager, executor)); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/CentralDogmaBuilder.java b/server/src/main/java/com/linecorp/centraldogma/server/CentralDogmaBuilder.java index 238dbc8df8..1e35ced3cc 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/CentralDogmaBuilder.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/CentralDogmaBuilder.java @@ -118,7 +118,7 @@ public final class CentralDogmaBuilder { // AuthConfig properties @Nullable private AuthProviderFactory authProviderFactory; - private final ImmutableSet.Builder administrators = new Builder<>(); + private final ImmutableSet.Builder systemAdministrators = new Builder<>(); private boolean caseSensitiveLoginNames; private String sessionCacheSpec = DEFAULT_SESSION_CACHE_SPEC; private long sessionTimeoutMillis = DEFAULT_SESSION_TIMEOUT_MILLIS; @@ -416,22 +416,22 @@ public CentralDogmaBuilder authProviderFactory(AuthProviderFactory authProviderF } /** - * Adds administrators to the set. + * Adds system administrators to the set. */ - public CentralDogmaBuilder administrators(String... administrators) { - requireNonNull(administrators, "administrators"); - for (final String administrator : administrators) { - this.administrators.add(administrator); + public CentralDogmaBuilder systemAdministrators(String... systemAdministrators) { + requireNonNull(systemAdministrators, "systemAdministrators"); + for (final String systemAdministrator : systemAdministrators) { + this.systemAdministrators.add(systemAdministrator); } return this; } /** - * Adds administrators to the set. + * Adds system administrators to the set. */ - public CentralDogmaBuilder administrators(Iterable administrators) { - requireNonNull(administrators, "administrators"); - this.administrators.addAll(administrators); + public CentralDogmaBuilder systemAdministrators(Iterable systemAdministrators) { + requireNonNull(systemAdministrators, "systemAdministrators"); + this.systemAdministrators.addAll(systemAdministrators); return this; } @@ -587,11 +587,11 @@ public CentralDogma build() { private CentralDogmaConfig buildConfig() { final List ports = !this.ports.isEmpty() ? this.ports : Collections.singletonList(DEFAULT_PORT); - final Set adminSet = administrators.build(); + final Set systemAdminSet = systemAdministrators.build(); final AuthConfig authCfg; if (authProviderFactory != null) { authCfg = new AuthConfig( - authProviderFactory, adminSet, caseSensitiveLoginNames, + authProviderFactory, systemAdminSet, caseSensitiveLoginNames, sessionCacheSpec, sessionTimeoutMillis, sessionValidationSchedule, authProviderProperties != null ? Jackson.valueToTree(authProviderProperties) : null); } else { diff --git a/server/src/main/java/com/linecorp/centraldogma/server/auth/AuthConfig.java b/server/src/main/java/com/linecorp/centraldogma/server/auth/AuthConfig.java index 5f36326f75..6748cad774 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/auth/AuthConfig.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/auth/AuthConfig.java @@ -60,7 +60,7 @@ public final class AuthConfig { private final AuthProviderFactory factory; - private final Set administrators; + private final Set systemAdministrators; private final boolean caseSensitiveLoginNames; private final String sessionCacheSpec; @@ -74,7 +74,7 @@ public final class AuthConfig { * Creates a new instance. * * @param factoryClassName the fully-qualified class name of the {@link AuthProviderFactory} - * @param administrators the login names of the administrators + * @param systemAdministrators the login names of the system administrators * @param caseSensitiveLoginNames the flag whether case-sensitive matching is performed when login names * are compared * @param sessionCacheSpec the cache specification which determines the capacity and behavior of @@ -86,7 +86,7 @@ public final class AuthConfig { @JsonCreator public AuthConfig( @JsonProperty("factoryClassName") String factoryClassName, - @JsonProperty("administrators") @Nullable Set administrators, + @JsonProperty("systemAdministrators") @Nullable Set systemAdministrators, @JsonProperty("caseSensitiveLoginNames") @Nullable Boolean caseSensitiveLoginNames, @JsonProperty("sessionCacheSpec") @Nullable String sessionCacheSpec, @JsonProperty("sessionTimeoutMillis") @Nullable Long sessionTimeoutMillis, @@ -96,7 +96,7 @@ public AuthConfig( .getClassLoader() .loadClass(requireNonNull(factoryClassName, "factoryClassName")) .getDeclaredConstructor().newInstance(), - administrators != null ? ImmutableSet.copyOf(administrators) : ImmutableSet.of(), + systemAdministrators != null ? ImmutableSet.copyOf(systemAdministrators) : ImmutableSet.of(), firstNonNull(caseSensitiveLoginNames, false), firstNonNull(sessionCacheSpec, DEFAULT_SESSION_CACHE_SPEC), firstNonNull(sessionTimeoutMillis, DEFAULT_SESSION_TIMEOUT_MILLIS), @@ -108,7 +108,7 @@ public AuthConfig( * Creates a new instance. * * @param factory the {@link AuthProviderFactory} instance - * @param administrators the login names of the administrators + * @param systemAdministrators the login names of the system administrators * @param caseSensitiveLoginNames the flag whether case-sensitive matching is performed when login names * are compared * @param sessionCacheSpec the cache specification which determines the capacity and behavior of @@ -118,14 +118,14 @@ public AuthConfig( * @param properties the additional properties which are used in the factory */ public AuthConfig(AuthProviderFactory factory, - Set administrators, + Set systemAdministrators, boolean caseSensitiveLoginNames, String sessionCacheSpec, long sessionTimeoutMillis, String sessionValidationSchedule, @Nullable JsonNode properties) { this.factory = requireNonNull(factory, "factory"); - this.administrators = requireNonNull(administrators, "administrators"); + this.systemAdministrators = requireNonNull(systemAdministrators, "systemAdministrators"); this.caseSensitiveLoginNames = caseSensitiveLoginNames; this.sessionCacheSpec = validateCacheSpec(requireNonNull(sessionCacheSpec, "sessionCacheSpec")); checkArgument(sessionTimeoutMillis > 0, @@ -152,11 +152,11 @@ public String factoryClassName() { } /** - * Returns the usernames of the users with administrator rights. + * Returns the usernames of the users with system administrator rights. */ @JsonProperty - public Set administrators() { - return administrators; + public Set systemAdministrators() { + return systemAdministrators; } /** diff --git a/server/src/main/java/com/linecorp/centraldogma/server/command/AbstractCommandExecutor.java b/server/src/main/java/com/linecorp/centraldogma/server/command/AbstractCommandExecutor.java index 66356e8d0f..1ac55ae08c 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/command/AbstractCommandExecutor.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/command/AbstractCommandExecutor.java @@ -126,7 +126,7 @@ public final CompletableFuture execute(Command command) { if (!isStarted()) { throw new ReadOnlyException("running in read-only mode. command: " + command); } - if (!writable && !(command instanceof AdministrativeCommand)) { + if (!writable && !(command instanceof SystemAdministrativeCommand)) { // Reject all commands except for AdministrativeCommand when the replica is in read-only mode. // AdministrativeCommand is allowed because it is used to change the read-only mode or migrate // metadata under maintenance mode. diff --git a/server/src/main/java/com/linecorp/centraldogma/server/command/ForcePushCommand.java b/server/src/main/java/com/linecorp/centraldogma/server/command/ForcePushCommand.java index 64936b51cc..cae8f4c659 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/command/ForcePushCommand.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/command/ForcePushCommand.java @@ -26,7 +26,7 @@ * A {@link Command} which is used to force-push {@code delegate} even the server is in read-only mode. * This command is useful for migrating the repository content during maintenance mode. */ -public final class ForcePushCommand extends AdministrativeCommand { +public final class ForcePushCommand extends SystemAdministrativeCommand { private final Command delegate; diff --git a/server/src/main/java/com/linecorp/centraldogma/server/command/AdministrativeCommand.java b/server/src/main/java/com/linecorp/centraldogma/server/command/SystemAdministrativeCommand.java similarity index 79% rename from server/src/main/java/com/linecorp/centraldogma/server/command/AdministrativeCommand.java rename to server/src/main/java/com/linecorp/centraldogma/server/command/SystemAdministrativeCommand.java index 49704002bc..d668924eb2 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/command/AdministrativeCommand.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/command/SystemAdministrativeCommand.java @@ -20,9 +20,9 @@ import com.linecorp.centraldogma.common.Author; -abstract class AdministrativeCommand extends RootCommand { - AdministrativeCommand(CommandType commandType, @Nullable Long timestamp, - @Nullable Author author) { +abstract class SystemAdministrativeCommand extends RootCommand { + SystemAdministrativeCommand(CommandType commandType, @Nullable Long timestamp, + @Nullable Author author) { super(commandType, timestamp, author); } } diff --git a/server/src/main/java/com/linecorp/centraldogma/server/command/UpdateServerStatusCommand.java b/server/src/main/java/com/linecorp/centraldogma/server/command/UpdateServerStatusCommand.java index 1184822b5b..ef160a07b1 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/command/UpdateServerStatusCommand.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/command/UpdateServerStatusCommand.java @@ -33,7 +33,7 @@ * A {@link Command} which is used to update the status of all servers in the cluster. */ @JsonInclude(Include.NON_NULL) -public final class UpdateServerStatusCommand extends AdministrativeCommand { +public final class UpdateServerStatusCommand extends SystemAdministrativeCommand { private final ServerStatus serverStatus; diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/CsrfTokenAuthorizer.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/CsrfTokenAuthorizer.java index fac3340046..ea582bcd32 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/CsrfTokenAuthorizer.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/CsrfTokenAuthorizer.java @@ -39,8 +39,8 @@ public class CsrfTokenAuthorizer implements Authorizer { public CompletionStage authorize(ServiceRequestContext ctx, HttpRequest data) { final OAuth2Token token = AuthTokenExtractors.oAuth2().apply(data.headers()); if (token != null && CsrfToken.ANONYMOUS.equals(token.accessToken())) { - AuthUtil.setCurrentUser(ctx, User.ADMIN); - HttpApiUtil.setVerboseResponses(ctx, User.ADMIN); + AuthUtil.setCurrentUser(ctx, User.SYSTEM_ADMIN); + HttpApiUtil.setVerboseResponses(ctx, User.SYSTEM_ADMIN); return CompletableFuture.completedFuture(true); } else { return CompletableFuture.completedFuture(false); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/SessionTokenAuthorizer.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/SessionTokenAuthorizer.java index e03094da85..937266c166 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/SessionTokenAuthorizer.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/admin/auth/SessionTokenAuthorizer.java @@ -16,7 +16,7 @@ package com.linecorp.centraldogma.server.internal.admin.auth; -import static com.linecorp.centraldogma.server.metadata.User.LEVEL_ADMIN; +import static com.linecorp.centraldogma.server.metadata.User.LEVEL_SYSTEM_ADMIN; import static com.linecorp.centraldogma.server.metadata.User.LEVEL_USER; import static java.util.Objects.requireNonNull; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -41,11 +41,11 @@ public class SessionTokenAuthorizer implements Authorizer { private final SessionManager sessionManager; - private final Set administrators; + private final Set systemAdministrators; - public SessionTokenAuthorizer(SessionManager sessionManager, Set administrators) { + public SessionTokenAuthorizer(SessionManager sessionManager, Set systemAdministrators) { this.sessionManager = requireNonNull(sessionManager, "sessionManager"); - this.administrators = requireNonNull(administrators, "administrators"); + this.systemAdministrators = requireNonNull(systemAdministrators, "systemAdministrators"); } @Override @@ -60,8 +60,9 @@ public CompletionStage authorize(ServiceRequestContext ctx, HttpRequest return false; } final String username = session.username(); - final List roles = administrators.contains(username) ? LEVEL_ADMIN - : LEVEL_USER; + final List roles = + systemAdministrators.contains(username) ? LEVEL_SYSTEM_ADMIN + : LEVEL_USER; final User user = new User(username, roles); ctx.logBuilder().authenticatedUser("user/" + username); AuthUtil.setCurrentUser(ctx, user); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ContentServiceV1.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ContentServiceV1.java index 13fe541901..569ead31f0 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ContentServiceV1.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ContentServiceV1.java @@ -198,7 +198,7 @@ public CompletableFuture push( CommitMessageDto commitMessage, @RequestConverter(ChangesRequestConverter.class) Iterable> changes) { final User user = AuthUtil.currentUser(ctx); - checkPush(repository.name(), changes, user.isAdmin()); + checkPush(repository.name(), changes, user.isSystemAdmin()); meterRegistry.counter("commits.push", "project", repository.parent().name(), "repository", repository.name()) @@ -444,7 +444,7 @@ public CompletableFuture> mergeFiles( * Checks if the commit is for creating a file and raises a {@link InvalidPushException} if the * given {@code repoName} field is one of {@code meta} and {@code dogma} which are internal repositories. */ - public static void checkPush(String repoName, Iterable> changes, boolean isAdmin) { + public static void checkPush(String repoName, Iterable> changes, boolean isSystemAdmin) { if (Project.REPO_META.equals(repoName)) { final boolean hasChangesOtherThanMetaRepoFiles = Streams.stream(changes).anyMatch(change -> !isMetaFile(change.path())); @@ -453,8 +453,8 @@ public static void checkPush(String repoName, Iterable> changes, boole "The " + Project.REPO_META + " repository is reserved for internal usage."); } - if (isAdmin) { - // Admin may push the legacy files to test the mirror migration. + if (isSystemAdmin) { + // A system admin may push the legacy files to test the mirror migration. } else { for (Change change : changes) { // 'mirrors.json' and 'credentials.json' are disallowed to be created or modified. diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/CredentialServiceV1.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/CredentialServiceV1.java index b0972be664..fca1d07c28 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/CredentialServiceV1.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/CredentialServiceV1.java @@ -70,7 +70,7 @@ public CredentialServiceV1(ProjectApiManager projectApiManager, CommandExecutor public CompletableFuture> listCredentials(User loginUser, @Param String projectName) { final CompletableFuture> future = metaRepo(projectName, loginUser).credentials(); - if (loginUser.isAdmin()) { + if (loginUser.isSystemAdmin()) { return future; } return future.thenApply(credentials -> { @@ -91,7 +91,7 @@ public CompletableFuture> listCredentials(User loginUser, public CompletableFuture getCredentialById(User loginUser, @Param String projectName, @Param String id) { final CompletableFuture future = metaRepo(projectName, loginUser).credential(id); - if (loginUser.isAdmin()) { + if (loginUser.isSystemAdmin()) { return future; } return future.thenApply(Credential::withoutSecret); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/HttpApiUtil.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/HttpApiUtil.java index a4939bb2d0..9fdd37ff9a 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/HttpApiUtil.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/HttpApiUtil.java @@ -309,7 +309,7 @@ public static void throwUnsafelyIfNonNull(@Nullable Throwable cause) { } public static void setVerboseResponses(ServiceRequestContext ctx, User user) { - ctx.setAttr(VERBOSE_RESPONSES, Flags.verboseResponses() || user.isAdmin()); + ctx.setAttr(VERBOSE_RESPONSES, Flags.verboseResponses() || user.isSystemAdmin()); } private static boolean isVerboseResponse(ServiceRequestContext ctx) { diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/MetadataApiService.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/MetadataApiService.java index a10fcf667f..d12fca167a 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/MetadataApiService.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/MetadataApiService.java @@ -48,8 +48,8 @@ import com.linecorp.centraldogma.internal.jsonpatch.ReplaceOperation; import com.linecorp.centraldogma.server.QuotaConfig; import com.linecorp.centraldogma.server.command.CommandExecutor; -import com.linecorp.centraldogma.server.internal.api.auth.RequiresAdministrator; import com.linecorp.centraldogma.server.internal.api.auth.RequiresRole; +import com.linecorp.centraldogma.server.internal.api.auth.RequiresSystemAdministrator; import com.linecorp.centraldogma.server.metadata.MetadataService; import com.linecorp.centraldogma.server.metadata.PerRolePermissions; import com.linecorp.centraldogma.server.metadata.Permission; @@ -298,7 +298,7 @@ public CompletableFuture removeSpecificTokenPermission(@Param String p */ @Patch("/metadata/{projectName}/repos/{repoName}/quota/write") @Consumes("application/json-patch+json") - @RequiresAdministrator + @RequiresSystemAdministrator public CompletableFuture updateWriteQuota(@Param String projectName, @Param String repoName, QuotaConfig quota, diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1.java index 150233a415..9a97c09483 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1.java @@ -46,8 +46,8 @@ import com.linecorp.centraldogma.internal.api.v1.CreateProjectRequest; import com.linecorp.centraldogma.internal.api.v1.ProjectDto; import com.linecorp.centraldogma.server.command.CommandExecutor; -import com.linecorp.centraldogma.server.internal.api.auth.RequiresAdministrator; import com.linecorp.centraldogma.server.internal.api.auth.RequiresRole; +import com.linecorp.centraldogma.server.internal.api.auth.RequiresSystemAdministrator; import com.linecorp.centraldogma.server.internal.api.converter.CreateApiResponseConverter; import com.linecorp.centraldogma.server.internal.storage.project.ProjectApiManager; import com.linecorp.centraldogma.server.metadata.Member; @@ -95,13 +95,13 @@ public CompletableFuture> listProjects(@Param @Nullable String } private static ProjectRole getUserRole(Project project, User user) { - if (user.isAdmin()) { + if (user.isSystemAdmin()) { return ProjectRole.OWNER; } final ProjectMetadata metadata = project.metadata(); if (metadata == null) { - // Metadata is null for the internal project which belongs to administrators. + // Metadata is null for the internal project which belongs to system administrators. return ProjectRole.GUEST; } @@ -188,7 +188,7 @@ public CompletableFuture purgeProject(@Param String projectName, Author au */ @Consumes("application/json-patch+json") @Patch("/projects/{projectName}") - @RequiresAdministrator + @RequiresSystemAdministrator public CompletableFuture patchProject(@Param String projectName, JsonNode node, Author author, User user) { checkUnremoveArgument(node); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1.java index 5a9ebf3c98..0d331a5902 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/RepositoryServiceV1.java @@ -100,7 +100,7 @@ public CompletableFuture> listRepositories(ServiceRequestCon } return project.repos().list().values().stream() - .filter(r -> user.isAdmin() || !Project.REPO_DOGMA.equals(r.name())) + .filter(r -> user.isSystemAdmin() || !Project.REPO_DOGMA.equals(r.name())) .filter(r -> hasOwnerRole || !Project.REPO_META.equals(r.name())) .map(DtoConverter::convert) .collect(toImmutableList()); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/AdministrativeService.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/SystemAdministrativeService.java similarity index 93% rename from server/src/main/java/com/linecorp/centraldogma/server/internal/api/AdministrativeService.java rename to server/src/main/java/com/linecorp/centraldogma/server/internal/api/SystemAdministrativeService.java index 7e8e36acf0..6a261b05e5 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/AdministrativeService.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/SystemAdministrativeService.java @@ -27,16 +27,16 @@ import com.linecorp.centraldogma.server.command.Command; import com.linecorp.centraldogma.server.command.CommandExecutor; import com.linecorp.centraldogma.server.internal.api.UpdateServerStatusRequest.Scope; -import com.linecorp.centraldogma.server.internal.api.auth.RequiresAdministrator; +import com.linecorp.centraldogma.server.internal.api.auth.RequiresSystemAdministrator; import com.linecorp.centraldogma.server.management.ServerStatus; import com.linecorp.centraldogma.server.management.ServerStatusManager; @ProducesJson -public final class AdministrativeService extends AbstractService { +public final class SystemAdministrativeService extends AbstractService { private final ServerStatusManager serverStatusManager; - public AdministrativeService(CommandExecutor executor, ServerStatusManager serverStatusManager) { + public SystemAdministrativeService(CommandExecutor executor, ServerStatusManager serverStatusManager) { super(executor); this.serverStatusManager = serverStatusManager; } @@ -62,7 +62,7 @@ public ServerStatus status() { */ @Put("/status") @Consumes("application/json") - @RequiresAdministrator + @RequiresSystemAdministrator public CompletableFuture updateStatus(UpdateServerStatusRequest statusRequest) throws Exception { // TODO(trustin): Consider extracting this into common utility or Armeria. diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenLevelRequest.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenLevelRequest.java index 2f2a111c75..cead450bd8 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenLevelRequest.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenLevelRequest.java @@ -23,7 +23,7 @@ public final class TokenLevelRequest { private final String level; @JsonCreator - TokenLevelRequest(@JsonProperty("level") String level) { + public TokenLevelRequest(@JsonProperty("level") String level) { this.level = level; } diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenService.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenService.java index 5e6aa2689d..6005f1d527 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenService.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/TokenService.java @@ -48,7 +48,7 @@ import com.linecorp.centraldogma.common.Revision; import com.linecorp.centraldogma.internal.Jackson; import com.linecorp.centraldogma.server.command.CommandExecutor; -import com.linecorp.centraldogma.server.internal.api.auth.RequiresAdministrator; +import com.linecorp.centraldogma.server.internal.api.auth.RequiresSystemAdministrator; import com.linecorp.centraldogma.server.internal.api.converter.CreateApiResponseConverter; import com.linecorp.centraldogma.server.metadata.MetadataService; import com.linecorp.centraldogma.server.metadata.Token; @@ -86,7 +86,7 @@ public TokenService(CommandExecutor executor, MetadataService mds) { */ @Get("/tokens") public CompletableFuture> listTokens(User loginUser) { - if (loginUser.isAdmin()) { + if (loginUser.isSystemAdmin()) { return mds.getTokens() .thenApply(tokens -> tokens.appIds().values()); } else { @@ -105,20 +105,24 @@ public CompletableFuture> listTokens(User loginUser) { @StatusCode(201) @ResponseConverter(CreateApiResponseConverter.class) public CompletableFuture> createToken(@Param String appId, + // TODO(minwoox): Remove isAdmin field. @Param @Default("false") boolean isAdmin, + @Param @Default("false") boolean isSystemAdmin, @Param @Nullable String secret, Author author, User loginUser) { - checkArgument(!isAdmin || loginUser.isAdmin(), - "Only administrators are allowed to create an admin-level token."); + final boolean isSystemAdminToken = isSystemAdmin || isAdmin; + checkArgument(!isSystemAdminToken || loginUser.isSystemAdmin(), + "Only system administrators are allowed to create a system admin-level token."); - checkArgument(secret == null || loginUser.isAdmin(), - "Only administrators are allowed to create a new token from the given secret string"); + checkArgument(secret == null || loginUser.isSystemAdmin(), + "Only system administrators are allowed to create a new token from " + + " the given secret string"); final CompletableFuture tokenFuture; if (secret != null) { - tokenFuture = mds.createToken(author, appId, secret, isAdmin); + tokenFuture = mds.createToken(author, appId, secret, isSystemAdminToken); } else { - tokenFuture = mds.createToken(author, appId, isAdmin); + tokenFuture = mds.createToken(author, appId, isSystemAdminToken); } return tokenFuture .thenCompose(unused -> mds.findTokenByAppId(appId)) @@ -150,7 +154,7 @@ public CompletableFuture deleteToken(ServiceRequestContext ctx, *

Purges a token of the specified ID that was deleted before. */ @Delete("/tokens/{appId}/removed") - @RequiresAdministrator + @RequiresSystemAdministrator public CompletableFuture purgeToken(ServiceRequestContext ctx, @Param String appId, Author author, User loginUser) { @@ -198,34 +202,36 @@ public CompletableFuture updateToken(ServiceRequestContext ctx, *

Updates a permission of a token of the specified ID. */ @Patch("/tokens/{appId}/level") - @RequiresAdministrator + @RequiresSystemAdministrator public CompletableFuture updateTokenLevel(ServiceRequestContext ctx, @Param String appId, TokenLevelRequest tokenLevelRequest, Author author, User loginUser) { final String newTokenLevel = tokenLevelRequest.level().toLowerCase(); - checkArgument("user".equals(newTokenLevel) || "admin".equals(newTokenLevel), - "token level: %s (expected: user or admin)" + tokenLevelRequest.level()); + checkArgument("user".equals(newTokenLevel) || "admin".equals(newTokenLevel) || + "systemadmin".equals(newTokenLevel), + "token level: %s (expected: user or systemadmin)" + tokenLevelRequest.level()); return getTokenOrRespondForbidden(ctx, appId, loginUser).thenCompose( token -> { - boolean toBeAdmin = false; + boolean toBeSystemAdmin = false; switch (newTokenLevel) { case "user": - if (!token.isAdmin()) { + if (!token.isSystemAdmin()) { throw HttpStatusException.of(HttpStatus.NOT_MODIFIED); } break; case "admin": - if (token.isAdmin()) { + case "systemadmin": + if (token.isSystemAdmin()) { throw HttpStatusException.of(HttpStatus.NOT_MODIFIED); } - toBeAdmin = true; + toBeSystemAdmin = true; break; } - return mds.updateTokenLevel(author, appId, toBeAdmin).thenCompose( + return mds.updateTokenLevel(author, appId, toBeSystemAdmin).thenCompose( unused -> mds.findTokenByAppId(appId).thenApply(Token::withoutSecret)); }); } @@ -233,8 +239,8 @@ public CompletableFuture updateTokenLevel(ServiceRequestContext ctx, private CompletableFuture getTokenOrRespondForbidden(ServiceRequestContext ctx, String appId, User loginUser) { return mds.findTokenByAppId(appId).thenApply(token -> { - // Give permission to the administrators. - if (!loginUser.isAdmin() && + // Give permission to the system administrators. + if (!loginUser.isSystemAdmin() && !token.creation().user().equals(loginUser.id())) { return HttpApiUtil.throwResponse(ctx, HttpStatus.FORBIDDEN, "Unauthorized token: %s", token); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresPermissionDecorator.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresPermissionDecorator.java index 3c663ac88c..6ce69c13b5 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresPermissionDecorator.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresPermissionDecorator.java @@ -85,8 +85,8 @@ public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exc checkArgument(!isNullOrEmpty(repoName), "no repository name is specified"); if (Project.REPO_DOGMA.equals(repoName)) { - if (!user.isAdmin()) { - return throwForbiddenResponse(ctx, projectName, repoName, "administrator"); + if (!user.isSystemAdmin()) { + return throwForbiddenResponse(ctx, projectName, repoName); } return unwrap().serve(ctx, req); } @@ -94,10 +94,10 @@ public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exc } private static HttpResponse throwForbiddenResponse(ServiceRequestContext ctx, String projectName, - String repoName, String adminOrOwner) { + String repoName) { return HttpApiUtil.throwResponse(ctx, HttpStatus.FORBIDDEN, - "Repository '%s/%s' can be accessed only by an %s.", - projectName, repoName, adminOrOwner); + "Repository '%s/%s' can be accessed only by a system administrator.", + projectName, repoName); } /** diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresRoleDecorator.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresRoleDecorator.java index 16291f1c1a..f330b64886 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresRoleDecorator.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresRoleDecorator.java @@ -71,7 +71,7 @@ public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exc if (cause != null) { return handleException(ctx, cause); } - if (!user.isAdmin() && !accessibleRoles.contains(role)) { + if (!user.isSystemAdmin() && !accessibleRoles.contains(role)) { return HttpApiUtil.throwResponse( ctx, HttpStatus.FORBIDDEN, "You must have one of the following roles to access the project '%s': %s", diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresAdministrator.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresSystemAdministrator.java similarity index 82% rename from server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresAdministrator.java rename to server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresSystemAdministrator.java index 8878e001bc..bd59ea0e42 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresAdministrator.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresSystemAdministrator.java @@ -22,15 +22,15 @@ import com.linecorp.armeria.server.annotation.Decorator; import com.linecorp.armeria.server.annotation.DecoratorFactory; -import com.linecorp.centraldogma.server.internal.api.auth.RequiresAdministratorDecorator.RequiresAdministratorDecoratorFactory; +import com.linecorp.centraldogma.server.internal.api.auth.RequiresSystemAdministratorDecorator.RequiresSystemAdministratorDecoratorFactory; /** - * A {@link Decorator} to allow a request from an administrator only. + * A {@link Decorator} to allow a request from a system administrator only. */ -@DecoratorFactory(RequiresAdministratorDecoratorFactory.class) +@DecoratorFactory(RequiresSystemAdministratorDecoratorFactory.class) @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) -public @interface RequiresAdministrator { +public @interface RequiresSystemAdministrator { /** * A special parameter in order to specify the order of a {@link Decorator}. */ diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresAdministratorDecorator.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresSystemAdministratorDecorator.java similarity index 73% rename from server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresAdministratorDecorator.java rename to server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresSystemAdministratorDecorator.java index dba1fc32b3..da25622dd2 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresAdministratorDecorator.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/auth/RequiresSystemAdministratorDecorator.java @@ -31,34 +31,34 @@ import com.linecorp.centraldogma.server.metadata.User; /** - * A {@link Decorator} to allow a request from an administrator only. + * A {@link Decorator} to allow a request from a system administrator only. */ -public final class RequiresAdministratorDecorator extends SimpleDecoratingHttpService { +public final class RequiresSystemAdministratorDecorator extends SimpleDecoratingHttpService { - RequiresAdministratorDecorator(HttpService delegate) { + RequiresSystemAdministratorDecorator(HttpService delegate) { super(delegate); } @Override public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception { final User user = AuthUtil.currentUser(ctx); - if (user.isAdmin()) { + if (user.isSystemAdmin()) { return unwrap().serve(ctx, req); } return HttpApiUtil.throwResponse( ctx, HttpStatus.FORBIDDEN, - "You must be an administrator to perform this operation."); + "You must be a system administrator to perform this operation."); } /** - * A {@link DecoratorFactoryFunction} which creates a {@link RequiresAdministratorDecorator}. + * A {@link DecoratorFactoryFunction} which creates a {@link RequiresSystemAdministratorDecorator}. */ - public static final class RequiresAdministratorDecoratorFactory - implements DecoratorFactoryFunction { + public static final class RequiresSystemAdministratorDecoratorFactory + implements DecoratorFactoryFunction { @Override public Function - newDecorator(RequiresAdministrator parameter) { - return RequiresAdministratorDecorator::new; + newDecorator(RequiresSystemAdministrator parameter) { + return RequiresSystemAdministratorDecorator::new; } } } diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/converter/HttpApiRequestConverter.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/converter/HttpApiRequestConverter.java index f8bd9579b3..beec74d8fe 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/api/converter/HttpApiRequestConverter.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/api/converter/HttpApiRequestConverter.java @@ -70,11 +70,10 @@ public Object convertRequest( checkArgument(!isNullOrEmpty(repositoryName), "repository name should not be null or empty."); - if (Project.REPO_DOGMA.equals(repositoryName) && - !user.isAdmin()) { + if (Project.REPO_DOGMA.equals(repositoryName) && !user.isSystemAdmin()) { return HttpApiUtil.throwResponse( ctx, HttpStatus.FORBIDDEN, - "Repository '%s/%s' can be accessed only by an administrator.", + "Repository '%s/%s' can be accessed only by a system administrator.", projectName, Project.REPO_DOGMA); } // RepositoryNotFoundException would be thrown if there is no project or no repository. diff --git a/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/project/ProjectApiManager.java b/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/project/ProjectApiManager.java index 29882ab826..d5da31a99f 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/project/ProjectApiManager.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/internal/storage/project/ProjectApiManager.java @@ -57,20 +57,20 @@ public ProjectApiManager(ProjectManager projectManager, CommandExecutor commandE public Map listProjects(@Nullable User user) { final Map projects = projectManager.list(); - if (isAdmin()) { + if (isSystemAdmin()) { return projects; } return listProjectsWithoutInternal(projects, user); } - private static boolean isAdmin() { + private static boolean isSystemAdmin() { final User currentUserOrNull = AuthUtil.currentUserOrNull(); if (currentUserOrNull == null) { return false; } - return currentUserOrNull.isAdmin(); + return currentUserOrNull.isSystemAdmin(); } public static Map listProjectsWithoutInternal(Map projects, @@ -147,7 +147,8 @@ public Project getProject(String projectName, @Nullable User user) { if (user == null) { throw new IllegalArgumentException("Cannot access " + projectName); } - if (user.isAdmin()) { + + if (user.isSystemAdmin()) { return project; } final ProjectMetadata metadata = project.metadata(); @@ -165,7 +166,7 @@ private static boolean isInternalProject(String projectName) { } public boolean exists(String projectName) { - if (isInternalProject(projectName) && !isAdmin()) { + if (isInternalProject(projectName) && !isSystemAdmin()) { throw new IllegalArgumentException("Cannot access " + projectName); } return projectManager.exists(projectName); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/metadata/MetadataService.java b/server/src/main/java/com/linecorp/centraldogma/server/metadata/MetadataService.java index c6827c1b18..6c4c33a17a 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/metadata/MetadataService.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/metadata/MetadataService.java @@ -807,7 +807,7 @@ private CompletableFuture replacePermissionAtPointer(Author author, public CompletableFuture> findPermissions(String projectName, String repoName, User user) { requireNonNull(user, "user"); - if (user.isAdmin()) { + if (user.isSystemAdmin()) { return CompletableFuture.completedFuture(PerRolePermissions.ALL_PERMISSION); } if (user instanceof UserWithToken) { @@ -888,7 +888,7 @@ public CompletableFuture findRole(String projectName, User user) { requireNonNull(projectName, "projectName"); requireNonNull(user, "user"); - if (user.isAdmin()) { + if (user.isSystemAdmin()) { return CompletableFuture.completedFuture(ProjectRole.OWNER); } return getProject(projectName).thenApply(project -> { @@ -920,11 +920,11 @@ public CompletableFuture createToken(Author author, String appId) { } /** - * Creates a new {@link Token} with the specified {@code appId}, {@code isAdmin} and an auto-generated + * Creates a new {@link Token} with the specified {@code appId}, {@code isSystemAdmin} and an auto-generated * secret. */ - public CompletableFuture createToken(Author author, String appId, boolean isAdmin) { - return createToken(author, appId, SECRET_PREFIX + UUID.randomUUID(), isAdmin); + public CompletableFuture createToken(Author author, String appId, boolean isSystemAdmin) { + return createToken(author, appId, SECRET_PREFIX + UUID.randomUUID(), isSystemAdmin); } /** @@ -935,17 +935,17 @@ public CompletableFuture createToken(Author author, String appId, Stri } /** - * Creates a new {@link Token} with the specified {@code appId}, {@code secret} and {@code isAdmin}. + * Creates a new {@link Token} with the specified {@code appId}, {@code secret} and {@code isSystemAdmin}. */ public CompletableFuture createToken(Author author, String appId, String secret, - boolean isAdmin) { + boolean isSystemAdmin) { requireNonNull(author, "author"); requireNonNull(appId, "appId"); requireNonNull(secret, "secret"); checkArgument(secret.startsWith(SECRET_PREFIX), "secret must start with: " + SECRET_PREFIX); - final Token newToken = new Token(appId, secret, isAdmin, UserAndTimestamp.of(author)); + final Token newToken = new Token(appId, secret, isSystemAdmin, UserAndTimestamp.of(author)); final JsonPointer appIdPath = JsonPointer.compile("/appIds" + encodeSegment(newToken.id())); final String newTokenSecret = newToken.secret(); assert newTokenSecret != null; @@ -986,9 +986,9 @@ public CompletableFuture destroyToken(Author author, String appId) { } else { final String secret = token.secret(); assert secret != null; - appIdsBuilder.put(appId, new Token(token.appId(), secret, token.isAdmin(), - token.isAdmin(), token.creation(), token.deactivation(), - userAndTimestamp)); + appIdsBuilder.put(appId, new Token(token.appId(), secret, token.isSystemAdmin(), + token.isSystemAdmin(), token.creation(), + token.deactivation(), userAndTimestamp)); } } final Map newAppIds = appIdsBuilder.build(); @@ -1007,7 +1007,7 @@ public Revision purgeToken(Author author, String appId) { requireNonNull(appId, "appId"); final Collection projects = listProjectsWithoutInternal(projectManager.list(), - User.ADMIN).values(); + User.SYSTEM_ADMIN).values(); // Remove the token from projects that only have the token. for (Project project : projects) { final ProjectMetadata projectMetadata = fetchMetadata(project.name()).join().object(); @@ -1087,8 +1087,8 @@ public CompletableFuture activateToken(Author author, String appId) { if (!entry.getKey().equals(appId)) { appIdsBuilder.put(entry); } else { - appIdsBuilder.put(appId, - new Token(token.appId(), secret, token.isAdmin(), token.creation())); + appIdsBuilder.put(appId, new Token(token.appId(), secret, token.isSystemAdmin(), + token.creation())); } } final Map newAppIds = appIdsBuilder.build(); @@ -1128,7 +1128,8 @@ public CompletableFuture deactivateToken(Author author, String appId) if (!entry.getKey().equals(appId)) { appIdsBuilder.put(entry); } else { - appIdsBuilder.put(appId, new Token(token.appId(), secret, token.isAdmin(), token.isAdmin(), + appIdsBuilder.put(appId, new Token(token.appId(), secret, token.isSystemAdmin(), + token.isSystemAdmin(), token.creation(), userAndTimestamp, null)); } } @@ -1143,18 +1144,18 @@ public CompletableFuture deactivateToken(Author author, String appId) /** * Update the {@link Token} of the specified {@code appId} to user or admin. */ - public CompletableFuture updateTokenLevel(Author author, String appId, boolean toBeAdmin) { + public CompletableFuture updateTokenLevel(Author author, String appId, boolean toBeSystemAdmin) { requireNonNull(author, "author"); requireNonNull(appId, "appId"); final String commitSummary = - "Update the token level: " + appId + " to " + (toBeAdmin ? "admin" : "user"); - + "Update the token level: " + appId + " to " + (toBeSystemAdmin ? "admin" : "user"); final ContentTransformer transformer = new ContentTransformer<>( TOKEN_JSON, EntryType.JSON, node -> { final Tokens tokens = tokens(node); final Token token = tokens.get(appId); // Raise an exception if not found. - if (toBeAdmin == token.isAdmin()) { - throw new IllegalArgumentException("The token is already " + (toBeAdmin ? "admin" : "user")); + if (toBeSystemAdmin == token.isSystemAdmin()) { + throw new IllegalArgumentException( + "The token is already " + (toBeSystemAdmin ? "admin" : "user")); } final ImmutableMap.Builder appIdsBuilder = ImmutableMap.builder(); @@ -1162,7 +1163,7 @@ public CompletableFuture updateTokenLevel(Author author, String appId, if (!entry.getKey().equals(appId)) { appIdsBuilder.put(entry); } else { - appIdsBuilder.put(appId, token.withAdmin(toBeAdmin)); + appIdsBuilder.put(appId, token.withSystemAdmin(toBeSystemAdmin)); } } final Map newAppIds = appIdsBuilder.build(); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/metadata/Token.java b/server/src/main/java/com/linecorp/centraldogma/server/metadata/Token.java index 358c51eceb..8d642fe794 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/metadata/Token.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/metadata/Token.java @@ -49,9 +49,9 @@ public final class Token implements Identifiable { private final String secret; /** - * Specifies whether this token is for administrators. + * Specifies whether this token is for system administrators. */ - private final boolean isAdmin; + private final boolean isSystemAdmin; /** * Specifies when this token is created by whom. @@ -67,8 +67,8 @@ public final class Token implements Identifiable { @Nullable private final UserAndTimestamp deletion; - Token(String appId, String secret, boolean isAdmin, UserAndTimestamp creation) { - this(appId, secret, isAdmin, isAdmin, creation, null, null); + Token(String appId, String secret, boolean isSystemAdmin, UserAndTimestamp creation) { + this(appId, secret, null, isSystemAdmin, creation, null, null); } /** @@ -86,16 +86,16 @@ public Token(@JsonProperty("appId") String appId, assert isAdmin != null || isSystemAdmin != null; this.appId = Util.validateFileName(appId, "appId"); this.secret = Util.validateFileName(secret, "secret"); - this.isAdmin = isSystemAdmin != null ? isSystemAdmin : isAdmin; + this.isSystemAdmin = isSystemAdmin != null ? isSystemAdmin : isAdmin; this.creation = requireNonNull(creation, "creation"); this.deactivation = deactivation; this.deletion = deletion; } - private Token(String appId, boolean isAdmin, UserAndTimestamp creation, + private Token(String appId, boolean isSystemAdmin, UserAndTimestamp creation, @Nullable UserAndTimestamp deactivation, @Nullable UserAndTimestamp deletion) { this.appId = Util.validateFileName(appId, "appId"); - this.isAdmin = isAdmin; + this.isSystemAdmin = isSystemAdmin; this.creation = requireNonNull(creation, "creation"); this.deactivation = deactivation; this.deletion = deletion; @@ -125,11 +125,11 @@ public String secret() { } /** - * Returns whether this token has administrative privileges. + * Returns whether this token has system administrative privileges. */ @JsonProperty - public boolean isAdmin() { - return isAdmin; + public boolean isSystemAdmin() { + return isSystemAdmin; } /** @@ -179,7 +179,7 @@ public String toString() { // Do not add "secret" to prevent it from logging. return MoreObjects.toStringHelper(this).omitNullValues() .add("appId", appId()) - .add("isAdmin", isAdmin()) + .add("isSystemAdmin", isSystemAdmin()) .add("creation", creation()) .add("deactivation", deactivation()) .add("deletion", deletion()) @@ -190,19 +190,19 @@ public String toString() { * Returns a new {@link Token} instance without its secret. */ public Token withoutSecret() { - return new Token(appId(), isAdmin(), creation(), deactivation(), deletion()); + return new Token(appId(), isSystemAdmin(), creation(), deactivation(), deletion()); } /** - * Returns a new {@link Token} instance with {@code isAdmin}. + * Returns a new {@link Token} instance without its secret. * This method must be called by the token whose secret is not null. */ - public Token withAdmin(boolean isAdmin) { - if (isAdmin == isAdmin()) { + public Token withSystemAdmin(boolean isSystemAdmin) { + if (isSystemAdmin == isSystemAdmin()) { return this; } final String secret = secret(); assert secret != null; - return new Token(appId(), secret, isAdmin, isAdmin, creation(), deactivation(), deletion()); + return new Token(appId(), secret, null, isSystemAdmin, creation(), deactivation(), deletion()); } } diff --git a/server/src/main/java/com/linecorp/centraldogma/server/metadata/User.java b/server/src/main/java/com/linecorp/centraldogma/server/metadata/User.java index ce5147f316..8f9a6820e1 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/metadata/User.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/metadata/User.java @@ -42,22 +42,23 @@ public class User implements Identifiable, Serializable { private static final long serialVersionUID = -5429782019985526549L; private static final String LEVEL_USER_STR = "LEVEL_USER"; - private static final String LEVEL_ADMIN_STR = "LEVEL_ADMIN"; + private static final String LEVEL_SYSTEM_ADMIN_STR = "LEVEL_SYSTEM_ADMIN"; // System-wide roles for a user. It is different from the role in a project. public static final List LEVEL_USER = ImmutableList.of(LEVEL_USER_STR); - public static final List LEVEL_ADMIN = ImmutableList.of(LEVEL_ADMIN_STR, LEVEL_USER_STR); + public static final List LEVEL_SYSTEM_ADMIN = + ImmutableList.of(LEVEL_SYSTEM_ADMIN_STR, LEVEL_USER_STR); public static final User DEFAULT = new User("user@localhost.localdomain", LEVEL_USER); - public static final User ADMIN = new User("admin@localhost.localdomain", LEVEL_ADMIN); - public static final User SYSTEM = new User("system@localhost.localdomain", LEVEL_ADMIN); + public static final User SYSTEM_ADMIN = new User("admin@localhost.localdomain", LEVEL_SYSTEM_ADMIN); + public static final User SYSTEM = new User("system@localhost.localdomain", LEVEL_SYSTEM_ADMIN); private final String login; private final String name; private final String email; private final List roles; - private final boolean isAdmin; + private final boolean isSystemAdmin; /** * Creates a new instance. @@ -71,7 +72,7 @@ public User(@JsonProperty("login") String login, this.name = requireNonNull(name, "name"); this.email = requireNonNull(email, "email"); this.roles = ImmutableList.copyOf(requireNonNull(roles, "roles")); - isAdmin = roles.stream().anyMatch(LEVEL_ADMIN_STR::equals); + isSystemAdmin = roles.stream().anyMatch(LEVEL_SYSTEM_ADMIN_STR::equals); } /** @@ -95,7 +96,7 @@ public User(String login, List roles) { name = Util.emailToUsername(email, "login"); this.roles = ImmutableList.copyOf(roles); - isAdmin = roles.stream().anyMatch(LEVEL_ADMIN_STR::equals); + isSystemAdmin = roles.stream().anyMatch(LEVEL_SYSTEM_ADMIN_STR::equals); } /** @@ -136,10 +137,10 @@ public String id() { } /** - * Returns {@code true} if this user has administrative privileges. + * Returns {@code true} if this user has system administrative privileges. */ - public boolean isAdmin() { - return isAdmin; + public boolean isSystemAdmin() { + return isSystemAdmin; } @Override @@ -167,7 +168,7 @@ public String toString() { .add("name", name()) .add("email", email()) .add("roles", roles()) - .add("isAdmin", isAdmin()) + .add("isSystemAdmin", isSystemAdmin()) .toString(); } } diff --git a/server/src/main/java/com/linecorp/centraldogma/server/metadata/UserWithToken.java b/server/src/main/java/com/linecorp/centraldogma/server/metadata/UserWithToken.java index 8d3e5e69a8..d115ced519 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/metadata/UserWithToken.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/metadata/UserWithToken.java @@ -45,8 +45,8 @@ public Token token() { } @Override - public boolean isAdmin() { - return token.isAdmin(); + public boolean isSystemAdmin() { + return token.isSystemAdmin(); } @Override diff --git a/server/src/main/java/com/linecorp/centraldogma/server/storage/project/Project.java b/server/src/main/java/com/linecorp/centraldogma/server/storage/project/Project.java index 97ec01c216..fb3f6c14d0 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/storage/project/Project.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/storage/project/Project.java @@ -32,12 +32,12 @@ /** * A top-level element in Central Dogma storage model. A project has {@code "dogma"} and {@code "meta"} - * repositories by default which contain project configuration files accessible by administrators + * repositories by default which contain project configuration files accessible by system administrators * and project owners respectively. */ public interface Project { /** - * The repository that contains project configuration files, which are accessible by administrators. + * The repository that contains project configuration files, which are accessible by system administrators. */ String REPO_DOGMA = "dogma"; diff --git a/server/src/test/java/com/linecorp/centraldogma/server/internal/admin/model/SerializationTest.java b/server/src/test/java/com/linecorp/centraldogma/server/internal/admin/model/SerializationTest.java index 0b14d4c689..380b436506 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/internal/admin/model/SerializationTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/internal/admin/model/SerializationTest.java @@ -67,7 +67,7 @@ void testValidProject() throws IOException { final Member member = new Member(userLogin, ProjectRole.MEMBER, newCreationTag()); final RepositoryMetadata repositoryMetadata = new RepositoryMetadata("sample", newCreationTag(), PerRolePermissions.ofDefault()); - final Token token = new Token("testApp", "testSecret", false, false, newCreationTag(), null, null); + final Token token = new Token("testApp", "testSecret", null, false, newCreationTag(), null, null); final ProjectMetadata metadata = new ProjectMetadata("test", ImmutableMap.of(repositoryMetadata.name(), repositoryMetadata), @@ -141,7 +141,7 @@ void testRemovedProject() throws IOException { newCreationTag()); final RepositoryMetadata repositoryMetadata = new RepositoryMetadata("sample", newCreationTag(), PerRolePermissions.ofDefault()); - final Token token = new Token("testApp", "testSecret", false, false, newCreationTag(), null, null); + final Token token = new Token("testApp", "testSecret", null, false, newCreationTag(), null, null); final ProjectMetadata metadata = new ProjectMetadata("test", ImmutableMap.of(repositoryMetadata.name(), repositoryMetadata), diff --git a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1ListProjectTest.java b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1ListProjectTest.java index 8b47852de5..0711a218ca 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1ListProjectTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1ListProjectTest.java @@ -66,7 +66,7 @@ class ProjectServiceV1ListProjectTest { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); } @@ -76,18 +76,18 @@ protected boolean runForEachTest() { } }; - private BlockingWebClient adminClient; + private BlockingWebClient systemAdminClient; private BlockingWebClient normalClient; @BeforeEach void setUp() throws JsonProcessingException { final URI uri = dogma.httpClient().uri(); - adminClient = WebClient.builder(uri) - .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), - TestAuthMessageUtil.USERNAME, - TestAuthMessageUtil.PASSWORD))) - .build() - .blocking(); + systemAdminClient = WebClient.builder(uri) + .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), + TestAuthMessageUtil.USERNAME, + TestAuthMessageUtil.PASSWORD))) + .build() + .blocking(); normalClient = WebClient.builder(uri) .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), TestAuthMessageUtil.USERNAME2, @@ -104,7 +104,7 @@ void listProjects() { createProject(normalClient, "trustin"); createProject(normalClient, "hyangtack"); createProject(normalClient, "minwoox"); - createProject(adminClient, "jrhee17"); + createProject(systemAdminClient, "jrhee17"); AggregatedHttpResponse aRes = normalClient.get(PROJECTS_PREFIX); assertThat(aRes.headers().status()).isEqualTo(HttpStatus.OK); @@ -156,7 +156,7 @@ void listProjects() { .isEqualTo(String.format(normalUserExpect, "")); // Admin fetches internal project "dogma" as well. - aRes = adminClient.get(PROJECTS_PREFIX); + aRes = systemAdminClient.get(PROJECTS_PREFIX); assertThat(aRes.headers().status()).isEqualTo(HttpStatus.OK); final String adminUserExpect = @@ -258,8 +258,8 @@ void listRemovedProjects() throws IOException { @Test void userRoleWithLoginUser() { - createProject(adminClient, "trustin"); - createProject(adminClient, "hyangtack"); + createProject(systemAdminClient, "trustin"); + createProject(systemAdminClient, "hyangtack"); final Map projects = getProjects(normalClient); assertThat(projects).hasSize(2); @@ -268,11 +268,11 @@ void userRoleWithLoginUser() { .containsExactlyInAnyOrder(ProjectRole.GUEST, ProjectRole.GUEST); AggregatedHttpResponse aRes = - adminClient.prepare() - .post("/api/v1/metadata/trustin/members") - .contentJson(new IdentifierWithRole( + systemAdminClient.prepare() + .post("/api/v1/metadata/trustin/members") + .contentJson(new IdentifierWithRole( TestAuthMessageUtil.USERNAME2, "MEMBER")) - .execute(); + .execute(); assertThat(aRes.status()).isEqualTo(HttpStatus.OK); await().untilAsserted(() -> { final Map projects0 = getProjects(normalClient); @@ -280,11 +280,11 @@ void userRoleWithLoginUser() { assertThat(projects0.get("hyangtack").userRole()).isEqualTo(ProjectRole.GUEST); }); - aRes = adminClient.prepare() - .post("/api/v1/metadata/hyangtack/members") - .contentJson(new IdentifierWithRole( + aRes = systemAdminClient.prepare() + .post("/api/v1/metadata/hyangtack/members") + .contentJson(new IdentifierWithRole( TestAuthMessageUtil.USERNAME2, "OWNER")) - .execute(); + .execute(); assertThat(aRes.status()).isEqualTo(HttpStatus.OK); await().untilAsserted(() -> { final Map projects0 = getProjects(normalClient); diff --git a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1Test.java b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1Test.java index d5d7e999ee..7621b52e3f 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1Test.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/ProjectServiceV1Test.java @@ -64,25 +64,25 @@ class ProjectServiceV1Test { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); } }; private static final ObjectMapper mapper = new ObjectMapper(); - private BlockingWebClient adminClient; + private BlockingWebClient systemAdminClient; private BlockingWebClient normalClient; @BeforeEach void setUp() throws JsonProcessingException, UnknownHostException { final URI uri = dogma.httpClient().uri(); - adminClient = WebClient.builder(uri) - .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), - TestAuthMessageUtil.USERNAME, - TestAuthMessageUtil.PASSWORD))) - .build() - .blocking(); + systemAdminClient = WebClient.builder(uri) + .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), + TestAuthMessageUtil.USERNAME, + TestAuthMessageUtil.PASSWORD))) + .build() + .blocking(); normalClient = WebClient.builder(uri) .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), TestAuthMessageUtil.USERNAME2, @@ -155,9 +155,9 @@ void removeProject() { .status()).isEqualTo(HttpStatus.NO_CONTENT); // Cannot remove internal dogma project. - assertThat(adminClient.delete(PROJECTS_PREFIX + "/dogma") - .headers() - .status()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(systemAdminClient.delete(PROJECTS_PREFIX + "/dogma") + .headers() + .status()).isEqualTo(HttpStatus.BAD_REQUEST); } @Test @@ -169,14 +169,14 @@ void removeAbsentProject() { @Test void purgeProject() { removeProject(); - assertThat(adminClient.delete(PROJECTS_PREFIX + "/foo/removed") - .headers() - .status()).isEqualTo(HttpStatus.NO_CONTENT); + assertThat(systemAdminClient.delete(PROJECTS_PREFIX + "/foo/removed") + .headers() + .status()).isEqualTo(HttpStatus.NO_CONTENT); // Illegal access to the internal project. - assertThat(adminClient.delete(PROJECTS_PREFIX + "/dogma/removed") - .headers() - .status()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(systemAdminClient.delete(PROJECTS_PREFIX + "/dogma/removed") + .headers() + .status()).isEqualTo(HttpStatus.BAD_REQUEST); } @Test @@ -190,7 +190,7 @@ void unremoveProject() { HttpHeaderNames.CONTENT_TYPE, MediaType.JSON_PATCH); final String unremovePatch = "[{\"op\":\"replace\",\"path\":\"/status\",\"value\":\"active\"}]"; - final AggregatedHttpResponse aRes = adminClient.execute(headers, unremovePatch); + final AggregatedHttpResponse aRes = systemAdminClient.execute(headers, unremovePatch); assertThat(ResponseHeaders.of(aRes.headers()).status()).isEqualTo(HttpStatus.OK); final String expectedJson = '{' + @@ -214,7 +214,7 @@ void unremoveAbsentProject() { "application/json-patch+json"); final String unremovePatch = "[{\"op\":\"replace\",\"path\":\"/status\",\"value\":\"active\"}]"; - final AggregatedHttpResponse aRes = adminClient.execute(headers, unremovePatch); + final AggregatedHttpResponse aRes = systemAdminClient.execute(headers, unremovePatch); assertThat(ResponseHeaders.of(aRes.headers()).status()).isEqualTo(HttpStatus.NOT_FOUND); } } diff --git a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/AdministrativeServiceTest.java b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/SystemAdministrativeServiceTest.java similarity index 99% rename from server/src/test/java/com/linecorp/centraldogma/server/internal/api/AdministrativeServiceTest.java rename to server/src/test/java/com/linecorp/centraldogma/server/internal/api/SystemAdministrativeServiceTest.java index 824e4bd200..5cdf0ef14c 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/AdministrativeServiceTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/SystemAdministrativeServiceTest.java @@ -36,7 +36,7 @@ import com.linecorp.centraldogma.server.management.ServerStatus; import com.linecorp.centraldogma.testing.junit.CentralDogmaExtension; -class AdministrativeServiceTest { +class SystemAdministrativeServiceTest { @RegisterExtension final CentralDogmaExtension dogma = new CentralDogmaExtension() { diff --git a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/TokenServiceTest.java b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/TokenServiceTest.java index ecd07d4203..74d19095cc 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/internal/api/TokenServiceTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/internal/api/TokenServiceTest.java @@ -75,14 +75,14 @@ class TokenServiceTest { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); } }; - private static final Author adminAuthor = Author.ofEmail("admin@localhost.com"); + private static final Author systemAdminAuthor = Author.ofEmail("systemAdmin@localhost.com"); private static final Author guestAuthor = Author.ofEmail("guest@localhost.com"); - private static final User admin = new User("admin@localhost.com", User.LEVEL_ADMIN); + private static final User systemAdmin = new User("systemAdmin@localhost.com", User.LEVEL_SYSTEM_ADMIN); private static final User guest = new User("guest@localhost.com"); private static final JsonNode activation = Jackson.valueToTree( ImmutableList.of( @@ -97,7 +97,7 @@ protected void configure(CentralDogmaBuilder builder) { private static TokenService tokenService; private static MetadataService metadataService; - private static WebClient adminClient; + private static WebClient systemAdminClient; // ctx is only used for getting the blocking task executor. private final ServiceRequestContext ctx = @@ -112,11 +112,11 @@ static String sessionId(WebClient webClient, String username, String password) @BeforeAll static void setUp() throws JsonMappingException, JsonParseException { final URI uri = dogma.httpClient().uri(); - adminClient = WebClient.builder(uri) - .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), - TestAuthMessageUtil.USERNAME, - TestAuthMessageUtil.PASSWORD))) - .build(); + systemAdminClient = WebClient.builder(uri) + .auth(AuthToken.ofOAuth2(sessionId(dogma.httpClient(), + TestAuthMessageUtil.USERNAME, + TestAuthMessageUtil.PASSWORD))) + .build(); metadataService = new MetadataService(manager.projectManager(), manager.executor()); tokenService = new TokenService(manager.executor(), metadataService); } @@ -126,18 +126,19 @@ public void tearDown() { final Tokens tokens = metadataService.getTokens().join(); tokens.appIds().forEach((appId, token) -> { if (!token.isDeleted()) { - metadataService.destroyToken(adminAuthor, appId); + metadataService.destroyToken(systemAdminAuthor, appId); } - metadataService.purgeToken(adminAuthor, appId); + metadataService.purgeToken(systemAdminAuthor, appId); }); } @Test - void adminToken() { - final Token token = tokenService.createToken("forAdmin1", true, null, adminAuthor, admin).join() + void systemAdminToken() { + final Token token = tokenService.createToken("forAdmin1", true, true, null, + systemAdminAuthor, systemAdmin).join() .content(); assertThat(token.isActive()).isTrue(); - assertThatThrownBy(() -> tokenService.createToken("forAdmin2", true, null, guestAuthor, guest) + assertThatThrownBy(() -> tokenService.createToken("forAdmin2", true, true, null, guestAuthor, guest) .join()) .isInstanceOf(IllegalArgumentException.class); @@ -146,30 +147,32 @@ void adminToken() { metadataService.addToken(Author.SYSTEM, "myPro", "forAdmin1", ProjectRole.OWNER).join(); assertThat(metadataService.getProject("myPro").join().tokens().containsKey("forAdmin1")).isTrue(); - final Collection tokens = tokenService.listTokens(admin).join(); + final Collection tokens = tokenService.listTokens(systemAdmin).join(); assertThat(tokens.stream().filter(t -> !StringUtil.isNullOrEmpty(t.secret()))).hasSize(1); assertThatThrownBy(() -> tokenService.deleteToken(ctx, "forAdmin1", guestAuthor, guest) .join()) .hasCauseInstanceOf(HttpResponseException.class); - assertThat(tokenService.deleteToken(ctx, "forAdmin1", adminAuthor, admin).thenCompose( - unused -> tokenService.purgeToken(ctx, "forAdmin1", adminAuthor, admin)).join()).satisfies( - t -> { + assertThat(tokenService.deleteToken(ctx, "forAdmin1", systemAdminAuthor, systemAdmin) + .thenCompose(unused -> tokenService.purgeToken( + ctx, "forAdmin1", systemAdminAuthor, systemAdmin)).join()) + .satisfies(t -> { assertThat(t.appId()).isEqualTo(token.appId()); - assertThat(t.isAdmin()).isEqualTo(token.isAdmin()); + assertThat(t.isSystemAdmin()).isEqualTo(token.isSystemAdmin()); assertThat(t.creation()).isEqualTo(token.creation()); assertThat(t.isDeleted()).isTrue(); }); - assertThat(tokenService.listTokens(admin).join().size()).isEqualTo(0); + assertThat(tokenService.listTokens(systemAdmin).join().size()).isEqualTo(0); assertThat(metadataService.getProject("myPro").join().tokens().size()).isEqualTo(0); } @Test void userToken() { - final Token userToken1 = tokenService.createToken("forUser1", false, null, adminAuthor, admin) + final Token userToken1 = tokenService.createToken("forUser1", false, false, null, systemAdminAuthor, + systemAdmin) .join().content(); - final Token userToken2 = tokenService.createToken("forUser2", false, null, guestAuthor, guest) + final Token userToken2 = tokenService.createToken("forUser2", false, false, null, guestAuthor, guest) .join().content(); assertThat(userToken1.isActive()).isTrue(); assertThat(userToken2.isActive()).isTrue(); @@ -178,117 +181,126 @@ void userToken() { assertThat(tokens.stream().filter(token -> !StringUtil.isNullOrEmpty(token.secret())).count()) .isEqualTo(0); - assertThat(tokenService.deleteToken(ctx, "forUser1", adminAuthor, admin).thenCompose( - unused -> tokenService.purgeToken(ctx, "forUser1", adminAuthor, admin)).join()).satisfies(t -> { - assertThat(t.appId()).isEqualTo(userToken1.appId()); - assertThat(t.isAdmin()).isEqualTo(userToken1.isAdmin()); - assertThat(t.creation()).isEqualTo(userToken1.creation()); - assertThat(t.deactivation()).isEqualTo(userToken1.deactivation()); - }); - assertThat(tokenService.deleteToken(ctx, "forUser2", guestAuthor, guest).thenCompose( - unused -> tokenService.purgeToken(ctx, "forUser2", guestAuthor, guest)).join()).satisfies(t -> { - assertThat(t.appId()).isEqualTo(userToken2.appId()); - assertThat(t.isAdmin()).isEqualTo(userToken2.isAdmin()); - assertThat(t.creation()).isEqualTo(userToken2.creation()); - assertThat(t.deactivation()).isEqualTo(userToken2.deactivation()); - }); + assertThat(tokenService.deleteToken(ctx, "forUser1", systemAdminAuthor, systemAdmin) + .thenCompose(unused -> tokenService.purgeToken( + ctx, "forUser1", systemAdminAuthor, systemAdmin)).join()) + .satisfies(t -> { + assertThat(t.appId()).isEqualTo(userToken1.appId()); + assertThat(t.isSystemAdmin()).isEqualTo(userToken1.isSystemAdmin()); + assertThat(t.creation()).isEqualTo(userToken1.creation()); + assertThat(t.deactivation()).isEqualTo(userToken1.deactivation()); + }); + assertThat(tokenService.deleteToken(ctx, "forUser2", guestAuthor, guest) + .thenCompose(unused -> tokenService.purgeToken( + ctx, "forUser2", guestAuthor, guest)).join()) + .satisfies(t -> { + assertThat(t.appId()).isEqualTo(userToken2.appId()); + assertThat(t.isSystemAdmin()).isEqualTo(userToken2.isSystemAdmin()); + assertThat(t.creation()).isEqualTo(userToken2.creation()); + assertThat(t.deactivation()).isEqualTo(userToken2.deactivation()); + }); } @Test void nonRandomToken() { - final Token token = tokenService.createToken("forAdmin1", true, "appToken-secret", adminAuthor, - admin) + final Token token = tokenService.createToken("forAdmin1", true, true, "appToken-secret", + systemAdminAuthor, + systemAdmin) .join().content(); assertThat(token.isActive()).isTrue(); - final Collection tokens = tokenService.listTokens(admin).join(); + final Collection tokens = tokenService.listTokens(systemAdmin).join(); assertThat(tokens.stream().filter(t -> !StringUtil.isNullOrEmpty(t.secret()))).hasSize(1); - assertThatThrownBy(() -> tokenService.createToken("forUser1", true, "appToken-secret", guestAuthor, - guest) + assertThatThrownBy(() -> tokenService.createToken("forUser1", true, true, + "appToken-secret", guestAuthor, guest) .join()) .isInstanceOf(IllegalArgumentException.class); final ServiceRequestContext ctx = ServiceRequestContext.of( HttpRequest.of(HttpMethod.DELETE, "/tokens/{appId}/removed")); - tokenService.deleteToken(this.ctx, "forAdmin1", adminAuthor, admin).thenCompose( - unused -> tokenService.purgeToken(ctx, "forAdmin1", adminAuthor, admin)).join(); + tokenService.deleteToken(this.ctx, "forAdmin1", systemAdminAuthor, systemAdmin).thenCompose( + unused -> tokenService.purgeToken(ctx, "forAdmin1", systemAdminAuthor, systemAdmin)).join(); } @Test public void updateToken() { - final Token token = tokenService.createToken("forUpdate", true, null, adminAuthor, admin).join() + final Token token = tokenService.createToken("forUpdate", true, true, null, + systemAdminAuthor, systemAdmin).join() .content(); assertThat(token.isActive()).isTrue(); - tokenService.updateToken(ctx, "forUpdate", deactivation, adminAuthor, admin).join(); + tokenService.updateToken(ctx, "forUpdate", deactivation, systemAdminAuthor, systemAdmin).join(); final Token deactivatedToken = metadataService.findTokenByAppId("forUpdate").join(); assertThat(deactivatedToken.isActive()).isFalse(); - tokenService.updateToken(ctx, "forUpdate", activation, adminAuthor, admin).join(); + tokenService.updateToken(ctx, "forUpdate", activation, systemAdminAuthor, systemAdmin).join(); final Token activatedToken = metadataService.findTokenByAppId("forUpdate").join(); assertThat(activatedToken.isActive()).isTrue(); assertThatThrownBy( () -> tokenService.updateToken(ctx, "forUpdate", Jackson.valueToTree( - ImmutableList.of(ImmutableMap.of())), adminAuthor, admin).join()) + ImmutableList.of(ImmutableMap.of())), systemAdminAuthor, systemAdmin).join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(IllegalArgumentException.class); - tokenService.deleteToken(ctx, "forUpdate", adminAuthor, admin).join(); + tokenService.deleteToken(ctx, "forUpdate", systemAdminAuthor, systemAdmin).join(); final Token deletedToken = metadataService.findTokenByAppId("forUpdate").join(); assertThat(deletedToken.isDeleted()).isTrue(); assertThatThrownBy( - () -> tokenService.updateToken(ctx, "forUpdate", activation, adminAuthor, admin).join()) + () -> tokenService.updateToken(ctx, "forUpdate", activation, + systemAdminAuthor, systemAdmin).join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(IllegalArgumentException.class); } @Test void updateTokenLevel() { - final Token token = tokenService.createToken("forUpdate", false, null, adminAuthor, admin).join() + final Token token = tokenService.createToken("forUpdate", false, false, null, + systemAdminAuthor, systemAdmin).join() .content(); assertThat(token.isActive()).isTrue(); - final Token userToken = tokenService.updateTokenLevel(ctx, "forUpdate", new TokenLevelRequest("ADMIN"), - adminAuthor, admin) + final Token userToken = tokenService.updateTokenLevel( + ctx, "forUpdate", new TokenLevelRequest("SYSTEMADMIN"), + systemAdminAuthor, systemAdmin) .join(); - assertThat(userToken.isAdmin()).isTrue(); + assertThat(userToken.isSystemAdmin()).isTrue(); final Token adminToken = tokenService.updateTokenLevel(ctx, "forUpdate", new TokenLevelRequest("USER"), - adminAuthor, admin) + systemAdminAuthor, systemAdmin) .join(); - assertThat(adminToken.isAdmin()).isFalse(); + assertThat(adminToken.isSystemAdmin()).isFalse(); assertThatThrownBy( () -> tokenService.updateTokenLevel(ctx, "forUpdate", new TokenLevelRequest("INVALID"), - adminAuthor, admin).join()) + systemAdminAuthor, systemAdmin).join()) .isInstanceOf(IllegalArgumentException.class); } @Test void createTokenAndUpdateLevel() throws JsonParseException { - assertThat(adminClient.post(API_V1_PATH_PREFIX + "tokens", - QueryParams.of("appId", "forUpdate", "isAdmin", false), - HttpData.empty()) - .aggregate() - .join() - .headers() - .get(HttpHeaderNames.LOCATION)).isEqualTo("/tokens/forUpdate"); + assertThat(systemAdminClient.post(API_V1_PATH_PREFIX + "tokens", + QueryParams.of("appId", "forUpdate", "isSystemAdmin", false), + HttpData.empty()) + .aggregate() + .join() + .headers() + .get(HttpHeaderNames.LOCATION)).isEqualTo("/tokens/forUpdate"); final RequestHeaders headers = RequestHeaders.of(HttpMethod.PATCH, API_V1_PATH_PREFIX + "tokens/forUpdate/level", HttpHeaderNames.CONTENT_TYPE, MediaType.JSON); - final String body = "{\"level\":\"ADMIN\"}"; - final AggregatedHttpResponse response = adminClient.execute(headers, body).aggregate().join(); + final String body = "{\"level\":\"SYSTEMADMIN\"}"; + final AggregatedHttpResponse response = systemAdminClient.execute(headers, body).aggregate().join(); final JsonNode jsonNode = Jackson.readTree(response.contentUtf8()); assertThat(jsonNode.get("appId").asText()).isEqualTo("forUpdate"); - assertThat(jsonNode.get("admin").asBoolean()).isEqualTo(true); + assertThat(jsonNode.get("systemAdmin").asBoolean()).isEqualTo(true); - final AggregatedHttpResponse response2 = adminClient.execute(headers, body).aggregate().join(); + final AggregatedHttpResponse response2 = systemAdminClient.execute(headers, body).aggregate().join(); assertThat(response2.status()).isEqualTo(HttpStatus.NOT_MODIFIED); } } diff --git a/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataApiServiceTest.java b/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataApiServiceTest.java index 5c09fed86f..11b287611f 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataApiServiceTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataApiServiceTest.java @@ -45,7 +45,7 @@ class MetadataApiServiceTest { @Override protected void configure(CentralDogmaBuilder builder) { - builder.administrators(TestAuthMessageUtil.USERNAME); + builder.systemAdministrators(TestAuthMessageUtil.USERNAME); builder.authProviderFactory(new TestAuthProviderFactory()); } }; @@ -61,24 +61,25 @@ void grantPermissionToMemberForMetaRepository() throws Exception { assertThat(response.status()).isEqualTo(HttpStatus.OK); final String sessionId = Jackson.readValue(response.content().array(), AccessToken.class) .accessToken(); - final WebClient adminClient = WebClient.builder(client.uri()) - .auth(AuthToken.ofOAuth2(sessionId)).build(); + final WebClient systemAdminClient = WebClient.builder(client.uri()) + .auth(AuthToken.ofOAuth2(sessionId)).build(); final RequestHeaders headers = RequestHeaders.of(HttpMethod.POST, PROJECTS_PREFIX, HttpHeaderNames.CONTENT_TYPE, MediaType.JSON); final String body = "{\"name\": \"" + projectName + "\"}"; // Create a project. - assertThat(adminClient.execute(headers, body).aggregate().join().status()).isSameAs(HttpStatus.CREATED); + assertThat(systemAdminClient.execute(headers, body).aggregate().join().status()) + .isSameAs(HttpStatus.CREATED); final String memberToken = "appToken-secret-member"; // Create a token with a non-random secret. HttpRequest request = HttpRequest.builder() .post("/api/v1/tokens") .content(MediaType.FORM_DATA, - "secret=" + memberToken + "&isAdmin=false&appId=foo") + "secret=" + memberToken + "&isSystemAdmin=false&appId=foo") .build(); - AggregatedHttpResponse res = adminClient.execute(request).aggregate().join(); + AggregatedHttpResponse res = systemAdminClient.execute(request).aggregate().join(); assertThat(res.status()).isEqualTo(HttpStatus.CREATED); - res = adminClient.get("/api/v1/tokens").aggregate().join(); + res = systemAdminClient.get("/api/v1/tokens").aggregate().join(); assertThat(res.contentUtf8()).contains("\"secret\":\"" + memberToken + '"'); // Add as a member to the project @@ -90,7 +91,7 @@ void grantPermissionToMemberForMetaRepository() throws Exception { "\"role\":\"MEMBER\"" + '}') .build(); - res = adminClient.execute(request).aggregate().join(); + res = systemAdminClient.execute(request).aggregate().join(); assertThat(res.status()).isSameAs(HttpStatus.OK); final WebClient memberClient = WebClient.builder(client.uri()) @@ -110,7 +111,7 @@ void grantPermissionToMemberForMetaRepository() throws Exception { " \"guest\": [ ]\n" + '}') .build(); - adminClient.execute(request).aggregate().join(); + systemAdminClient.execute(request).aggregate().join(); // Now the member can access the meta repository. res = memberClient.get("/api/v1/projects/" + projectName + "/repos/meta/list").aggregate().join(); diff --git a/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataServiceTest.java b/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataServiceTest.java index f9d7346db9..57a77d1686 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataServiceTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/metadata/MetadataServiceTest.java @@ -437,17 +437,17 @@ void updateUser() { mds.createToken(author, app1).join(); token = mds.getTokens().join().get(app1); assertThat(token).isNotNull(); - assertThat(token.isAdmin()).isFalse(); + assertThat(token.isSystemAdmin()).isFalse(); mds.updateTokenLevel(author, app1, true).join(); token = mds.getTokens().join().get(app1); - assertThat(token.isAdmin()).isTrue(); + assertThat(token.isSystemAdmin()).isTrue(); assertThatThrownBy(() -> mds.updateTokenLevel(author, app1, true).join()) .hasCauseInstanceOf(IllegalArgumentException.class); mds.updateTokenLevel(author, app1, false).join(); token = mds.getTokens().join().get(app1); - assertThat(token.isAdmin()).isFalse(); + assertThat(token.isSystemAdmin()).isFalse(); assertThatThrownBy(() -> mds.updateTokenLevel(author, app1, false).join()) .hasCauseInstanceOf(IllegalArgumentException.class); } diff --git a/server/src/test/java/com/linecorp/centraldogma/server/metadata/TokenTest.java b/server/src/test/java/com/linecorp/centraldogma/server/metadata/TokenTest.java index 30fd885db7..ce8bc67c6c 100644 --- a/server/src/test/java/com/linecorp/centraldogma/server/metadata/TokenTest.java +++ b/server/src/test/java/com/linecorp/centraldogma/server/metadata/TokenTest.java @@ -15,28 +15,88 @@ */ package com.linecorp.centraldogma.server.metadata; +import static com.linecorp.centraldogma.internal.jsonpatch.JsonPatchOperation.asJsonArray; +import static com.linecorp.centraldogma.server.metadata.MetadataService.TOKEN_JSON; import static org.assertj.core.api.Assertions.assertThat; +import java.util.Collection; + +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonPointer; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.linecorp.armeria.common.HttpMethod; +import com.linecorp.armeria.common.HttpRequest; +import com.linecorp.armeria.server.ServiceRequestContext; +import com.linecorp.centraldogma.common.Author; +import com.linecorp.centraldogma.common.Change; +import com.linecorp.centraldogma.common.Revision; import com.linecorp.centraldogma.internal.Jackson; +import com.linecorp.centraldogma.internal.jsonpatch.AddOperation; +import com.linecorp.centraldogma.internal.jsonpatch.TestAbsenceOperation; +import com.linecorp.centraldogma.server.internal.api.TokenLevelRequest; +import com.linecorp.centraldogma.server.internal.api.TokenService; +import com.linecorp.centraldogma.server.storage.project.InternalProjectInitializer; +import com.linecorp.centraldogma.server.storage.project.Project; +import com.linecorp.centraldogma.server.storage.repository.Repository; +import com.linecorp.centraldogma.testing.internal.ProjectManagerExtension; class TokenTest { + @RegisterExtension + static final ProjectManagerExtension manager = new ProjectManagerExtension(); + private static final String APP_ID = "foo-id"; private static final String APP_SECRET = "appToken-foo"; + private static final Author AUTHOR = Author.ofEmail("systemAdmin@localhost.com"); + private static final User USER = new User("systemAdmin@localhost.com", User.LEVEL_SYSTEM_ADMIN); + + private static final ServiceRequestContext CTX = + ServiceRequestContext.builder(HttpRequest.of(HttpMethod.GET, "/")).build(); + + private static TokenService tokenService; + private static MetadataService metadataService; + + @BeforeAll + static void setUp() throws JsonParseException { + metadataService = new MetadataService(manager.projectManager(), manager.executor()); + tokenService = new TokenService(manager.executor(), metadataService); + + // Put the legacy token. + final Repository dogmaRepository = + manager.projectManager().get(InternalProjectInitializer.INTERNAL_PROJECT_DOGMA).repos() + .get(Project.REPO_DOGMA); + final JsonPointer appIdPath = JsonPointer.compile("/appIds/" + APP_ID); + final JsonPointer secretPath = JsonPointer.compile("/secrets/" + APP_SECRET); + final Change change = Change.ofJsonPatch( + TOKEN_JSON, + asJsonArray(new TestAbsenceOperation(appIdPath), + new TestAbsenceOperation(secretPath), + new AddOperation(appIdPath, Jackson.readTree(tokenJson(true))), + new AddOperation(secretPath, Jackson.valueToTree(APP_ID)))); + + dogmaRepository.commit(Revision.HEAD, System.currentTimeMillis(), AUTHOR, + "Add the legacy token", change).join(); + } @Test void deserializeToken() throws Exception { final String legacyTokenJson = tokenJson(true); final Token legacyToken = Jackson.readValue(legacyTokenJson, Token.class); assertThat(legacyToken.appId()).isEqualTo(APP_ID); - assertThat(legacyToken.isAdmin()).isTrue(); + assertThat(legacyToken.isSystemAdmin()).isTrue(); final String tokenJson = tokenJson(false); final Token token = Jackson.readValue(tokenJson, Token.class); assertThat(token.appId()).isEqualTo(APP_ID); - assertThat(token.isAdmin()).isTrue(); + assertThat(token.isSystemAdmin()).isTrue(); } private static String tokenJson(boolean legacy) { @@ -48,4 +108,51 @@ private static String tokenJson(boolean legacy) { " \"timestamp\": \"2018-04-10T09:58:20.032Z\"" + "}}"; } + + @Test + void updateToken() throws JsonParseException { + final Collection tokens = tokenService.listTokens(USER).join(); + assertThat(tokens.size()).isOne(); + final Token token = Iterables.getFirst(tokens, null); + assertThat(token.appId()).isEqualTo(APP_ID); + assertThat(token.isSystemAdmin()).isTrue(); + assertThat(token.isActive()).isTrue(); + + final JsonNode deactivation = Jackson.valueToTree( + ImmutableList.of( + ImmutableMap.of("op", "replace", + "path", "/status", + "value", "inactive"))); + + tokenService.updateToken(CTX, APP_ID, deactivation, AUTHOR, USER).join(); + Token updated = metadataService.findTokenByAppId(APP_ID).join(); + assertThat(updated.appId()).isEqualTo(APP_ID); + assertThat(updated.isSystemAdmin()).isTrue(); + assertThat(updated.isActive()).isFalse(); + + final JsonNode activation = Jackson.valueToTree( + ImmutableList.of( + ImmutableMap.of("op", "replace", + "path", "/status", + "value", "active"))); + + tokenService.updateToken(CTX, APP_ID, activation, AUTHOR, USER).join(); + updated = metadataService.findTokenByAppId(APP_ID).join(); + assertThat(updated.appId()).isEqualTo(APP_ID); + assertThat(updated.isSystemAdmin()).isTrue(); + assertThat(updated.isActive()).isTrue(); + } + + @Test + void updateTokenLevel() { + final Token userToken = + tokenService.updateTokenLevel(CTX, APP_ID, new TokenLevelRequest("USER"), AUTHOR, USER) + .join(); + assertThat(userToken.isSystemAdmin()).isFalse(); + + final Token updatedToken = + tokenService.updateTokenLevel(CTX, APP_ID, new TokenLevelRequest("SYSTEMADMIN"), + AUTHOR, USER).join(); + assertThat(updatedToken.isSystemAdmin()).isTrue(); + } } diff --git a/site/src/sphinx/auth.rst b/site/src/sphinx/auth.rst index 2a32aad229..a66fc31139 100644 --- a/site/src/sphinx/auth.rst +++ b/site/src/sphinx/auth.rst @@ -31,7 +31,7 @@ The authentication configuration consists of the following properties: ... "authentication": { "factoryClassName": "the fully-qualified class name of an AuthenticationProviderFactory", - "administrators": [], + "systemAdministrators": [], "caseSensitiveLoginNames": false, "sessionCacheSpec": "maximumSize=8192,expireAfterWrite=604800s", "sessionTimeoutMillis": 604800000, @@ -46,9 +46,10 @@ The authentication configuration consists of the following properties: ``com.linecorp.centraldogma.server.auth.saml.SamlAuthProviderFactory`` or ``com.linecorp.centraldogma.server.auth.shiro.ShiroAuthProviderFactory``. -- ``administrators`` (string array) +- ``systemAdministrators`` (string array) - - login names of the administrators. A user who has a login name specified here will get the administrator role. + - login names of the system administrators. A user who has a login name specified here will get the + system administrator role. - ``caseSensitiveLoginNames`` (boolean) @@ -89,7 +90,7 @@ the authentication to. ... "authentication": { "factoryClassName": "com.linecorp.centraldogma.server.auth.saml.SamlAuthProviderFactory", - "administrators": [], + "systemAdministrators": [], "caseSensitiveLoginNames": false, "sessionCacheSpec": "maximumSize=8192,expireAfterWrite=604800s", "sessionTimeoutMillis": 604800000, @@ -225,7 +226,7 @@ in the ``properties`` property. ... "authentication": { "factoryClassName": "com.linecorp.centraldogma.server.auth.shiro.ShiroAuthProviderFactory", - "administrators": [], + "systemAdministrators": [], "caseSensitiveLoginNames": false, "sessionCacheSpec": "maximumSize=8192,expireAfterWrite=604800s", "sessionTimeoutMillis": 604800000, @@ -270,10 +271,10 @@ When you add a user as a member of the project, you need to choose the role of t There are 4 user role types in the access control system of Central Dogma, but you can choose one of ``Owner`` and ``Member`` role in the UI. More information about the role is as follows. -- ``Administrator`` +- ``System Administrator`` - - the user that all permissions are assigned to, a.k.a 'super user'. Only an administrator can restore - removed project. The administrators can be configured in ``conf/dogma.json`` as described the above. + - the user that all permissions are assigned to, a.k.a 'super user'. Only a system administrator can restore + removed project. The system administrators can be configured in ``conf/dogma.json`` as described the above. - ``Owner`` of a project @@ -335,8 +336,8 @@ request comes from. Anyone who is logged into the Central Dogma can create a new ``Application Token``, and the token is shared for everyone. So any owner of a project can add any token to their project. However only both the token -creator and the administrator are allowed to deactivate and/or remove the token. +creator and the system administrator are allowed to deactivate and/or remove the token. -There are two levels of a token, which are ``Admin`` and ``User``. ``Admin`` level token can be created by -only the administrators. A client who sends a request with the token is allowed to access administrator-level -APIs. +There are two levels of a token, which are ``System Admin`` and ``User``. ``System Admin`` level token can be +created by only the system administrators. A client who sends a request with the token is allowed to access +system administrator-level APIs. diff --git a/testing-internal/src/main/java/com/linecorp/centraldogma/testing/internal/CentralDogmaReplicationExtension.java b/testing-internal/src/main/java/com/linecorp/centraldogma/testing/internal/CentralDogmaReplicationExtension.java index 8da60014f4..8894792f12 100644 --- a/testing-internal/src/main/java/com/linecorp/centraldogma/testing/internal/CentralDogmaReplicationExtension.java +++ b/testing-internal/src/main/java/com/linecorp/centraldogma/testing/internal/CentralDogmaReplicationExtension.java @@ -114,7 +114,7 @@ private List newDogmaCluster(int numReplicas) throws I @Override protected void configure(CentralDogmaBuilder builder) { builder.port(new InetSocketAddress(NetUtil.LOCALHOST4, dogmaPort), SessionProtocol.HTTP) - .administrators(TestAuthMessageUtil.USERNAME) + .systemAdministrators(TestAuthMessageUtil.USERNAME) .authProviderFactory(factory) .gracefulShutdownTimeout(new GracefulShutdownTimeout(0, 0)) .replication(new ZooKeeperReplicationConfig(serverId, zooKeeperServers)); diff --git a/webapp/src/dogma/common/components/ProjectSearchBox.tsx b/webapp/src/dogma/common/components/ProjectSearchBox.tsx index 3a1eb5f189..6dd8675f7a 100644 --- a/webapp/src/dogma/common/components/ProjectSearchBox.tsx +++ b/webapp/src/dogma/common/components/ProjectSearchBox.tsx @@ -41,7 +41,7 @@ const DropdownIndicator = ( const ProjectSearchBox = ({ id, size, placeholder, autoFocus }: ProjectSearchBoxProps) => { const { colorMode } = useColorMode(); - const { data, isLoading } = useGetProjectsQuery({ admin: false }); + const { data, isLoading } = useGetProjectsQuery({ systemAdmin: false }); const projects = data || []; const projectOptions: ProjectOptionType[] = projects.map((project: ProjectDto) => ({ value: project.name, diff --git a/webapp/src/dogma/common/components/UserRole.tsx b/webapp/src/dogma/common/components/UserRole.tsx index ba6f5609b2..12cc662ab2 100644 --- a/webapp/src/dogma/common/components/UserRole.tsx +++ b/webapp/src/dogma/common/components/UserRole.tsx @@ -10,7 +10,7 @@ function badgeColor(role: string) { case 'member': return 'green'; case 'owner': - case 'admin': + case 'system admin': return 'blue'; default: return 'gray'; diff --git a/webapp/src/dogma/features/api/apiSlice.ts b/webapp/src/dogma/features/api/apiSlice.ts index 5942899c53..639b5cd661 100644 --- a/webapp/src/dogma/features/api/apiSlice.ts +++ b/webapp/src/dogma/features/api/apiSlice.ts @@ -37,7 +37,7 @@ export type ApiAction = { }; export type GetProjects = { - admin: boolean; + systemAdmin: boolean; }; export type GetHistory = { @@ -104,7 +104,7 @@ export const apiSlice = createApi({ async queryFn(arg, _queryApi, _extraOptions, fetchWithBQ) { const projects = await fetchWithBQ('/api/v1/projects'); if (projects.error) return { error: projects.error as FetchBaseQueryError }; - if (arg.admin) { + if (arg.systemAdmin) { const removedProjects = await fetchWithBQ('/api/v1/projects?status=removed'); if (removedProjects.error) return { error: removedProjects.error as FetchBaseQueryError }; return { diff --git a/webapp/src/dogma/features/auth/ProjectRole.tsx b/webapp/src/dogma/features/auth/ProjectRole.tsx index ce031c614f..7ab919f4af 100644 --- a/webapp/src/dogma/features/auth/ProjectRole.tsx +++ b/webapp/src/dogma/features/auth/ProjectRole.tsx @@ -15,7 +15,7 @@ type WithProjectRoleProps = { export function findUserRole(user: UserDto, metadata: ProjectMetadataDto) { let role: ProjectRole; if (metadata && user) { - if (user.admin) { + if (user.systemAdmin) { role = 'OWNER'; } else { role = metadata.members[user.email]?.role as ProjectRole; diff --git a/webapp/src/dogma/features/auth/UserDto.ts b/webapp/src/dogma/features/auth/UserDto.ts index 446dcf6b26..dcfdfc9856 100644 --- a/webapp/src/dogma/features/auth/UserDto.ts +++ b/webapp/src/dogma/features/auth/UserDto.ts @@ -19,5 +19,5 @@ export interface UserDto { name: string; email: string; roles: string[]; - admin: boolean; + systemAdmin: boolean; } diff --git a/webapp/src/dogma/features/auth/authSlice.ts b/webapp/src/dogma/features/auth/authSlice.ts index 16b203c965..fde9d43118 100644 --- a/webapp/src/dogma/features/auth/authSlice.ts +++ b/webapp/src/dogma/features/auth/authSlice.ts @@ -133,7 +133,7 @@ const anonymousUser: UserDto = { name: 'Anonymous', email: 'anonymous@localhost', roles: [], - admin: false, + systemAdmin: false, }; export const authSlice = createSlice({ diff --git a/webapp/src/dogma/features/project/Projects.tsx b/webapp/src/dogma/features/project/Projects.tsx index 8a7e3abb46..92dfece275 100644 --- a/webapp/src/dogma/features/project/Projects.tsx +++ b/webapp/src/dogma/features/project/Projects.tsx @@ -71,7 +71,7 @@ export const Projects = () => { error, isLoading, } = useGetProjectsQuery({ - admin: user?.admin || false, + systemAdmin: user?.systemAdmin || false, }); let filteredProjects = projects; @@ -164,8 +164,8 @@ export const Projects = () => { } } - if (user.admin) { - // Restore project button for admin users. + if (user.systemAdmin) { + // Restore project button for system admin users. return ; } else { return null; diff --git a/webapp/src/dogma/features/project/settings/credentials/CredentialView.tsx b/webapp/src/dogma/features/project/settings/credentials/CredentialView.tsx index 79d71454e0..0fa04825c0 100644 --- a/webapp/src/dogma/features/project/settings/credentials/CredentialView.tsx +++ b/webapp/src/dogma/features/project/settings/credentials/CredentialView.tsx @@ -61,14 +61,14 @@ interface SecretViewerProps { const SecretViewer = ({ dispatch, secretProvider }: SecretViewerProps) => { const [showSecret, setShowSecret] = useState(false); - const admin = useAppSelector((state) => state.auth.user.admin); + const systemAdmin = useAppSelector((state) => state.auth.user.systemAdmin); return ( {showSecret ? secretProvider() : '****'} - {admin ? ( + {systemAdmin ? (