ARTEMIS-594 support HTTPS access to hawtio
This commit is contained in:
parent
b88969cd7d
commit
23475caca9
|
@ -72,6 +72,7 @@ public class Create extends InputAbstract {
|
||||||
public static final String ETC_LOGGING_PROPERTIES = "etc/logging.properties";
|
public static final String ETC_LOGGING_PROPERTIES = "etc/logging.properties";
|
||||||
public static final String ETC_BOOTSTRAP_XML = "etc/bootstrap.xml";
|
public static final String ETC_BOOTSTRAP_XML = "etc/bootstrap.xml";
|
||||||
public static final String ETC_BROKER_XML = "etc/broker.xml";
|
public static final String ETC_BROKER_XML = "etc/broker.xml";
|
||||||
|
public static final String ETC_WEB_KEYSTORE = "etc/keystore.jks";
|
||||||
|
|
||||||
public static final String ETC_ARTEMIS_ROLES_PROPERTIES = "etc/artemis-roles.properties";
|
public static final String ETC_ARTEMIS_ROLES_PROPERTIES = "etc/artemis-roles.properties";
|
||||||
public static final String ETC_ARTEMIS_USERS_PROPERTIES = "etc/artemis-users.properties";
|
public static final String ETC_ARTEMIS_USERS_PROPERTIES = "etc/artemis-users.properties";
|
||||||
|
@ -624,6 +625,9 @@ public class Create extends InputAbstract {
|
||||||
filters.put("${bootstrap-web-settings}", applyFilters(readTextFile(ETC_BOOTSTRAP_WEB_SETTINGS_TXT), filters));
|
filters.put("${bootstrap-web-settings}", applyFilters(readTextFile(ETC_BOOTSTRAP_WEB_SETTINGS_TXT), filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//keystore
|
||||||
|
write(ETC_WEB_KEYSTORE);
|
||||||
|
|
||||||
if (noAmqpAcceptor) {
|
if (noAmqpAcceptor) {
|
||||||
filters.put("${amqp-acceptor}", "");
|
filters.put("${amqp-acceptor}", "");
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -33,6 +33,21 @@ public class WebServerDTO extends ComponentDTO {
|
||||||
@XmlAttribute(required = true)
|
@XmlAttribute(required = true)
|
||||||
public String path;
|
public String path;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public Boolean clientAuth;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String keyStorePath;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String keyStorePassword;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String trustStorePath;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String trustStorePassword;
|
||||||
|
|
||||||
@XmlElementRef
|
@XmlElementRef
|
||||||
public List<AppDTO> apps;
|
public List<AppDTO> apps;
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,16 @@ import org.apache.activemq.artemis.dto.AppDTO;
|
||||||
import org.apache.activemq.artemis.dto.ComponentDTO;
|
import org.apache.activemq.artemis.dto.ComponentDTO;
|
||||||
import org.apache.activemq.artemis.dto.WebServerDTO;
|
import org.apache.activemq.artemis.dto.WebServerDTO;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
|
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||||
import org.eclipse.jetty.server.handler.HandlerList;
|
import org.eclipse.jetty.server.handler.HandlerList;
|
||||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -47,7 +52,33 @@ public class WebServerComponent implements ExternalComponent {
|
||||||
webServerConfig = (WebServerDTO) config;
|
webServerConfig = (WebServerDTO) config;
|
||||||
uri = new URI(webServerConfig.bind);
|
uri = new URI(webServerConfig.bind);
|
||||||
server = new Server();
|
server = new Server();
|
||||||
ServerConnector connector = new ServerConnector(server);
|
String scheme = uri.getScheme();
|
||||||
|
ServerConnector connector = null;
|
||||||
|
|
||||||
|
if ("https".equals(scheme)) {
|
||||||
|
SslContextFactory sslFactory = new SslContextFactory();
|
||||||
|
sslFactory.setKeyStorePath(webServerConfig.keyStorePath == null ? artemisInstance + "/etc/keystore.jks" : webServerConfig.keyStorePath);
|
||||||
|
sslFactory.setKeyStorePassword(webServerConfig.keyStorePassword == null ? "password" : webServerConfig.keyStorePassword);
|
||||||
|
if (webServerConfig.clientAuth != null) {
|
||||||
|
sslFactory.setNeedClientAuth(webServerConfig.clientAuth);
|
||||||
|
if (webServerConfig.clientAuth) {
|
||||||
|
sslFactory.setTrustStorePath(webServerConfig.trustStorePath);
|
||||||
|
sslFactory.setTrustStorePassword(webServerConfig.trustStorePassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslFactory, "HTTP/1.1");
|
||||||
|
|
||||||
|
HttpConfiguration https = new HttpConfiguration();
|
||||||
|
https.addCustomizer(new SecureRequestCustomizer());
|
||||||
|
HttpConnectionFactory httpFactory = new HttpConnectionFactory(https);
|
||||||
|
|
||||||
|
connector = new ServerConnector(server, sslConnectionFactory, httpFactory);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
connector = new ServerConnector(server);
|
||||||
|
}
|
||||||
connector.setPort(uri.getPort());
|
connector.setPort(uri.getPort());
|
||||||
connector.setHost(uri.getHost());
|
connector.setHost(uri.getHost());
|
||||||
|
|
||||||
|
|
|
@ -37,16 +37,22 @@ import io.netty.handler.codec.http.HttpMethod;
|
||||||
import io.netty.handler.codec.http.HttpObject;
|
import io.netty.handler.codec.http.HttpObject;
|
||||||
import io.netty.handler.codec.http.HttpRequest;
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
import io.netty.handler.codec.http.HttpVersion;
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import org.apache.activemq.artemis.component.WebServerComponent;
|
import org.apache.activemq.artemis.component.WebServerComponent;
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
|
||||||
import org.apache.activemq.artemis.dto.WebServerDTO;
|
import org.apache.activemq.artemis.dto.WebServerDTO;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
|
||||||
public class WebServerComponentTest extends Assert {
|
public class WebServerComponentTest extends Assert {
|
||||||
|
|
||||||
static final String URL = System.getProperty("url", "http://localhost:8161/WebServerComponentTest.txt");
|
static final String URL = System.getProperty("url", "http://localhost:8161/WebServerComponentTest.txt");
|
||||||
|
static final String SECURE_URL = System.getProperty("url", "https://localhost:8448/WebServerComponentTest.txt");
|
||||||
private Bootstrap bootstrap;
|
private Bootstrap bootstrap;
|
||||||
private EventLoopGroup group;
|
private EventLoopGroup group;
|
||||||
|
|
||||||
|
@ -94,6 +100,119 @@ public class WebServerComponentTest extends Assert {
|
||||||
Assert.assertFalse(webServerComponent.isStarted());
|
Assert.assertFalse(webServerComponent.isStarted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void simpleSecureServer() throws Exception {
|
||||||
|
WebServerDTO webServerDTO = new WebServerDTO();
|
||||||
|
webServerDTO.bind = "https://localhost:8448";
|
||||||
|
webServerDTO.path = "webapps";
|
||||||
|
webServerDTO.keyStorePath = "./src/test/resources/server.keystore";
|
||||||
|
webServerDTO.keyStorePassword = "password";
|
||||||
|
|
||||||
|
WebServerComponent webServerComponent = new WebServerComponent();
|
||||||
|
Assert.assertFalse(webServerComponent.isStarted());
|
||||||
|
webServerComponent.configure(webServerDTO, "./src/test/resources/", "./src/test/resources/");
|
||||||
|
webServerComponent.start();
|
||||||
|
// Make the connection attempt.
|
||||||
|
String keyStoreProvider = "JKS";
|
||||||
|
|
||||||
|
SSLContext context = SSLSupport.createContext(keyStoreProvider,
|
||||||
|
webServerDTO.keyStorePath,
|
||||||
|
webServerDTO.keyStorePassword,
|
||||||
|
keyStoreProvider,
|
||||||
|
webServerDTO.keyStorePath,
|
||||||
|
webServerDTO.keyStorePassword);
|
||||||
|
|
||||||
|
SSLEngine engine = context.createSSLEngine();
|
||||||
|
engine.setUseClientMode(true);
|
||||||
|
engine.setWantClientAuth(true);
|
||||||
|
final SslHandler sslHandler = new SslHandler(engine);
|
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
final ClientHandler clientHandler = new ClientHandler(latch);
|
||||||
|
bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
|
ch.pipeline().addLast(sslHandler);
|
||||||
|
ch.pipeline().addLast(new HttpClientCodec());
|
||||||
|
ch.pipeline().addLast(clientHandler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Channel ch = bootstrap.connect("localhost", 8448).sync().channel();
|
||||||
|
|
||||||
|
URI uri = new URI(SECURE_URL);
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
|
||||||
|
request.headers().set(HttpHeaders.Names.HOST, "localhost");
|
||||||
|
|
||||||
|
// Send the HTTP request.
|
||||||
|
ch.writeAndFlush(request);
|
||||||
|
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientHandler.body, "12345");
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
ch.close();
|
||||||
|
Assert.assertTrue(webServerComponent.isStarted());
|
||||||
|
webServerComponent.stop();
|
||||||
|
Assert.assertFalse(webServerComponent.isStarted());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void simpleSecureServerWithClientAuth() throws Exception {
|
||||||
|
WebServerDTO webServerDTO = new WebServerDTO();
|
||||||
|
webServerDTO.bind = "https://localhost:8448";
|
||||||
|
webServerDTO.path = "webapps";
|
||||||
|
webServerDTO.keyStorePath = "./src/test/resources/server.keystore";
|
||||||
|
webServerDTO.keyStorePassword = "password";
|
||||||
|
webServerDTO.clientAuth = true;
|
||||||
|
webServerDTO.trustStorePath = "./src/test/resources/server.keystore";
|
||||||
|
webServerDTO.trustStorePassword = "password";
|
||||||
|
|
||||||
|
WebServerComponent webServerComponent = new WebServerComponent();
|
||||||
|
Assert.assertFalse(webServerComponent.isStarted());
|
||||||
|
webServerComponent.configure(webServerDTO, "./src/test/resources/", "./src/test/resources/");
|
||||||
|
webServerComponent.start();
|
||||||
|
// Make the connection attempt.
|
||||||
|
String keyStoreProvider = "JKS";
|
||||||
|
|
||||||
|
SSLContext context = SSLSupport.createContext(keyStoreProvider,
|
||||||
|
webServerDTO.keyStorePath,
|
||||||
|
webServerDTO.keyStorePassword,
|
||||||
|
keyStoreProvider,
|
||||||
|
webServerDTO.trustStorePath,
|
||||||
|
webServerDTO.trustStorePassword);
|
||||||
|
|
||||||
|
SSLEngine engine = context.createSSLEngine();
|
||||||
|
engine.setUseClientMode(true);
|
||||||
|
engine.setWantClientAuth(true);
|
||||||
|
final SslHandler sslHandler = new SslHandler(engine);
|
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
final ClientHandler clientHandler = new ClientHandler(latch);
|
||||||
|
bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
|
ch.pipeline().addLast(sslHandler);
|
||||||
|
ch.pipeline().addLast(new HttpClientCodec());
|
||||||
|
ch.pipeline().addLast(clientHandler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Channel ch = bootstrap.connect("localhost", 8448).sync().channel();
|
||||||
|
|
||||||
|
URI uri = new URI(SECURE_URL);
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
|
||||||
|
request.headers().set(HttpHeaders.Names.HOST, "localhost");
|
||||||
|
|
||||||
|
// Send the HTTP request.
|
||||||
|
ch.writeAndFlush(request);
|
||||||
|
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientHandler.body, "12345");
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
ch.close();
|
||||||
|
Assert.assertTrue(webServerComponent.isStarted());
|
||||||
|
webServerComponent.stop();
|
||||||
|
Assert.assertFalse(webServerComponent.isStarted());
|
||||||
|
}
|
||||||
|
|
||||||
class ClientHandler extends SimpleChannelInboundHandler<HttpObject> {
|
class ClientHandler extends SimpleChannelInboundHandler<HttpObject> {
|
||||||
|
|
||||||
private CountDownLatch latch;
|
private CountDownLatch latch;
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue