diff --git a/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ServerConstants.java b/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ServerConstants.java
index 9b8f909862..56067da213 100644
--- a/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ServerConstants.java
+++ b/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ServerConstants.java
@@ -38,5 +38,9 @@ public class ServerConstants {
public final static String JMX_HTTP_ENABLE = "jmx.http.enable";
public final static String JMX_HTTP_PORT = "jmx.http.port";
+
+ public static final String SERVER_ALLOW_DIR_LISTING = "server.allow.dir.list";
+ public static final String SERVER_ALLOW_HTTP_METHODS = "server.allow.http.methods";
+ public static final String SERVER_DISALLOW_HTTP_METHODS = "server.disallow.http.methods";
}
\ No newline at end of file
diff --git a/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java b/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java
index 5373c3f5a8..587ef50190 100644
--- a/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java
+++ b/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java
@@ -33,18 +33,17 @@
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.Enumeration;
import javax.management.Attribute;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
+import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
-import mx4j.tools.adaptor.http.HttpAdaptor;
-import mx4j.tools.adaptor.http.XSLTProcessor;
-
import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.security.ConstraintMapping;
@@ -61,6 +60,7 @@
import org.eclipse.jetty.server.session.AbstractSession;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.HashedSession;
+import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.security.Password;
import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -73,6 +73,7 @@
import org.jumpmind.symmetric.common.ServerConstants;
import org.jumpmind.symmetric.common.SystemConstants;
import org.jumpmind.symmetric.transport.TransportManagerFactory;
+import org.jumpmind.symmetric.web.HttpMethodFilter;
import org.jumpmind.symmetric.web.ServletUtils;
import org.jumpmind.symmetric.web.SymmetricEngineHolder;
import org.jumpmind.symmetric.web.WebConstants;
@@ -83,6 +84,9 @@
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
+import mx4j.tools.adaptor.http.HttpAdaptor;
+import mx4j.tools.adaptor.http.XSLTProcessor;
+
/**
* Start up SymmetricDS through an embedded Jetty instance.
*
@@ -149,6 +153,12 @@ public enum Mode {
protected String httpSslVerifiedServerNames = "all";
+ protected String allowDirListing = "false";
+
+ protected String disallowedMethods = "OPTIONS";
+
+ protected String allowedMethods = "";
+
protected boolean allowSelfSignedCerts = true;
public SymmetricWebServer() {
@@ -203,7 +213,9 @@ protected void initFromProperties() {
System.getProperty(ServerConstants.HTTPS_VERIFIED_SERVERS, httpSslVerifiedServerNames));
allowSelfSignedCerts = serverProperties.is(ServerConstants.HTTPS_ALLOW_SELF_SIGNED_CERTS,
Boolean.parseBoolean(System.getProperty(ServerConstants.HTTPS_ALLOW_SELF_SIGNED_CERTS, "" + allowSelfSignedCerts)));
-
+ allowDirListing = serverProperties.get(ServerConstants.SERVER_ALLOW_DIR_LISTING, "false");
+ allowedMethods = serverProperties.get(ServerConstants.SERVER_ALLOW_HTTP_METHODS, "");
+ disallowedMethods = serverProperties.get(ServerConstants.SERVER_DISALLOW_HTTP_METHODS, "OPTIONS");
}
public SymmetricWebServer start(int httpPort, int jmxPort, String propertiesUrl) throws Exception {
@@ -257,11 +269,17 @@ public SymmetricWebServer start(int httpPort, int securePort, int httpJmxPort, M
webapp.setContextPath(webHome);
webapp.setWar(webAppDir);
webapp.setResourceBase(webAppDir);
- // webapp.addServlet(DefaultServlet.class, "/*");
+
+ webapp.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", allowDirListing);
SessionManager sm = new SessionManager();
webapp.getSessionHandler().setSessionManager(sm);
+ FilterHolder filterHolder = new FilterHolder(HttpMethodFilter.class);
+ filterHolder.setInitParameter("server.allow.http.methods", allowedMethods);
+ filterHolder.setInitParameter("server.disallow.http.methods", disallowedMethods);
+ webapp.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
+
webapp.getServletContext().getContextHandler()
.setMaxFormContentSize(Integer.parseInt(System.getProperty("org.eclipse.jetty.server.Request.maxFormContentSize", "800000")));
webapp.getServletContext().getContextHandler()
@@ -388,25 +406,25 @@ protected Connector[] getConnectors(Server server, int port, int securePort, Mod
/* Prevent POODLE attack */
String ignoredProtocols = System.getProperty(SecurityConstants.SYSPROP_SSL_IGNORE_PROTOCOLS);
if (ignoredProtocols != null && ignoredProtocols.length() > 0) {
- String[] protocols = ignoredProtocols.split(",");
- sslConnectorFactory.addExcludeProtocols(protocols);
+ String[] protocols = ignoredProtocols.split(",");
+ sslConnectorFactory.addExcludeProtocols(protocols);
}
else {
- sslConnectorFactory.addExcludeProtocols("SSLv3");
+ sslConnectorFactory.addExcludeProtocols("SSLv3");
}
-
+
String ignoredCiphers = System.getProperty(SecurityConstants.SYSPROP_SSL_IGNORE_CIPHERS);
if (ignoredCiphers != null && ignoredCiphers.length() > 0) {
- String[] ciphers = ignoredCiphers.split(",");
- sslConnectorFactory.addExcludeCipherSuites(ciphers);
+ String[] ciphers = ignoredCiphers.split(",");
+ sslConnectorFactory.addExcludeCipherSuites(ciphers);
}
-
+
sslConnectorFactory.setCertAlias(System.getProperty(SecurityConstants.SYSPROP_KEYSTORE_CERT_ALIAS,
SecurityConstants.ALIAS_SYM_PRIVATE_KEY));
sslConnectorFactory.setKeyStore(securityService.getKeyStore());
sslConnectorFactory.setTrustStore(securityService.getTrustStore());
-
+
HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer());
@@ -593,9 +611,9 @@ public SessionManager() {
setLazyLoad(true);
setDeleteUnrestorableSessions(true);
setSessionCookie(getSessionCookie() + (httpPort > 0 ? httpPort
- : httpsPort));
+ : httpsPort));
}
-
+
@Override
protected AbstractSession newSession(HttpServletRequest request) {
return new Session(this, request);
diff --git a/symmetric-server/src/main/java/org/jumpmind/symmetric/web/HttpMethodFilter.java b/symmetric-server/src/main/java/org/jumpmind/symmetric/web/HttpMethodFilter.java
new file mode 100644
index 0000000000..6451de16bb
--- /dev/null
+++ b/symmetric-server/src/main/java/org/jumpmind/symmetric/web/HttpMethodFilter.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to JumpMind Inc under one or more contributor
+ * license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding
+ * copyright ownership. JumpMind Inc licenses this file
+ * to you under the GNU General Public License, version 3.0 (GPLv3)
+ * (the "License"); you may not use this file except in compliance
+ * with the License.
+ *
+ * You should have received a copy of the GNU General Public License,
+ * version 3.0 (GPLv3) along with this library; if not, see
+ * .
+ *
+ * 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.jumpmind.symmetric.web;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+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.apache.commons.lang.StringUtils;
+
+public class HttpMethodFilter implements Filter {
+
+ private Set allowedMethods = new HashSet();
+ private Set disallowedMethods = new HashSet();
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ String allowMethodsConfig = filterConfig.getInitParameter("server.allow.http.methods");
+ loadMethods(allowMethodsConfig, allowedMethods);
+ String disallowMethodsConfig = filterConfig.getInitParameter("server.disallow.http.methods");
+ loadMethods(disallowMethodsConfig, disallowedMethods);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ String method = httpRequest.getMethod().toUpperCase();
+
+ if (disallowedMethods.contains(method)) {
+ forbid(method, request, response);
+ } else if (!allowedMethods.isEmpty() && !allowedMethods.contains(method)) {
+ forbid(method, request, response);
+ } else {
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ protected void forbid(String method, ServletRequest request, ServletResponse response) throws IOException {
+ HttpServletResponse httpResponse = (HttpServletResponse)response;
+ httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Method " + method + " is not allowed.");
+ }
+
+ protected void loadMethods(String configuredValue, Set methods) {
+ if (!StringUtils.isEmpty(configuredValue)) {
+ String[] methodsSplit = configuredValue.split(",");
+ for (String method : methodsSplit) {
+ if (!StringUtils.isEmpty(method)) {
+ methods.add(method.toUpperCase());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+ // Empty.
+ }
+
+}