Allow admins to create team-scoped API keys
This commit is contained in:
+13
-4
@@ -71,7 +71,7 @@ public class ApiKeyManagementService {
|
||||
User caller = requireCaller();
|
||||
migrateLegacyKey(caller);
|
||||
|
||||
boolean isManager = policyAuthority.canEditPolicies();
|
||||
boolean isManager = isTeamKeyManager();
|
||||
Long teamId = policyAuthority.currentUserTeamId();
|
||||
String teamName = teamId == null ? null : teamNameFor(teamId);
|
||||
|
||||
@@ -153,9 +153,10 @@ public class ApiKeyManagementService {
|
||||
Long teamId = null;
|
||||
String teamName = null;
|
||||
if (scope.isTeamScoped()) {
|
||||
if (!policyAuthority.canEditPolicies()) {
|
||||
if (!isTeamKeyManager()) {
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.FORBIDDEN, "Only a team leader may create team API keys");
|
||||
HttpStatus.FORBIDDEN,
|
||||
"Team API keys can only be created by a team leader or an admin");
|
||||
}
|
||||
teamId = policyAuthority.currentUserTeamId();
|
||||
if (teamId == null) {
|
||||
@@ -204,12 +205,20 @@ public class ApiKeyManagementService {
|
||||
clearLegacyColumnIfMatches(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Team keys are managed by a team leader (the SaaS rule) or an admin (either flavor) - an admin
|
||||
* is effectively a leader for this purpose, which the SaaS team-leader-only check misses.
|
||||
*/
|
||||
private boolean isTeamKeyManager() {
|
||||
return policyAuthority.canEditPolicies() || userService.isCurrentUserAdmin();
|
||||
}
|
||||
|
||||
/** Whether the caller may revoke a given key. */
|
||||
private boolean canManage(User caller, ApiKey key) {
|
||||
if (key.getScope() == ApiKeyScope.PERSONAL) {
|
||||
return key.getOwnerUserId().equals(caller.getId());
|
||||
}
|
||||
return policyAuthority.canEditPolicies()
|
||||
return isTeamKeyManager()
|
||||
&& key.getTeamId() != null
|
||||
&& key.getTeamId().equals(policyAuthority.currentUserTeamId());
|
||||
}
|
||||
|
||||
+18
@@ -235,6 +235,24 @@ class ApiKeyManagementServiceTest {
|
||||
assertThat(saved.getValue().getTeamId()).isEqualTo(5L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an admin who is not a team leader can still create a team key")
|
||||
void adminCanCreateTeamKey() {
|
||||
when(policyAuthority.canEditPolicies()).thenReturn(false);
|
||||
when(userService.isCurrentUserAdmin()).thenReturn(true);
|
||||
when(policyAuthority.currentUserTeamId()).thenReturn(5L);
|
||||
Team team = new Team();
|
||||
team.setName("Acme");
|
||||
when(teamRepository.findById(5L)).thenReturn(Optional.of(team));
|
||||
|
||||
service.createKey(new CreateApiKeyRequest("Admin team key", "team-members"));
|
||||
|
||||
ArgumentCaptor<ApiKey> saved = ArgumentCaptor.forClass(ApiKey.class);
|
||||
verify(apiKeyRepository).save(saved.capture());
|
||||
assertThat(saved.getValue().getScope()).isEqualTo(ApiKeyScope.TEAM_MEMBERS);
|
||||
assertThat(saved.getValue().getTeamId()).isEqualTo(5L);
|
||||
}
|
||||
|
||||
// ---- revocation ---------------------------------------------------------
|
||||
|
||||
@Test
|
||||
|
||||
@@ -7078,7 +7078,7 @@ secretKeyCaption = "Secret key"
|
||||
secretWarning = "Store this in a secrets manager. Stirling only ever stores a hash, so there is no way to recover it later."
|
||||
subtitle = "Scope the key to the minimum it needs. You can revoke it at any time."
|
||||
subtitleCreated = "Copy this secret now — it won't be shown again."
|
||||
teamScopeLeaderOnly = "Only team leaders can create team-scoped keys."
|
||||
teamScopeLeaderOnly = "Team-scoped keys need team-leader or admin rights and a team to scope them to."
|
||||
title = "Create API key"
|
||||
titleCreated = "Key created"
|
||||
yourTeam = "your team"
|
||||
|
||||
Reference in New Issue
Block a user