From c3cb1c85b95bf26c5bb946e44b249bbc841c9e82 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Mon, 27 May 2013 10:15:02 +0200
Subject: [PATCH] OO-615: implements a simple filter to allow CORS (cross
 origin resource sharing) but restricted to the rest api

---
 .../java/org/olat/core/helpers/Settings.java  |  9 ++
 .../olat/core/servlets/CrossOriginFilter.java | 86 +++++++++++++++++++
 .../resources/serviceconfig/brasatoconfig.xml |  1 +
 .../resources/serviceconfig/olat.properties   |  5 ++
 src/main/webapp-gae/WEB-INF/web.xml           | 10 +++
 src/main/webapp-jbossas7/WEB-INF/web.xml      | 10 +++
 src/main/webapp-tomcat/WEB-INF/web.xml        | 11 ++-
 7 files changed, 131 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/org/olat/core/servlets/CrossOriginFilter.java

diff --git a/src/main/java/org/olat/core/helpers/Settings.java b/src/main/java/org/olat/core/helpers/Settings.java
index ebef2b90dfa..17d8513e398 100644
--- a/src/main/java/org/olat/core/helpers/Settings.java
+++ b/src/main/java/org/olat/core/helpers/Settings.java
@@ -86,6 +86,7 @@ public class Settings implements Initializable, Destroyable, GenericEventListene
 	private static Date buildDate;
 	private static String repoRevision;
 	private static String patchRepoRevision;
+	private static String crossOriginFilter;
 	
 	/**
 	 * [used by spring]
@@ -447,6 +448,14 @@ public class Settings implements Initializable, Destroyable, GenericEventListene
 		return createServerURI() + WebappHelper.getServletContextPath();
 	}
 	
+	public static String getCrossOriginFilter() {
+		return crossOriginFilter;
+	}
+	
+	public void setCrossOriginFilter(String crossOriginFilter) {
+		Settings.crossOriginFilter = crossOriginFilter;
+	}
+	
 	/**
 	 * @return True if this is a JUnit test.
 	 * 
diff --git a/src/main/java/org/olat/core/servlets/CrossOriginFilter.java b/src/main/java/org/olat/core/servlets/CrossOriginFilter.java
new file mode 100644
index 00000000000..acdec93b4a5
--- /dev/null
+++ b/src/main/java/org/olat/core/servlets/CrossOriginFilter.java
@@ -0,0 +1,86 @@
+/**
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ */
+package org.olat.core.servlets;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.olat.core.helpers.Settings;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Allow cross origin for our javascript client
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class CrossOriginFilter implements Filter {
+
+	@Override
+	public void init(FilterConfig filterConfig) throws ServletException {
+		//
+	}
+	
+	@Override
+	public void destroy() {
+		//
+	}
+
+	@Override
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+		addHeaders(request, response);
+		chain.doFilter(request, response);
+		addHeaders(request, response);
+	}
+	
+	private void addHeaders(ServletRequest request, ServletResponse response) {
+		if(response instanceof HttpServletResponse) {
+			HttpServletRequest httpRequest = (HttpServletRequest)request;
+			HttpServletResponse httpResponse = (HttpServletResponse)response;
+			String origin = httpRequest.getHeader("origin");
+			if(isDomainAllowed(origin)) {
+				if(origin != null && !origin.isEmpty()) {
+					httpResponse.setHeader("Access-Control-Allow-Origin", origin);
+				}
+				String headers = httpRequest.getHeader("access-control-request-headers");
+				if(headers != null && !headers.isEmpty()) {
+					httpResponse.setHeader("Access-Control-Allow-Headers", headers);
+				}
+				httpResponse.setHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE, GET, OPTIONS");
+				httpResponse.setHeader("Access-Control-Max-Age", "1728000");
+
+				String method = httpRequest.getHeader("access-control-request-method");
+				if("OPTIONS".equals(method)) {
+					httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
+				}
+			}
+		}
+	}
+	
+	private boolean isDomainAllowed(String origin) {
+		String allowedDomains = Settings.getCrossOriginFilter();
+		if(StringHelper.containsNonWhitespace(allowedDomains) && StringHelper.containsNonWhitespace(origin)) {
+			if("*".equals(allowedDomains)) {
+				return true;
+			}
+			String[] domains = allowedDomains.split(",");
+			for(String domain:domains) {
+				if(domain.equals(origin)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/resources/serviceconfig/brasatoconfig.xml b/src/main/resources/serviceconfig/brasatoconfig.xml
index c2bc567f115..b88a076c4bf 100644
--- a/src/main/resources/serviceconfig/brasatoconfig.xml
+++ b/src/main/resources/serviceconfig/brasatoconfig.xml
@@ -87,6 +87,7 @@
 						<value>.*Lynx.*</value>					<!-- Lynx console browser (no js) -->
 					</list>
 				</property>
+				<property name="crossOriginFilter" value="${allow.cross.origin.domain}"/>
 				<!-- 
 					Set the system theme here. Make sure the directory webapp/WEB-INF/static/themes/YOURTHEME exists. 
 					This is only the default value in case no user configuration is found. Use the administration GUI to
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 9ddb18f9f08..63d1736ed97 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -434,6 +434,11 @@ server.modjk.enabled=false
 # OLAT JMX server port (must be unique per node in a cluster)
 jmx.rmi.port=3000
 
+#allow an other web site to use the REST API with Javascript
+#list of domains separated with , or * for allow all
+allow.cross.origin.domain=
+allow.cross.origin.domain.values=*,www.frentix.com
+
 ########################################################################
 # Database settings
 ########################################################################
diff --git a/src/main/webapp-gae/WEB-INF/web.xml b/src/main/webapp-gae/WEB-INF/web.xml
index 28e771dc555..ea5c9f695a4 100644
--- a/src/main/webapp-gae/WEB-INF/web.xml
+++ b/src/main/webapp-gae/WEB-INF/web.xml
@@ -88,6 +88,11 @@
 		<filter-class>org.olat.resource.accesscontrol.provider.paypal.PaypalIPNFilter</filter-class>
 	</filter>
 	
+	<filter>
+		<filter-name>CrossOriginFilter</filter-name>
+		<filter-class>org.olat.core.servlets.CrossOriginFilter</filter-class>
+	</filter>
+	
 	<filter>
 		<filter-name>RESTApiLoginFilter</filter-name>
 		<filter-class>org.olat.restapi.security.RestApiLoginFilter</filter-class>
@@ -110,6 +115,11 @@
 		<url-pattern>/paypal/*</url-pattern>
 	</filter-mapping>
 	
+	<filter-mapping>
+		<filter-name>CrossOriginFilter</filter-name>
+		<url-pattern>/restapi/*</url-pattern>
+	</filter-mapping>
+	
 	<filter-mapping>
 		<filter-name>RESTApiLoginFilter</filter-name>
 		<url-pattern>/restapi/*</url-pattern>
diff --git a/src/main/webapp-jbossas7/WEB-INF/web.xml b/src/main/webapp-jbossas7/WEB-INF/web.xml
index d19be54471a..768669de4ff 100644
--- a/src/main/webapp-jbossas7/WEB-INF/web.xml
+++ b/src/main/webapp-jbossas7/WEB-INF/web.xml
@@ -88,6 +88,11 @@
 		<filter-class>org.olat.resource.accesscontrol.provider.paypal.PaypalIPNFilter</filter-class>
 	</filter>
 	
+	<filter>
+		<filter-name>CrossOriginFilter</filter-name>
+		<filter-class>org.olat.core.servlets.CrossOriginFilter</filter-class>
+	</filter>
+	
 	<filter>
 		<filter-name>RESTApiLoginFilter</filter-name>
 		<filter-class>org.olat.restapi.security.RestApiLoginFilter</filter-class>
@@ -110,6 +115,11 @@
 		<url-pattern>/paypal/*</url-pattern>
 	</filter-mapping>
 	
+	<filter-mapping>
+		<filter-name>CrossOriginFilter</filter-name>
+		<url-pattern>/restapi/*</url-pattern>
+	</filter-mapping>
+	
 	<filter-mapping>
 		<filter-name>RESTApiLoginFilter</filter-name>
 		<url-pattern>/restapi/*</url-pattern>
diff --git a/src/main/webapp-tomcat/WEB-INF/web.xml b/src/main/webapp-tomcat/WEB-INF/web.xml
index 3aa223e1cf2..9f04e675c9b 100644
--- a/src/main/webapp-tomcat/WEB-INF/web.xml
+++ b/src/main/webapp-tomcat/WEB-INF/web.xml
@@ -83,6 +83,11 @@
 		<filter-class>org.olat.resource.accesscontrol.provider.paypal.PaypalIPNFilter</filter-class>
 	</filter>
 	
+	<filter>
+		<filter-name>CrossOriginFilter</filter-name>
+		<filter-class>org.olat.core.servlets.CrossOriginFilter</filter-class>
+	</filter>
+	
 	<filter>
 		<filter-name>RESTApiLoginFilter</filter-name>
 		<filter-class>org.olat.restapi.security.RestApiLoginFilter</filter-class>
@@ -94,11 +99,15 @@
 		<url-pattern>/paypal/*</url-pattern>
 	</filter-mapping>
 	
+	<filter-mapping>
+		<filter-name>CrossOriginFilter</filter-name>
+		<url-pattern>/restapi/*</url-pattern>
+	</filter-mapping>
+	
 	<filter-mapping>
 		<filter-name>RESTApiLoginFilter</filter-name>
 		<url-pattern>/restapi/*</url-pattern>
 	</filter-mapping>
-
 	
 	<!-- 3. Listeners -->
     <!-- triggers the above spring files to be processed by the spring framework  -->
-- 
GitLab