aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject git commit: Add CORS support to thrift end points.
Date Thu, 29 May 2014 18:14:42 GMT
Repository: incubator-aurora
Updated Branches:
  refs/heads/master ab286ac19 -> 207928b22


Add CORS support to thrift end points.

Add CORS support for thrift end points. Added a command line option to explicitly enable that
support since this may a potential security issue and we may not want to enable it in production.

Testing Done:
Local laptop. Attached screenshot.
Called the API from another JS app and was able to make a successful $http.post().

Bugs closed: AURORA-390

Reviewed at https://reviews.apache.org/r/21497/


Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/207928b2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/207928b2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/207928b2

Branch: refs/heads/master
Commit: 207928b22ef15789c3bddfe731dcb7588f9876ae
Parents: ab286ac
Author: Suman Karumuri <mansu@apache.org>
Authored: Thu May 29 11:13:32 2014 -0700
Committer: Suman Karumuri <skarumuri@twitter.com>
Committed: Thu May 29 11:13:32 2014 -0700

----------------------------------------------------------------------
 build.gradle                                    |  3 +-
 .../aurora/scheduler/http/CorsFilter.java       | 74 ++++++++++++++++++++
 .../scheduler/http/SchedulerAPIServlet.java     | 31 ++++++++
 .../aurora/scheduler/http/ServletModule.java    | 24 +++++++
 .../scheduler/thrift/SchedulerAPIServlet.java   | 31 --------
 .../aurora/scheduler/thrift/ThriftModule.java   |  7 --
 .../aurora/scheduler/http/CorsFilterTest.java   | 59 ++++++++++++++++
 7 files changed, 190 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 1e36bbd..aeb430d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -482,7 +482,8 @@ run {
     '-vlog=INFO',
     '-testing_isolated_scheduler=true',
     '-testing_log_file_path=/tmp/testing_log_file',
-    '-viz_job_url_prefix=http://fake_viz_domain.com/stats?'
+    '-viz_job_url_prefix=http://fake_viz_domain.com/stats?',
+    '-enable_cors_support'
   ]
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/src/main/java/org/apache/aurora/scheduler/http/CorsFilter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/CorsFilter.java b/src/main/java/org/apache/aurora/scheduler/http/CorsFilter.java
new file mode 100644
index 0000000..5b2e735
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/http/CorsFilter.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed 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.
+ */
+package org.apache.aurora.scheduler.http;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.HttpMethod;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.net.HttpHeaders;
+import com.twitter.common.base.MorePreconditions;
+import com.twitter.common.net.http.filters.AbstractHttpFilter;
+
+/*
+ * A filter that adds CORS headers to HTTP responses. This filter enables CORS support for
a single
+ * domain.
+ */
+public class CorsFilter extends AbstractHttpFilter {
+
+  @VisibleForTesting
+  static final String ALLOWED_METHODS = Joiner.on(",")
+      .join(ImmutableSet.of(
+          HttpMethod.DELETE,
+          HttpMethod.GET,
+          HttpMethod.HEAD,
+          HttpMethod.OPTIONS,
+          HttpMethod.POST,
+          HttpMethod.PUT));
+
+  @VisibleForTesting
+  static final String ALLOWED_HEADERS = Joiner.on(",")
+      .join(ImmutableSet.of(
+          HttpHeaders.ACCEPT,
+          HttpHeaders.CONTENT_TYPE,
+          HttpHeaders.ORIGIN,
+          HttpHeaders.X_REQUESTED_WITH));
+
+  private final String allowedOriginDomain;
+
+  /*
+   * param allowedOriginDomain a domain for which CORS is enabled.
+   */
+  public CorsFilter(String allowedOriginDomain) {
+    this.allowedOriginDomain = MorePreconditions.checkNotBlank(allowedOriginDomain);
+  }
+
+  @Override
+  public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain
chain)
+      throws IOException, ServletException {
+
+    response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, allowedOriginDomain);
+    response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, ALLOWED_METHODS);
+    response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, ALLOWED_HEADERS);
+
+    chain.doFilter(request, response);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/src/main/java/org/apache/aurora/scheduler/http/SchedulerAPIServlet.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/SchedulerAPIServlet.java b/src/main/java/org/apache/aurora/scheduler/http/SchedulerAPIServlet.java
new file mode 100644
index 0000000..33ad43b
--- /dev/null
+++ b/src/main/java/org/apache/aurora/scheduler/http/SchedulerAPIServlet.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed 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.
+ */
+package org.apache.aurora.scheduler.http;
+
+import javax.inject.Inject;
+
+import org.apache.aurora.gen.AuroraAdmin;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.server.TServlet;
+
+/**
+ * A servlet that exposes the scheduler Thrift API over HTTP/JSON.
+ */
+class SchedulerAPIServlet extends TServlet {
+
+  @Inject
+  SchedulerAPIServlet(AuroraAdmin.Iface schedulerThriftInterface) {
+    super(new AuroraAdmin.Processor<>(schedulerThriftInterface), new TJSONProtocol.Factory());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java b/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
index 28e4741..d104eab 100644
--- a/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
+++ b/src/main/java/org/apache/aurora/scheduler/http/ServletModule.java
@@ -32,6 +32,8 @@ import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
 import com.twitter.common.application.http.Registration;
 import com.twitter.common.application.modules.LifecycleModule;
 import com.twitter.common.application.modules.LocalServiceRegistry;
+import com.twitter.common.args.Arg;
+import com.twitter.common.args.CmdLine;
 import com.twitter.common.base.ExceptionalCommand;
 import com.twitter.common.net.pool.DynamicHostSet;
 import com.twitter.common.net.pool.DynamicHostSet.MonitorException;
@@ -41,6 +43,7 @@ import org.apache.aurora.scheduler.cron.CronJobManager;
 import org.apache.aurora.scheduler.quota.QuotaManager;
 import org.apache.aurora.scheduler.state.SchedulerCore;
 import org.apache.aurora.scheduler.storage.entities.IServerInfo;
+import org.mortbay.servlet.GzipFilter;
 
 import static com.sun.jersey.api.core.ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS;
 import static com.sun.jersey.api.core.ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS;
@@ -51,6 +54,14 @@ import static com.sun.jersey.api.json.JSONConfiguration.FEATURE_POJO_MAPPING;
  */
 public class ServletModule extends AbstractModule {
 
+  @CmdLine(name = "enable_cors_support", help = "Enable CORS support for thrift end points.")
+  private static final Arg<Boolean> ENABLE_CORS_SUPPORT = Arg.create(false);
+
+  // More info on CORS can be found at http://enable-cors.org/index.html
+  @CmdLine(name = "enable_cors_for",
+      help = "List of domains for which CORS support should be enabled.")
+  private static final Arg<String> ENABLE_CORS_FOR = Arg.create("*");
+
   private static final Map<String, String> CONTAINER_PARAMS = ImmutableMap.of(
       FEATURE_POJO_MAPPING, Boolean.TRUE.toString(),
       PROPERTY_CONTAINER_REQUEST_FILTERS, GZIPContentEncodingFilter.class.getName(),
@@ -63,6 +74,13 @@ public class ServletModule extends AbstractModule {
     requireBinding(IServerInfo.class);
     requireBinding(QuotaManager.class);
 
+    // Register /api end point
+    Registration.registerServlet(binder(), "/api", SchedulerAPIServlet.class, true);
+
+    // NOTE: GzipFilter is applied only to /api instead of globally because the Jersey-managed
+    // servlets have a conflicting filter applied to them.
+    Registration.registerServletFilter(binder(), GzipFilter.class, "/api/*");
+
     // Bindings required for the leader redirector.
     requireBinding(LocalServiceRegistry.class);
     requireBinding(Key.get(new TypeLiteral<DynamicHostSet<ServiceInstance>>()
{ }));
@@ -84,6 +102,12 @@ public class ServletModule extends AbstractModule {
         bind(LeaderRedirectFilter.class).in(Singleton.class);
         filter("/scheduler").through(LeaderRedirectFilter.class);
 
+        // Add CORS support for all /api end points.
+        if (ENABLE_CORS_SUPPORT.get()) {
+          bind(CorsFilter.class).toInstance(new CorsFilter(ENABLE_CORS_FOR.get()));
+          filter("/api*").through(CorsFilter.class);
+        }
+
         registerJerseyEndpoint("/cron", Cron.class);
         registerJerseyEndpoint("/maintenance", Maintenance.class);
         registerJerseyEndpoint("/mname", Mname.class);

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerAPIServlet.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerAPIServlet.java b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerAPIServlet.java
deleted file mode 100644
index fc07ddc..0000000
--- a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerAPIServlet.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed 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.
- */
-package org.apache.aurora.scheduler.thrift;
-
-import javax.inject.Inject;
-
-import org.apache.aurora.gen.AuroraAdmin;
-import org.apache.thrift.protocol.TJSONProtocol;
-import org.apache.thrift.server.TServlet;
-
-/**
- * A servlet that exposes the scheduler Thrift API over HTTP/JSON.
- */
-class SchedulerAPIServlet extends TServlet {
-
-  @Inject
-  SchedulerAPIServlet(AuroraAdmin.Iface schedulerThriftInterface) {
-    super(new AuroraAdmin.Processor<>(schedulerThriftInterface), new TJSONProtocol.Factory());
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java b/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java
index 33653d2..aa35182 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java
@@ -14,11 +14,9 @@
 package org.apache.aurora.scheduler.thrift;
 
 import com.google.inject.AbstractModule;
-import com.twitter.common.application.http.Registration;
 
 import org.apache.aurora.gen.AuroraAdmin;
 import org.apache.aurora.scheduler.thrift.aop.AopModule;
-import org.mortbay.servlet.GzipFilter;
 
 /**
  * Binding module to configure a thrift server.
@@ -29,11 +27,6 @@ public class ThriftModule extends AbstractModule {
   protected void configure() {
     bind(AuroraAdmin.Iface.class).to(SchedulerThriftInterface.class);
 
-    Registration.registerServlet(binder(), "/api", SchedulerAPIServlet.class, true);
-    // NOTE: GzipFilter is applied only to /api instead of globally because the Jersey-managed
-    // servlets from ServletModule have a conflicting filter applied to them.
-    Registration.registerServletFilter(binder(), GzipFilter.class, "/api/*");
-
     install(new AopModule());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/207928b2/src/test/java/org/apache/aurora/scheduler/http/CorsFilterTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/http/CorsFilterTest.java b/src/test/java/org/apache/aurora/scheduler/http/CorsFilterTest.java
new file mode 100644
index 0000000..2fa29ee
--- /dev/null
+++ b/src/test/java/org/apache/aurora/scheduler/http/CorsFilterTest.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed 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.
+ */
+package org.apache.aurora.scheduler.http;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.google.common.net.HttpHeaders;
+import com.twitter.common.testing.easymock.EasyMockTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.replay;
+
+public class CorsFilterTest extends EasyMockTest {
+
+  private static final String DUMMY_ALLOWED_ORIGIN_DOMAIN = "test";
+
+  private HttpServletRequest request;
+  private HttpServletResponse response;
+  private FilterChain chain;
+
+  @Before
+  public void setUp() {
+    request = createMock(HttpServletRequest.class);
+    response = createMock(HttpServletResponse.class);
+    chain = createMock(FilterChain.class);
+  }
+
+  @Test
+  public void testCorsSupport() throws IOException, ServletException {
+    CorsFilter corsFilter = new CorsFilter(DUMMY_ALLOWED_ORIGIN_DOMAIN);
+
+    response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, DUMMY_ALLOWED_ORIGIN_DOMAIN);
+    response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, CorsFilter.ALLOWED_METHODS);
+    response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, CorsFilter.ALLOWED_HEADERS);
+    chain.doFilter(request, response);
+
+    replay(response);
+
+    corsFilter.doFilter(request, response, chain);
+  }
+}


Mime
View raw message