You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by ne...@apache.org on 2022/02/24 02:52:45 UTC
[helix] branch nealsun/Helix-ACL-authorization updated: Add Authorization Components to helix-rest (#1967)
This is an automated email from the ASF dual-hosted git repository.
nealsun pushed a commit to branch nealsun/Helix-ACL-authorization
in repository https://gitbox.apache.org/repos/asf/helix.git
The following commit(s) were added to refs/heads/nealsun/Helix-ACL-authorization by this push:
new ac9680a Add Authorization Components to helix-rest (#1967)
ac9680a is described below
commit ac9680a8450ffc14f048e324782ce8f037d28fb6
Author: Neal Sun <ne...@linkedin.com>
AuthorDate: Wed Feb 23 18:51:42 2022 -0800
Add Authorization Components to helix-rest (#1967)
* Add Authorization Components to helix-rest
* Address some comments
---
.../apache/helix/rest/server/HelixRestServer.java | 24 ++++
.../rest/server/authValidator/AuthValidator.java | 27 ++++
.../server/authValidator/NoopAuthValidator.java | 29 +++++
.../helix/rest/server/filters/ClusterAuth.java | 33 +++++
.../rest/server/filters/ClusterAuthFilter.java | 46 +++++++
.../helix/rest/server/filters/NamespaceAuth.java | 33 +++++
.../rest/server/filters/NamespaceAuthFilter.java | 46 +++++++
.../server/resources/helix/ClusterAccessor.java | 38 ++++++
.../server/resources/helix/InstancesAccessor.java | 2 +
.../rest/server/resources/helix/JobAccessor.java | 2 +
.../server/resources/helix/MetadataAccessor.java | 2 +
.../resources/helix/PerInstanceAccessor.java | 2 +
.../resources/helix/PropertyStoreAccessor.java | 2 +
.../server/resources/helix/ResourceAccessor.java | 2 +
.../helix/ResourceAssignmentOptimizerAccessor.java | 2 +
.../rest/server/resources/helix/TaskAccessor.java | 2 +
.../server/resources/helix/WorkflowAccessor.java | 2 +
.../resources/metadata/NamespacesAccessor.java | 2 +
.../MetadataStoreDirectoryAccessor.java | 2 +
.../resources/zookeeper/ZooKeeperAccessor.java | 2 +
.../helix/rest/server/TestAuthValidator.java | 143 +++++++++++++++++++++
21 files changed, 443 insertions(+)
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 8137739..b72f535 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
@@ -40,8 +40,12 @@ import org.apache.helix.rest.common.ContextPropertyKeys;
import org.apache.helix.rest.common.HelixRestNamespace;
import org.apache.helix.rest.common.ServletType;
import org.apache.helix.rest.server.auditlog.AuditLogger;
+import org.apache.helix.rest.server.authValidator.AuthValidator;
+import org.apache.helix.rest.server.authValidator.NoopAuthValidator;
import org.apache.helix.rest.server.filters.AuditLogFilter;
import org.apache.helix.rest.server.filters.CORSFilter;
+import org.apache.helix.rest.server.filters.ClusterAuthFilter;
+import org.apache.helix.rest.server.filters.NamespaceAuthFilter;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -57,6 +61,7 @@ import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
public class HelixRestServer {
private static Logger LOG = LoggerFactory.getLogger(HelixRestServer.class);
@@ -73,6 +78,8 @@ public class HelixRestServer {
private List<HelixRestNamespace> _helixNamespaces;
private ServletContextHandler _servletContextHandler;
private List<AuditLogger> _auditLoggers;
+ private AuthValidator _clusterAuthValidator;
+ private AuthValidator _namespaceAuthValidator;
// Key is name of namespace, value of the resource config of that namespace
private Map<String, ResourceConfig> _resourceConfigMap;
@@ -94,8 +101,21 @@ public class HelixRestServer {
init(namespaces, port, urlPrefix, auditLoggers);
}
+ public HelixRestServer(List<HelixRestNamespace> namespaces, int port, String urlPrefix,
+ List<AuditLogger> auditLoggers, AuthValidator clusterAuthValidator,
+ AuthValidator namespaceAuthValidator) {
+ init(namespaces, port, urlPrefix, auditLoggers, clusterAuthValidator, namespaceAuthValidator);
+ }
+
private void init(List<HelixRestNamespace> namespaces, int port, String urlPrefix,
List<AuditLogger> auditLoggers) {
+ init(namespaces, port, urlPrefix, auditLoggers, new NoopAuthValidator(),
+ new NoopAuthValidator());
+ }
+
+ private void init(List<HelixRestNamespace> namespaces, int port, String urlPrefix,
+ List<AuditLogger> auditLoggers, AuthValidator clusterAuthValidator,
+ AuthValidator namespaceAuthValidator) {
if (namespaces.size() == 0) {
throw new IllegalArgumentException(
"No namespace specified! Please provide ZOOKEEPER address or namespace manifest.");
@@ -108,6 +128,8 @@ public class HelixRestServer {
_resourceConfigMap = new HashMap<>();
_servletContextHandler = new ServletContextHandler(_server, _urlPrefix);
_helixNamespaces = namespaces;
+ _clusterAuthValidator = clusterAuthValidator;
+ _namespaceAuthValidator = namespaceAuthValidator;
// Initialize all namespaces.
// If there is not a default namespace (namespace.isDefault() is false),
@@ -175,6 +197,8 @@ public class HelixRestServer {
cfg.register(new CORSFilter());
}
cfg.register(new AuditLogFilter(_auditLoggers));
+ cfg.register(new ClusterAuthFilter(_clusterAuthValidator));
+ cfg.register(new NamespaceAuthFilter(_namespaceAuthValidator));
return cfg;
}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/authValidator/AuthValidator.java b/helix-rest/src/main/java/org/apache/helix/rest/server/authValidator/AuthValidator.java
new file mode 100644
index 0000000..801540e
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/authValidator/AuthValidator.java
@@ -0,0 +1,27 @@
+package org.apache.helix.rest.server.authValidator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.ws.rs.container.ContainerRequestContext;
+
+
+public interface AuthValidator {
+ boolean validate(ContainerRequestContext request);
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/authValidator/NoopAuthValidator.java b/helix-rest/src/main/java/org/apache/helix/rest/server/authValidator/NoopAuthValidator.java
new file mode 100644
index 0000000..4fc6e8c
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/authValidator/NoopAuthValidator.java
@@ -0,0 +1,29 @@
+package org.apache.helix.rest.server.authValidator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.ws.rs.container.ContainerRequestContext;
+
+
+public class NoopAuthValidator implements AuthValidator {
+ public boolean validate(ContainerRequestContext request) {
+ return true;
+ }
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/filters/ClusterAuth.java b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/ClusterAuth.java
new file mode 100644
index 0000000..e807de6
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/ClusterAuth.java
@@ -0,0 +1,33 @@
+package org.apache.helix.rest.server.filters;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.ws.rs.NameBinding;
+
+
+@NameBinding
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ClusterAuth {
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/filters/ClusterAuthFilter.java b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/ClusterAuthFilter.java
new file mode 100644
index 0000000..4956ec9
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/ClusterAuthFilter.java
@@ -0,0 +1,46 @@
+package org.apache.helix.rest.server.filters;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.helix.rest.server.authValidator.AuthValidator;
+
+
+@ClusterAuth
+@Provider
+public class ClusterAuthFilter implements ContainerRequestFilter {
+
+ AuthValidator _authValidator;
+
+ public ClusterAuthFilter(AuthValidator authValidator) {
+ _authValidator = authValidator;
+ }
+
+ @Override
+ public void filter(ContainerRequestContext request) {
+ if (!_authValidator.validate(request)) {
+ request.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+ }
+ }
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/filters/NamespaceAuth.java b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/NamespaceAuth.java
new file mode 100644
index 0000000..003bcb9
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/NamespaceAuth.java
@@ -0,0 +1,33 @@
+package org.apache.helix.rest.server.filters;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.ws.rs.NameBinding;
+
+
+@NameBinding
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NamespaceAuth {
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/filters/NamespaceAuthFilter.java b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/NamespaceAuthFilter.java
new file mode 100644
index 0000000..818c12f
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/filters/NamespaceAuthFilter.java
@@ -0,0 +1,46 @@
+package org.apache.helix.rest.server.filters;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.helix.rest.server.authValidator.AuthValidator;
+
+
+@NamespaceAuth
+@Provider
+public class NamespaceAuthFilter implements ContainerRequestFilter {
+
+ AuthValidator _authValidator;
+
+ public NamespaceAuthFilter(AuthValidator authValidator) {
+ _authValidator = authValidator;
+ }
+
+ @Override
+ public void filter(ContainerRequestContext request) {
+ if (!_authValidator.validate(request)) {
+ request.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+ }
+ }
+}
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 daea45f..6c14207 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
@@ -67,6 +67,8 @@ import org.apache.helix.model.RESTConfig;
import org.apache.helix.model.StateModelDefinition;
import org.apache.helix.model.builder.HelixConfigScopeBuilder;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
+import org.apache.helix.rest.server.filters.NamespaceAuth;
import org.apache.helix.rest.server.json.cluster.ClusterTopology;
import org.apache.helix.rest.server.service.ClusterService;
import org.apache.helix.rest.server.service.ClusterServiceImpl;
@@ -98,6 +100,7 @@ public class ClusterAccessor extends AbstractHelixResource {
clusterName
}
+ @NamespaceAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -111,6 +114,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(dataMap);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -149,6 +153,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(clusterInfo);
}
+ @NamespaceAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@PUT
@@ -185,6 +190,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return created();
}
+ @NamespaceAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@DELETE
@@ -206,6 +212,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
@@ -330,6 +337,7 @@ public class ClusterAccessor extends AbstractHelixResource {
service.addVirtualTopologyGroup(clusterId, customFieldsMap);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -404,6 +412,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return details;
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
@@ -437,6 +446,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(ImmutableMap.of("acknowledged", true));
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -461,6 +471,7 @@ public class ClusterAccessor extends AbstractHelixResource {
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@PUT
@@ -492,6 +503,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@DELETE
@@ -514,6 +526,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -534,6 +547,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return notFound();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
@@ -576,6 +590,7 @@ public class ClusterAccessor extends AbstractHelixResource {
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -590,6 +605,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK(objectMapper.writeValueAsString(clusterTopology));
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -605,6 +621,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(topologyMap);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -620,6 +637,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(faultZoneMap);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
@@ -674,6 +692,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -694,6 +713,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(controllerInfo);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -703,6 +723,7 @@ public class ClusterAccessor extends AbstractHelixResource {
getControllerHistory(clusterId, ControllerHistory.HistoryType.CONTROLLER_LEADERSHIP));
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -712,6 +733,7 @@ public class ClusterAccessor extends AbstractHelixResource {
getControllerHistory(clusterId, ControllerHistory.HistoryType.MAINTENANCE));
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -728,6 +750,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return notFound(String.format("Cluster %s is not in maintenance mode!", clusterId));
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -746,6 +769,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(controllerMessages);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -758,6 +782,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(message.getRecord());
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -774,6 +799,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(clusterStateModelDefs);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -790,6 +816,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(stateModelDef.getRecord());
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@PUT
@@ -815,6 +842,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
@@ -844,6 +872,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@DELETE
@@ -870,6 +899,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@PUT
@@ -902,6 +932,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
@@ -951,6 +982,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -973,6 +1005,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return JSONRepresentation(config.getRecord());
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@DELETE
@@ -991,6 +1024,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -1005,6 +1039,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return ZKUtil.isClusterSetup(cluster, zkClient);
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@PUT
@@ -1039,6 +1074,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.READ_REQUEST)
@Timed(name = HttpConstants.READ_REQUEST)
@GET
@@ -1060,6 +1096,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return notFound();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@DELETE
@@ -1070,6 +1107,7 @@ public class ClusterAccessor extends AbstractHelixResource {
return OK();
}
+ @ClusterAuth
@ResponseMetered(name = HttpConstants.WRITE_REQUEST)
@Timed(name = HttpConstants.WRITE_REQUEST)
@POST
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
index 93537e3..fefe5c3 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstancesAccessor.java
@@ -49,6 +49,7 @@ import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.InstanceConfig;
import org.apache.helix.rest.clusterMaintenanceService.MaintenanceManagementService;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.rest.server.json.cluster.ClusterTopology;
import org.apache.helix.rest.server.json.instance.StoppableCheck;
import org.apache.helix.rest.server.resources.exceptions.HelixHealthException;
@@ -57,6 +58,7 @@ import org.apache.helix.rest.server.service.ClusterServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/instances")
public class InstancesAccessor extends AbstractHelixResource {
private final static Logger _logger = LoggerFactory.getLogger(InstancesAccessor.class);
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/JobAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/JobAccessor.java
index d6dc610..912a00a 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/JobAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/JobAccessor.java
@@ -42,6 +42,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.helix.HelixException;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.task.JobConfig;
import org.apache.helix.task.JobContext;
import org.apache.helix.task.TaskConfig;
@@ -52,6 +53,7 @@ import org.apache.helix.zookeeper.zkclient.exception.ZkNoNodeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/workflows/{workflowName}/jobs")
public class JobAccessor extends AbstractHelixResource {
private static Logger _logger = LoggerFactory.getLogger(JobAccessor.class.getName());
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/MetadataAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/MetadataAccessor.java
index 40b61d9..d9cc16b 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/MetadataAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/MetadataAccessor.java
@@ -29,8 +29,10 @@ import org.apache.helix.rest.common.ContextPropertyKeys;
import org.apache.helix.rest.common.HelixRestNamespace;
import org.apache.helix.rest.common.HelixRestUtils;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.NamespaceAuth;
import org.apache.helix.rest.server.resources.AbstractResource;
+@NamespaceAuth
@Path("")
public class MetadataAccessor extends AbstractResource {
@ResponseMetered(name = HttpConstants.READ_REQUEST)
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
index 3fd284e..f9d171e 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PerInstanceAccessor.java
@@ -61,6 +61,7 @@ import org.apache.helix.model.builder.HelixConfigScopeBuilder;
import org.apache.helix.rest.clusterMaintenanceService.HealthCheck;
import org.apache.helix.rest.clusterMaintenanceService.MaintenanceManagementService;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.rest.server.json.instance.InstanceInfo;
import org.apache.helix.rest.server.json.instance.StoppableCheck;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
@@ -68,6 +69,7 @@ import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/instances/{instanceName}")
public class PerInstanceAccessor extends AbstractHelixResource {
private final static Logger LOG = LoggerFactory.getLogger(PerInstanceAccessor.class);
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PropertyStoreAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PropertyStoreAccessor.java
index 3dbb273..7fafcf1 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PropertyStoreAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/PropertyStoreAccessor.java
@@ -38,12 +38,14 @@ import org.apache.helix.BaseDataAccessor;
import org.apache.helix.PropertyPathBuilder;
import org.apache.helix.msdcommon.util.ZkValidationUtil;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/propertyStore")
public class PropertyStoreAccessor extends AbstractHelixResource {
private static Logger LOG = LoggerFactory.getLogger(PropertyStoreAccessor.class);
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAccessor.java
index ec63076..cc49885 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAccessor.java
@@ -55,11 +55,13 @@ import org.apache.helix.model.ResourceConfig;
import org.apache.helix.model.StateModelDefinition;
import org.apache.helix.model.builder.HelixConfigScopeBuilder;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/resources")
public class ResourceAccessor extends AbstractHelixResource {
private final static Logger _logger = LoggerFactory.getLogger(ResourceAccessor.class);
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAssignmentOptimizerAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAssignmentOptimizerAccessor.java
index 0ecae71..9324523 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAssignmentOptimizerAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ResourceAssignmentOptimizerAccessor.java
@@ -54,11 +54,13 @@ import org.apache.helix.model.InstanceConfig;
import org.apache.helix.model.ResourceAssignment;
import org.apache.helix.model.ResourceConfig;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.util.HelixUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/partitionAssignment")
public class ResourceAssignmentOptimizerAccessor extends AbstractHelixResource {
private static Logger LOG = LoggerFactory.getLogger(
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/TaskAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/TaskAccessor.java
index a8a7b74..70f17dd 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/TaskAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/TaskAccessor.java
@@ -33,11 +33,13 @@ import com.codahale.metrics.annotation.ResponseMetered;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.task.TaskDriver;
import org.apache.helix.zookeeper.zkclient.exception.ZkNoNodeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/workflows/{workflowName}/jobs/{jobName}/tasks")
public class TaskAccessor extends AbstractHelixResource {
private static Logger _logger = LoggerFactory.getLogger(TaskAccessor.class.getName());
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/WorkflowAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/WorkflowAccessor.java
index c2929a2..ddfa31e 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/WorkflowAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/WorkflowAccessor.java
@@ -47,6 +47,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.helix.HelixException;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.ClusterAuth;
import org.apache.helix.task.JobConfig;
import org.apache.helix.task.JobDag;
import org.apache.helix.task.JobQueue;
@@ -59,6 +60,7 @@ import org.apache.helix.zookeeper.zkclient.exception.ZkNoNodeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ClusterAuth
@Path("/clusters/{clusterId}/workflows")
public class WorkflowAccessor extends AbstractHelixResource {
private static Logger _logger = LoggerFactory.getLogger(WorkflowAccessor.class.getName());
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadata/NamespacesAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadata/NamespacesAccessor.java
index 9ae0c19..0d29ab2 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadata/NamespacesAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadata/NamespacesAccessor.java
@@ -31,9 +31,11 @@ import com.codahale.metrics.annotation.Timed;
import org.apache.helix.rest.common.ContextPropertyKeys;
import org.apache.helix.rest.common.HelixRestNamespace;
import org.apache.helix.rest.common.HttpConstants;
+import org.apache.helix.rest.server.filters.NamespaceAuth;
import org.apache.helix.rest.server.resources.AbstractResource;
+@NamespaceAuth
@Path("/namespaces")
public class NamespacesAccessor extends AbstractResource {
@ResponseMetered(name = HttpConstants.READ_REQUEST)
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadatastore/MetadataStoreDirectoryAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadatastore/MetadataStoreDirectoryAccessor.java
index 781e723..4687f8b 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadatastore/MetadataStoreDirectoryAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/metadatastore/MetadataStoreDirectoryAccessor.java
@@ -53,6 +53,7 @@ import org.apache.helix.rest.metadatastore.MetadataStoreDirectory;
import org.apache.helix.rest.metadatastore.ZkMetadataStoreDirectory;
import org.apache.helix.rest.metadatastore.datamodel.MetadataStoreShardingKey;
import org.apache.helix.rest.metadatastore.datamodel.MetadataStoreShardingKeysByRealm;
+import org.apache.helix.rest.server.filters.NamespaceAuth;
import org.apache.helix.rest.server.resources.AbstractResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -62,6 +63,7 @@ import org.slf4j.LoggerFactory;
* Provides REST endpoints for accessing metadata store directory service,
* which responds to read/write requests of metadata store realms, sharding keys, etc..
*/
+@NamespaceAuth
@Path("")
public class MetadataStoreDirectoryAccessor extends AbstractResource {
private static final Logger LOG = LoggerFactory.getLogger(MetadataStoreDirectoryAccessor.class);
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java
index 4450017..762d603 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java
@@ -40,6 +40,7 @@ import org.apache.helix.msdcommon.util.ZkValidationUtil;
import org.apache.helix.rest.common.ContextPropertyKeys;
import org.apache.helix.rest.common.HttpConstants;
import org.apache.helix.rest.server.ServerContext;
+import org.apache.helix.rest.server.filters.NamespaceAuth;
import org.apache.helix.rest.server.resources.AbstractResource;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
@@ -50,6 +51,7 @@ import org.slf4j.LoggerFactory;
* ZooKeeperAccessor provides methods for accessing ZooKeeper resources (ZNodes).
* It provides basic ZooKeeper features supported by ZkClient.
*/
+@NamespaceAuth
@Path("/zookeeper{path: /.+}")
public class ZooKeeperAccessor extends AbstractResource {
private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperAccessor.class.getName());
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
new file mode 100644
index 0000000..bbc0e60
--- /dev/null
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestAuthValidator.java
@@ -0,0 +1,143 @@
+package org.apache.helix.rest.server;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.ws.rs.client.Entity;
+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.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.http.HttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+
+public class TestAuthValidator extends AbstractTestClass {
+ private String _mockBaseUri;
+ private CloseableHttpClient _httpClient;
+
+ @Test
+ public void testDefaultAuthValidator() throws JsonProcessingException {
+ String testClusterName = "testDefaultAuthValidator";
+ put("clusters/" + testClusterName, 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(testClusterName));
+ }
+
+ @Test(dependsOnMethods = "testDefaultAuthValidator")
+ public void testCustomAuthValidator() throws IOException, InterruptedException {
+ String testClusterName = "testCustomAuthValidator";
+ 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);
+
+ 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
+ HelixRestServer server =
+ new HelixRestServer(namespaces, newPort, getBaseUri().getPath(), Collections.emptyList(),
+ mockAuthValidatorReject, mockAuthValidatorPass);
+ server.start();
+
+ HttpUriRequest request =
+ buildRequest("/clusters/" + testClusterName, HttpConstants.RestVerbs.PUT, "");
+ sendRequestAndValidate(request, Response.Status.CREATED.getStatusCode());
+ request = buildRequest("/clusters/" + testClusterName, 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/" + testClusterName, HttpConstants.RestVerbs.GET, "");
+ sendRequestAndValidate(request, Response.Status.OK.getStatusCode());
+ request = buildRequest("/clusters", HttpConstants.RestVerbs.GET, "");
+ sendRequestAndValidate(request, Response.Status.FORBIDDEN.getStatusCode());
+
+ server.shutdown();
+ _httpClient.close();
+ }
+
+ private HttpUriRequest buildRequest(String urlSuffix, HttpConstants.RestVerbs requestMethod,
+ String jsonEntity) {
+ String url = _mockBaseUri + urlSuffix;
+ switch (requestMethod) {
+ case PUT:
+ HttpPut httpPut = new HttpPut(url);
+ httpPut.setEntity(new StringEntity(jsonEntity, ContentType.APPLICATION_JSON));
+ return httpPut;
+ case DELETE:
+ return new HttpDelete(url);
+ case GET:
+ return new HttpGet(url);
+ default:
+ throw new IllegalArgumentException("Unsupported requestMethod: " + requestMethod);
+ }
+ }
+
+ private void sendRequestAndValidate(HttpUriRequest request, int expectedResponseCode)
+ throws IllegalArgumentException, IOException {
+ HttpResponse response = _httpClient.execute(request);
+ Assert.assertEquals(response.getStatusLine().getStatusCode(), expectedResponseCode);
+ }
+
+
+}