summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMorten Tokle <mortent@oath.com>2019-04-04 15:00:51 +0200
committerMorten Tokle <mortent@oath.com>2019-04-04 15:00:51 +0200
commit37cacaa4b1944fc4faf814d19bd01225557aa7ab (patch)
tree23a160d3bb478d1de2580d8e478df59a6b981e1f /controller-server
parent3e879db9b073b48a2c22c0737c3077915c6207ed (diff)
Introduce SecurityContext
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java29
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilter.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java49
3 files changed, 31 insertions, 55 deletions
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 fee6bb7c44c..aabb658b7c1 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
@@ -16,11 +16,11 @@ import com.yahoo.vespa.athenz.api.AthenzPrincipal;
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.athenz.ApplicationAction;
-import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
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.RolePrincipal;
+import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
+import com.yahoo.vespa.hosted.controller.athenz.ApplicationAction;
+import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.vespa.hosted.controller.tenant.UserTenant;
@@ -32,7 +32,6 @@ import java.util.Set;
import java.util.logging.Logger;
import static com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities.SCREWDRIVER_DOMAIN;
-import static java.util.Objects.requireNonNull;
/**
* Enriches the request principal with roles from Athenz.
@@ -59,8 +58,8 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
protected Optional<ErrorResponse> filterRequest(DiscFilterRequest request) {
try {
AthenzPrincipal athenzPrincipal = (AthenzPrincipal) request.getUserPrincipal();
- request.setUserPrincipal(new AthenzRolePrincipal(athenzPrincipal.getIdentity(),
- membership(athenzPrincipal, request.getUri())));
+ request.setAttribute(SecurityContext.ATTRIBUTE_NAME, new SecurityContext(athenzPrincipal,
+ membership(athenzPrincipal, request.getUri())));
return Optional.empty();
}
catch (Exception e) {
@@ -113,22 +112,4 @@ public class AthenzRoleFilter extends CorsRequestFilterBase { // TODO: No need f
throw new RuntimeException("Failed to authorize operation: (" + e.getMessage() + ")", e);
}
}
-
-
- private static class AthenzRolePrincipal extends AthenzPrincipal implements RolePrincipal {
-
- private final RoleMembership roles;
-
- private AthenzRolePrincipal(AthenzIdentity athenzIdentity, RoleMembership roles) {
- super(requireNonNull(athenzIdentity));
- this.roles = requireNonNull(roles);
- }
-
- @Override
- public RoleMembership roles() {
- return roles;
- }
-
- }
-
}
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 8c473bcaaec..a1a586b689d 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
@@ -13,7 +13,7 @@ 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.RolePrincipal;
+import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import java.security.Principal;
import java.util.Optional;
@@ -47,7 +47,9 @@ public class ControllerAuthorizationFilter extends CorsRequestFilterBase {
public Optional<ErrorResponse> filterRequest(DiscFilterRequest request) {
try {
Principal principal = request.getUserPrincipal();
- if ( ! (principal instanceof RolePrincipal))
+ Optional<SecurityContext> securityContext = Optional.ofNullable((SecurityContext)request.getAttribute(SecurityContext.ATTRIBUTE_NAME));
+
+ if (securityContext.isEmpty())
return Optional.of(new ErrorResponse(Response.Status.FORBIDDEN, "Access denied"));
Action action = Action.from(HttpRequest.Method.valueOf(request.getMethod()));
@@ -56,7 +58,7 @@ public class ControllerAuthorizationFilter extends CorsRequestFilterBase {
if (Role.everyone.limitedTo(system).allows(action, request.getUri()))
return Optional.empty();
- RoleMembership roles = ((RolePrincipal) principal).roles();
+ RoleMembership roles = securityContext.get().roles();
if (roles.allows(action, request.getUri()))
return Optional.empty();
}
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 459320741a9..13c5d219878 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,15 +7,13 @@ 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.restapi.ApplicationRequestToDiscFilterRequestWrapper;
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.RolePrincipal;
+import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
+import com.yahoo.vespa.hosted.controller.restapi.ApplicationRequestToDiscFilterRequestWrapper;
import org.junit.Test;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.security.Principal;
import java.util.Optional;
import java.util.Set;
@@ -37,40 +35,35 @@ public class ControllerAuthorizationFilterTest {
public void operator() {
ControllerTester tester = new ControllerTester();
ControllerAuthorizationFilter filter = createFilter(tester);
- RolePrincipal operatorPrincipal = new RolePrincipal() {
- @Override public RoleMembership roles() { return Role.hostedOperator.limitedTo(tester.controller().system()); }
- @Override public String getName() { return "operator"; }
- };
- assertIsAllowed(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", operatorPrincipal)));
- assertIsAllowed(invokeFilter(filter, createRequest(Method.PUT, "/application/v4/user", operatorPrincipal)));
- assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", operatorPrincipal)));
+ 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)));
+ assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", securityContext)));
}
@Test
public void unprivileged() {
ControllerTester tester = new ControllerTester();
- RolePrincipal everyonePrincipal = new RolePrincipal() {
- @Override public RoleMembership roles() { return Role.everyone.limitedTo(tester.controller().system()); }
- @Override public String getName() { return "user"; }
- };
+ SecurityContext securityContext = new SecurityContext(() -> "user", Role.everyone.limitedTo(tester.controller().system()));
+
ControllerAuthorizationFilter filter = createFilter(tester);
- assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", everyonePrincipal)));
- assertIsAllowed(invokeFilter(filter, createRequest(Method.PUT, "/application/v4/user", everyonePrincipal)));
- assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", everyonePrincipal)));
+ 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)));
}
@Test
public void unprivilegedInPublic() {
ControllerTester tester = new ControllerTester();
tester.zoneRegistry().setSystemName(SystemName.Public);
- RolePrincipal everyonePrincipal = new RolePrincipal() {
- @Override public RoleMembership roles() { return Role.everyone.limitedTo(tester.controller().system()); }
- @Override public String getName() { return "user"; }
- };
+
+ SecurityContext securityContext = new SecurityContext(() -> "user", Role.everyone.limitedTo(tester.controller().system()));
+
ControllerAuthorizationFilter filter = createFilter(tester);
- assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", everyonePrincipal)));
- assertIsForbidden(invokeFilter(filter, createRequest(Method.PUT, "/application/v4/user", everyonePrincipal)));
- assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", everyonePrincipal)));
+ assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", securityContext)));
+ assertIsForbidden(invokeFilter(filter, createRequest(Method.PUT, "/application/v4/user", securityContext)));
+ assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", securityContext)));
}
private static void assertIsAllowed(Optional<AuthorizationResponse> response) {
@@ -96,8 +89,9 @@ public class ControllerAuthorizationFilterTest {
.map(response -> new AuthorizationResponse(response.getStatus(), getErrorMessage(responseHandlerMock)));
}
- private static DiscFilterRequest createRequest(Method method, String path, Principal principal) {
- Request request = new Request(path, new byte[0], Request.Method.valueOf(method.name()), principal);
+ private static DiscFilterRequest createRequest(Method method, String path, SecurityContext securityContext) {
+ Request request = new Request(path, new byte[0], Request.Method.valueOf(method.name()), securityContext.principal());
+ request.getAttributes().put(SecurityContext.ATTRIBUTE_NAME, securityContext);
return new ApplicationRequestToDiscFilterRequestWrapper(request);
}
@@ -118,5 +112,4 @@ public class ControllerAuthorizationFilterTest {
this.message = message;
}
}
-
}