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 e863c1a97e..4c56188f3f 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 @@ - - - - + + + + + + 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 f453cb6a1f..e0728f799e 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/BindingDTO.java b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/BindingDTO.java new file mode 100644 index 0000000000..32cfcb91ce --- /dev/null +++ b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/BindingDTO.java @@ -0,0 +1,135 @@ +/* + * 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; + +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.List; + +@XmlRootElement(name = "binding") +@XmlAccessorType(XmlAccessType.FIELD) +public class BindingDTO { + + @XmlAttribute + public String uri; + + @XmlElementRef + public List apps; + + @XmlAttribute + public Boolean clientAuth; + + @XmlAttribute + public String passwordCodec; + + @XmlAttribute + public String keyStorePath; + + @XmlAttribute + public String trustStorePath; + + @XmlAttribute + private String includedTLSProtocols; + + @XmlAttribute + private String excludedTLSProtocols; + + @XmlAttribute + private String includedCipherSuites; + + @XmlAttribute + private String excludedCipherSuites; + + @XmlAttribute + private String keyStorePassword; + + @XmlAttribute + private String trustStorePassword; + + 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; + } + + 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); + } + + public void setIncludedCipherSuites(String... cipherSuites) { + includedCipherSuites = marshalArray(cipherSuites); + } + + public String[] getExcludedCipherSuites() { + return unmarshalArray(excludedCipherSuites); + } + + 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 749208545f..b6b648783f 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,61 +16,75 @@ */ 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; @XmlAttribute public String customizer; + @XmlElementRef + private List bindings; + + @Deprecated @XmlElementRef public List 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; + public List getBindings() { + if (bindings == null || bindings.isEmpty()) { + return Collections.singletonList(convertToBindingDTO()); } - - return text.split(","); + return bindings; } - private String marshalArray(String[] array) { - if (array == null) { - return null; - } - - return String.join(",", array); + public void setBindings(List bindings) { + this.bindings = bindings; } - public String[] getIncludedTLSProtocols() { - return unmarshalArray(includedTLSProtocols); + 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 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); - } - - public void setIncludedCipherSuites(String... cipherSuites) { - includedCipherSuites = marshalArray(cipherSuites); - } - - public String[] getExcludedCipherSuites() { - return unmarshalArray(excludedCipherSuites); - } - - 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 0000000000..728232fcc5 --- /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 bd51f6fa2d..b3d3e2a3d8 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() { + public void testWebServerWithBinding() { + BindingDTO binding = new BindingDTO(); + binding.uri = "http://localhost:0"; + WebServerDTO webServer = new WebServerDTO(); + webServer.setBindings(Collections.singletonList(binding)); - webServer.setIncludedTLSProtocols(""); - Assert.assertArrayEquals(new String[] {""}, webServer.getIncludedTLSProtocols()); - - webServer.setExcludedTLSProtocols(""); - Assert.assertArrayEquals(new String[] {""}, webServer.getExcludedTLSProtocols()); - - webServer.setIncludedCipherSuites(""); - Assert.assertArrayEquals(new String[] {""}, webServer.getIncludedCipherSuites()); - - 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() { + public void testWebServerWithMultipleBindings() { + BindingDTO binding1 = new BindingDTO(); + binding1.uri = "http://localhost:0"; + BindingDTO binding2 = new BindingDTO(); + binding2.uri = "http://localhost:1"; + WebServerDTO webServer = new WebServerDTO(); + webServer.setBindings(List.of(binding1, binding2)); - webServer.setIncludedTLSProtocols(null); - Assert.assertNull(webServer.getIncludedTLSProtocols()); - - webServer.setExcludedTLSProtocols(null); - Assert.assertNull(webServer.getExcludedTLSProtocols()); - - webServer.setIncludedCipherSuites(null); - Assert.assertNull(webServer.getIncludedCipherSuites()); - - webServer.setExcludedCipherSuites(null); - Assert.assertNull(webServer.getExcludedCipherSuites()); + 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); } + + @Test + public void testWebServerConfigAndBinding() { + BindingDTO binding = new BindingDTO(); + binding.uri = "http://localhost:0"; + + WebServerDTO webServer = new WebServerDTO(); + webServer.bind = "http://localhost:1"; + webServer.setBindings(Collections.singletonList(binding)); + + 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 98b580a07f..b7087092bd 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 consoleUrls = new ArrayList<>(); + private final List jolokiaUrls = new ArrayList<>(); private List 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 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"); + + httpConfiguration.addCustomizer(new SecureRequestCustomizer()); + httpConfiguration.setSendServerVersion(false); + HttpConnectionFactory httpFactory = new HttpConnectionFactory(httpConfiguration); + + connector = new ServerConnector(server, sslConnectionFactory, httpFactory); + + } 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); - SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslFactory, "HTTP/1.1"); - - httpConfiguration.addCustomizer(new SecureRequestCustomizer()); - httpConfiguration.setSendServerVersion(false); - HttpConnectionFactory httpFactory = new HttpConnectionFactory(httpConfiguration); - - connector = new ServerConnector(server, sslConnectionFactory, httpFactory); - - } else { - httpConfiguration.setSendServerVersion(false); - ConnectionFactory connectionFactory = new HttpConnectionFactory(httpConfiguration); - connector = new ServerConnector(server, connectionFactory); + 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 23763a347d..f7a08a6d73 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.getKeyStorePassword()); - assertEquals(trustPassword, broker.web.getTrustStorePassword()); + 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("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 affa9abb79..c726aa9cab 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 @@ - - + + + + diff --git a/artemis-web/src/test/resources/bootstrap_web.xml b/artemis-web/src/test/resources/bootstrap_web.xml index 847a869245..a23dbfa332 100644 --- a/artemis-web/src/test/resources/bootstrap_web.xml +++ b/artemis-web/src/test/resources/bootstrap_web.xml @@ -25,8 +25,10 @@ - - + + + + diff --git a/artemis-web/src/test/resources/bootstrap_web_codec.xml b/artemis-web/src/test/resources/bootstrap_web_codec.xml index 7b5351531a..1c250b1a6b 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 @@ - - + + + + diff --git a/artemis-web/src/test/resources/bootstrap_web_old_config.xml b/artemis-web/src/test/resources/bootstrap_web_old_config.xml new file mode 100644 index 0000000000..981c910919 --- /dev/null +++ b/artemis-web/src/test/resources/bootstrap_web_old_config.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/user-manual/en/masking-passwords.md b/docs/user-manual/en/masking-passwords.md index 6ef819f1d1..d104823343 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 - - + + + + ``` diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md index 55f3ed8536..10a807f64e 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 - - + + + + ``` @@ -1372,11 +1374,12 @@ Alternatively you can edit the above configuration to enable secure access using HTTPS protocol. e.g.: ```xml - - + + + + ``` @@ -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 - - + + + + ``` diff --git a/docs/user-manual/en/using-server.md b/docs/user-manual/en/using-server.md index e5fbe0904f..c2426a3231 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: - - - - + + + + + + ``` diff --git a/docs/user-manual/en/web-server.md b/docs/user-manual/en/web-server.md index cd639635be..8008e953ea 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 - - - - + + + + + + ``` 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 - - - - + + + + + + ``` @@ -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 - - - - + + + + + + ``` \ 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 6c58a273d7..6964b19fc7 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 @@ - - - + + + + + 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 6674bbcd68..28e999abdf 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 - + + ``` ## 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 ab8b440843..219da84bae 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(); - wdto.apps.add(appDTO); - wdto.bind = "http://localhost:0"; + BindingDTO bindingDTO = new BindingDTO(); + bindingDTO.uri = "http://localhost:0"; + bindingDTO.apps = new ArrayList(); + 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 274fb5acb8..700da3d78a 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(); - wdto.apps.add(appDTO); - wdto.bind = "http://localhost:0"; + BindingDTO bindingDTO = new BindingDTO(); + bindingDTO.uri = "http://localhost:0"; + bindingDTO.apps = new ArrayList(); + 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 ea4da157d3..611625e725 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 @@ - - - - + + + + + +