From 5c53251ef2d984d9dc201e4db4fc65adfe77201a Mon Sep 17 00:00:00 2001 From: toby Date: Thu, 7 Nov 2019 16:35:22 +0100 Subject: Add method and use this in already supported restapi --- .../com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java index 752409d5694..e9ca79e2b86 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java @@ -191,8 +191,9 @@ public class UserApiHandler extends LoggingRequestHandler { var user = new UserId(require("user", Inspector::asString, requestObject)); var roles = SlimeStream.fromArray(requestObject.field("roles"), Inspector::asString) .map(roleName -> Roles.toRole(tenant, roleName)) - .peek(role -> users.addUsers(role, List.of(user))) .collect(Collectors.toUnmodifiableList()); + + users.addRoles(user, roles); return new MessageResponse(user + " is now a member of " + roles.stream().map(Role::toString).collect(Collectors.joining(", "))); } -- cgit v1.2.3 From aefd579cf74faf45d4279071daff6f2401597514 Mon Sep 17 00:00:00 2001 From: toby Date: Fri, 8 Nov 2019 10:02:52 +0100 Subject: Add symetric removeRoles to user management api --- .../api/integration/stubs/MockUserManagement.java | 7 +++ .../api/integration/user/UserManagement.java | 3 ++ .../controller/restapi/user/UserApiHandler.java | 51 +++++++++++++--------- 3 files changed, 41 insertions(+), 20 deletions(-) (limited to 'controller-server') diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java index 145b468688c..cdec8e60072 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java @@ -54,6 +54,13 @@ public class MockUserManagement implements UserManagement { memberships.get(role).removeIf(user -> users.contains(new UserId(user.email()))); } + @Override + public void removeRoles(UserId user, Collection roles) { + for (Role role : roles) { + removeUsers(role, Collections.singletonList(user)); + } + } + @Override public List listUsers(Role role) { return List.copyOf(memberships.get(role)); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java index efe31f6f118..ee3c48e85d3 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java @@ -27,6 +27,9 @@ public interface UserManagement { /** Ensures none of the given users are part of the given role, or throws if the role does not exist. */ void removeUsers(Role role, Collection users); + /** Ensures the given users are not part of the given role, or throws if the roles does not exist. */ + void removeRoles(UserId user, Collection roles); + /** Returns all users in the given role, or throws if the role does not exist. */ List listUsers(Role role); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java index e9ca79e2b86..15d7556b389 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java @@ -8,8 +8,10 @@ import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.LoggingRequestHandler; import com.yahoo.io.IOUtils; +import com.yahoo.restapi.ErrorResponse; +import com.yahoo.restapi.MessageResponse; import com.yahoo.restapi.Path; -import com.yahoo.slime.ArrayTraverser; +import com.yahoo.restapi.SlimeJsonResponse; import com.yahoo.slime.Cursor; import com.yahoo.slime.Inspector; import com.yahoo.slime.Slime; @@ -23,9 +25,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.user.UserId; import com.yahoo.vespa.hosted.controller.api.integration.user.UserManagement; import com.yahoo.vespa.hosted.controller.api.role.Role; import com.yahoo.vespa.hosted.controller.api.role.RoleDefinition; -import com.yahoo.restapi.ErrorResponse; -import com.yahoo.restapi.MessageResponse; -import com.yahoo.restapi.SlimeJsonResponse; import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal; import com.yahoo.vespa.hosted.controller.restapi.application.EmptyResponse; import com.yahoo.yolean.Exceptions; @@ -218,11 +217,13 @@ public class UserApiHandler extends LoggingRequestHandler { TenantName tenant = TenantName.from(tenantName); String roleName = require("roleName", Inspector::asString, requestObject); UserId user = new UserId(require("user", Inspector::asString, requestObject)); - Role role = Roles.toRole(tenant, roleName); + List roles = Collections.singletonList(Roles.toRole(tenant, roleName)); - removeTenantRoleMember(tenant, user, role); + enforceLastAdminOfTenant(tenant, user, roles); + removeDeveloperKey(tenant, user, roles); + users.removeRoles(user, roles); - return new MessageResponse(user+" is no longer a member of "+role); + return new MessageResponse(user + " is no longer a member of " + roles.stream().map(Role::toString).collect(Collectors.joining(", "))); } private HttpResponse removeMultipleTenantRoleMembers(String tenantName, Inspector requestObject) { @@ -232,24 +233,34 @@ public class UserApiHandler extends LoggingRequestHandler { .map(roleName -> Roles.toRole(tenant, roleName)) .collect(Collectors.toUnmodifiableList()); - roles.forEach(role -> removeTenantRoleMember(tenant, user, role)); + enforceLastAdminOfTenant(tenant, user, roles); + removeDeveloperKey(tenant, user, roles); + users.removeRoles(user, roles); return new MessageResponse(user + " is no longer a member of " + roles.stream().map(Role::toString).collect(Collectors.joining(", "))); } - private void removeTenantRoleMember(TenantName tenantName, UserId user, Role role) { - if ( role.definition() == RoleDefinition.administrator - && Set.of(user.value()).equals(users.listUsers(role).stream().map(User::email).collect(Collectors.toSet()))) - throw new IllegalArgumentException("Can't remove the last administrator of a tenant."); - - if (role.definition().equals(RoleDefinition.developer)) - controller.tenants().lockIfPresent(tenantName, LockedTenant.Cloud.class, tenant -> { - PublicKey key = tenant.get().developerKeys().inverse().get(new SimplePrincipal(user.value())); - if (key != null) - controller.tenants().store(tenant.withoutDeveloperKey(key)); - }); + private void enforceLastAdminOfTenant(TenantName tenantName, UserId user, List roles) { + for (Role role : roles) { + if (role.definition().equals(RoleDefinition.administrator)) { + if (Set.of(user.value()).equals(users.listUsers(role).stream().map(User::email).collect(Collectors.toSet()))) { + throw new IllegalArgumentException("Can't remove the last administrator of a tenant."); + } + } + } + } - users.removeUsers(role, List.of(user)); + private void removeDeveloperKey(TenantName tenantName, UserId user, List roles) { + for (Role role : roles) { + if (role.definition().equals(RoleDefinition.developer)) { + controller.tenants().lockIfPresent(tenantName, LockedTenant.Cloud.class, tenant -> { + PublicKey key = tenant.get().developerKeys().inverse().get(new SimplePrincipal(user.value())); + if (key != null) + controller.tenants().store(tenant.withoutDeveloperKey(key)); + }); + break; + } + } } private HttpResponse removeApplicationRoleMember(String tenantName, String applicationName, HttpRequest request) { -- cgit v1.2.3 From 26a7636873b991f88147a89173a0df84d43fac89 Mon Sep 17 00:00:00 2001 From: toby Date: Fri, 8 Nov 2019 10:22:50 +0100 Subject: Rename remove add methods to differentiate it to roles crud operations --- .../hosted/controller/api/integration/stubs/MockUserManagement.java | 4 ++-- .../hosted/controller/api/integration/user/UserManagement.java | 4 ++-- .../yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'controller-server') diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java index cdec8e60072..ee7337b524d 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockUserManagement.java @@ -43,7 +43,7 @@ public class MockUserManagement implements UserManagement { } @Override - public void addRoles(UserId user, Collection roles) { + public void addToRoles(UserId user, Collection roles) { for (Role role : roles) { addUsers(role, Collections.singletonList(user)); } @@ -55,7 +55,7 @@ public class MockUserManagement implements UserManagement { } @Override - public void removeRoles(UserId user, Collection roles) { + public void removeFromRoles(UserId user, Collection roles) { for (Role role : roles) { removeUsers(role, Collections.singletonList(user)); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java index ee3c48e85d3..922f0f11244 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/UserManagement.java @@ -22,13 +22,13 @@ public interface UserManagement { void addUsers(Role role, Collection users); /** Ensures the given user exist, and are part of the given roles, or throws if the roles does not exist. */ - void addRoles(UserId user, Collection roles); + void addToRoles(UserId user, Collection roles); /** Ensures none of the given users are part of the given role, or throws if the role does not exist. */ void removeUsers(Role role, Collection users); /** Ensures the given users are not part of the given role, or throws if the roles does not exist. */ - void removeRoles(UserId user, Collection roles); + void removeFromRoles(UserId user, Collection roles); /** Returns all users in the given role, or throws if the role does not exist. */ List listUsers(Role role); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java index 15d7556b389..7c686fb12a2 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java @@ -192,7 +192,7 @@ public class UserApiHandler extends LoggingRequestHandler { .map(roleName -> Roles.toRole(tenant, roleName)) .collect(Collectors.toUnmodifiableList()); - users.addRoles(user, roles); + users.addToRoles(user, roles); return new MessageResponse(user + " is now a member of " + roles.stream().map(Role::toString).collect(Collectors.joining(", "))); } @@ -221,7 +221,7 @@ public class UserApiHandler extends LoggingRequestHandler { enforceLastAdminOfTenant(tenant, user, roles); removeDeveloperKey(tenant, user, roles); - users.removeRoles(user, roles); + users.removeFromRoles(user, roles); return new MessageResponse(user + " is no longer a member of " + roles.stream().map(Role::toString).collect(Collectors.joining(", "))); } @@ -235,7 +235,7 @@ public class UserApiHandler extends LoggingRequestHandler { enforceLastAdminOfTenant(tenant, user, roles); removeDeveloperKey(tenant, user, roles); - users.removeRoles(user, roles); + users.removeFromRoles(user, roles); return new MessageResponse(user + " is no longer a member of " + roles.stream().map(Role::toString).collect(Collectors.joining(", "))); } -- cgit v1.2.3 From 7e94f8ca539eaf2277920e714d8cc551c50d97d3 Mon Sep 17 00:00:00 2001 From: toby Date: Fri, 8 Nov 2019 10:31:29 +0100 Subject: Break out once we have tested one administrator --- .../com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java | 1 + 1 file changed, 1 insertion(+) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java index 7c686fb12a2..8a3adcce30e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java @@ -246,6 +246,7 @@ public class UserApiHandler extends LoggingRequestHandler { if (Set.of(user.value()).equals(users.listUsers(role).stream().map(User::email).collect(Collectors.toSet()))) { throw new IllegalArgumentException("Can't remove the last administrator of a tenant."); } + break; } } } -- cgit v1.2.3