fixes cors problems

Project: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/commit/6029baec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/tree/6029baec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/diff/6029baec

Branch: refs/heads/develop
Commit: 6029baec9e10bca9dbca317092505122cc922e8d
Parents: c7d85fc
Author: tkurz <[email protected]>
Authored: Mon Apr 8 10:26:26 2013 +0200
Committer: tkurz <[email protected]>
Committed: Mon Apr 8 10:26:26 2013 +0200

----------------------------------------------------------------------
 .../src/main/webapp/WEB-INF/web.xml                |    3 +-
 .../platform/core/filters/MarmottaCorsFilter.java  |  100 +++++++++++++
 .../marmotta/platform/core/util/CorsHandler.java   |   90 ++++++++++++
 .../platform/core/test/cors/CorsFilterTest.java    |  111 +++++++++++++++
 .../sparql/webservices/SparqlWebService.java       |    3 +-
 5 files changed, 305 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/6029baec/launchers/marmotta-webapp/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/launchers/marmotta-webapp/src/main/webapp/WEB-INF/web.xml 
b/launchers/marmotta-webapp/src/main/webapp/WEB-INF/web.xml
index 2f53049..1e417bf 100644
--- a/launchers/marmotta-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/launchers/marmotta-webapp/src/main/webapp/WEB-INF/web.xml
@@ -60,6 +60,7 @@
     </filter-mapping>
 
     <!-- handle OPTIONS requests -->
+    <!--
     <filter>
       <filter-name>MarmottaOptionsFilter</filter-name>
       
<filter-class>org.apache.marmotta.platform.core.servlet.MarmottaOptionsFilter</filter-class>
@@ -68,7 +69,7 @@
         <filter-name>MarmottaOptionsFilter</filter-name>
         <url-pattern>/*</url-pattern>
     </filter-mapping>
-
+    -->
     <!-- Serve static resources from file system and from .jar files of the 
respective modules -->
     <filter>
         <filter-name>MarmottaResourceFilter</filter-name>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/6029baec/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/filters/MarmottaCorsFilter.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/filters/MarmottaCorsFilter.java
 
b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/filters/MarmottaCorsFilter.java
new file mode 100644
index 0000000..8828135
--- /dev/null
+++ 
b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/filters/MarmottaCorsFilter.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package org.apache.marmotta.platform.core.filters;
+
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.api.modules.MarmottaHttpFilter;
+import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
+import org.apache.marmotta.platform.core.util.CorsHandler;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ...
+ * <p/>
+ * Author: Thomas Kurz ([email protected])
+ */
+@ApplicationScoped
+public class MarmottaCorsFilter implements MarmottaHttpFilter {
+
+    public static Map<String,Object> options;
+
+    @Inject
+    ConfigurationService configurationService;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        initializeOptions();
+    }
+
+    public void configChanged(@Observes ConfigurationChangedEvent event) {
+        if (event.getKeys().contains("kiwi.allow_origin")
+                || event.getKeys().contains("kiwi.allow_methods")) {
+            initializeOptions();
+        }
+    }
+
+    private void initializeOptions() {
+        options = new HashMap<String,Object>();
+        
options.put("Access-Control-Allow-Origin",configurationService.getStringConfiguration("kiwi.allow_origin","*"));
+        options.put("Access-Control-Allow-Methods", 
configurationService.getStringConfiguration("kiwi.allow_methods","POST, PUT, 
GET, DELETE, HEAD"));
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws IOException, ServletException {
+        if(response instanceof HttpServletResponse) {
+            HttpServletResponse resp = (HttpServletResponse)response;
+            HttpServletRequest req  = (HttpServletRequest)request;
+
+            String origin = req.getHeader("Origin");
+
+            if(origin != null) {
+                CorsHandler.run(req,resp,options);
+            }
+
+            if(req.getMethod().equalsIgnoreCase("OPTIONS")) {
+                resp.setStatus(200);
+            }
+        }
+        chain.doFilter(request,response);
+    }
+
+    @Override
+    public void destroy() {
+        //
+    }
+
+    @Override
+    public String getPattern() {
+        return "^/.*";
+    }
+
+    @Override
+    public int getPriority() {
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/6029baec/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/util/CorsHandler.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/util/CorsHandler.java
 
b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/util/CorsHandler.java
new file mode 100644
index 0000000..abd6b61
--- /dev/null
+++ 
b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/util/CorsHandler.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package org.apache.marmotta.platform.core.util;
+
+import org.apache.commons.lang.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ...
+ * <p/>
+ * Author: Thomas Kurz ([email protected])
+ */
+public class CorsHandler {
+
+    private static final String[] CORS_HEADERS= {
+            "Access-Control-Allow-Origin",
+            "Access-Control-Expose-Headers",
+            "Access-Control-Max-Age",
+            "Access-Control-Allow-Credentials",
+            "Access-Control-Allow-Methods",
+            "Access-Control-Allow-Headers"};
+
+    /**
+     * This method sets the response headers for CORS request. The options may 
contain following fields:
+     * <ul>
+     * <li>
+     *     "Access-Control-Allow-Origin" : List&lt;String&gt; | "*"
+     * </li>
+     * <li>
+     *     "Access-Control-Expose-Headers" : List&lt;String&gt;
+     * </li>
+     * <li>
+     *     "Access-Control-Max-Age" : long
+     * </li>
+     * <li>
+     *    "Access-Control-Allow-Credentials" : boolean
+     * </li>
+     * <li>
+     *     "Access-Control-Allow-Methods" : List&lt;String&gt;
+     * </li>
+     * <li>
+     *     "Access-Control-Allow-Headers" : List&lt;String&gt;
+     * </li>
+     * </ul>
+     * @param request the HTTP servlet request
+     * @param response the HTTP servlet response
+     * @param options the options
+     */
+    public static void run(HttpServletRequest request, HttpServletResponse 
response, Map<String,Object> options) {
+
+        //remove all existing cors headers
+        for(String header : CORS_HEADERS) {
+            response.setHeader(header,null);
+        }
+
+        //add headers from options
+        for(String key : options.keySet()) {
+            response.addHeader(key,buildHeader(options.get(key)));
+        }
+
+    }
+
+    private static String buildHeader(Object value) {
+        if(value instanceof List) {
+            return StringUtils.join((List)value,",");
+        }
+        return value.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/6029baec/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/cors/CorsFilterTest.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/cors/CorsFilterTest.java
 
b/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/cors/CorsFilterTest.java
new file mode 100644
index 0000000..52390fe
--- /dev/null
+++ 
b/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/cors/CorsFilterTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+package org.apache.marmotta.platform.core.test.cors;
+
+import com.google.common.collect.Lists;
+import com.jayway.restassured.RestAssured;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.test.base.JettyMarmotta;
+import 
org.apache.marmotta.platform.core.webservices.config.ConfigurationWebService;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import static com.jayway.restassured.RestAssured.given;
+
+/**
+ * ...
+ * <p/>
+ * Author: Thomas Kurz ([email protected])
+ */
+public class CorsFilterTest {
+
+    private static JettyMarmotta marmotta;
+    private static ConfigurationService configurationService;
+
+    @BeforeClass
+    public static void setUp() {
+        marmotta = new JettyMarmotta("/marmotta", 
ConfigurationWebService.class);
+        configurationService = marmotta.getService(ConfigurationService.class);
+
+        RestAssured.baseURI = "http://localhost";;
+        RestAssured.port = marmotta.getPort();
+        RestAssured.basePath = marmotta.getContext();
+
+    }
+
+    @AfterClass
+    public static void tearDown() {
+        marmotta.shutdown();
+    }
+
+    /**
+     * Sparql Service should use the basic cors functionality
+     */
+    @Test
+    public void testCorsRequestOnSparqlService() throws 
UnsupportedEncodingException {
+
+        //options request
+        given().header("Origin", "http://otherhost.com";).
+        expect().statusCode(200).
+        expect().header("Access-Control-Allow-Origin", "*").
+        expect().header("Access-Control-Allow-Methods","POST, PUT, GET, 
DELETE, HEAD").
+        when().options("/config/list");
+
+        //change configuration and retry
+        
configurationService.setConfiguration("Access-Control-Allow-Origin","http://otherhost.com";);
+
+        given().header("Origin", "http://otherhost.com";).
+        expect().statusCode(200).
+        expect().header("Access-Control-Allow-Origin", "http://otherhost.com";).
+        expect().header("Access-Control-Allow-Methods","POST, PUT, GET, 
DELETE, HEAD").
+        when().options("/config/list");
+
+        //get request
+        given().header("Origin", "http://otherhost.com";).
+        given().header("Content-Type","application/json").
+        given().content("[\"test\"]").
+        expect().statusCode(200).
+        expect().header("Access-Control-Allow-Origin", "http://otherhost.com";).
+        expect().header("Access-Control-Allow-Methods","POST, PUT, GET, 
DELETE, HEAD").
+        when().post("/config/data/key");
+
+    }
+
+    /**
+     * resource Service should overwrite the basic cors functionality
+     */
+    @Test
+    public void testCorsRequestOnResourceService() {
+        //change configuration
+        
configurationService.setConfiguration("Access-Control-Allow-Origin","http://my.host.com";);
+
+        //options request
+        given().header("Origin", "http://otherhost.com";).
+        expect().statusCode(201).
+        expect().header("Access-Control-Allow-Origin", "*").
+        expect().header("Access-Control-Allow-Methods","POST, PUT, GET, 
DELETE, HEAD").
+        when().post("/resource/123");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/6029baec/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
----------------------------------------------------------------------
diff --git 
a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
 
b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
index f15f6df..b6d520e 100644
--- 
a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
+++ 
b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
@@ -185,7 +185,7 @@ public class SparqlWebService {
      * 
      * @param reqHeaders
      * @return responde
-     */
+
     @OPTIONS
     @Path(UPDATE)
     public Response 
optionsResourceRemote(@HeaderParam("Access-Control-Request-Headers") String 
reqHeaders) {
@@ -200,6 +200,7 @@ public class SparqlWebService {
                 .build();
 
     }
+    */
     
     /**
      * Execute a SPARQL 1.1 tuple query on the LMF triple store using the 
query passed as form parameter to the

Reply via email to