diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2019-04-04 16:35:27 +0200 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2019-04-04 16:35:27 +0200 |
commit | f83e2033db821695a7984577a1ee18c617fc0b55 (patch) | |
tree | 0d192897ebd99c6cbc4adf4e2cd4e9329b60b0b3 /controller-api | |
parent | 37cacaa4b1944fc4faf814d19bd01225557aa7ab (diff) |
Replace RoleMembership with a bound Role, using enum ProtoRole for declarations
Diffstat (limited to 'controller-api')
13 files changed, 349 insertions, 282 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ApplicationRole.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ApplicationRole.java new file mode 100644 index 00000000000..b1018fb08a6 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ApplicationRole.java @@ -0,0 +1,29 @@ +package com.yahoo.vespa.hosted.controller.api.role; + +import com.yahoo.config.provision.ApplicationName; +import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.TenantName; + +/** + * A {@link Role} with a {@link Context} of a {@link SystemName} a {@link TenantName} and an {@link ApplicationName}. + * + * @author jonmv + */ +public class ApplicationRole extends Role { + + ApplicationRole(ProtoRole protoRole, SystemName system, TenantName tenant, ApplicationName application) { + super(protoRole, Context.limitedTo(tenant, application, system)); + } + + /** Returns the {@link TenantName} this is bound to. */ + public TenantName tenant() { return context.tenant().get(); } + + /** Returns the {@link ApplicationName} this is bound to. */ + public ApplicationName application() { return context.application().get(); } + + @Override + public String toString() { + return "role '" + proto() + "' of '" + application() + "' owned by '" + tenant() + "'"; + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ProtoRole.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ProtoRole.java new file mode 100644 index 00000000000..44d0d2356bd --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ProtoRole.java @@ -0,0 +1,101 @@ +package com.yahoo.vespa.hosted.controller.api.role; + +import java.util.EnumSet; +import java.util.Set; + +/** + * This declares all tenant roles known to the controller. A role contains one or more {@link Policy}s which decide + * what actions a member of a role can perform. + * + * Optionally, some role definition also inherit all policies from a "lower ranking" role. Read the list of roles + * from {@code everyone} to {@code tenantAdmin}, in order, to see what policies these roles. + * + * See {@link Role} for roles bound to a context, where policies can be evaluated. + * + * @author mpolden + * @author jonmv + */ +public enum ProtoRole { + + /** Deus ex machina. */ + hostedOperator(Policy.operator), + + /** Build service which may submit new applications for continuous deployment. */ + buildService(Policy.submission, + Policy.applicationRead), + + /** Base role which every user is part of. */ + everyone(Policy.classifiedRead, + Policy.publicRead, + Policy.userCreate, + Policy.tenantCreate), + + /** Application reader which can see all information about an application, its tenant and deployments. */ + applicationReader(everyone, + Policy.tenantRead, + Policy.applicationRead, + Policy.deploymentRead), + + /** Application developer with access to deploy to development zones. */ + applicationDeveloper(applicationReader, + Policy.developmentDeployment), + + /** Application operator with access to normal, operational tasks of an application. */ + applicationOperator(applicationDeveloper, + Policy.applicationOperations), + + /** Application administrator with full access to an already existing application, including emergency operations. */ + applicationAdmin(applicationOperator, + Policy.applicationUpdate, + Policy.productionDeployment, + Policy.submission), + + /** Application administrator with the additional ability to delete an application. */ + applicationOwner(applicationOperator, + Policy.applicationDelete), + + /** Tenant operator with admin access to all applications under the tenant, as well as the ability to create applications. */ + tenantOperator(applicationAdmin, + Policy.applicationCreate), + + /** Tenant admin with full access to all tenant resources, except deleting the tenant. */ + tenantAdmin(tenantOperator, + Policy.applicationDelete, + Policy.manager, + Policy.tenantUpdate), + + /** Tenant admin with full access to all tenant resources. */ + tenantOwner(tenantAdmin, + Policy.tenantDelete), + + /** Build and continuous delivery service. */ // TODO replace with buildService, when everyone is on new pipeline. + tenantPipeline(everyone, + Policy.submission, + Policy.deploymentPipeline, + Policy.productionDeployment), + + /** Tenant administrator with full access to all child resources. */ + athenzTenantAdmin(everyone, + Policy.tenantRead, + Policy.tenantUpdate, + Policy.tenantDelete, + Policy.applicationCreate, + Policy.applicationUpdate, + Policy.applicationDelete, + Policy.applicationOperations, + Policy.developmentDeployment); + + private final Set<Policy> policies; + + ProtoRole(Policy... policies) { + this.policies = EnumSet.copyOf(Set.of(policies)); + } + + ProtoRole(ProtoRole inherited, Policy... policies) { + this.policies = EnumSet.copyOf(Set.of(policies)); + this.policies.addAll(inherited.policies); + } + + Set<Policy> policies() { return policies; } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java index e452464dcd4..c98ddd5a37c 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java @@ -2,126 +2,46 @@ package com.yahoo.vespa.hosted.controller.api.role; import java.net.URI; -import com.yahoo.config.provision.ApplicationName; -import com.yahoo.config.provision.SystemName; -import com.yahoo.config.provision.TenantName; +import java.util.Objects; -import java.util.EnumSet; -import java.util.Map; -import java.util.Set; +import static java.util.Objects.requireNonNull; /** - * This declares all tenant roles known to the controller. A role contains one or more {@link Policy}s which decide - * what actions a member of a role can perform. + * A role is a combination of a {@link ProtoRole} and a {@link Context}, which allows evaluation + * of access control for a given action on a resource. Create using {@link Roles}. * - * Optionally, some role definition also inherit all policies from a "lower ranking" role. Read the list of roles - * from {@code everyone} to {@code tenantAdmin}, in order, to see what policies these roles. - * - * @author mpolden * @author jonmv */ -public class Role implements RoleInSystem, RoleInSystemWithTenant, RoleInSystemWithTenantAndApplication { - - /** Deus ex machina. */ - public static final RoleInSystem hostedOperator = new Role(Policy.operator); - - /** Build service which may submit new applications for continuous deployment. */ - public static final RoleInSystemWithTenantAndApplication buildService = new Role(Policy.submission, - Policy.applicationRead); - - /** Base role which every user is part of. */ - public static final RoleInSystem everyone = new Role(Policy.classifiedRead, - Policy.publicRead, - Policy.userCreate, - Policy.tenantCreate); - - /** Application reader which can see all information about an application, its tenant and deployments. */ - public static final RoleInSystemWithTenantAndApplication applicationReader = new Role(everyone, - Policy.tenantRead, - Policy.applicationRead, - Policy.deploymentRead); - - /** Application developer with access to deploy to development zones. */ - public static final RoleInSystemWithTenantAndApplication applicationDeveloper = new Role(applicationReader, - Policy.developmentDeployment); - - /** Application operator with access to normal, operational tasks of an application. */ - public static final RoleInSystemWithTenantAndApplication applicationOperator = new Role(applicationDeveloper, - Policy.applicationOperations); - - /** Application administrator with full access to an already existing application, including emergency operations. */ - public static final RoleInSystemWithTenantAndApplication applicationAdmin = new Role(applicationOperator, - Policy.applicationUpdate, - Policy.productionDeployment, - Policy.submission); - - /** Application administrator with the additional ability to delete an application. */ - public static final RoleInSystemWithTenantAndApplication applicationOwner = new Role(applicationOperator, - Policy.applicationDelete); +public abstract class Role { - /** Tenant operator with admin access to all applications under the tenant, as well as the ability to create applications. */ - public static final RoleInSystemWithTenant tenantOperator = new Role(applicationAdmin, - Policy.applicationCreate); + private final ProtoRole protoRole; + final Context context; - /** Tenant admin with full access to all tenant resources, except deleting the tenant. */ - public static final RoleInSystemWithTenant tenantAdmin = new Role(tenantOperator, - Policy.applicationDelete, - Policy.manager, - Policy.tenantUpdate); - - /** Tenant admin with full access to all tenant resources. */ - public static final RoleInSystemWithTenant tenantOwner = new Role(tenantAdmin, - Policy.tenantDelete); - - /** Build and continuous delivery service. */ // TODO replace with buildService, when everyone is on new pipeline. - public static final RoleInSystemWithTenantAndApplication tenantPipeline = new Role(everyone, - Policy.submission, - Policy.deploymentPipeline, - Policy.productionDeployment); - - /** Tenant administrator with full access to all child resources. */ - public static final RoleInSystemWithTenant athenzTenantAdmin = new Role(everyone, - Policy.tenantRead, - Policy.tenantUpdate, - Policy.tenantDelete, - Policy.applicationCreate, - Policy.applicationUpdate, - Policy.applicationDelete, - Policy.applicationOperations, - Policy.developmentDeployment); - - private final Set<Policy> policies; - - private Role(Policy... policies) { - this.policies = EnumSet.copyOf(Set.of(policies)); + Role(ProtoRole protoRole, Context context) { + this.protoRole = requireNonNull(protoRole); + this.context = requireNonNull(context); } - private Role(Object inherited, Policy... policies) { - this.policies = EnumSet.copyOf(Set.of(policies)); - this.policies.addAll(((Role) inherited).policies); - } - - /** - * Returns whether this role is allowed to perform action in given role context. Action is allowed if at least one - * policy evaluates to true. - */ - public boolean allows(Action action, URI uri, Context context) { - return policies.stream().anyMatch(policy -> policy.evaluate(action, uri, context)); - } + /** Returns the proto role of this role. */ + public ProtoRole proto() { return protoRole; } - @Override - public RoleMembership limitedTo(SystemName system) { - return new RoleMembership(Map.of(this, Set.of(Context.unlimitedIn(system)))); + /** Returns whether this role is allowed to perform the given action on the given resource. */ + public boolean allows(Action action, URI uri) { + return protoRole.policies().stream().anyMatch(policy -> policy.evaluate(action, uri, context)); } @Override - public RoleMembership limitedTo(TenantName tenant, SystemName system) { - return new RoleMembership(Map.of(this, Set.of(Context.limitedTo(tenant, system)))); + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Role role = (Role) o; + return protoRole == role.protoRole && + Objects.equals(context, role.context); } @Override - public RoleMembership limitedTo(ApplicationName application, TenantName tenant, SystemName system) { - return new RoleMembership(Map.of(this, Set.of(Context.limitedTo(tenant, application, system)))); + public int hashCode() { + return Objects.hash(protoRole, context); } } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystem.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystem.java deleted file mode 100644 index 144a02c4987..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystem.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.yahoo.vespa.hosted.controller.api.role; - -import com.yahoo.config.provision.SystemName; - -/** A role which requires only the context of a system. */ -public interface RoleInSystem { - RoleMembership limitedTo(SystemName system); -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenant.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenant.java deleted file mode 100644 index ab8aa29b7cc..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenant.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.yahoo.vespa.hosted.controller.api.role; - -import com.yahoo.config.provision.SystemName; -import com.yahoo.config.provision.TenantName; - -/** A role which requires the context of a system and a tenant. */ -public interface RoleInSystemWithTenant { - RoleMembership limitedTo(TenantName tenant, SystemName system); -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenantAndApplication.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenantAndApplication.java deleted file mode 100644 index 31a903c998a..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenantAndApplication.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.yahoo.vespa.hosted.controller.api.role; - -import com.yahoo.config.provision.ApplicationName; -import com.yahoo.config.provision.SystemName; -import com.yahoo.config.provision.TenantName; - -/** A role which requires the context of a system, a tenant, and an application. */ -public interface RoleInSystemWithTenantAndApplication { - RoleMembership limitedTo(ApplicationName application, TenantName tenant, SystemName system); -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembership.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembership.java deleted file mode 100644 index f046b0d7203..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembership.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.role; - -import java.net.URI; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * A list of roles and their associated contexts. This defines the role membership of a tenant, and in which contexts - * (see {@link Context}) those roles apply. - * - * @author mpolden - * @author jonmv - */ -public class RoleMembership { - - private final Map<Role, Set<Context>> roles; - - RoleMembership(Map<Role, Set<Context>> roles) { - this.roles = roles.entrySet().stream() - .collect(Collectors.toUnmodifiableMap(entry -> entry.getKey(), - entry -> Set.copyOf(entry.getValue()))); - } - - public RoleMembership and(RoleMembership other) { - return new RoleMembership(Stream.concat(this.roles.entrySet().stream(), - other.roles.entrySet().stream()) - .collect(Collectors.toMap(Map.Entry::getKey, - Map.Entry::getValue, - (set1, set2) -> Stream.concat(set1.stream(), set2.stream()) - .collect(Collectors.toUnmodifiableSet())))); - } - - /** - * Returns whether any role in this allows action to take place in path - */ - public boolean allows(Action action, URI uri) { - return roles.entrySet().stream().anyMatch(kv -> { - Role role = kv.getKey(); - Set<Context> contexts = kv.getValue(); - return contexts.stream().anyMatch(context -> role.allows(action, uri, context)); - }); - } - - /** - * Returns the set of contexts for which the given role is valid. - */ - public Set<Context> contextsFor(Object role) { // TODO fix. - return roles.getOrDefault((Role) role, Collections.emptySet()); - } - - @Override - public String toString() { - return "roles " + roles; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if ( ! (o instanceof RoleMembership)) return false; - return Objects.equals(roles, ((RoleMembership) o).roles); - } - - @Override - public int hashCode() { - return Objects.hash(roles); - } - -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Roles.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Roles.java new file mode 100644 index 00000000000..92374dfff74 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Roles.java @@ -0,0 +1,88 @@ +package com.yahoo.vespa.hosted.controller.api.role; + +import com.yahoo.config.provision.ApplicationName; +import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.TenantName; + +import java.util.Objects; + +/** + * Use if you need to create {@link Role}s for its system. + * + * This also defines the relationship between {@link ProtoRole}s and their required {@link Context}s. + * + * @author jonmv + */ +public class Roles { + + private final SystemName system; + + /** Create a Roles which can be used to create bound roles for the given system. */ + public Roles(SystemName system) { + this.system = Objects.requireNonNull(system); + } + + // General roles. + /** Returns a {@link ProtoRole#hostedOperator} for the current system. */ + public UnboundRole hostedOperator() { + return new UnboundRole(ProtoRole.hostedOperator, system); + } + + /** Returns a {@link ProtoRole#everyone} for the current system. */ + public UnboundRole everyone() { + return new UnboundRole(ProtoRole.everyone, system); + } + + // Athenz based roles. + /** Returns a {@link ProtoRole#athenzTenantAdmin} for the current system and given tenant. */ + public TenantRole athenzTenantAdmin(TenantName tenant) { + return new TenantRole(ProtoRole.athenzTenantAdmin, system, tenant); + } + + /** Returns a {@link ProtoRole#tenantPipeline} for the current system and given tenant and application. */ + public ApplicationRole tenantPipeline(TenantName tenant, ApplicationName application) { + return new ApplicationRole(ProtoRole.tenantPipeline, system, tenant, application); + } + + // Other identity provider based roles. + /** Returns a {@link ProtoRole#tenantOwner} for the current system and given tenant. */ + public TenantRole tenantOwner(TenantName tenant) { + return new TenantRole(ProtoRole.tenantOwner, system, tenant); + } + + /** Returns a {@link ProtoRole#tenantAdmin} for the current system and given tenant. */ + public TenantRole tenantAdmin(TenantName tenant) { + return new TenantRole(ProtoRole.tenantAdmin, system, tenant); + } + + /** Returns a {@link ProtoRole#tenantOperator} for the current system and given tenant. */ + public TenantRole tenantOperator(TenantName tenant) { + return new TenantRole(ProtoRole.tenantOperator, system, tenant); + } + + /** Returns a {@link ProtoRole#applicationOwner} for the current system and given tenant and application. */ + public ApplicationRole applicationOwner(TenantName tenant, ApplicationName application) { + return new ApplicationRole(ProtoRole.applicationOwner, system, tenant, application); + } + + /** Returns a {@link ProtoRole#applicationAdmin} for the current system and given tenant and application. */ + public ApplicationRole applicationAdmin(TenantName tenant, ApplicationName application) { + return new ApplicationRole(ProtoRole.applicationAdmin, system, tenant, application); + } + + /** Returns a {@link ProtoRole#applicationOperator} for the current system and given tenant and application. */ + public ApplicationRole applicationOperator(TenantName tenant, ApplicationName application) { + return new ApplicationRole(ProtoRole.applicationOperator, system, tenant, application); + } + + /** Returns a {@link ProtoRole#applicationDeveloper} for the current system and given tenant and application. */ + public ApplicationRole applicationDeveloper(TenantName tenant, ApplicationName application) { + return new ApplicationRole(ProtoRole.applicationDeveloper, system, tenant, application); + } + + /** Returns a {@link ProtoRole#applicationReader} for the current system and given tenant and application. */ + public ApplicationRole applicationReader(TenantName tenant, ApplicationName application) { + return new ApplicationRole(ProtoRole.applicationReader, system, tenant, application); + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/SecurityContext.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/SecurityContext.java index 1ad98e761f5..41444258a68 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/SecurityContext.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/SecurityContext.java @@ -3,24 +3,27 @@ package com.yahoo.vespa.hosted.controller.api.role; import java.security.Principal; import java.util.Objects; +import java.util.Set; + +import static java.util.Objects.requireNonNull; public class SecurityContext { public static final String ATTRIBUTE_NAME = SecurityContext.class.getName(); private final Principal principal; - private final RoleMembership roles; + private final Set<Role> roles; - public SecurityContext(Principal principal, RoleMembership roles) { - this.principal = principal; - this.roles = roles; + public SecurityContext(Principal principal, Set<Role> roles) { + this.principal = requireNonNull(principal); + this.roles = Set.copyOf(roles); } public Principal principal() { return principal; } - public RoleMembership roles() { + public Set<Role> roles() { return roles; } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/TenantRole.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/TenantRole.java new file mode 100644 index 00000000000..c3f8a5ef1b8 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/TenantRole.java @@ -0,0 +1,25 @@ +package com.yahoo.vespa.hosted.controller.api.role; + +import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.TenantName; + +/** + * A {@link Role} with a {@link Context} of a {@link SystemName} and a {@link TenantName}. + * + * @author jonmv + */ +public class TenantRole extends Role { + + TenantRole(ProtoRole protoRole, SystemName system, TenantName tenant) { + super(protoRole, Context.limitedTo(tenant, system)); + } + + /** Returns the {@link TenantName} this is bound to. */ + public TenantName tenant() { return context.tenant().get(); } + + @Override + public String toString() { + return "role '" + proto() + "' of '" + tenant() + "'"; + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/UnboundRole.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/UnboundRole.java new file mode 100644 index 00000000000..ba01d949713 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/UnboundRole.java @@ -0,0 +1,21 @@ +package com.yahoo.vespa.hosted.controller.api.role; + +import com.yahoo.config.provision.SystemName; + +/** + * A {@link Role} with a {@link Context} of only a {@link SystemName}. + * + * @author jonmv + */ +public class UnboundRole extends Role { + + UnboundRole(ProtoRole protoRole, SystemName system) { + super(protoRole, Context.unlimitedIn(system)); + } + + @Override + public String toString() { + return "role '" + proto() + "'"; + } + +} diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembershipTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembershipTest.java deleted file mode 100644 index c2eeb17c367..00000000000 --- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembershipTest.java +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.role; - -import com.yahoo.config.provision.ApplicationName; -import com.yahoo.config.provision.SystemName; -import com.yahoo.config.provision.TenantName; -import org.junit.Test; - -import java.net.URI; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * @author mpolden - */ -public class RoleMembershipTest { - - @Test - public void operator_membership() { - RoleMembership roles = Role.hostedOperator.limitedTo(SystemName.main); - - // Operator actions - assertFalse(roles.allows(Action.create, URI.create("/not/explicitly/defined"))); - assertTrue(roles.allows(Action.create, URI.create("/controller/v1/foo"))); - assertTrue(roles.allows(Action.update, URI.create("/os/v1/bar"))); - assertTrue(roles.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); - assertTrue(roles.allows(Action.update, URI.create("/application/v4/tenant/t2/application/a2"))); - } - - @Test - public void tenant_membership() { - RoleMembership roles = Role.athenzTenantAdmin.limitedTo(TenantName.from("t1"), SystemName.main); - assertFalse(roles.allows(Action.create, URI.create("/not/explicitly/defined"))); - assertFalse("Deny access to operator API", roles.allows(Action.create, URI.create("/controller/v1/foo"))); - assertFalse("Deny access to other tenant and app", roles.allows(Action.update, URI.create("/application/v4/tenant/t2/application/a2"))); - assertTrue(roles.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); - - RoleMembership multiContext = Role.athenzTenantAdmin.limitedTo(TenantName.from("t1"), SystemName.main) - .and(Role.athenzTenantAdmin.limitedTo(TenantName.from("t2"), SystemName.main)); - assertFalse("Deny access to other tenant and app", multiContext.allows(Action.update, URI.create("/application/v4/tenant/t3/application/a3"))); - assertTrue(multiContext.allows(Action.update, URI.create("/application/v4/tenant/t2/application/a2"))); - assertTrue(multiContext.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); - - RoleMembership publicSystem = Role.athenzTenantAdmin.limitedTo(TenantName.from("t1"), SystemName.vaas); - assertFalse(publicSystem.allows(Action.read, URI.create("/controller/v1/foo"))); - assertTrue(publicSystem.allows(Action.read, URI.create("/badge/v1/badge"))); - assertTrue(multiContext.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); - } - - @Test - public void build_service_membership() { - RoleMembership roles = Role.tenantPipeline.limitedTo(ApplicationName.from("a1"), TenantName.from("t1"), SystemName.vaas); - assertFalse(roles.allows(Action.create, URI.create("/not/explicitly/defined"))); - assertFalse(roles.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); - assertTrue(roles.allows(Action.create, URI.create("/application/v4/tenant/t1/application/a1/jobreport"))); - assertFalse("No global read access", roles.allows(Action.read, URI.create("/controller/v1/foo"))); - } - - @Test - public void multi_role_membership() { - RoleMembership roles = Role.athenzTenantAdmin.limitedTo(TenantName.from("t1"), SystemName.main) - .and(Role.tenantPipeline.limitedTo(ApplicationName.from("a1"), TenantName.from("t1"), SystemName.main)); - assertFalse(roles.allows(Action.create, URI.create("/not/explicitly/defined"))); - assertFalse(roles.allows(Action.create, URI.create("/controller/v1/foo"))); - assertTrue(roles.allows(Action.create, URI.create("/application/v4/tenant/t1/application/a1/jobreport"))); - assertTrue(roles.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); - assertTrue("Global read access", roles.allows(Action.read, URI.create("/controller/v1/foo"))); - assertTrue("Dashboard read access", roles.allows(Action.read, URI.create("/"))); - assertTrue("Dashboard read access", roles.allows(Action.read, URI.create("/d/nodes"))); - assertTrue("Dashboard read access", roles.allows(Action.read, URI.create("/statuspage/v1/incidents"))); - } - -} diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java new file mode 100644 index 00000000000..1badd157b1b --- /dev/null +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java @@ -0,0 +1,54 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.role; + +import com.yahoo.config.provision.ApplicationName; +import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.TenantName; +import org.junit.Test; + +import java.net.URI; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author mpolden + */ +public class RoleTest { + + @Test + public void operator_membership() { + Role role = new Roles(SystemName.main).hostedOperator(); + + // Operator actions + assertFalse(role.allows(Action.create, URI.create("/not/explicitly/defined"))); + assertTrue(role.allows(Action.create, URI.create("/controller/v1/foo"))); + assertTrue(role.allows(Action.update, URI.create("/os/v1/bar"))); + assertTrue(role.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); + assertTrue(role.allows(Action.update, URI.create("/application/v4/tenant/t2/application/a2"))); + } + + @Test + public void tenant_membership() { + Role role = new Roles(SystemName.main).athenzTenantAdmin(TenantName.from("t1")); + assertFalse(role.allows(Action.create, URI.create("/not/explicitly/defined"))); + assertFalse("Deny access to operator API", role.allows(Action.create, URI.create("/controller/v1/foo"))); + assertFalse("Deny access to other tenant and app", role.allows(Action.update, URI.create("/application/v4/tenant/t2/application/a2"))); + assertTrue(role.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); + + Role publicSystem = new Roles(SystemName.vaas).athenzTenantAdmin(TenantName.from("t1")); + assertFalse(publicSystem.allows(Action.read, URI.create("/controller/v1/foo"))); + assertTrue(publicSystem.allows(Action.read, URI.create("/badge/v1/badge"))); + assertTrue(publicSystem.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); + } + + @Test + public void build_service_membership() { + Role role = new Roles(SystemName.vaas).tenantPipeline(TenantName.from("t1"), ApplicationName.from("a1")); + assertFalse(role.allows(Action.create, URI.create("/not/explicitly/defined"))); + assertFalse(role.allows(Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); + assertTrue(role.allows(Action.create, URI.create("/application/v4/tenant/t1/application/a1/jobreport"))); + assertFalse("No global read access", role.allows(Action.read, URI.create("/controller/v1/foo"))); + } + +} |