This is an automated email from the ASF dual-hosted git repository. nealsun pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/helix.git
The following commit(s) were added to refs/heads/master by this push: new b4f8bd52f Add AclRegister interfaces and ClusterAccessor integration (#2153) b4f8bd52f is described below commit b4f8bd52ffad0154cb0967e0817df134f8a39e0b Author: Neal Sun <ne...@linkedin.com> AuthorDate: Tue Jun 21 10:48:32 2022 -0700 Add AclRegister interfaces and ClusterAccessor integration (#2153) Add AclRegister interfaces and ClusterAccessor integration --- .../AclRegister.java} | 12 ++-- .../NoopAclRegister.java} | 14 +++-- .../helix/rest/common/ContextPropertyKeys.java | 3 +- .../apache/helix/rest/server/HelixRestServer.java | 14 +++-- .../server/resources/helix/ClusterAccessor.java | 13 +++++ ...TestAuthValidator.java => TestAclRegister.java} | 68 ++++++---------------- .../helix/rest/server/TestAuthValidator.java | 5 +- 7 files changed, 63 insertions(+), 66 deletions(-) diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java b/helix-rest/src/main/java/org/apache/helix/rest/acl/AclRegister.java similarity index 79% copy from helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java copy to helix-rest/src/main/java/org/apache/helix/rest/acl/AclRegister.java index 6bd8d1611..3c7b8992c 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/acl/AclRegister.java @@ -1,4 +1,4 @@ -package org.apache.helix.rest.common; +package org.apache.helix.rest.acl; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,8 +19,10 @@ package org.apache.helix.rest.common; * under the License. */ -public enum ContextPropertyKeys { - SERVER_CONTEXT, - METADATA, - ALL_NAMESPACES +import javax.servlet.http.HttpServletRequest; + + +public interface AclRegister { + // Create an ACL entry based on the request + void createACL(HttpServletRequest request); } diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java b/helix-rest/src/main/java/org/apache/helix/rest/acl/NoopAclRegister.java similarity index 80% copy from helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java copy to helix-rest/src/main/java/org/apache/helix/rest/acl/NoopAclRegister.java index 6bd8d1611..3d3b84f9e 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/acl/NoopAclRegister.java @@ -1,4 +1,4 @@ -package org.apache.helix.rest.common; +package org.apache.helix.rest.acl; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,8 +19,12 @@ package org.apache.helix.rest.common; * under the License. */ -public enum ContextPropertyKeys { - SERVER_CONTEXT, - METADATA, - ALL_NAMESPACES +import javax.servlet.http.HttpServletRequest; + + +public class NoopAclRegister implements AclRegister { + + public void createACL(HttpServletRequest request) { + + } } diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java b/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java index 6bd8d1611..1c5d5690a 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/ContextPropertyKeys.java @@ -22,5 +22,6 @@ package org.apache.helix.rest.common; public enum ContextPropertyKeys { SERVER_CONTEXT, METADATA, - ALL_NAMESPACES + ALL_NAMESPACES, + ACL_REGISTER, } diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/HelixRestServer.java b/helix-rest/src/main/java/org/apache/helix/rest/server/HelixRestServer.java index b72f53512..f8e78ee75 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/server/HelixRestServer.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/server/HelixRestServer.java @@ -36,6 +36,8 @@ import com.codahale.metrics.SlidingTimeWindowReservoir; import com.codahale.metrics.jersey2.InstrumentedResourceMethodApplicationListener; import com.codahale.metrics.jmx.JmxReporter; import org.apache.helix.HelixException; +import org.apache.helix.rest.acl.AclRegister; +import org.apache.helix.rest.acl.NoopAclRegister; import org.apache.helix.rest.common.ContextPropertyKeys; import org.apache.helix.rest.common.HelixRestNamespace; import org.apache.helix.rest.common.ServletType; @@ -80,6 +82,7 @@ public class HelixRestServer { private List<AuditLogger> _auditLoggers; private AuthValidator _clusterAuthValidator; private AuthValidator _namespaceAuthValidator; + private AclRegister _aclRegister; // Key is name of namespace, value of the resource config of that namespace private Map<String, ResourceConfig> _resourceConfigMap; @@ -103,19 +106,20 @@ public class HelixRestServer { public HelixRestServer(List<HelixRestNamespace> namespaces, int port, String urlPrefix, List<AuditLogger> auditLoggers, AuthValidator clusterAuthValidator, - AuthValidator namespaceAuthValidator) { - init(namespaces, port, urlPrefix, auditLoggers, clusterAuthValidator, namespaceAuthValidator); + AuthValidator namespaceAuthValidator, AclRegister aclRegister) { + init(namespaces, port, urlPrefix, auditLoggers, clusterAuthValidator, namespaceAuthValidator, + aclRegister); } private void init(List<HelixRestNamespace> namespaces, int port, String urlPrefix, List<AuditLogger> auditLoggers) { init(namespaces, port, urlPrefix, auditLoggers, new NoopAuthValidator(), - new NoopAuthValidator()); + new NoopAuthValidator(), new NoopAclRegister()); } private void init(List<HelixRestNamespace> namespaces, int port, String urlPrefix, List<AuditLogger> auditLoggers, AuthValidator clusterAuthValidator, - AuthValidator namespaceAuthValidator) { + AuthValidator namespaceAuthValidator, AclRegister aclRegister) { if (namespaces.size() == 0) { throw new IllegalArgumentException( "No namespace specified! Please provide ZOOKEEPER address or namespace manifest."); @@ -130,6 +134,7 @@ public class HelixRestServer { _helixNamespaces = namespaces; _clusterAuthValidator = clusterAuthValidator; _namespaceAuthValidator = namespaceAuthValidator; + _aclRegister = aclRegister; // Initialize all namespaces. // If there is not a default namespace (namespace.isDefault() is false), @@ -191,6 +196,7 @@ public class HelixRestServer { cfg.property(ContextPropertyKeys.ALL_NAMESPACES.name(), _helixNamespaces); } cfg.property(ContextPropertyKeys.METADATA.name(), namespace); + cfg.property(ContextPropertyKeys.ACL_REGISTER.name(), _aclRegister); if (Boolean.getBoolean(CORS_ENABLED)) { // NOTE: CORS is disabled by default unless otherwise specified in System Properties. diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java index e0790c00e..7a6cd6bd1 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java @@ -66,6 +66,8 @@ import org.apache.helix.model.Message; import org.apache.helix.model.RESTConfig; import org.apache.helix.model.StateModelDefinition; import org.apache.helix.model.builder.HelixConfigScopeBuilder; +import org.apache.helix.rest.acl.AclRegister; +import org.apache.helix.rest.common.ContextPropertyKeys; import org.apache.helix.rest.common.HttpConstants; import org.apache.helix.rest.server.filters.ClusterAuth; import org.apache.helix.rest.server.filters.NamespaceAuth; @@ -181,6 +183,13 @@ public class ClusterAccessor extends AbstractHelixResource { } } + try { + getAclRegister().createACL(_servletRequest); + } catch (Exception ex) { + LOG.error("Failed to create ACL for cluster {}. Exception: {}.", clusterId, ex); + return serverError(ex); + } + try { clusterSetup.addCluster(clusterId, recreateIfExists, cloudConfig); } catch (Exception ex) { @@ -1212,4 +1221,8 @@ public class ClusterAccessor extends AbstractHelixResource { } return history; } + + private AclRegister getAclRegister() { + return (AclRegister) _application.getProperties().get(ContextPropertyKeys.ACL_REGISTER.name()); + } } diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestAclRegister.java similarity index 55% copy from helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java copy to helix-rest/src/test/java/org/apache/helix/rest/server/TestAclRegister.java index eecb73165..0a043cd11 100644 --- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java +++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestAclRegister.java @@ -28,12 +28,11 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; import org.apache.helix.TestHelper; +import org.apache.helix.rest.acl.AclRegister; import org.apache.helix.rest.common.HelixRestNamespace; import org.apache.helix.rest.common.HttpConstants; -import org.apache.helix.rest.server.authValidator.AuthValidator; -import org.apache.helix.rest.server.resources.helix.ClusterAccessor; +import org.apache.helix.rest.server.authValidator.NoopAuthValidator; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; @@ -49,77 +48,48 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -public class TestAuthValidator extends AbstractTestClass { +public class TestAclRegister extends AbstractTestClass { private String _mockBaseUri; private CloseableHttpClient _httpClient; - private static String CLASSNAME_TEST_DEFAULT_AUTH = "testDefaultAuthValidator"; - private static String CLASSNAME_TEST_CST_AUTH = "testCustomAuthValidator"; - - @AfterClass - public void afterClass() { - TestHelper.dropCluster(CLASSNAME_TEST_DEFAULT_AUTH, _gZkClient); - TestHelper.dropCluster(CLASSNAME_TEST_CST_AUTH, _gZkClient); - } + private static String CLASSNAME_TEST_DEFAULT_ACL_REGISTER = "testDefaultAclRegister"; + private static String CLASSNAME_TEST_CUSTOM_ACL_REGISTER = "testCustomACLRegister"; @Test - public void testDefaultAuthValidator() throws JsonProcessingException { - put("clusters/" + CLASSNAME_TEST_DEFAULT_AUTH, null, Entity.entity("", MediaType.APPLICATION_JSON_TYPE), + public void testDefaultAclRegister() { + put("clusters/testCluster", null, Entity.entity("", MediaType.APPLICATION_JSON_TYPE), Response.Status.CREATED.getStatusCode()); - String body = get("clusters/", null, Response.Status.OK.getStatusCode(), true); - JsonNode node = OBJECT_MAPPER.readTree(body); - String clustersStr = node.get(ClusterAccessor.ClusterProperties.clusters.name()).toString(); - Assert.assertTrue(clustersStr.contains(CLASSNAME_TEST_DEFAULT_AUTH)); + TestHelper.dropCluster("testCluster", _gZkClient); } - @Test(dependsOnMethods = "testDefaultAuthValidator") - public void testCustomAuthValidator() throws IOException, InterruptedException { + @Test(dependsOnMethods = "testDefaultAclRegister") + public void testCustomACLRegister() throws IOException, InterruptedException { int newPort = getBaseUri().getPort() + 1; - // Start a second server for testing Distributed Leader Election for writes _mockBaseUri = HttpConstants.HTTP_PROTOCOL_PREFIX + getBaseUri().getHost() + ":" + newPort; _httpClient = HttpClients.createDefault(); - AuthValidator mockAuthValidatorPass = Mockito.mock(AuthValidator.class); - when(mockAuthValidatorPass.validate(any())).thenReturn(true); - AuthValidator mockAuthValidatorReject = Mockito.mock(AuthValidator.class); - when(mockAuthValidatorReject.validate(any())).thenReturn(false); + AclRegister mockAclRegister = Mockito.mock(AclRegister.class); + Mockito.doThrow(new RuntimeException()).when(mockAclRegister).createACL(any()); List<HelixRestNamespace> namespaces = new ArrayList<>(); namespaces.add(new HelixRestNamespace(HelixRestNamespace.DEFAULT_NAMESPACE_NAME, HelixRestNamespace.HelixMetadataStoreType.ZOOKEEPER, ZK_ADDR, true)); - // Create a server that allows operations based on namespace auth and rejects operations based - // on cluster auth + // Create a server that passes acl resource creation HelixRestServer server = new HelixRestServer(namespaces, newPort, getBaseUri().getPath(), Collections.emptyList(), - mockAuthValidatorReject, mockAuthValidatorPass); + new NoopAuthValidator(), new NoopAuthValidator(), mockAclRegister); server.start(); HttpUriRequest request = - buildRequest("/clusters/" + CLASSNAME_TEST_CST_AUTH, HttpConstants.RestVerbs.PUT, ""); - sendRequestAndValidate(request, Response.Status.CREATED.getStatusCode()); - request = buildRequest("/clusters/" + CLASSNAME_TEST_CST_AUTH, HttpConstants.RestVerbs.GET, ""); - sendRequestAndValidate(request, Response.Status.FORBIDDEN.getStatusCode()); - - server.shutdown(); - _httpClient.close(); - - // Create a server that rejects operations based on namespace auth and allows operations based - // on cluster auth - server = - new HelixRestServer(namespaces, newPort, getBaseUri().getPath(), Collections.emptyList(), - mockAuthValidatorPass, mockAuthValidatorReject); - server.start(); - _httpClient = HttpClients.createDefault(); - - request = buildRequest("/clusters/" + CLASSNAME_TEST_CST_AUTH, HttpConstants.RestVerbs.GET, ""); - sendRequestAndValidate(request, Response.Status.OK.getStatusCode()); - request = buildRequest("/clusters", HttpConstants.RestVerbs.GET, ""); - sendRequestAndValidate(request, Response.Status.FORBIDDEN.getStatusCode()); + buildRequest("/clusters/testCluster", HttpConstants.RestVerbs.PUT, ""); + sendRequestAndValidate(request, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + request = + buildRequest("/clusters/testCluster", HttpConstants.RestVerbs.GET, ""); + sendRequestAndValidate(request, Response.Status.NOT_FOUND.getStatusCode()); server.shutdown(); _httpClient.close(); diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java index eecb73165..c0271a4a1 100644 --- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java +++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java @@ -30,6 +30,7 @@ import javax.ws.rs.core.Response; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import org.apache.helix.TestHelper; +import org.apache.helix.rest.acl.NoopAclRegister; import org.apache.helix.rest.common.HelixRestNamespace; import org.apache.helix.rest.common.HttpConstants; import org.apache.helix.rest.server.authValidator.AuthValidator; @@ -96,7 +97,7 @@ public class TestAuthValidator extends AbstractTestClass { // on cluster auth HelixRestServer server = new HelixRestServer(namespaces, newPort, getBaseUri().getPath(), Collections.emptyList(), - mockAuthValidatorReject, mockAuthValidatorPass); + mockAuthValidatorReject, mockAuthValidatorPass, new NoopAclRegister()); server.start(); HttpUriRequest request = @@ -112,7 +113,7 @@ public class TestAuthValidator extends AbstractTestClass { // on cluster auth server = new HelixRestServer(namespaces, newPort, getBaseUri().getPath(), Collections.emptyList(), - mockAuthValidatorPass, mockAuthValidatorReject); + mockAuthValidatorPass, mockAuthValidatorReject, new NoopAclRegister()); server.start(); _httpClient = HttpClients.createDefault();