You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2021/12/14 14:39:05 UTC
[activemq-artemis] branch main updated: ARTEMIS-3574 multiple bindings for embedded webserver
This is an automated email from the ASF dual-hosted git repository.
clebertsuconic pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/main by this push:
new 1823343 ARTEMIS-3574 multiple bindings for embedded webserver
1823343 is described below
commit 182334359c0f8f63a7cd8b69a42d9b4cee48dc9c
Author: Marlon Müller <ma...@united-internet.de>
AuthorDate: Wed Oct 27 15:21:04 2021 +0200
ARTEMIS-3574 multiple bindings for embedded webserver
* Add BindingDTO to allow configuring multiple addresses to listen on
* Start a new ServerConnector for each binding and deploy the corresponding web-applications
* Update documentation and tests
* Add tests to verify old and new configuration style produce equal results
---
.../cli/commands/etc/bootstrap-web-settings.txt | 10 +-
.../org/apache/activemq/cli/test/ArtemisTest.java | 9 +-
.../dto/{WebServerDTO.java => BindingDTO.java} | 65 ++++----
.../apache/activemq/artemis/dto/WebServerDTO.java | 100 +++++-------
.../activemq/artemis/dto/test/BindingDTOTest.java | 85 ++++++++++
.../artemis/dto/test/WebServerDTOTest.java | 105 ++++++++-----
.../artemis/component/WebServerComponent.java | 172 ++++++++++++---------
.../activemq/cli/test/WebServerComponentTest.java | 106 ++++++++-----
.../src/test/resources/bootstrap_secure_web.xml | 6 +-
artemis-web/src/test/resources/bootstrap_web.xml | 6 +-
.../src/test/resources/bootstrap_web_codec.xml | 6 +-
..._web_codec.xml => bootstrap_web_old_config.xml} | 4 +-
docs/user-manual/en/masking-passwords.md | 10 +-
docs/user-manual/en/security.md | 34 ++--
docs/user-manual/en/using-server.md | 10 +-
docs/user-manual/en/web-server.md | 43 ++++--
.../main/resources/activemq/server0/bootstrap.xml | 8 +-
.../artemis-jms-bridge/readme.md | 3 +-
.../cluster/failover/ReplicatedFailoverTest.java | 12 +-
...orumNettyNoGroupNameReplicatedFailoverTest.java | 13 +-
.../main/resources/containerService/bootstrap.xml | 10 +-
21 files changed, 497 insertions(+), 320 deletions(-)
diff --git a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/bootstrap-web-settings.txt b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/bootstrap-web-settings.txt
index e863c1a..4c56188 100644
--- a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/bootstrap-web-settings.txt
+++ b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/bootstrap-web-settings.txt
@@ -1,6 +1,8 @@
<!-- The web server is only bound to localhost by default -->
- <web bind="${web.protocol}://${http.host}:${http.port}" path="web"${extra.web.attributes}>
- <app url="activemq-branding" war="activemq-branding.war"/>
- <app url="artemis-plugin" war="artemis-plugin.war"/>
- <app url="console" war="console.war"/>
+ <web path="web"${extra.web.attributes}>
+ <binding uri="${web.protocol}://${http.host}:${http.port}">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ <app url="artemis-plugin" war="artemis-plugin.war"/>
+ <app url="console" war="console.war"/>
+ </binding>
</web>
diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
index f453cb6..e0728f7 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
@@ -254,8 +254,9 @@ public class ArtemisTest extends CliTestBase {
assertTrue(bootstrapFile.exists());
Document config = parseXml(bootstrapFile);
Element webElem = (Element) config.getElementsByTagName("web").item(0);
+ Element bindingElem = (Element) webElem.getElementsByTagName("binding").item(0);
- String bindAttr = webElem.getAttribute("bind");
+ String bindAttr = bindingElem.getAttribute("uri");
String bindStr = "http://" + Create.HTTP_HOST + ":" + Create.HTTP_PORT;
assertEquals(bindAttr, bindStr);
@@ -273,8 +274,9 @@ public class ArtemisTest extends CliTestBase {
assertTrue(bootstrapFile.exists());
config = parseXml(bootstrapFile);
webElem = (Element) config.getElementsByTagName("web").item(0);
+ bindingElem = (Element) webElem.getElementsByTagName("binding").item(0);
- bindAttr = webElem.getAttribute("bind");
+ bindAttr = bindingElem.getAttribute("uri");
bindStr = "https://localhost:" + Create.HTTP_PORT;
assertEquals(bindAttr, bindStr);
@@ -299,8 +301,9 @@ public class ArtemisTest extends CliTestBase {
config = parseXml(bootstrapFile);
webElem = (Element) config.getElementsByTagName("web").item(0);
+ bindingElem = (Element) webElem.getElementsByTagName("binding").item(0);
- bindAttr = webElem.getAttribute("bind");
+ bindAttr = bindingElem.getAttribute("uri");
bindStr = "https://localhost:" + Create.HTTP_PORT;
assertEquals(bindAttr, bindStr);
diff --git a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/BindingDTO.java
similarity index 89%
copy from artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
copy to artemis-dto/src/main/java/org/apache/activemq/artemis/dto/BindingDTO.java
index 7492085..32cfcb9 100644
--- a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
+++ b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/BindingDTO.java
@@ -25,15 +25,15 @@ import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
-@XmlRootElement(name = "web")
+@XmlRootElement(name = "binding")
@XmlAccessorType(XmlAccessType.FIELD)
-public class WebServerDTO extends ComponentDTO {
+public class BindingDTO {
@XmlAttribute
- public String bind;
+ public String uri;
- @XmlAttribute(required = true)
- public String path;
+ @XmlElementRef
+ public List<AppDTO> apps;
@XmlAttribute
public Boolean clientAuth;
@@ -48,21 +48,6 @@ public class WebServerDTO extends ComponentDTO {
public String trustStorePath;
@XmlAttribute
- public String customizer;
-
- @XmlElementRef
- public List<AppDTO> apps;
-
- @XmlElementRef(required = false)
- public RequestLogDTO requestLog;
-
- @XmlAttribute
- private String keyStorePassword;
-
- @XmlAttribute
- private String trustStorePassword;
-
- @XmlAttribute
private String includedTLSProtocols;
@XmlAttribute
@@ -74,9 +59,11 @@ public class WebServerDTO extends ComponentDTO {
@XmlAttribute
private String excludedCipherSuites;
- public WebServerDTO() {
- componentClassName = "org.apache.activemq.artemis.component.WebServerComponent";
- }
+ @XmlAttribute
+ private String keyStorePassword;
+
+ @XmlAttribute
+ private String trustStorePassword;
public String getKeyStorePassword() throws Exception {
return getPassword(this.keyStorePassword);
@@ -98,22 +85,6 @@ public class WebServerDTO extends ComponentDTO {
this.trustStorePassword = trustStorePassword;
}
- private String[] unmarshalArray(String text) {
- if (text == null) {
- return null;
- }
-
- return text.split(",");
- }
-
- private String marshalArray(String[] array) {
- if (array == null) {
- return null;
- }
-
- return String.join(",", array);
- }
-
public String[] getIncludedTLSProtocols() {
return unmarshalArray(includedTLSProtocols);
}
@@ -145,4 +116,20 @@ public class WebServerDTO extends ComponentDTO {
public void setExcludedCipherSuites(String... cipherSuites) {
excludedCipherSuites = marshalArray(cipherSuites);
}
+
+ private String[] unmarshalArray(String text) {
+ if (text == null) {
+ return null;
+ }
+
+ return text.split(",");
+ }
+
+ private String marshalArray(String[] array) {
+ if (array == null || (array.length == 1 && array[0] == null)) {
+ return null;
+ }
+
+ return String.join(",", array);
+ }
}
diff --git a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
index 7492085..b6b6487 100644
--- a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
+++ b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
@@ -16,34 +16,38 @@
*/
package org.apache.activemq.artemis.dto;
-import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
-
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Collections;
import java.util.List;
@XmlRootElement(name = "web")
@XmlAccessorType(XmlAccessType.FIELD)
public class WebServerDTO extends ComponentDTO {
+ @Deprecated
@XmlAttribute
public String bind;
@XmlAttribute(required = true)
public String path;
+ @Deprecated
@XmlAttribute
public Boolean clientAuth;
+ @Deprecated
@XmlAttribute
public String passwordCodec;
+ @Deprecated
@XmlAttribute
public String keyStorePath;
+ @Deprecated
@XmlAttribute
public String trustStorePath;
@@ -51,26 +55,36 @@ public class WebServerDTO extends ComponentDTO {
public String customizer;
@XmlElementRef
+ private List<BindingDTO> bindings;
+
+ @Deprecated
+ @XmlElementRef
public List<AppDTO> apps;
@XmlElementRef(required = false)
public RequestLogDTO requestLog;
+ @Deprecated
@XmlAttribute
private String keyStorePassword;
+ @Deprecated
@XmlAttribute
private String trustStorePassword;
+ @Deprecated
@XmlAttribute
private String includedTLSProtocols;
+ @Deprecated
@XmlAttribute
private String excludedTLSProtocols;
+ @Deprecated
@XmlAttribute
private String includedCipherSuites;
+ @Deprecated
@XmlAttribute
private String excludedCipherSuites;
@@ -78,71 +92,35 @@ public class WebServerDTO extends ComponentDTO {
componentClassName = "org.apache.activemq.artemis.component.WebServerComponent";
}
- public String getKeyStorePassword() throws Exception {
- return getPassword(this.keyStorePassword);
- }
-
- private String getPassword(String password) throws Exception {
- return PasswordMaskingUtil.resolveMask(password, this.passwordCodec);
- }
-
- public void setKeyStorePassword(String keyStorePassword) {
- this.keyStorePassword = keyStorePassword;
- }
-
- public String getTrustStorePassword() throws Exception {
- return getPassword(this.trustStorePassword);
- }
-
- public void setTrustStorePassword(String trustStorePassword) {
- this.trustStorePassword = trustStorePassword;
- }
-
- private String[] unmarshalArray(String text) {
- if (text == null) {
- return null;
- }
-
- return text.split(",");
- }
-
- private String marshalArray(String[] array) {
- if (array == null) {
- return null;
+ public List<BindingDTO> getBindings() {
+ if (bindings == null || bindings.isEmpty()) {
+ return Collections.singletonList(convertToBindingDTO());
}
-
- return String.join(",", array);
- }
-
- public String[] getIncludedTLSProtocols() {
- return unmarshalArray(includedTLSProtocols);
- }
-
- public void setIncludedTLSProtocols(String... protocols) {
- includedTLSProtocols = marshalArray(protocols);
- }
-
- public String[] getExcludedTLSProtocols() {
- return unmarshalArray(excludedTLSProtocols);
- }
-
- public void setExcludedTLSProtocols(String... protocols) {
- excludedTLSProtocols = marshalArray(protocols);
- }
-
- public String[] getIncludedCipherSuites() {
- return unmarshalArray(includedCipherSuites);
+ return bindings;
}
- public void setIncludedCipherSuites(String... cipherSuites) {
- includedCipherSuites = marshalArray(cipherSuites);
+ public void setBindings(List<BindingDTO> bindings) {
+ this.bindings = bindings;
}
- public String[] getExcludedCipherSuites() {
- return unmarshalArray(excludedCipherSuites);
+ private BindingDTO convertToBindingDTO() {
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = bind;
+ bindingDTO.apps = apps;
+ bindingDTO.clientAuth = clientAuth;
+ bindingDTO.passwordCodec = passwordCodec;
+ bindingDTO.keyStorePath = keyStorePath;
+ bindingDTO.setKeyStorePassword(keyStorePassword);
+ bindingDTO.trustStorePath = trustStorePath;
+ bindingDTO.setTrustStorePassword(trustStorePassword);
+ bindingDTO.setIncludedTLSProtocols(includedTLSProtocols);
+ bindingDTO.setExcludedTLSProtocols(excludedTLSProtocols);
+ bindingDTO.setIncludedCipherSuites(includedCipherSuites);
+ bindingDTO.setExcludedCipherSuites(excludedCipherSuites);
+ return bindingDTO;
}
- public void setExcludedCipherSuites(String... cipherSuites) {
- excludedCipherSuites = marshalArray(cipherSuites);
+ public BindingDTO getDefaultBinding() {
+ return getBindings().get(0);
}
}
diff --git a/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/BindingDTOTest.java b/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/BindingDTOTest.java
new file mode 100644
index 0000000..728232f
--- /dev/null
+++ b/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/BindingDTOTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.activemq.artemis.dto.test;
+
+import org.apache.activemq.artemis.dto.BindingDTO;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BindingDTOTest extends Assert {
+
+ @Test
+ public void testDefault() {
+ BindingDTO binding = new BindingDTO();
+
+ Assert.assertNull(binding.getIncludedTLSProtocols());
+ Assert.assertNull(binding.getExcludedTLSProtocols());
+ Assert.assertNull(binding.getIncludedCipherSuites());
+ Assert.assertNull(binding.getExcludedCipherSuites());
+ }
+
+ @Test
+ public void testValues() {
+ BindingDTO binding = new BindingDTO();
+
+ binding.setIncludedTLSProtocols("TLSv1.2");
+ Assert.assertArrayEquals(new String[] {"TLSv1.2"}, binding.getIncludedTLSProtocols());
+
+ binding.setExcludedTLSProtocols("TLSv1,TLSv1.1");
+ Assert.assertArrayEquals(new String[] {"TLSv1", "TLSv1.1"}, binding.getExcludedTLSProtocols());
+
+ binding.setIncludedCipherSuites( "^SSL_.*$");
+ Assert.assertArrayEquals(new String[] {"^SSL_.*$"}, binding.getIncludedCipherSuites());
+
+ binding.setExcludedCipherSuites( "^.*_(MD5|SHA|SHA1)$,^TLS_RSA_.*$,^.*_NULL_.*$,^.*_anon_.*$");
+ Assert.assertArrayEquals(new String[] {"^.*_(MD5|SHA|SHA1)$", "^TLS_RSA_.*$", "^.*_NULL_.*$", "^.*_anon_.*$"}, binding.getExcludedCipherSuites());
+ }
+
+ @Test
+ public void testEmptyValues() {
+ BindingDTO binding = new BindingDTO();
+
+ binding.setIncludedTLSProtocols("");
+ Assert.assertArrayEquals(new String[] {""}, binding.getIncludedTLSProtocols());
+
+ binding.setExcludedTLSProtocols("");
+ Assert.assertArrayEquals(new String[] {""}, binding.getExcludedTLSProtocols());
+
+ binding.setIncludedCipherSuites("");
+ Assert.assertArrayEquals(new String[] {""}, binding.getIncludedCipherSuites());
+
+ binding.setExcludedCipherSuites("");
+ Assert.assertArrayEquals(new String[] {""}, binding.getExcludedCipherSuites());
+ }
+
+ @Test
+ public void testNullValues() {
+ BindingDTO binding = new BindingDTO();
+
+ binding.setIncludedTLSProtocols(null);
+ Assert.assertNull(binding.getIncludedTLSProtocols());
+
+ binding.setExcludedTLSProtocols(null);
+ Assert.assertNull(binding.getExcludedTLSProtocols());
+
+ binding.setIncludedCipherSuites(null);
+ Assert.assertNull(binding.getIncludedCipherSuites());
+
+ binding.setExcludedCipherSuites(null);
+ Assert.assertNull(binding.getExcludedCipherSuites());
+ }
+}
diff --git a/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/WebServerDTOTest.java b/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/WebServerDTOTest.java
index bd51f6f..b3d3e2a 100644
--- a/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/WebServerDTOTest.java
+++ b/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/test/WebServerDTOTest.java
@@ -16,70 +16,95 @@
*/
package org.apache.activemq.artemis.dto.test;
+import org.apache.activemq.artemis.dto.BindingDTO;
import org.apache.activemq.artemis.dto.WebServerDTO;
import org.junit.Assert;
import org.junit.Test;
-public class WebServerDTOTest extends Assert {
+import java.util.Collections;
+import java.util.List;
+
+public class WebServerDTOTest {
@Test
- public void testDefault() {
+ public void testDefault() throws Exception {
WebServerDTO webServer = new WebServerDTO();
- Assert.assertNull(webServer.getIncludedTLSProtocols());
- Assert.assertNull(webServer.getExcludedTLSProtocols());
- Assert.assertNull(webServer.getIncludedCipherSuites());
- Assert.assertNull(webServer.getExcludedCipherSuites());
+ Assert.assertNotNull(webServer.getBindings());
+ Assert.assertEquals(1, webServer.getBindings().size());
+ Assert.assertNotNull(webServer.getDefaultBinding());
+
+ BindingDTO defaultBinding = webServer.getDefaultBinding();
+ Assert.assertNull(defaultBinding.uri);
+ Assert.assertNull(defaultBinding.apps);
+ Assert.assertNull(defaultBinding.clientAuth);
+ Assert.assertNull(defaultBinding.passwordCodec);
+ Assert.assertNull(defaultBinding.keyStorePath);
+ Assert.assertNull(defaultBinding.trustStorePath);
+ Assert.assertNull(defaultBinding.getIncludedTLSProtocols());
+ Assert.assertNull(defaultBinding.getExcludedTLSProtocols());
+ Assert.assertNull(defaultBinding.getIncludedCipherSuites());
+ Assert.assertNull(defaultBinding.getExcludedCipherSuites());
+ Assert.assertNull(defaultBinding.getKeyStorePassword());
+ Assert.assertNull(defaultBinding.getTrustStorePassword());
}
@Test
- public void testValues() {
+ public void testWebServerConfig() {
WebServerDTO webServer = new WebServerDTO();
+ webServer.bind = "http://localhost:0";
- webServer.setIncludedTLSProtocols("TLSv1.2");
- Assert.assertArrayEquals(new String[] {"TLSv1.2"}, webServer.getIncludedTLSProtocols());
-
- webServer.setExcludedTLSProtocols("TLSv1,TLSv1.1");
- Assert.assertArrayEquals(new String[] {"TLSv1", "TLSv1.1"}, webServer.getExcludedTLSProtocols());
-
- webServer.setIncludedCipherSuites( "^SSL_.*$");
- Assert.assertArrayEquals(new String[] {"^SSL_.*$"}, webServer.getIncludedCipherSuites());
-
- webServer.setExcludedCipherSuites( "^.*_(MD5|SHA|SHA1)$,^TLS_RSA_.*$,^.*_NULL_.*$,^.*_anon_.*$");
- Assert.assertArrayEquals(new String[] {"^.*_(MD5|SHA|SHA1)$", "^TLS_RSA_.*$", "^.*_NULL_.*$", "^.*_anon_.*$"}, webServer.getExcludedCipherSuites());
+ Assert.assertNotNull(webServer.getBindings());
+ Assert.assertEquals(1, webServer.getBindings().size());
+ Assert.assertNotNull(webServer.getDefaultBinding());
+ Assert.assertEquals("http://localhost:0", webServer.getDefaultBinding().uri);
}
@Test
- public void testEmptyValues() {
- WebServerDTO webServer = new WebServerDTO();
-
- webServer.setIncludedTLSProtocols("");
- Assert.assertArrayEquals(new String[] {""}, webServer.getIncludedTLSProtocols());
-
- webServer.setExcludedTLSProtocols("");
- Assert.assertArrayEquals(new String[] {""}, webServer.getExcludedTLSProtocols());
+ public void testWebServerWithBinding() {
+ BindingDTO binding = new BindingDTO();
+ binding.uri = "http://localhost:0";
- webServer.setIncludedCipherSuites("");
- Assert.assertArrayEquals(new String[] {""}, webServer.getIncludedCipherSuites());
+ WebServerDTO webServer = new WebServerDTO();
+ webServer.setBindings(Collections.singletonList(binding));
- webServer.setExcludedCipherSuites("");
- Assert.assertArrayEquals(new String[] {""}, webServer.getExcludedCipherSuites());
+ Assert.assertNotNull(webServer.getBindings());
+ Assert.assertEquals(1, webServer.getBindings().size());
+ Assert.assertNotNull(webServer.getDefaultBinding());
+ Assert.assertEquals("http://localhost:0", webServer.getDefaultBinding().uri);
}
@Test
- public void testNullValues() {
- WebServerDTO webServer = new WebServerDTO();
+ public void testWebServerWithMultipleBindings() {
+ BindingDTO binding1 = new BindingDTO();
+ binding1.uri = "http://localhost:0";
+ BindingDTO binding2 = new BindingDTO();
+ binding2.uri = "http://localhost:1";
- webServer.setIncludedTLSProtocols(null);
- Assert.assertNull(webServer.getIncludedTLSProtocols());
+ WebServerDTO webServer = new WebServerDTO();
+ webServer.setBindings(List.of(binding1, binding2));
+
+ Assert.assertNotNull(webServer.getBindings());
+ Assert.assertEquals(2, webServer.getBindings().size());
+ Assert.assertNotNull(webServer.getDefaultBinding());
+ Assert.assertEquals("http://localhost:0", webServer.getDefaultBinding().uri);
+ Assert.assertEquals("http://localhost:0", webServer.getBindings().get(0).uri);
+ Assert.assertEquals("http://localhost:1", webServer.getBindings().get(1).uri);
+ }
- webServer.setExcludedTLSProtocols(null);
- Assert.assertNull(webServer.getExcludedTLSProtocols());
+ @Test
+ public void testWebServerConfigAndBinding() {
+ BindingDTO binding = new BindingDTO();
+ binding.uri = "http://localhost:0";
- webServer.setIncludedCipherSuites(null);
- Assert.assertNull(webServer.getIncludedCipherSuites());
+ WebServerDTO webServer = new WebServerDTO();
+ webServer.bind = "http://localhost:1";
+ webServer.setBindings(Collections.singletonList(binding));
- webServer.setExcludedCipherSuites(null);
- Assert.assertNull(webServer.getExcludedCipherSuites());
+ Assert.assertNotNull(webServer.getBindings());
+ Assert.assertEquals(1, webServer.getBindings().size());
+ Assert.assertNotNull(webServer.getDefaultBinding());
+ Assert.assertEquals("http://localhost:0", webServer.getDefaultBinding().uri);
}
+
}
diff --git a/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java b/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
index 98b580a..b708709 100644
--- a/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
+++ b/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
@@ -16,25 +16,14 @@
*/
package org.apache.activemq.artemis.component;
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Locale;
-
import org.apache.activemq.artemis.ActiveMQWebLogger;
import org.apache.activemq.artemis.components.ExternalComponent;
import org.apache.activemq.artemis.dto.AppDTO;
+import org.apache.activemq.artemis.dto.BindingDTO;
import org.apache.activemq.artemis.dto.ComponentDTO;
import org.apache.activemq.artemis.dto.WebServerDTO;
import org.eclipse.jetty.security.DefaultAuthenticatorFactory;
import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NCSARequestLog;
@@ -53,6 +42,16 @@ import org.eclipse.jetty.webapp.WebAppContext;
import org.jboss.logging.Logger;
import javax.servlet.DispatcherType;
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
public class WebServerComponent implements ExternalComponent {
@@ -61,19 +60,17 @@ public class WebServerComponent implements ExternalComponent {
private Server server;
private HandlerList handlers;
private WebServerDTO webServerConfig;
- private URI uri;
- private String consoleUrl;
+ private final List<String> consoleUrls = new ArrayList<>();
+ private final List<String> jolokiaUrls = new ArrayList<>();
private List<WebAppContext> webContexts;
- private ServerConnector connector;
+ private ServerConnector[] connectors;
private Path artemisHomePath;
private Path temporaryWarDir;
@Override
public void configure(ComponentDTO config, String artemisInstance, String artemisHome) throws Exception {
webServerConfig = (WebServerDTO) config;
- uri = new URI(webServerConfig.bind);
server = new Server();
- String scheme = uri.getScheme();
HttpConfiguration httpConfiguration = new HttpConfiguration();
@@ -85,49 +82,63 @@ public class WebServerComponent implements ExternalComponent {
}
}
- if ("https".equals(scheme)) {
- SslContextFactory.Server sslFactory = new SslContextFactory.Server();
- sslFactory.setKeyStorePath(webServerConfig.keyStorePath == null ? artemisInstance + "/etc/keystore.jks" : webServerConfig.keyStorePath);
- sslFactory.setKeyStorePassword(webServerConfig.getKeyStorePassword() == null ? "password" : webServerConfig.getKeyStorePassword());
- String[] ips = sslFactory.getIncludeProtocols();
+ List<BindingDTO> bindings = webServerConfig.getBindings();
+ connectors = new ServerConnector[bindings.size()];
+ String[] virtualHosts = new String[bindings.size()];
- if (webServerConfig.getIncludedTLSProtocols() != null) {
- sslFactory.setIncludeProtocols(webServerConfig.getIncludedTLSProtocols());
- }
- if (webServerConfig.getExcludedTLSProtocols() != null) {
- sslFactory.setExcludeProtocols(webServerConfig.getExcludedTLSProtocols());
- }
- if (webServerConfig.getIncludedCipherSuites() != null) {
- sslFactory.setIncludeCipherSuites(webServerConfig.getIncludedCipherSuites());
- }
- if (webServerConfig.getExcludedCipherSuites() != null) {
- sslFactory.setExcludeCipherSuites(webServerConfig.getExcludedCipherSuites());
- }
- if (webServerConfig.clientAuth != null) {
- sslFactory.setNeedClientAuth(webServerConfig.clientAuth);
- if (webServerConfig.clientAuth) {
- sslFactory.setTrustStorePath(webServerConfig.trustStorePath);
- sslFactory.setTrustStorePassword(webServerConfig.getTrustStorePassword());
+ for (int i = 0; i < bindings.size(); i++) {
+ BindingDTO binding = bindings.get(i);
+ URI uri = new URI(binding.uri);
+ String scheme = uri.getScheme();
+ ServerConnector connector;
+
+ if ("https".equals(scheme)) {
+ SslContextFactory.Server sslFactory = new SslContextFactory.Server();
+ sslFactory.setKeyStorePath(binding.keyStorePath == null ? artemisInstance + "/etc/keystore.jks" : binding.keyStorePath);
+ sslFactory.setKeyStorePassword(binding.getKeyStorePassword() == null ? "password" : binding.getKeyStorePassword());
+
+ if (binding.getIncludedTLSProtocols() != null) {
+ sslFactory.setIncludeProtocols(binding.getIncludedTLSProtocols());
+ }
+ if (binding.getExcludedTLSProtocols() != null) {
+ sslFactory.setExcludeProtocols(binding.getExcludedTLSProtocols());
+ }
+ if (binding.getIncludedCipherSuites() != null) {
+ sslFactory.setIncludeCipherSuites(binding.getIncludedCipherSuites());
+ }
+ if (binding.getExcludedCipherSuites() != null) {
+ sslFactory.setExcludeCipherSuites(binding.getExcludedCipherSuites());
+ }
+ if (binding.clientAuth != null) {
+ sslFactory.setNeedClientAuth(binding.clientAuth);
+ if (binding.clientAuth) {
+ sslFactory.setTrustStorePath(binding.trustStorePath);
+ sslFactory.setTrustStorePassword(binding.getTrustStorePassword());
+ }
}
- }
- SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslFactory, "HTTP/1.1");
+ SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslFactory, "HTTP/1.1");
- httpConfiguration.addCustomizer(new SecureRequestCustomizer());
- httpConfiguration.setSendServerVersion(false);
- HttpConnectionFactory httpFactory = new HttpConnectionFactory(httpConfiguration);
+ httpConfiguration.addCustomizer(new SecureRequestCustomizer());
+ httpConfiguration.setSendServerVersion(false);
+ HttpConnectionFactory httpFactory = new HttpConnectionFactory(httpConfiguration);
- connector = new ServerConnector(server, sslConnectionFactory, httpFactory);
+ connector = new ServerConnector(server, sslConnectionFactory, httpFactory);
- } else {
- httpConfiguration.setSendServerVersion(false);
- ConnectionFactory connectionFactory = new HttpConnectionFactory(httpConfiguration);
- connector = new ServerConnector(server, connectionFactory);
+ } else {
+ httpConfiguration.setSendServerVersion(false);
+ ConnectionFactory connectionFactory = new HttpConnectionFactory(httpConfiguration);
+ connector = new ServerConnector(server, connectionFactory);
+ }
+ connector.setPort(uri.getPort());
+ connector.setHost(uri.getHost());
+ connector.setName("Connector-" + i);
+
+ connectors[i] = connector;
+ virtualHosts[i] = "@Connector-" + i;
}
- connector.setPort(uri.getPort());
- connector.setHost(uri.getHost());
- server.setConnectors(new Connector[]{connector});
+ server.setConnectors(connectors);
handlers = new HandlerList();
@@ -140,18 +151,22 @@ public class WebServerComponent implements ExternalComponent {
Files.createDirectories(temporaryWarDir);
}
- if (webServerConfig.apps != null && webServerConfig.apps.size() > 0) {
- webContexts = new ArrayList<>();
- for (AppDTO app : webServerConfig.apps) {
- Path dirToUse = homeWarDir;
- if (new File(instanceWarDir.toFile().toString() + File.separator + app.war).exists()) {
- dirToUse = instanceWarDir;
- }
- WebAppContext webContext = deployWar(app.url, app.war, dirToUse);
- webContext.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
- webContexts.add(webContext);
- if (app.war.startsWith("console")) {
- consoleUrl = webServerConfig.bind + "/" + app.url;
+ for (int i = 0; i < bindings.size(); i++) {
+ BindingDTO binding = bindings.get(i);
+ if (binding.apps != null && binding.apps.size() > 0) {
+ webContexts = new ArrayList<>();
+ for (AppDTO app : binding.apps) {
+ Path dirToUse = homeWarDir;
+ if (new File(instanceWarDir.toFile().toString() + File.separator + app.war).exists()) {
+ dirToUse = instanceWarDir;
+ }
+ WebAppContext webContext = deployWar(app.url, app.war, dirToUse, virtualHosts[i]);
+ webContext.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
+ webContexts.add(webContext);
+ if (app.war.startsWith("console")) {
+ consoleUrls.add(binding.uri + "/" + app.url);
+ jolokiaUrls.add(binding.uri + "/" + app.url + "/jolokia");
+ }
}
}
}
@@ -165,6 +180,7 @@ public class WebServerComponent implements ExternalComponent {
homeContext.setContextPath("/");
homeContext.setResourceBase(homeWarDir.toString());
homeContext.setHandler(homeResourceHandler);
+ homeContext.setVirtualHosts(virtualHosts);
homeContext.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
ResourceHandler instanceResourceHandler = new ResourceHandler();
@@ -176,6 +192,7 @@ public class WebServerComponent implements ExternalComponent {
instanceContext.setContextPath("/");
instanceContext.setResourceBase(instanceWarDir.toString());
instanceContext.setHandler(instanceResourceHandler);
+ instanceContext.setVirtualHosts(virtualHosts);
homeContext.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
DefaultHandler defaultHandler = new DefaultHandler();
@@ -263,12 +280,15 @@ public class WebServerComponent implements ExternalComponent {
}
cleanupTmp();
server.start();
- ActiveMQWebLogger.LOGGER.webserverStarted(webServerConfig.bind);
- if (consoleUrl != null) {
- ActiveMQWebLogger.LOGGER.jolokiaAvailable(consoleUrl + "/jolokia");
- ActiveMQWebLogger.LOGGER.consoleAvailable(consoleUrl);
- }
+ String bindings = webServerConfig.getBindings()
+ .stream()
+ .map(binding -> binding.uri)
+ .collect(Collectors.joining(", "));
+ ActiveMQWebLogger.LOGGER.webserverStarted(bindings);
+
+ ActiveMQWebLogger.LOGGER.jolokiaAvailable(String.join(", ", jolokiaUrls));
+ ActiveMQWebLogger.LOGGER.consoleAvailable(String.join(", ", consoleUrls));
}
public void internalStop() throws Exception {
@@ -324,11 +344,19 @@ public class WebServerComponent implements ExternalComponent {
/**
* @return started server's port number; useful if it was specified as 0 (to use a random port)
*/
+ @Deprecated
public int getPort() {
- return (connector != null) ? connector.getLocalPort() : -1;
+ return getPort(0);
}
- private WebAppContext deployWar(String url, String warFile, Path warDirectory) throws IOException {
+ public int getPort(int connectorIndex) {
+ if (connectorIndex < connectors.length) {
+ return connectors[connectorIndex].getLocalPort();
+ }
+ return -1;
+ }
+
+ private WebAppContext deployWar(String url, String warFile, Path warDirectory, String virtualHost) {
WebAppContext webapp = new WebAppContext();
if (url.startsWith("/")) {
webapp.setContextPath(url);
@@ -347,6 +375,8 @@ public class WebServerComponent implements ExternalComponent {
// https://github.com/eclipse/jetty.project/commit/7e91d34177a880ecbe70009e8f200d02e3a0c5dd
webapp.getSecurityHandler().setAuthenticatorFactory(new DefaultAuthenticatorFactory());
+ webapp.setVirtualHosts(new String[]{virtualHost});
+
handlers.addHandler(webapp);
return webapp;
}
diff --git a/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java b/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
index 23763a3..f7a08a6 100644
--- a/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
+++ b/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
@@ -27,6 +27,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
@@ -62,6 +63,7 @@ import org.apache.activemq.artemis.component.WebServerComponent;
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.dto.AppDTO;
+import org.apache.activemq.artemis.dto.BindingDTO;
import org.apache.activemq.artemis.dto.BrokerDTO;
import org.apache.activemq.artemis.dto.WebServerDTO;
import org.apache.activemq.artemis.utils.ThreadLeakCheckRule;
@@ -114,8 +116,10 @@ public class WebServerComponentTest extends Assert {
}
private void internalSimpleServer(boolean useCustomizer) throws Exception {
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "http://localhost:0";
WebServerDTO webServerDTO = new WebServerDTO();
- webServerDTO.bind = "http://localhost:0";
+ webServerDTO.setBindings(Collections.singletonList(bindingDTO));
webServerDTO.path = "webapps";
if (useCustomizer) {
webServerDTO.customizer = TestCustomizer.class.getName();
@@ -162,8 +166,10 @@ public class WebServerComponentTest extends Assert {
@Test
public void testComponentStopBehavior() throws Exception {
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "http://localhost:0";
WebServerDTO webServerDTO = new WebServerDTO();
- webServerDTO.bind = "http://localhost:0";
+ webServerDTO.setBindings(Collections.singletonList(bindingDTO));
webServerDTO.path = "webapps";
WebServerComponent webServerComponent = new WebServerComponent();
Assert.assertFalse(webServerComponent.isStarted());
@@ -206,20 +212,22 @@ public class WebServerComponentTest extends Assert {
@Test
public void simpleSecureServer() throws Exception {
- WebServerDTO webServerDTO = new WebServerDTO();
- webServerDTO.bind = "https://localhost:0";
- webServerDTO.path = "webapps";
- webServerDTO.keyStorePath = "./src/test/resources/server.keystore";
- webServerDTO.setKeyStorePassword("password");
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "https://localhost:0";
+ bindingDTO.keyStorePath = "./src/test/resources/server.keystore";
+ bindingDTO.setKeyStorePassword("password");
if (System.getProperty("java.vendor").contains("IBM")) {
//By default on IBM Java 8 JVM, org.eclipse.jetty.util.ssl.SslContextFactory doesn't include TLSv1.2
// while it excludes all TLSv1 and TLSv1.1 cipher suites.
- webServerDTO.setIncludedTLSProtocols("TLSv1.2");
+ bindingDTO.setIncludedTLSProtocols("TLSv1.2");
// Remove excluded cipher suites matching the prefix `SSL` because the names of the IBM Java 8 JVM cipher suites
// have the prefix `SSL` while the `DEFAULT_EXCLUDED_CIPHER_SUITES` of org.eclipse.jetty.util.ssl.SslContextFactory
// includes "^SSL_.*$". So all IBM JVM cipher suites are excluded by SslContextFactory using the `DEFAULT_EXCLUDED_CIPHER_SUITES`.
- webServerDTO.setExcludedCipherSuites(Arrays.stream(new SslContextFactory.Server().getExcludeCipherSuites()).filter(s -> !Pattern.matches(s, "SSL_")).toArray(String[]::new));
+ bindingDTO.setExcludedCipherSuites(Arrays.stream(new SslContextFactory.Server().getExcludeCipherSuites()).filter(s -> !Pattern.matches(s, "SSL_")).toArray(String[]::new));
}
+ WebServerDTO webServerDTO = new WebServerDTO();
+ webServerDTO.setBindings(Collections.singletonList(bindingDTO));
+ webServerDTO.path = "webapps";
WebServerComponent webServerComponent = new WebServerComponent();
Assert.assertFalse(webServerComponent.isStarted());
@@ -230,10 +238,10 @@ public class WebServerComponentTest extends Assert {
// Make the connection attempt.
SSLContext context = new SSLSupport()
- .setKeystorePath(webServerDTO.keyStorePath)
- .setKeystorePassword(webServerDTO.getKeyStorePassword())
- .setTruststorePath(webServerDTO.keyStorePath)
- .setTruststorePassword(webServerDTO.getKeyStorePassword())
+ .setKeystorePath(bindingDTO.keyStorePath)
+ .setKeystorePassword(bindingDTO.getKeyStorePassword())
+ .setTruststorePath(bindingDTO.keyStorePath)
+ .setTruststorePassword(bindingDTO.getKeyStorePassword())
.createContext();
SSLEngine engine = context.createSSLEngine();
@@ -279,23 +287,25 @@ public class WebServerComponentTest extends Assert {
@Test
public void simpleSecureServerWithClientAuth() throws Exception {
- WebServerDTO webServerDTO = new WebServerDTO();
- webServerDTO.bind = "https://localhost:0";
- webServerDTO.path = "webapps";
- webServerDTO.keyStorePath = "./src/test/resources/server.keystore";
- webServerDTO.setKeyStorePassword("password");
- webServerDTO.clientAuth = true;
- webServerDTO.trustStorePath = "./src/test/resources/server.keystore";
- webServerDTO.setTrustStorePassword("password");
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "https://localhost:0";
+ bindingDTO.keyStorePath = "./src/test/resources/server.keystore";
+ bindingDTO.setKeyStorePassword("password");
+ bindingDTO.clientAuth = true;
+ bindingDTO.trustStorePath = "./src/test/resources/server.keystore";
+ bindingDTO.setTrustStorePassword("password");
if (System.getProperty("java.vendor").contains("IBM")) {
//By default on IBM Java 8 JVM, org.eclipse.jetty.util.ssl.SslContextFactory doesn't include TLSv1.2
// while it excludes all TLSv1 and TLSv1.1 cipher suites.
- webServerDTO.setIncludedTLSProtocols("TLSv1.2");
+ bindingDTO.setIncludedTLSProtocols("TLSv1.2");
// Remove excluded cipher suites matching the prefix `SSL` because the names of the IBM Java 8 JVM cipher suites
// have the prefix `SSL` while the `DEFAULT_EXCLUDED_CIPHER_SUITES` of org.eclipse.jetty.util.ssl.SslContextFactory
// includes "^SSL_.*$". So all IBM JVM cipher suites are excluded by SslContextFactory using the `DEFAULT_EXCLUDED_CIPHER_SUITES`.
- webServerDTO.setExcludedCipherSuites(Arrays.stream(new SslContextFactory.Server().getExcludeCipherSuites()).filter(s -> !Pattern.matches(s, "SSL_")).toArray(String[]::new));
+ bindingDTO.setExcludedCipherSuites(Arrays.stream(new SslContextFactory.Server().getExcludeCipherSuites()).filter(s -> !Pattern.matches(s, "SSL_")).toArray(String[]::new));
}
+ WebServerDTO webServerDTO = new WebServerDTO();
+ webServerDTO.setBindings(Collections.singletonList(bindingDTO));
+ webServerDTO.path = "webapps";
WebServerComponent webServerComponent = new WebServerComponent();
Assert.assertFalse(webServerComponent.isStarted());
@@ -306,10 +316,10 @@ public class WebServerComponentTest extends Assert {
// Make the connection attempt.
SSLContext context = new SSLSupport()
- .setKeystorePath(webServerDTO.keyStorePath)
- .setKeystorePassword(webServerDTO.getKeyStorePassword())
- .setTruststorePath(webServerDTO.trustStorePath)
- .setTruststorePassword(webServerDTO.getTrustStorePassword())
+ .setKeystorePath(bindingDTO.keyStorePath)
+ .setKeystorePassword(bindingDTO.getKeyStorePassword())
+ .setTruststorePath(bindingDTO.trustStorePath)
+ .setTruststorePassword(bindingDTO.getTrustStorePassword())
.createContext();
SSLEngine engine = context.createSSLEngine();
@@ -358,7 +368,7 @@ public class WebServerComponentTest extends Assert {
XmlBrokerFactoryHandler xmlHandler = new XmlBrokerFactoryHandler();
BrokerDTO broker = xmlHandler.createBroker(bootstrap.toURI(), brokerHome.getAbsolutePath(), brokerHome.getAbsolutePath(), brokerHome.toURI());
assertNotNull(broker.web);
- assertNull(broker.web.passwordCodec);
+ assertNull(broker.web.getDefaultBinding().passwordCodec);
}
@Test
@@ -370,8 +380,8 @@ public class WebServerComponentTest extends Assert {
XmlBrokerFactoryHandler xmlHandler = new XmlBrokerFactoryHandler();
BrokerDTO broker = xmlHandler.createBroker(bootstrap.toURI(), brokerHome.getAbsolutePath(), brokerHome.getAbsolutePath(), brokerHome.toURI());
assertNotNull(broker.web);
- assertEquals(keyPassword, broker.web.getKeyStorePassword());
- assertEquals(trustPassword, broker.web.getTrustStorePassword());
+ assertEquals(keyPassword, broker.web.getDefaultBinding().getKeyStorePassword());
+ assertEquals(trustPassword, broker.web.getDefaultBinding().getTrustStorePassword());
}
@Test
@@ -383,24 +393,44 @@ public class WebServerComponentTest extends Assert {
XmlBrokerFactoryHandler xmlHandler = new XmlBrokerFactoryHandler();
BrokerDTO broker = xmlHandler.createBroker(bootstrap.toURI(), brokerHome.getAbsolutePath(), brokerHome.getAbsolutePath(), brokerHome.toURI());
assertNotNull(broker.web);
- assertNotNull("password codec not picked up!", broker.web.passwordCodec);
+ assertNotNull("password codec not picked up!", broker.web.getDefaultBinding().passwordCodec);
+
+ assertEquals(keyPassword, broker.web.getDefaultBinding().getKeyStorePassword());
+ assertEquals(trustPassword, broker.web.getDefaultBinding().getTrustStorePassword());
+ }
+
+ @Test
+ public void testOldConfigurationStyle() throws Exception {
+ final String keyPassword = "keypass";
+ final String trustPassword = "trustpass";
+
+ File bootstrap = new File("./target/test-classes/bootstrap_web_old_config.xml");
+ File brokerHome = new File("./target");
+ XmlBrokerFactoryHandler xmlHandler = new XmlBrokerFactoryHandler();
+ BrokerDTO broker = xmlHandler.createBroker(bootstrap.toURI(), brokerHome.getAbsolutePath(), brokerHome.getAbsolutePath(), brokerHome.toURI());
+ assertNotNull(broker.web);
+ assertNotNull("password codec not picked up!", broker.web.getDefaultBinding().passwordCodec);
- assertEquals(keyPassword, broker.web.getKeyStorePassword());
- assertEquals(trustPassword, broker.web.getTrustStorePassword());
+ assertEquals("http://localhost:8161", broker.web.getDefaultBinding().uri);
+ assertEquals(keyPassword, broker.web.getDefaultBinding().getKeyStorePassword());
+ assertEquals(trustPassword, broker.web.getDefaultBinding().getTrustStorePassword());
}
@Test
public void testServerCleanupBeforeStart() throws Exception {
final String warName = "simple-app.war";
createTestWar(warName);
- WebServerDTO webServerDTO = new WebServerDTO();
- webServerDTO.bind = "http://localhost:0";
- webServerDTO.path = "";
- webServerDTO.apps = new ArrayList<>();
+
AppDTO app = new AppDTO();
app.url = "simple-app/";
app.war = warName;
- webServerDTO.apps.add(app);
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "http://localhost:0";
+ bindingDTO.apps = new ArrayList<>();
+ bindingDTO.apps.add(app);
+ WebServerDTO webServerDTO = new WebServerDTO();
+ webServerDTO.setBindings(Collections.singletonList(bindingDTO));
+ webServerDTO.path = "";
WebServerComponent webServerComponent = new WebServerComponent();
Assert.assertFalse(webServerComponent.isStarted());
testedComponents.add(webServerComponent);
diff --git a/artemis-web/src/test/resources/bootstrap_secure_web.xml b/artemis-web/src/test/resources/bootstrap_secure_web.xml
index affa9ab..c726aa9 100644
--- a/artemis-web/src/test/resources/bootstrap_secure_web.xml
+++ b/artemis-web/src/test/resources/bootstrap_secure_web.xml
@@ -25,8 +25,10 @@
<server configuration="${artemis.URI.instance}/etc/broker.xml"/>
<!-- The web server is only bound to localhost by default -->
- <web bind="https://localhost:8443" path="web" keyStorePassword="ENC(-5a2376c61c668aaf)" trustStorePassword="ENC(3d617352d12839eb71208edf41d66b34)">
- <app url="activemq-branding" war="activemq-branding.war"/>
+ <web path="web">
+ <binding uri="https://localhost:8443" keyStorePassword="ENC(-5a2376c61c668aaf)" trustStorePassword="ENC(3d617352d12839eb71208edf41d66b34)">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ </binding>
</web>
diff --git a/artemis-web/src/test/resources/bootstrap_web.xml b/artemis-web/src/test/resources/bootstrap_web.xml
index 847a869..a23dbfa 100644
--- a/artemis-web/src/test/resources/bootstrap_web.xml
+++ b/artemis-web/src/test/resources/bootstrap_web.xml
@@ -25,8 +25,10 @@
<server configuration="${artemis.URI.instance}/etc/broker.xml"/>
<!-- The web server is only bound to localhost by default -->
- <web bind="http://localhost:8161" path="web">
- <app url="activemq-branding" war="activemq-branding.war"/>
+ <web path="web">
+ <binding uri="http://localhost:8161">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ </binding>
</web>
diff --git a/artemis-web/src/test/resources/bootstrap_web_codec.xml b/artemis-web/src/test/resources/bootstrap_web_codec.xml
index 7b53515..1c250b1 100644
--- a/artemis-web/src/test/resources/bootstrap_web_codec.xml
+++ b/artemis-web/src/test/resources/bootstrap_web_codec.xml
@@ -25,8 +25,10 @@
<server configuration="${artemis.URI.instance}/etc/broker.xml"/>
<!-- The web server is only bound to localhost by default -->
- <web bind="https://localhost:8443" path="web" passwordCodec="org.apache.activemq.artemis.utils.MaskPasswordResolvingTest$SimplePasswordCodec" keyStorePassword="ENC(youneverknow)" trustStorePassword="ENC(youcanguess)">
- <app url="console" war="console.war"/>
+ <web path="web">
+ <binding uri="https://localhost:8443" passwordCodec="org.apache.activemq.artemis.utils.MaskPasswordResolvingTest$SimplePasswordCodec" keyStorePassword="ENC(youneverknow)" trustStorePassword="ENC(youcanguess)">
+ <app url="console" war="console.war"/>
+ </binding>
</web>
diff --git a/artemis-web/src/test/resources/bootstrap_web_codec.xml b/artemis-web/src/test/resources/bootstrap_web_old_config.xml
similarity index 91%
copy from artemis-web/src/test/resources/bootstrap_web_codec.xml
copy to artemis-web/src/test/resources/bootstrap_web_old_config.xml
index 7b53515..981c910 100644
--- a/artemis-web/src/test/resources/bootstrap_web_codec.xml
+++ b/artemis-web/src/test/resources/bootstrap_web_old_config.xml
@@ -25,8 +25,8 @@
<server configuration="${artemis.URI.instance}/etc/broker.xml"/>
<!-- The web server is only bound to localhost by default -->
- <web bind="https://localhost:8443" path="web" passwordCodec="org.apache.activemq.artemis.utils.MaskPasswordResolvingTest$SimplePasswordCodec" keyStorePassword="ENC(youneverknow)" trustStorePassword="ENC(youcanguess)">
- <app url="console" war="console.war"/>
+ <web path="web" bind="http://localhost:8161" passwordCodec="org.apache.activemq.artemis.utils.MaskPasswordResolvingTest$SimplePasswordCodec" keyStorePassword="ENC(youneverknow)" trustStorePassword="ENC(youcanguess)">
+ <app url="activemq-branding" war="activemq-branding.war"/>
</web>
diff --git a/docs/user-manual/en/masking-passwords.md b/docs/user-manual/en/masking-passwords.md
index 6ef819f..d104823 100644
--- a/docs/user-manual/en/masking-passwords.md
+++ b/docs/user-manual/en/masking-passwords.md
@@ -224,10 +224,12 @@ You can also set the `passwordCodec` attribute if you want to use a password
codec other than the default one. For example
```xml
-<web bind="https://localhost:8443" path="web"
- keyStorePassword="ENC(-5a2376c61c668aaf)"
- trustStorePassword="ENC(3d617352d12839eb71208edf41d66b34)">
- <app url="activemq-branding" war="activemq-branding.war"/>
+<web path="web">
+ <binding uri="https://localhost:8443"
+ keyStorePassword="ENC(-5a2376c61c668aaf)"
+ trustStorePassword="ENC(3d617352d12839eb71208edf41d66b34)">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ </binding>
</web>
```
diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md
index 55f3ed8..10a807f 100644
--- a/docs/user-manual/en/security.md
+++ b/docs/user-manual/en/security.md
@@ -1363,8 +1363,10 @@ documentation via an embedded server. By default the web access is plain HTTP.
It is configured in `bootstrap.xml`:
```xml
-<web bind="http://localhost:8161" path="web">
- <app url="console" war="console.war"/>
+<web path="web">
+ <binding uri="http://localhost:8161">
+ <app url="console" war="console.war"/>
+ </binding>
</web>
```
@@ -1372,11 +1374,12 @@ Alternatively you can edit the above configuration to enable secure access
using HTTPS protocol. e.g.:
```xml
-<web bind="https://localhost:8443"
- path="web"
- keyStorePath="${artemis.instance}/etc/keystore.jks"
- keyStorePassword="password">
- <app url="jolokia" war="jolokia-war-1.3.5.war"/>
+<web path="web">
+ <binding uri="https://localhost:8443"
+ keyStorePath="${artemis.instance}/etc/keystore.jks"
+ keyStorePassword="password">
+ <app url="jolokia" war="jolokia-war-1.3.5.war"/>
+ </binding>
</web>
```
@@ -1425,14 +1428,15 @@ keytool -storetype pkcs12 -keystore client-truststore.p12 -storepass securepass
- Enable secure access using HTTPS protocol with client authentication,
use the truststore file created in the previous step to set the trustStorePath and trustStorePassword:
```xml
-<web bind="https://localhost:8443"
- path="web"
- keyStorePath="${artemis.instance}/etc/server-keystore.p12"
- keyStorePassword="password"
- clientAuth="true"
- trustStorePath="${artemis.instance}/etc/client-truststore.p12"
- trustStorePassword="password">
- <app url="jolokia" war="jolokia-war-1.3.5.war"/>
+<web path="web">
+ <binding uri="https://localhost:8443"
+ keyStorePath="${artemis.instance}/etc/server-keystore.p12"
+ keyStorePassword="password"
+ clientAuth="true"
+ trustStorePath="${artemis.instance}/etc/client-truststore.p12"
+ trustStorePassword="password">
+ <app url="jolokia" war="jolokia-war-1.3.5.war"/>
+ </binding>
</web>
```
diff --git a/docs/user-manual/en/using-server.md b/docs/user-manual/en/using-server.md
index e5fbe09..c2426a3 100644
--- a/docs/user-manual/en/using-server.md
+++ b/docs/user-manual/en/using-server.md
@@ -457,10 +457,12 @@ The `bootstrap.xml` file is very simple. Let's take a look at an example:
<server configuration="file:/path/to/broker.xml"/>
- <web bind="http://localhost:8161" path="web">
- <app url="activemq-branding" war="activemq-branding.war"/>
- <app url="artemis-plugin" war="artemis-plugin.war"/>
- <app url="console" war="console.war"/>
+ <web path="web">
+ <binding uri="http://localhost:8161">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ <app url="artemis-plugin" war="artemis-plugin.war"/>
+ <app url="console" war="console.war"/>
+ </binding>
</web>
</broker>
```
diff --git a/docs/user-manual/en/web-server.md b/docs/user-manual/en/web-server.md
index cd63963..8008e95 100644
--- a/docs/user-manual/en/web-server.md
+++ b/docs/user-manual/en/web-server.md
@@ -12,21 +12,28 @@ The embedded Jetty instance is configured in `etc/bootstrap.xml` via the `web`
element, e.g.:
```xml
-<web bind="http://localhost:8161" path="web">
- <app url="activemq-branding" war="activemq-branding.war"/>
- <app url="artemis-plugin" war="artemis-plugin.war"/>
- <app url="console" war="console.war"/>
+<web path="web">
+ <binding uri="http://localhost:8161">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ <app url="artemis-plugin" war="artemis-plugin.war"/>
+ <app url="console" war="console.war"/>
+ </binding>
</web>
```
The `web` element has the following attributes:
-- `bind` The protocol to use (i.e. `http` or `https`) as well as the host and
- port on which to listen.
- `path` The name of the subdirectory in which to find the web application
archives (i.e. WAR files). This is a subdirectory of the broker's home or
instance directory.
- `customizer` The name of customizer class to load.
+
+The `web` element should contain at least one `binding` element to configure how
+clients can connect to the web-server. A `binding` element has the following
+attributes:
+
+- `uri` The protocol to use (i.e. `http` or `https`) as well as the host and
+ port on which to listen. This attribute is required.
- `clientAuth` Whether or not clients should present an SSL certificate when
they connect. Only applicable when using `https`.
- `passwordCodec` The custom coded to use for unmasking the `keystorePassword`
@@ -51,8 +58,8 @@ The `web` element has the following attributes:
- `excludedCipherSuites` A comma seperated list of excluded cipher suites.
Only applicable when using `https`.
-Each web application should be defined in an `app` element. The `app` element
-has the following attributes:
+Each web application should be defined in an `app` element inside an `binding` element.
+The `app` element has the following attributes:
- `url` The context to use for the web application.
- `war` The name of the web application archive on disk.
@@ -82,10 +89,12 @@ instance. Default values are based on this implementation.
Here is an example configuration:
```xml
-<web bind="http://localhost:8161" path="web">
- <app url="activemq-branding" war="activemq-branding.war"/>
- <app url="artemis-plugin" war="artemis-plugin.war"/>
- <app url="console" war="console.war"/>
+<web path="web">
+ <binding uri="http://localhost:8161">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ <app url="artemis-plugin" war="artemis-plugin.war"/>
+ <app url="console" war="console.war"/>
+ </binding>
<request-log filename="${artemis.instance}/log/http-access-yyyy_MM_dd.log" append="true" extended="true"/>
</web>
```
@@ -99,9 +108,11 @@ customizer to handle `X-Forwarded` headers.
Set the `customizer` attribute via the `web` element to enable the [`ForwardedRequestCustomizer`](https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/server/ForwardedRequestCustomizer.html) customizer, ie:
```xml
-<web bind="http://localhost:8161" path="web" customizer="org.eclipse.jetty.server.ForwardedRequestCustomizer">
- <app url="activemq-branding" war="activemq-branding.war"/>
- <app url="artemis-plugin" war="artemis-plugin.war"/>
- <app url="console" war="console.war"/>
+<web path="web" customizer="org.eclipse.jetty.server.ForwardedRequestCustomizer">
+ <binding uri="http://localhost:8161">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ <app url="artemis-plugin" war="artemis-plugin.war"/>
+ <app url="console" war="console.war"/>
+ </binding>
</web>
```
\ No newline at end of file
diff --git a/examples/features/standard/camel/camel-broker/src/main/resources/activemq/server0/bootstrap.xml b/examples/features/standard/camel/camel-broker/src/main/resources/activemq/server0/bootstrap.xml
index 6c58a27..6964b19 100644
--- a/examples/features/standard/camel/camel-broker/src/main/resources/activemq/server0/bootstrap.xml
+++ b/examples/features/standard/camel/camel-broker/src/main/resources/activemq/server0/bootstrap.xml
@@ -22,9 +22,11 @@
<server configuration="${artemis.URI.instance}/etc/broker.xml"/>
- <web bind="http://localhost:8080" path="web">
- <!-- ${war} is defined in the example's pom.xml -->
- <app url="camel" war="WARFILE"/>
+ <web path="web">
+ <binding uri="http://localhost:8080">
+ <!-- ${war} is defined in the example's pom.xml -->
+ <app url="camel" war="WARFILE"/>
+ </binding>
</web>
</broker>
diff --git a/examples/features/sub-modules/inter-broker-bridge/artemis-jms-bridge/readme.md b/examples/features/sub-modules/inter-broker-bridge/artemis-jms-bridge/readme.md
index 6674bbc..28e999a 100644
--- a/examples/features/sub-modules/inter-broker-bridge/artemis-jms-bridge/readme.md
+++ b/examples/features/sub-modules/inter-broker-bridge/artemis-jms-bridge/readme.md
@@ -126,7 +126,8 @@ http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/came
6) Edit `$ARTEMIS_INSTANCE/etc/bootstrap.xml` so that the embedded web broker runs on a different port that the 5.x broker (e.g. 8162):
```xml
-<web bind="http://localhost:8162" path="web">
+<web path="web">
+ <binding uri="http://localhost:8162"/>
```
## Testing
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/ReplicatedFailoverTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/ReplicatedFailoverTest.java
index ab8b440..219da84 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/ReplicatedFailoverTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/ReplicatedFailoverTest.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.concurrent.TimeUnit;
import com.sun.net.httpserver.HttpExchange;
@@ -34,6 +35,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ServiceComponent;
import org.apache.activemq.artemis.core.server.cluster.ha.ReplicatedPolicy;
import org.apache.activemq.artemis.dto.AppDTO;
+import org.apache.activemq.artemis.dto.BindingDTO;
import org.apache.activemq.artemis.dto.WebServerDTO;
import org.apache.activemq.artemis.tests.util.Wait;
import org.junit.Assert;
@@ -162,13 +164,15 @@ public class ReplicatedFailoverTest extends FailoverTest {
os.close();
}
});
- WebServerDTO wdto = new WebServerDTO();
AppDTO appDTO = new AppDTO();
appDTO.war = "console.war";
appDTO.url = "console";
- wdto.apps = new ArrayList<AppDTO>();
- wdto.apps.add(appDTO);
- wdto.bind = "http://localhost:0";
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "http://localhost:0";
+ bindingDTO.apps = new ArrayList<AppDTO>();
+ bindingDTO.apps.add(appDTO);
+ WebServerDTO wdto = new WebServerDTO();
+ wdto.setBindings(Collections.singletonList(bindingDTO));
wdto.path = "console";
WebServerComponent webServerComponent = new WebServerComponent();
webServerComponent.configure(wdto, ".", ".");
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/quorum/PluggableQuorumNettyNoGroupNameReplicatedFailoverTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/quorum/PluggableQuorumNettyNoGroupNameReplicatedFailoverTest.java
index 274fb5a..700da3d 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/quorum/PluggableQuorumNettyNoGroupNameReplicatedFailoverTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/quorum/PluggableQuorumNettyNoGroupNameReplicatedFailoverTest.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.concurrent.TimeUnit;
import com.sun.net.httpserver.HttpExchange;
@@ -35,6 +36,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.NodeManager;
import org.apache.activemq.artemis.core.server.ServiceComponent;
import org.apache.activemq.artemis.dto.AppDTO;
+import org.apache.activemq.artemis.dto.BindingDTO;
import org.apache.activemq.artemis.dto.WebServerDTO;
import org.apache.activemq.artemis.quorum.MutableLong;
import org.apache.activemq.artemis.quorum.file.FileBasedPrimitiveManager;
@@ -127,7 +129,6 @@ public class PluggableQuorumNettyNoGroupNameReplicatedFailoverTest extends Failo
@Test
public void testReplicatedFailbackBackupFromLiveBackToBackup() throws Exception {
-
InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8787);
HttpServer httpServer = HttpServer.create(address, 100);
httpServer.start();
@@ -143,13 +144,15 @@ public class PluggableQuorumNettyNoGroupNameReplicatedFailoverTest extends Failo
os.close();
}
});
- WebServerDTO wdto = new WebServerDTO();
AppDTO appDTO = new AppDTO();
appDTO.war = "console.war";
appDTO.url = "console";
- wdto.apps = new ArrayList<AppDTO>();
- wdto.apps.add(appDTO);
- wdto.bind = "http://localhost:0";
+ BindingDTO bindingDTO = new BindingDTO();
+ bindingDTO.uri = "http://localhost:0";
+ bindingDTO.apps = new ArrayList<AppDTO>();
+ bindingDTO.apps.add(appDTO);
+ WebServerDTO wdto = new WebServerDTO();
+ wdto.setBindings(Collections.singletonList(bindingDTO));
wdto.path = "console";
WebServerComponent webServerComponent = new WebServerComponent();
webServerComponent.configure(wdto, ".", ".");
diff --git a/tests/smoke-tests/src/main/resources/containerService/bootstrap.xml b/tests/smoke-tests/src/main/resources/containerService/bootstrap.xml
index ea4da15..611625e 100644
--- a/tests/smoke-tests/src/main/resources/containerService/bootstrap.xml
+++ b/tests/smoke-tests/src/main/resources/containerService/bootstrap.xml
@@ -26,10 +26,12 @@
<server configuration="file:/var/lib/artemis-instance/./etc//broker.xml"/>
<!-- The web server is only bound to localhost by default -->
- <web bind="http://localhost:8161" path="web">
- <app url="activemq-branding" war="activemq-branding.war"/>
- <app url="artemis-plugin" war="artemis-plugin.war"/>
- <app url="console" war="console.war"/>
+ <web path="web">
+ <binding uri="http://localhost:8161">
+ <app url="activemq-branding" war="activemq-branding.war"/>
+ <app url="artemis-plugin" war="artemis-plugin.war"/>
+ <app url="console" war="console.war"/>
+ </binding>
</web>