You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2015/08/12 17:15:58 UTC

svn commit: r1695555 - in /chemistry/opencmis/trunk/chemistry-opencmis-server: chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/ chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/ chemistry-opencmi...

Author: fmui
Date: Wed Aug 12 15:15:57 2015
New Revision: 1695555

URL: http://svn.apache.org/r1695555
Log:
CMIS-914: added server part (CMIS Endpoint Documents and CSRF protection)

Added:
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/cmis-endpoints.json
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/AbstractCmisEndpointsDocumentServlet.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/SimpleCmisEndpointsDocumentServlet.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/CsrfManager.java
Modified:
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/web.xml
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/CmisRepositoryContextListener.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/CmisAtomPubServlet.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/CmisBrowserBindingServlet.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/token/AbstractSimpleTokenHandler.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/AbstractService.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/CmisWebServicesServlet.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/RepositoryService.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/AbstractCmisHttpServlet.java

Added: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/cmis-endpoints.json
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/cmis-endpoints.json?rev=1695555&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/cmis-endpoints.json (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/cmis-endpoints.json Wed Aug 12 15:15:57 2015
@@ -0,0 +1,84 @@
+{
+  "endpoints": [
+    {
+      "displayName": "OpenCMIS CMIS 1.0 AtomPub Binding", 
+      "binding": "atompub",
+      "cmisVersion": "1.0", 
+      "cookies": "optional", 
+      "compression": "server", 
+      "url": "{webapp}/atom", 
+      "authentication": [
+        {
+          "displayName": "HTTP basic authentication", 
+          "type": "basic", 
+          "preference": 4, 
+          "documentationUrl": "https://chemistry.apache.org/java/opencmis.html"
+        }
+      ]
+    },
+    {
+      "displayName": "OpenCMIS CMIS 1.1 AtomPub Binding", 
+      "binding": "atompub",
+      "cmisVersion": "1.1", 
+      "cookies": "optional", 
+      "compression": "server", 
+      "url": "{webapp}/atom11", 
+      "authentication": [
+        {
+          "displayName": "HTTP basic authentication", 
+          "type": "basic", 
+          "preference": 2, 
+          "documentationUrl": "https://chemistry.apache.org/java/opencmis.html"
+        }
+      ]
+    },
+    {
+      "displayName": "OpenCMIS CMIS 1.0 Web Services Binding", 
+      "binding": "webservices",
+      "cmisVersion": "1.0", 
+      "cookies": "optional", 
+      "compression": "server", 
+      "url": "{webapp}/services/cmis?wsdl ", 
+      "authentication": [
+        {
+          "displayName": "UsernameToken authentication", 
+          "type": "usernameToken", 
+          "preference": 5, 
+          "documentationUrl": "https://chemistry.apache.org/java/opencmis.html"
+        }
+      ]
+    },
+    {
+      "displayName": "OpenCMIS CMIS 1.1 Web Services Binding", 
+      "binding": "webservices",
+      "cmisVersion": "1.1", 
+      "cookies": "optional", 
+      "compression": "server", 
+      "url": "{webapp}/services11/cmis?wsdl ", 
+      "authentication": [
+        {
+          "displayName": "UsernameToken authentication", 
+          "type": "usernameToken", 
+          "preference": 3, 
+          "documentationUrl": "https://chemistry.apache.org/java/opencmis.html"
+        }
+      ]
+    },
+    {
+      "displayName": "OpenCMIS CMIS 1.1 Browser Binding", 
+      "binding": "browser",
+      "cmisVersion": "1.1", 
+      "cookies": "optional", 
+      "compression": "server", 
+      "url": "{webapp}/browser", 
+      "authentication": [
+        {
+          "displayName": "HTTP basic authentication", 
+          "type": "basic", 
+          "preference": 1, 
+          "documentationUrl": "https://chemistry.apache.org/java/opencmis.html"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/web.xml?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/web.xml (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings-war/src/main/webapp/WEB-INF/web.xml Wed Aug 12 15:15:57 2015
@@ -112,7 +112,7 @@
     <!--
         Uncomment the following filter to enable CORS support for the browser binding.
         See http://software.dzhuvinov.com/cors-filter.html for details.
-        Put the CORS libraries into the WEB-INF/lib directory or uncomment the CORS depenedency in the pom.xml.
+        Put the CORS libraries into the WEB-INF/lib directory or uncomment the CORS dependency in the pom.xml.
     -->
     <!--
     <filter>
@@ -219,6 +219,16 @@
         </init-param>
         <load-on-startup>2</load-on-startup>
     </servlet>
+    
+    <servlet>
+        <servlet-name>cmisendpoints</servlet-name>
+        <servlet-class>org.apache.chemistry.opencmis.server.impl.endpoints.SimpleCmisEndpointsDocumentServlet</servlet-class>
+        <init-param>
+            <param-name>template</param-name>
+            <param-value>/WEB-INF/cmis-endpoints.json</param-value>
+        </init-param>
+        <load-on-startup>3</load-on-startup>
+    </servlet>
 
     <servlet-mapping>
         <servlet-name>cmisws10</servlet-name>
@@ -244,4 +254,9 @@
         <servlet-name>cmisbrowser</servlet-name>
         <url-pattern>/browser/*</url-pattern>
     </servlet-mapping>
+    
+    <servlet-mapping>
+        <servlet-name>cmisendpoints</servlet-name>
+        <url-pattern>/cmis-endpoints.json</url-pattern>
+    </servlet-mapping>
 </web-app>

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/CmisRepositoryContextListener.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/CmisRepositoryContextListener.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/CmisRepositoryContextListener.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/CmisRepositoryContextListener.java Wed Aug 12 15:15:57 2015
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 
@@ -47,6 +48,7 @@ public class CmisRepositoryContextListen
     private static final String CONFIG_FILENAME = "/repository.properties";
     private static final String PROPERTY_CLASS = "class";
 
+    @Override
     public void contextInitialized(ServletContextEvent sce) {
         // get config file name or use default
         String configFilename = sce.getServletContext().getInitParameter(CONFIG_INIT_PARAM);
@@ -67,6 +69,7 @@ public class CmisRepositoryContextListen
         sce.getServletContext().setAttribute(SERVICES_FACTORY, factory);
     }
 
+    @Override
     public void contextDestroyed(ServletContextEvent sce) {
         // destroy services factory
         CmisServiceFactory factory = (CmisServiceFactory) sce.getServletContext().getAttribute(SERVICES_FACTORY);
@@ -81,6 +84,13 @@ public class CmisRepositoryContextListen
     }
 
     /**
+     * Gets the service factory from the servlet context.
+     */
+    public static CmisServiceFactory getServiceFactory(final ServletContext servletContext) {
+        return (CmisServiceFactory) servletContext.getAttribute(SERVICES_FACTORY);
+    }
+
+    /**
      * Creates a service factory.
      */
     private CmisServiceFactory createServiceFactory(String filename) {

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/CmisAtomPubServlet.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/CmisAtomPubServlet.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/CmisAtomPubServlet.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/CmisAtomPubServlet.java Wed Aug 12 15:15:57 2015
@@ -170,6 +170,11 @@ public class CmisAtomPubServlet extends
 
         CallContext context = null;
         try {
+            // CSRF token check
+            if (!METHOD_GET.equals(request.getMethod()) && !METHOD_HEAD.equals(request.getMethod())) {
+                checkCsrfToken(request, response, false, false);
+            }
+
             // split path
             String[] pathFragments = HttpUtils.splitPath(request);
 
@@ -235,6 +240,9 @@ public class CmisAtomPubServlet extends
 
             // analyze the path
             if (pathFragments.length < 2) {
+                // CSRF check
+                checkCsrfToken(request, response, true, false);
+
                 // root -> service document
                 dispatcher.dispatch("", METHOD_GET, context, service, null, request, response);
                 return;
@@ -244,6 +252,9 @@ public class CmisAtomPubServlet extends
             String repositoryId = pathFragments[0];
             String resource = pathFragments[1];
 
+            // CSRF check
+            checkCsrfToken(request, response, false, RESOURCE_CONTENT.equals(resource) && METHOD_GET.equals(method));
+
             // dispatch
             boolean callServiceFound = dispatcher.dispatch(resource, method, context, service, repositoryId, request,
                     response);

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/CmisBrowserBindingServlet.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/CmisBrowserBindingServlet.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/CmisBrowserBindingServlet.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/CmisBrowserBindingServlet.java Wed Aug 12 15:15:57 2015
@@ -215,6 +215,12 @@ public class CmisBrowserBindingServlet e
         CallContext context = null;
 
         try {
+            // CSRF token check
+            String method = request.getMethod();
+            if (!METHOD_GET.equals(method) && !METHOD_HEAD.equals(method)) {
+                checkCsrfToken(request, response, false, false);
+            }
+
             // set default headers
             response.addHeader("Cache-Control", "private, max-age=0");
             response.addHeader("Server", ServerVersion.OPENCMIS_SERVER);
@@ -227,8 +233,6 @@ public class CmisBrowserBindingServlet e
                     pathFragments.length > 0 ? pathFragments[0] : null);
 
             // check HTTP method
-            String method = request.getMethod();
-
             if (METHOD_GET.equals(method)) {
                 request = new QueryStringHttpServletRequestWrapper(request);
             } else if (METHOD_POST.equals(method)) {
@@ -310,6 +314,9 @@ public class CmisBrowserBindingServlet e
 
             // analyze the path
             if (pathFragments.length < 1) {
+                // CSRF check
+                checkCsrfToken(request, response, true, false);
+
                 // root -> repository infos
                 repositoryDispatcher.dispatch("", METHOD_GET, context, service, null, request, response);
                 return;
@@ -341,6 +348,10 @@ public class CmisBrowserBindingServlet e
                         throw new CmisNotSupportedException("No selector");
                     }
 
+                    // CSRF check
+                    checkCsrfToken(request, response, SELECTOR_REPOSITORY_INFO.equalsIgnoreCase(selector), false);
+
+                    // dispatch
                     browserContext.setCallDetails(service, objectId, null, null);
                     callServiceFound = repositoryDispatcher.dispatch(selector, method, browserContext, service,
                             repositoryId, request, response);
@@ -367,6 +378,10 @@ public class CmisBrowserBindingServlet e
                         }
                     }
 
+                    // CSRF check
+                    checkCsrfToken(request, response, false, SELECTOR_CONTENT.equalsIgnoreCase(selector));
+
+                    // dispatch
                     callServiceFound = rootDispatcher.dispatch(selector, method, browserContext, service, repositoryId,
                             request, response);
                 }

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/token/AbstractSimpleTokenHandler.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/token/AbstractSimpleTokenHandler.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/token/AbstractSimpleTokenHandler.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/token/AbstractSimpleTokenHandler.java Wed Aug 12 15:15:57 2015
@@ -331,8 +331,7 @@ public abstract class AbstractSimpleToke
     }
 
     protected CmisServiceFactory getCmisServiceFactory(final ServletContext servletContext) {
-        CmisServiceFactory factory = (CmisServiceFactory) servletContext
-                .getAttribute(CmisRepositoryContextListener.SERVICES_FACTORY);
+        CmisServiceFactory factory = CmisRepositoryContextListener.getServiceFactory(servletContext);
 
         if (factory == null) {
             throw new CmisRuntimeException("Service factory not available! Configuration problem?");

Added: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/AbstractCmisEndpointsDocumentServlet.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/AbstractCmisEndpointsDocumentServlet.java?rev=1695555&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/AbstractCmisEndpointsDocumentServlet.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/AbstractCmisEndpointsDocumentServlet.java Wed Aug 12 15:15:57 2015
@@ -0,0 +1,84 @@
+/*
+ * 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.chemistry.opencmis.server.impl.endpoints;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.net.URL;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.chemistry.opencmis.commons.endpoints.CmisEndpointsDocument;
+import org.apache.chemistry.opencmis.commons.impl.endpoints.CmisEndpointsDocumentHelper;
+import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParseException;
+
+/**
+ * Serves the CMIS Endpoints Document.
+ */
+public abstract class AbstractCmisEndpointsDocumentServlet extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+        CmisEndpointsDocument doc = getCmisEndpointsDocument(req, resp);
+        if (doc == null) {
+            resp.sendError(HttpServletResponse.SC_NOT_FOUND, "CMIS Endpoints Document is not available!");
+            return;
+        }
+
+        resp.setContentType("application/json; charset=UTF-8");
+
+        PrintWriter pw = resp.getWriter();
+        CmisEndpointsDocumentHelper.write(doc, pw);
+    }
+
+    /**
+     * Returns a CMIS Endpoints Document.
+     */
+    public abstract CmisEndpointsDocument getCmisEndpointsDocument(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException;
+
+    public CmisEndpointsDocument readCmisEndpointsDocument(URL url) throws IOException, JSONParseException {
+        return CmisEndpointsDocumentHelper.read(url);
+    }
+
+    public CmisEndpointsDocument readCmisEndpointsDocument(File file) throws IOException, JSONParseException {
+        return CmisEndpointsDocumentHelper.read(file);
+    }
+
+    public CmisEndpointsDocument readCmisEndpointsDocument(InputStream in) throws IOException, JSONParseException {
+        return CmisEndpointsDocumentHelper.read(in);
+    }
+
+    public CmisEndpointsDocument readCmisEndpointsDocument(Reader in) throws IOException, JSONParseException {
+        return CmisEndpointsDocumentHelper.read(in);
+    }
+
+    public CmisEndpointsDocument readCmisEndpointsDocument(String in) throws JSONParseException {
+        return CmisEndpointsDocumentHelper.read(in);
+    }
+}

Added: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/SimpleCmisEndpointsDocumentServlet.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/SimpleCmisEndpointsDocumentServlet.java?rev=1695555&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/SimpleCmisEndpointsDocumentServlet.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/endpoints/SimpleCmisEndpointsDocumentServlet.java Wed Aug 12 15:15:57 2015
@@ -0,0 +1,69 @@
+package org.apache.chemistry.opencmis.server.impl.endpoints;
+
+import java.io.InputStream;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.chemistry.opencmis.commons.endpoints.CmisEndpointsDocument;
+import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
+import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A simple CMIS Endpoints Document servlet.
+ * 
+ * It reads an endpoints document from a file replace some strings.
+ */
+public class SimpleCmisEndpointsDocumentServlet extends AbstractCmisEndpointsDocumentServlet {
+
+    private static final long serialVersionUID = 1L;
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleCmisEndpointsDocumentServlet.class);
+
+    private static final String PARAM_ENDPOINT_TEMPLATE = "template";
+
+    private String endpointsDocument;
+
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+
+        String template = config.getInitParameter(PARAM_ENDPOINT_TEMPLATE);
+        if (template == null) {
+            LOG.error("CMIS Endpoints Document template provided!");
+            return;
+        }
+
+        // load template from file
+        try {
+            InputStream stream = config.getServletContext().getResourceAsStream(template);
+            if (stream != null) {
+                endpointsDocument = IOUtils.readAllLines(stream);
+            }
+        } catch (Exception e) {
+            LOG.error("Could not read CMIS Endpoints Document template from {}!", template, e);
+        }
+    }
+
+    @Override
+    public CmisEndpointsDocument getCmisEndpointsDocument(HttpServletRequest req, HttpServletResponse resp) {
+        if (endpointsDocument == null) {
+            // we don't have a template
+            return null;
+        }
+
+        UrlBuilder url = new UrlBuilder(req.getScheme(), req.getServerName(), req.getServerPort(), null);
+        url.addPath(req.getContextPath());
+
+        try {
+            return readCmisEndpointsDocument(endpointsDocument.replaceAll("\\{webapp\\}", url.toString()));
+        } catch (JSONParseException e) {
+            LOG.error("Invalid JSON!", e);
+            return null;
+        }
+    }
+}

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/AbstractService.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/AbstractService.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/AbstractService.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/AbstractService.java Wed Aug 12 15:15:57 2015
@@ -55,6 +55,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
 import org.apache.chemistry.opencmis.server.impl.CmisRepositoryContextListener;
 import org.apache.chemistry.opencmis.server.impl.ServerVersion;
+import org.apache.chemistry.opencmis.server.shared.CsrfManager;
 import org.apache.chemistry.opencmis.server.shared.ExceptionHelper;
 import org.apache.chemistry.opencmis.server.shared.TempStoreOutputStreamFactory;
 import org.slf4j.Logger;
@@ -78,8 +79,7 @@ public abstract class AbstractService {
                 MessageContext.SERVLET_CONTEXT);
 
         // get services factory
-        CmisServiceFactory factory = (CmisServiceFactory) servletContext
-                .getAttribute(CmisRepositoryContextListener.SERVICES_FACTORY);
+        CmisServiceFactory factory = CmisRepositoryContextListener.getServiceFactory(servletContext);
 
         if (factory == null) {
             throw new CmisRuntimeException("Service factory not available! Configuration problem?");
@@ -146,9 +146,35 @@ public abstract class AbstractService {
     }
 
     /**
+     * Checks the CSRF token.
+     */
+    protected void checkCsrfToken(WebServiceContext wsContext, boolean isRepositoryInfoRequest) {
+        HttpServletRequest request = (HttpServletRequest) wsContext.getMessageContext().get(
+                MessageContext.SERVLET_REQUEST);
+        HttpServletResponse response = (HttpServletResponse) wsContext.getMessageContext().get(
+                MessageContext.SERVLET_RESPONSE);
+
+        CsrfManager cm = (CsrfManager) request.getAttribute(CmisWebServicesServlet.CSRF_MANAGER);
+
+        cm.check(request, response, isRepositoryInfoRequest, false);
+    }
+
+    /**
      * Returns the {@link CmisService} object.
      */
     protected CmisService getService(WebServiceContext wsContext, String repositoryId) {
+        checkCsrfToken(wsContext, false);
+        CmisServiceFactory factory = getServiceFactory(wsContext);
+        CallContext context = createContext(wsContext, factory, repositoryId);
+        return factory.getService(context);
+    }
+
+    /**
+     * Returns the {@link CmisService} object for getRepositories() and
+     * getRepositoryInfo() calls.
+     */
+    protected CmisService getServiceForRepositoryInfo(WebServiceContext wsContext, String repositoryId) {
+        checkCsrfToken(wsContext, true);
         CmisServiceFactory factory = getServiceFactory(wsContext);
         CallContext context = createContext(wsContext, factory, repositoryId);
         return factory.getService(context);

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/CmisWebServicesServlet.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/CmisWebServicesServlet.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/CmisWebServicesServlet.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/CmisWebServicesServlet.java Wed Aug 12 15:15:57 2015
@@ -39,6 +39,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
 import org.apache.chemistry.opencmis.commons.server.CmisServiceFactory;
 import org.apache.chemistry.opencmis.server.impl.CmisRepositoryContextListener;
+import org.apache.chemistry.opencmis.server.shared.CsrfManager;
 import org.apache.chemistry.opencmis.server.shared.Dispatcher;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.cxf.Bus;
@@ -51,6 +52,7 @@ public class CmisWebServicesServlet exte
 
     public static final String PARAM_CMIS_VERSION = "cmisVersion";
     public static final String CMIS_VERSION = "org.apache.chemistry.opencmis.cmisVersion";
+    public static final String CSRF_MANAGER = "org.apache.chemistry.opencmis.csrfManager";
 
     private static final long serialVersionUID = 1L;
 
@@ -69,6 +71,8 @@ public class CmisWebServicesServlet exte
 
     private Map<String, String> docs;
 
+    private CsrfManager csrfManager;
+
     @Override
     public void init(ServletConfig config) throws ServletException {
 
@@ -95,6 +99,9 @@ public class CmisWebServicesServlet exte
         docs.put("core", readFile(config, path + "CMIS-Core.xsd.template"));
         docs.put("msg", readFile(config, path + "CMIS-Messaging.xsd.template"));
 
+        // set up CSRF manager
+        csrfManager = new CsrfManager(config);
+
         super.init(config);
     }
 
@@ -115,8 +122,9 @@ public class CmisWebServicesServlet exte
 
     @Override
     public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
-        // set CMIS version
+        // set CMIS version and CSRF Manager
         request.setAttribute(CMIS_VERSION, cmisVersion);
+        request.setAttribute(CSRF_MANAGER, csrfManager);
 
         try {
             // handle GET requests
@@ -248,8 +256,7 @@ public class CmisWebServicesServlet exte
     public void loadBus(ServletConfig servletConfig) {
         super.loadBus(servletConfig);
 
-        CmisServiceFactory factory = (CmisServiceFactory) getServletContext().getAttribute(
-                CmisRepositoryContextListener.SERVICES_FACTORY);
+        CmisServiceFactory factory = CmisRepositoryContextListener.getServiceFactory(servletConfig.getServletContext());
 
         if (factory == null) {
             throw new CmisRuntimeException("Service factory not available! Configuration problem?");

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/RepositoryService.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/RepositoryService.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/RepositoryService.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/webservices/RepositoryService.java Wed Aug 12 15:15:57 2015
@@ -61,7 +61,7 @@ public class RepositoryService extends A
     public List<CmisRepositoryEntryType> getRepositories(CmisExtensionType extension) throws CmisException {
         CmisService service = null;
         try {
-            service = getService(wsContext, null);
+            service = getServiceForRepositoryInfo(wsContext, null);
 
             if (stopBeforeService(service)) {
                 return null;
@@ -99,7 +99,7 @@ public class RepositoryService extends A
         CmisService service = null;
         CmisVersion cmisVersion = null;
         try {
-            service = getService(wsContext, repositoryId);
+            service = getServiceForRepositoryInfo(wsContext, repositoryId);
             cmisVersion = getCmisVersion(wsContext);
 
             if (stopBeforeService(service)) {

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/AbstractCmisHttpServlet.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/AbstractCmisHttpServlet.java?rev=1695555&r1=1695554&r2=1695555&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/AbstractCmisHttpServlet.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/AbstractCmisHttpServlet.java Wed Aug 12 15:15:57 2015
@@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletReq
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
 import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
 import org.apache.chemistry.opencmis.commons.impl.Constants;
 import org.apache.chemistry.opencmis.commons.server.CallContext;
@@ -47,6 +48,7 @@ public abstract class AbstractCmisHttpSe
     private String binding;
     private CmisVersion cmisVersion;
     private CallContextHandler callContextHandler;
+    private CsrfManager csrfManager;
 
     @Override
     public void init(ServletConfig config) throws ServletException {
@@ -65,12 +67,14 @@ public abstract class AbstractCmisHttpSe
         }
 
         // get service factory
-        factory = (CmisServiceFactory) config.getServletContext().getAttribute(
-                CmisRepositoryContextListener.SERVICES_FACTORY);
+        factory = CmisRepositoryContextListener.getServiceFactory(config.getServletContext());
 
         if (factory == null) {
             throw new ServletException("Service factory not available! Configuration problem?");
         }
+
+        // set up CSRF manager
+        csrfManager = new CsrfManager(config);
     }
 
     /**
@@ -106,6 +110,15 @@ public abstract class AbstractCmisHttpSe
     }
 
     /**
+     * Checks the CSRF if configured. Throws an
+     * {@link CmisPermissionDeniedException} if something is wrong.
+     */
+    protected void checkCsrfToken(HttpServletRequest req, HttpServletResponse resp, boolean isRepositoryInfoRequest,
+            boolean isContentRequest) {
+        csrfManager.check(req, resp, isRepositoryInfoRequest, isContentRequest);
+    }
+
+    /**
      * Creates a {@link CallContext} object from a servlet request.
      */
     protected CallContext createContext(ServletContext servletContext, HttpServletRequest request,

Added: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/CsrfManager.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/CsrfManager.java?rev=1695555&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/CsrfManager.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/CsrfManager.java Wed Aug 12 15:15:57 2015
@@ -0,0 +1,141 @@
+/*
+ * 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.chemistry.opencmis.server.shared;
+
+import java.security.SecureRandom;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
+
+public class CsrfManager {
+
+    public static final String CSRF_ATTR = "org.apache.chemistry.opencmis.csrftoken";
+
+    private static final String CSRF_HEADER = "header";
+    private static final String CSRF_PARAMETER = "parameter";
+    private static final String FETCH_VALUE = "fetch";
+
+    private static char[][] hexArrays = new char[][] { "0123456789ABCDEF".toCharArray(), //
+            "0123456789abcdef".toCharArray(), //
+            "ABCDEFGHIJKLMNOP".toCharArray(), //
+            "abcdefghijklmnop".toCharArray() };
+
+    private String csrfHeader;
+    private String csrfParameter;
+
+    private SecureRandom random = new SecureRandom();
+
+    public CsrfManager(String csrfHeader, String csrfParameter) {
+        if (csrfHeader != null) {
+            this.csrfHeader = csrfHeader.trim();
+            if (this.csrfHeader.length() == 0) {
+                throw new IllegalArgumentException("Invalid CSRF header!");
+            }
+            if (csrfParameter != null) {
+                this.csrfParameter = csrfParameter.trim();
+                if (this.csrfParameter.length() == 0) {
+                    throw new IllegalArgumentException("Invalid CSRF parameter!");
+                }
+            }
+        }
+    }
+
+    public CsrfManager(ServletConfig config) throws ServletException {
+        csrfHeader = config.getInitParameter(CSRF_HEADER);
+        if (csrfHeader != null) {
+            this.csrfHeader = csrfHeader.trim();
+            if (this.csrfHeader.length() == 0) {
+                throw new ServletException("Invalid CSRF header!");
+            }
+
+            // get parameter
+            csrfParameter = config.getInitParameter(CSRF_PARAMETER);
+            if (csrfParameter != null) {
+                this.csrfParameter = csrfParameter.trim();
+                if (this.csrfParameter.length() == 0) {
+                    throw new ServletException("Invalid CSRF parameter!");
+                }
+            }
+        }
+    }
+
+    public void check(HttpServletRequest req, HttpServletResponse resp, boolean isRepositoryInfoRequest,
+            boolean isContentRequest) {
+        if (csrfHeader == null) {
+            // no CSRF protection
+            return;
+        }
+
+        HttpSession httpSession = req.getSession(true);
+        String token = (String) httpSession.getAttribute(CSRF_ATTR);
+        String headerValue = req.getHeader(csrfHeader);
+
+        // check parameter if the header is not set and this is a content
+        // request
+        if (headerValue == null || headerValue.isEmpty()) {
+            if (isContentRequest && csrfParameter != null) {
+                String paramValue = req.getParameter(csrfParameter);
+                if (paramValue != null && paramValue.equals(token)) {
+                    return;
+                }
+            }
+
+            throw new CmisPermissionDeniedException("Invalid CSRF token!");
+        }
+
+        // check if a new token is requested
+        if (isRepositoryInfoRequest && FETCH_VALUE.equals(headerValue) && token == null) {
+            token = generateNewToken();
+            httpSession.setAttribute(CSRF_ATTR, token);
+            resp.addHeader(csrfHeader, token);
+            return;
+        }
+
+        // check if there is a token
+        if (token == null) {
+            throw new CmisPermissionDeniedException("Invalid CSRF token!");
+        }
+
+        // finally, check the token
+        if (!token.equals(headerValue)) {
+            throw new CmisPermissionDeniedException("Invalid CSRF token!");
+        }
+    }
+
+    private String generateNewToken() {
+        byte[] tokenBytes = new byte[16];
+        random.nextBytes(tokenBytes);
+
+        int ary = random.nextInt(hexArrays.length);
+
+        char[] token = new char[tokenBytes.length * 2];
+        for (int i = 0; i < tokenBytes.length; i++) {
+            int v = tokenBytes[i] & 0xFF;
+            token[i * 2] = hexArrays[ary][v >>> 4];
+            token[i * 2 + 1] = hexArrays[ary][v & 0x0F];
+        }
+
+        return new String(token);
+    }
+}