summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Marius Venstad <venstad@gmail.com>2019-04-04 16:35:27 +0200
committerJon Marius Venstad <venstad@gmail.com>2019-04-04 16:35:27 +0200
commitf83e2033db821695a7984577a1ee18c617fc0b55 (patch)
tree0d192897ebd99c6cbc4adf4e2cd4e9329b60b0b3
parent37cacaa4b1944fc4faf814d19bd01225557aa7ab (diff)
Replace RoleMembership with a bound Role, using enum ProtoRole for declarations
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ApplicationRole.java29
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/ProtoRole.java101
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java126
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystem.java8
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenant.java9
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleInSystemWithTenantAndApplication.java10
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembership.java73
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Roles.java88
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/SecurityContext.java13
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/TenantRole.java25
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/UnboundRole.java21
-rw-r--r--controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleMembershipTest.java74
-rw-r--r--controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java54
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java22
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilter.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java65
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java15
17 files changed, 410 insertions, 337 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")));
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java
index aabb658b7c1..f25deb11a52 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java
@@ -2,7 +2,6 @@ package com.yahoo.vespa.hosted.controller.restapi.filter;
import com.google.inject.Inject;
import com.yahoo.config.provision.ApplicationName;
-import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.http.filter.DiscFilterRequest;
@@ -17,10 +16,10 @@ import com.yahoo.vespa.athenz.client.zms.ZmsClientException;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.TenantController;
import com.yahoo.vespa.hosted.controller.api.role.Role;
-import com.yahoo.vespa.hosted.controller.api.role.RoleMembership;
-import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
+import com.yahoo.vespa.hosted.controller.api.role.Roles;
import com.yahoo.vespa.hosted.controller.athenz.ApplicationAction;
import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
+import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.vespa.hosted.controller.tenant.UserTenant;
@@ -44,14 +43,14 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
private final AthenzFacade athenz;
private final TenantController tenants;
- private final SystemName system;
+ private final Roles roles;
@Inject
public AthenzRoleFilter(CorsFilterConfig config, AthenzFacade athenz, Controller controller) {
super(Set.copyOf(config.allowedUrls()));
this.athenz = athenz;
this.tenants = controller.tenants();
- this.system = controller.system();
+ this.roles = new Roles(controller.system());
}
@Override
@@ -59,7 +58,7 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
try {
AthenzPrincipal athenzPrincipal = (AthenzPrincipal) request.getUserPrincipal();
request.setAttribute(SecurityContext.ATTRIBUTE_NAME, new SecurityContext(athenzPrincipal,
- membership(athenzPrincipal, request.getUri())));
+ roles(athenzPrincipal, request.getUri())));
return Optional.empty();
}
catch (Exception e) {
@@ -68,7 +67,7 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
}
}
- RoleMembership membership(AthenzPrincipal principal, URI uri) {
+ Set<Role> roles(AthenzPrincipal principal, URI uri) {
Path path = new Path(uri);
path.matches("/application/v4/tenant/{tenant}/{*}");
@@ -80,18 +79,18 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
AthenzIdentity identity = principal.getIdentity();
if (athenz.hasHostedOperatorAccess(identity))
- return Role.hostedOperator.limitedTo(system);
+ return Set.of(roles.hostedOperator());
if (tenant.isPresent() && isTenantAdmin(identity, tenant.get()))
- return Role.athenzTenantAdmin.limitedTo(tenant.get().name(), system);
+ return Set.of(roles.athenzTenantAdmin(tenant.get().name()));
if (identity.getDomain().equals(SCREWDRIVER_DOMAIN) && application.isPresent() && tenant.isPresent())
// NOTE: Only fine-grained deploy authorization for Athenz tenants
if ( tenant.get().type() != Tenant.Type.athenz
|| hasDeployerAccess(identity, ((AthenzTenant) tenant.get()).domain(), application.get()))
- return Role.tenantPipeline.limitedTo(application.get(), tenant.get().name(), system);
+ return Set.of(roles.tenantPipeline(tenant.get().name(), application.get()));
- return Role.everyone.limitedTo(system);
+ return Set.of(roles.everyone());
}
private boolean isTenantAdmin(AthenzIdentity identity, Tenant tenant) {
@@ -112,4 +111,5 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
throw new RuntimeException("Failed to authorize operation: (" + e.getMessage() + ")", e);
}
}
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilter.java
index a1a586b689d..39736d709d0 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilter.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilter.java
@@ -12,7 +12,7 @@ import com.yahoo.log.LogLevel;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.role.Action;
import com.yahoo.vespa.hosted.controller.api.role.Role;
-import com.yahoo.vespa.hosted.controller.api.role.RoleMembership;
+import com.yahoo.vespa.hosted.controller.api.role.Roles;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import java.security.Principal;
@@ -29,7 +29,7 @@ public class ControllerAuthorizationFilter extends CorsRequestFilterBase {
private static final Logger log = Logger.getLogger(ControllerAuthorizationFilter.class.getName());
- private final SystemName system;
+ private final Roles roles;
@Inject
public ControllerAuthorizationFilter(Controller controller,
@@ -40,7 +40,7 @@ public class ControllerAuthorizationFilter extends CorsRequestFilterBase {
ControllerAuthorizationFilter(SystemName system,
Set<String> allowedUrls) {
super(allowedUrls);
- this.system = system;
+ this.roles = new Roles(system);
}
@Override
@@ -54,12 +54,12 @@ public class ControllerAuthorizationFilter extends CorsRequestFilterBase {
Action action = Action.from(HttpRequest.Method.valueOf(request.getMethod()));
- // Avoid expensive lookups when request is always legal.
- if (Role.everyone.limitedTo(system).allows(action, request.getUri()))
+ // Avoid expensive look-ups when request is always legal.
+ if (roles.everyone().allows(action, request.getUri()))
return Optional.empty();
- RoleMembership roles = securityContext.get().roles();
- if (roles.allows(action, request.getUri()))
+ Set<Role> roles = securityContext.get().roles();
+ if (roles.stream().anyMatch(role -> role.allows(action, request.getUri())))
return Optional.empty();
}
catch (Exception e) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java
index e862e12a18b..dc4235e52bf 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java
@@ -10,16 +10,17 @@ import com.yahoo.vespa.athenz.api.AthenzUser;
import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.identifiers.ApplicationId;
import com.yahoo.vespa.hosted.controller.api.identifiers.ScrewdriverId;
+import com.yahoo.vespa.hosted.controller.api.role.Roles;
import com.yahoo.vespa.hosted.controller.athenz.ApplicationAction;
import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities;
import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzClientFactoryMock;
import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzDbMock;
-import com.yahoo.vespa.hosted.controller.api.role.Role;
import org.junit.Before;
import org.junit.Test;
import java.net.URI;
+import java.util.Set;
import static org.junit.Assert.assertEquals;
@@ -66,54 +67,56 @@ public class AthenzRoleFilterTest {
@Test
public void testTranslations() {
+ Roles roles = new Roles(tester.controller().system());
+
// Hosted operators are always members of the hostedOperator role.
- assertEquals(Role.hostedOperator.limitedTo(tester.controller().system()),
- filter.membership(HOSTED_OPERATOR, NO_CONTEXT_PATH));
+ assertEquals(Set.of(roles.hostedOperator()),
+ filter.roles(HOSTED_OPERATOR, NO_CONTEXT_PATH));
- assertEquals(Role.hostedOperator.limitedTo(tester.controller().system()),
- filter.membership(HOSTED_OPERATOR, TENANT_CONTEXT_PATH));
+ assertEquals(Set.of(roles.hostedOperator()),
+ filter.roles(HOSTED_OPERATOR, TENANT_CONTEXT_PATH));
- assertEquals(Role.hostedOperator.limitedTo(tester.controller().system()),
- filter.membership(HOSTED_OPERATOR, APPLICATION_CONTEXT_PATH));
+ assertEquals(Set.of(roles.hostedOperator()),
+ filter.roles(HOSTED_OPERATOR, APPLICATION_CONTEXT_PATH));
// Tenant admins are members of the athenzTenantAdmin role within their tenant subtree.
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(TENANT_PIPELINE, NO_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(TENANT_PIPELINE, NO_CONTEXT_PATH));
- assertEquals(Role.athenzTenantAdmin.limitedTo(TENANT, tester.controller().system()),
- filter.membership(TENANT_ADMIN, TENANT_CONTEXT_PATH));
+ assertEquals(Set.of(roles.athenzTenantAdmin(TENANT)),
+ filter.roles(TENANT_ADMIN, TENANT_CONTEXT_PATH));
- assertEquals(Role.athenzTenantAdmin.limitedTo(TENANT, tester.controller().system()),
- filter.membership(TENANT_ADMIN, APPLICATION_CONTEXT_PATH));
+ assertEquals(Set.of(roles.athenzTenantAdmin(TENANT)),
+ filter.roles(TENANT_ADMIN, APPLICATION_CONTEXT_PATH));
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(TENANT_ADMIN, TENANT2_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(TENANT_ADMIN, TENANT2_CONTEXT_PATH));
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(TENANT_ADMIN, APPLICATION2_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(TENANT_ADMIN, APPLICATION2_CONTEXT_PATH));
// Build services are members of the tenantPipeline role within their application subtree.
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(TENANT_PIPELINE, NO_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(TENANT_PIPELINE, NO_CONTEXT_PATH));
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(TENANT_PIPELINE, TENANT_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(TENANT_PIPELINE, TENANT_CONTEXT_PATH));
- assertEquals(Role.tenantPipeline.limitedTo(APPLICATION, TENANT, tester.controller().system()),
- filter.membership(TENANT_PIPELINE, APPLICATION_CONTEXT_PATH));
+ assertEquals(Set.of(roles.tenantPipeline(TENANT, APPLICATION)),
+ filter.roles(TENANT_PIPELINE, APPLICATION_CONTEXT_PATH));
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(TENANT_PIPELINE, APPLICATION2_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(TENANT_PIPELINE, APPLICATION2_CONTEXT_PATH));
// Unprivileged users are just members of the everyone role.
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(USER, NO_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(USER, NO_CONTEXT_PATH));
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(USER, TENANT_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(USER, TENANT_CONTEXT_PATH));
- assertEquals(Role.everyone.limitedTo(tester.controller().system()),
- filter.membership(USER, APPLICATION_CONTEXT_PATH));
+ assertEquals(Set.of(roles.everyone()),
+ filter.roles(USER, APPLICATION_CONTEXT_PATH));
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
index 13c5d219878..105e10eefd2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
@@ -7,7 +7,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.jdisc.http.HttpRequest.Method;
import com.yahoo.jdisc.http.filter.DiscFilterRequest;
import com.yahoo.vespa.hosted.controller.ControllerTester;
-import com.yahoo.vespa.hosted.controller.api.role.Role;
+import com.yahoo.vespa.hosted.controller.api.role.Roles;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.restapi.ApplicationRequestToDiscFilterRequestWrapper;
import org.junit.Test;
@@ -34,8 +34,9 @@ public class ControllerAuthorizationFilterTest {
@Test
public void operator() {
ControllerTester tester = new ControllerTester();
+ Roles roles = new Roles(tester.controller().system());
+ SecurityContext securityContext = new SecurityContext(() -> "operator", Set.of(roles.hostedOperator()));
ControllerAuthorizationFilter filter = createFilter(tester);
- SecurityContext securityContext = new SecurityContext(() -> "operator", Role.hostedOperator.limitedTo(tester.controller().system()));
assertIsAllowed(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", securityContext)));
assertIsAllowed(invokeFilter(filter, createRequest(Method.PUT, "/application/v4/user", securityContext)));
@@ -45,9 +46,10 @@ public class ControllerAuthorizationFilterTest {
@Test
public void unprivileged() {
ControllerTester tester = new ControllerTester();
- SecurityContext securityContext = new SecurityContext(() -> "user", Role.everyone.limitedTo(tester.controller().system()));
-
+ Roles roles = new Roles(tester.controller().system());
+ SecurityContext securityContext = new SecurityContext(() -> "user", Set.of(roles.everyone()));
ControllerAuthorizationFilter filter = createFilter(tester);
+
assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", securityContext)));
assertIsAllowed(invokeFilter(filter, createRequest(Method.PUT, "/application/v4/user", securityContext)));
assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", securityContext)));
@@ -57,8 +59,8 @@ public class ControllerAuthorizationFilterTest {
public void unprivilegedInPublic() {
ControllerTester tester = new ControllerTester();
tester.zoneRegistry().setSystemName(SystemName.Public);
-
- SecurityContext securityContext = new SecurityContext(() -> "user", Role.everyone.limitedTo(tester.controller().system()));
+ Roles roles = new Roles(tester.controller().system());
+ SecurityContext securityContext = new SecurityContext(() -> "user", Set.of(roles.everyone()));
ControllerAuthorizationFilter filter = createFilter(tester);
assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", securityContext)));
@@ -112,4 +114,5 @@ public class ControllerAuthorizationFilterTest {
this.message = message;
}
}
+
}