From cc161e7fd39752a2cc7d91cc7f1df5ba114f0991 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 23 Jun 2011 18:20:09 +0200 Subject: [PATCH] replace ssl and forward parameters with base url to fix #32 --- .../sonia/scm/config/ScmConfiguration.java | 96 +++++++++++++++++-- .../main/java/sonia/scm/util/HttpUtil.java | 27 +++++- .../main/java/sonia/scm/ScmServletModule.java | 4 +- .../rest/resources/RepositoryResource.java | 18 +--- .../{SSLFilter.java => BaseUrlFilter.java} | 55 +++++++++-- .../sonia/scm/web/cgi/DefaultCGIExecutor.java | 7 +- .../js/config/sonia.config.scmconfigpanel.js | 66 +++---------- 7 files changed, 184 insertions(+), 89 deletions(-) rename scm-webapp/src/main/java/sonia/scm/filter/{SSLFilter.java => BaseUrlFilter.java} (70%) diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index f4f174b24a..3c3cab687f 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -147,16 +147,20 @@ public class ScmConfiguration implements ListenerSupport this.servername = other.servername; this.dateFormat = other.dateFormat; this.pluginUrl = other.pluginUrl; - this.sslPort = other.sslPort; - this.enableSSL = other.enableSSL; - this.enablePortForward = other.enablePortForward; - this.forwardPort = other.forwardPort; this.anonymousAccessEnabled = other.anonymousAccessEnabled; this.adminUsers = other.adminUsers; this.adminGroups = other.adminGroups; this.enableProxy = other.enableProxy; this.proxyPort = other.proxyPort; this.proxyServer = other.proxyServer; + this.forceBaseUrl = other.forceBaseUrl; + this.baseUrl = other.baseUrl; + + // deprecated fields + this.sslPort = other.sslPort; + this.enableSSL = other.enableSSL; + this.enablePortForward = other.enablePortForward; + this.forwardPort = other.forwardPort; } /** @@ -195,6 +199,18 @@ public class ScmConfiguration implements ListenerSupport return adminUsers; } + /** + * Method description + * + * + * @return + * @since 1.5 + */ + public String getBaseUrl() + { + return baseUrl; + } + /** * Method description * @@ -211,7 +227,9 @@ public class ScmConfiguration implements ListenerSupport * * * @return + * @deprecated use {@link #getBaseUrl()} */ + @Deprecated public int getForwardPort() { return forwardPort; @@ -266,7 +284,9 @@ public class ScmConfiguration implements ListenerSupport * * * @return + * @deprecated use {@link #getBaseUrl()} and {@link #isForceBaseUrl()} */ + @Deprecated public int getSslPort() { return sslPort; @@ -288,7 +308,9 @@ public class ScmConfiguration implements ListenerSupport * * * @return + * @deprecated use {@link #getBaseUrl()} */ + @Deprecated public boolean isEnablePortForward() { return enablePortForward; @@ -310,12 +332,26 @@ public class ScmConfiguration implements ListenerSupport * * * @return + * @deprecated use {@link #getBaseUrl()} and {@link #isForceBaseUrl()} */ + @Deprecated public boolean isEnableSSL() { return enableSSL; } + /** + * Method description + * + * + * @return + * @since 1.5 + */ + public boolean isForceBaseUrl() + { + return forceBaseUrl; + } + //~--- set methods ---------------------------------------------------------- /** @@ -351,6 +387,18 @@ public class ScmConfiguration implements ListenerSupport this.anonymousAccessEnabled = anonymousAccessEnabled; } + /** + * Method description + * + * + * @param baseUrl + * @since 1.5 + */ + public void setBaseUrl(String baseUrl) + { + this.baseUrl = baseUrl; + } + /** * Method description * @@ -367,7 +415,9 @@ public class ScmConfiguration implements ListenerSupport * * * @param enablePortForward + * @deprecated use {@link #setBaseUrl(String)} */ + @Deprecated public void setEnablePortForward(boolean enablePortForward) { this.enablePortForward = enablePortForward; @@ -389,7 +439,9 @@ public class ScmConfiguration implements ListenerSupport * * * @param enableSSL + * @deprecated use {@link #setBaseUrl(String)} and {$link #setForceBaseUrl(boolean)} */ + @Deprecated public void setEnableSSL(boolean enableSSL) { this.enableSSL = enableSSL; @@ -399,8 +451,22 @@ public class ScmConfiguration implements ListenerSupport * Method description * * - * @param forwardPort + * @param forceBaseUrl + * @since 1.5 */ + public void setForceBaseUrl(boolean forceBaseUrl) + { + this.forceBaseUrl = forceBaseUrl; + } + + /** + * Method description + * + * + * @param forwardPort + * @deprecated use {@link #setBaseUrl(String)} + */ + @Deprecated public void setForwardPort(int forwardPort) { this.forwardPort = forwardPort; @@ -455,7 +521,9 @@ public class ScmConfiguration implements ListenerSupport * * * @param sslPort + * @deprecated use {@link #setBaseUrl(String)} and {$link #setForceBaseUrl(boolean)} */ + @Deprecated public void setSslPort(int sslPort) { this.sslPort = sslPort; @@ -473,10 +541,19 @@ public class ScmConfiguration implements ListenerSupport @XmlJavaTypeAdapter(XmlSetStringAdapter.class) private Set adminUsers; + /** Field description */ + @XmlElement(name = "base-url") + private String baseUrl; + /** Field description */ private boolean enableProxy = false; /** Field description */ + @XmlElement(name = "force-base-url") + private boolean forceBaseUrl; + + /** @deprecated use {@link $baseUrl} */ + @Deprecated private int forwardPort = 80; /** Field description */ @@ -492,13 +569,16 @@ public class ScmConfiguration implements ListenerSupport /** Field description */ private String servername = "localhost"; - /** Field description */ + /** @deprecated use {@link $baseUrl} and {$link $foreceBaseUrl} */ + @Deprecated private boolean enableSSL = false; - /** Field description */ + /** @deprecated use {@link $baseUrl} */ + @Deprecated private boolean enablePortForward = false; - /** Field description */ + /** @deprecated use {@link $baseUrl} and {$link $foreceBaseUrl} */ + @Deprecated private int sslPort = 8181; /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java index 23af768fc0..b497181fdf 100644 --- a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java @@ -83,6 +83,29 @@ public class HttpUtil //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @param configuration + * @param path + * + * @return + * @since 1.5 + */ + public static String getCompleteUrl(ScmConfiguration configuration, + String path) + { + String url = configuration.getBaseUrl(); + + if (url.endsWith("/") && path.startsWith("/")) + { + url = url.substring(0, url.length()); + } + + return url.concat(path); + } + /** * Method description * @@ -91,7 +114,9 @@ public class HttpUtil * @param request * * @return + * @deprecated use {@link #getCompleteUrl(sonia.scm.config.ScmConfiguration, java.lang.String)} */ + @Deprecated public static int getServerPort(ScmConfiguration configuration, HttpServletRequest request) { @@ -137,6 +162,6 @@ public class HttpUtil */ public static String getStrippedURI(HttpServletRequest request, String uri) { - return request.getRequestURI().substring(request.getContextPath().length()); + return uri.substring(request.getContextPath().length()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 5f23484ab2..efd5d60b43 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -45,8 +45,8 @@ import sonia.scm.cache.CacheManager; import sonia.scm.cache.EhCacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.filter.AdminSecurityFilter; +import sonia.scm.filter.BaseUrlFilter; import sonia.scm.filter.GZipFilter; -import sonia.scm.filter.SSLFilter; import sonia.scm.filter.SecurityFilter; import sonia.scm.group.GroupManager; import sonia.scm.group.xml.XmlGroupManager; @@ -225,7 +225,7 @@ public class ScmServletModule extends ServletModule * filter(PATTERN_PAGE, * PATTERN_STATIC_RESOURCES).through(StaticResourceFilter.class); */ - filter(PATTERN_ALL).through(SSLFilter.class); + filter(PATTERN_ALL).through(BaseUrlFilter.class); filterRegex(RESOURCE_REGEX).through(GZipFilter.class); filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class); filter(PATTERN_CONFIG, PATTERN_ADMIN).through(AdminSecurityFilter.class); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java index 36a5add717..0dc501c0b5 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java @@ -263,22 +263,10 @@ public class RepositoryResource if (handler != null) { - HttpServletRequest request = requestProvider.get(); - StringBuilder url = new StringBuilder(request.getScheme()); + String url = handler.createResourcePath(repository); - url.append("://").append(configuration.getServername()); - url.append(":").append(HttpUtil.getServerPort(configuration, request)); - - String ctxPath = request.getContextPath(); - - if (ctxPath.endsWith("/")) - { - ctxPath = ctxPath.substring(0, ctxPath.length() - 1); - } - - url.append(ctxPath); - url.append(handler.createResourcePath(repository)); - repository.setUrl(url.toString()); + url = HttpUtil.getCompleteUrl(configuration, url); + repository.setUrl(url); } } diff --git a/scm-webapp/src/main/java/sonia/scm/filter/SSLFilter.java b/scm-webapp/src/main/java/sonia/scm/filter/BaseUrlFilter.java similarity index 70% rename from scm-webapp/src/main/java/sonia/scm/filter/SSLFilter.java rename to scm-webapp/src/main/java/sonia/scm/filter/BaseUrlFilter.java index 426160fd66..1920943f57 100644 --- a/scm-webapp/src/main/java/sonia/scm/filter/SSLFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/filter/BaseUrlFilter.java @@ -39,6 +39,8 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import sonia.scm.config.ScmConfiguration; +import sonia.scm.util.HttpUtil; +import sonia.scm.util.Util; import sonia.scm.web.filter.HttpFilter; //~--- JDK imports ------------------------------------------------------------ @@ -55,7 +57,7 @@ import javax.servlet.http.HttpServletResponse; * @author Sebastian Sdorra */ @Singleton -public class SSLFilter extends HttpFilter +public class BaseUrlFilter extends HttpFilter { /** @@ -65,7 +67,7 @@ public class SSLFilter extends HttpFilter * @param configuration */ @Inject - public SSLFilter(ScmConfiguration configuration) + public BaseUrlFilter(ScmConfiguration configuration) { this.configuration = configuration; } @@ -88,20 +90,59 @@ public class SSLFilter extends HttpFilter HttpServletResponse response, FilterChain chain) throws IOException, ServletException { - if (request.isSecure() ||!configuration.isEnableSSL()) + if (Util.isEmpty(configuration.getBaseUrl())) + { + configuration.setBaseUrl(createDefaultBaseUrl(request)); + } + + if (!configuration.isForceBaseUrl() || isBaseUrl(request)) { chain.doFilter(request, response); } else { - StringBuilder url = new StringBuilder("https://"); + String url = HttpUtil.getCompleteUrl(configuration, + HttpUtil.getStrippedURI(request)); - url.append(request.getServerName()).append(":"); - url.append(configuration.getSslPort()).append(request.getRequestURI()); - response.sendRedirect(url.toString()); + response.sendRedirect(url); } } + /** + * Method description + * + * + * @param request + * + * @return + */ + private String createDefaultBaseUrl(HttpServletRequest request) + { + StringBuilder sb = new StringBuilder(request.getScheme()); + + sb.append("://").append(request.getServerName()).append(":"); + sb.append(String.valueOf(request.getServerPort())); + sb.append(request.getContextPath()); + + return sb.toString(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param request + * + * @return + */ + private boolean isBaseUrl(HttpServletRequest request) + { + return request.getRequestURL().toString().startsWith( + configuration.getBaseUrl()); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java index 9a09ff37ea..840e3ef74a 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java +++ b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java @@ -40,7 +40,6 @@ import org.slf4j.LoggerFactory; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; -import sonia.scm.util.HttpUtil; import sonia.scm.util.IOUtil; import sonia.scm.util.SystemUtil; import sonia.scm.util.Util; @@ -211,7 +210,8 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor private EnvList createEnvironment() { String pathInfo = request.getPathInfo(); - int serverPort = HttpUtil.getServerPort(configuration, request); + + // int serverPort = HttpUtil.getServerPort(configuration, request); String scriptName = request.getRequestURI().substring(0, request.getRequestURI().length() - pathInfo.length()); String scriptPath = context.getRealPath(scriptName); @@ -260,7 +260,8 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor env.set(ENV_SCRIPT_NAME, scriptName); env.set(ENV_SCRIPT_FILENAME, scriptPath); env.set(ENV_SERVER_NAME, Util.nonNull(request.getServerName())); - env.set(ENV_SERVER_PORT, Integer.toString(serverPort)); + + // env.set(ENV_SERVER_PORT, Integer.toString(serverPort)); env.set(ENV_SERVER_PROTOCOL, Util.nonNull(request.getProtocol())); env.set( ENV_SERVER_SOFTWARE, diff --git a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js index 74d2a722a2..79091bec1e 100644 --- a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js @@ -54,6 +54,8 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ enableProxyText: 'Enable Proxy', proxyServerText: 'Proxy Server', proxyPortText: 'Proxy Port', + baseUrlText: 'Base Url', + forceBaseUrlText: 'Force Base Url', // help @@ -74,6 +76,8 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ enableProxyHelpText: 'Enable Proxy', proxyServerHelpText: 'The proxy server', proxyPortHelpText: 'The proxy port', + baseUrlHelpText: 'The url of the application (with context path) i.e. http://localhost:8080/scm', + forceBaseUrlHelpText: 'Redirects to the base url if the request comes from a other url', initComponent: function(){ @@ -84,35 +88,22 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ title: this.titleText, items: [{ xtype: 'textfield', - fieldLabel: this.servnameText, - name: 'servername', - helpText: this.servernameHelpText, + fieldLabel: this.baseUrlText, + name: 'base-url', + helpText: this.baseUrlHelpText, allowBlank: false + },{ + xtype: 'checkbox', + fieldLabel: this.forceBaseUrlText, + name: 'force-base-url', + inputValue: 'true', + helpText: this.forceBaseUrlHelpText },{ xtype: 'textfield', fieldLabel: this.dateFormatText, name: 'dateFormat', helpText: this.dateFormatHelpText, allowBlank: false - },{ - xtype: 'checkbox', - fieldLabel: this.enableForwardingText, - name: 'enablePortForward', - inputValue: 'true', - helpText: this.enableForwardingHelpText, - listeners: { - check: function(){ - Ext.getCmp('serverport').setDisabled( ! this.checked ); - } - } - },{ - id: 'serverport', - xtype: 'numberfield', - fieldLabel: this.forwardPortText, - name: 'forwardPort', - disabled: true, - allowBlank: false, - helpText: this.forwardPortHelpText },{ xtype: 'textfield', fieldLabel: this.pluginRepositoryText, @@ -126,25 +117,6 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ name: 'anonymousAccessEnabled', inputValue: 'true', helpText: this.allowAnonymousAccessHelpText - },{ - xtype: 'checkbox', - fieldLabel: this.enableSSLText, - name: 'enableSSL', - inputValue: 'true', - helpText: this.enableSSLHelpText, - listeners: { - check: function(){ - Ext.getCmp('sslPort').setDisabled( ! this.checked ); - } - } - },{ - id: 'sslPort', - xtype: 'numberfield', - fieldLabel: this.sslPortText, - name: 'sslPort', - disabled: true, - allowBlank: false, - helpText: this.sslPortHelpText },{ xtype: 'checkbox', fieldLabel: this.enableProxyText, @@ -188,12 +160,6 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ }], onSubmit: function(values){ - if ( ! values.enableSSL ){ - values.sslPort = Ext.getCmp('sslPort').getValue(); - } - if ( ! values.enablePortForward ){ - values.forwardPort = Ext.getCmp('serverport').getValue(); - } this.el.mask(this.submitText); Ext.Ajax.request({ url: restUrl + 'config.json', @@ -225,12 +191,6 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ success: function(response){ var obj = Ext.decode(response.responseText); this.load(obj); - if ( obj.enablePortForward ){ - Ext.getCmp('serverport').setDisabled(false); - } - if ( obj.enableSSL ){ - Ext.getCmp('sslPort').setDisabled(false); - } if ( obj.enableProxy ){ Ext.getCmp('proxyServer').setDisabled(false); Ext.getCmp('proxyPort').setDisabled(false);