ARTEMIS-594 support HTTPS access to hawtio

This commit is contained in:
Howard Gao 2016-06-24 14:04:57 +08:00 committed by jbertram
parent b88969cd7d
commit 23475caca9
6 changed files with 170 additions and 1 deletions

View File

@ -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}", "");
} }

View File

@ -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;

View File

@ -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());

View File

@ -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.