ARTEMIS-3644 add cert info to CONNECTION_CREATED notification
This commit is contained in:
parent
f18dd80dc8
commit
e582ce03a5
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* 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.utils;
|
||||
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class CertificateUtil {
|
||||
private static final Logger logger = Logger.getLogger(CertificateUtil.class);
|
||||
|
||||
public static X509Certificate[] getCertsFromChannel(Channel channel) {
|
||||
Certificate[] plainCerts = null;
|
||||
ChannelHandler channelHandler = channel.pipeline().get("ssl");
|
||||
if (channelHandler != null && channelHandler instanceof SslHandler) {
|
||||
SslHandler sslHandler = (SslHandler) channelHandler;
|
||||
try {
|
||||
plainCerts = sslHandler.engine().getSession().getPeerCertificates();
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
X509Certificate[] x509Certs = null;
|
||||
if (plainCerts != null && plainCerts.length > 0) {
|
||||
x509Certs = new X509Certificate[plainCerts.length];
|
||||
for (int i = 0; i < plainCerts.length; i++) {
|
||||
if (plainCerts[i] instanceof X509Certificate) {
|
||||
x509Certs[i] = (X509Certificate) plainCerts[i];
|
||||
} else {
|
||||
try {
|
||||
x509Certs[i] = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(plainCerts[i].getEncoded()));
|
||||
} catch (Exception ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Failed to convert SSL cert", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Cert #" + i + " = " + x509Certs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return x509Certs;
|
||||
}
|
||||
}
|
|
@ -17,26 +17,42 @@
|
|||
|
||||
package org.apache.activemq.artemis.core.remoting;
|
||||
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnection;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.Principal;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class CertificateUtil {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CertificateUtil.class);
|
||||
|
||||
private static final String SSL_HANDLER_NAME = "ssl";
|
||||
|
||||
public static String getCertSubjectDN(RemotingConnection connection) {
|
||||
String certSubjectDN = "unavailable";
|
||||
X509Certificate[] certs = getCertsFromConnection(connection);
|
||||
if (certs != null && certs.length > 0 && certs[0] != null) {
|
||||
certSubjectDN = certs[0].getSubjectDN().getName();
|
||||
}
|
||||
return certSubjectDN;
|
||||
}
|
||||
|
||||
public static X509Certificate[] getCertsFromConnection(RemotingConnection remotingConnection) {
|
||||
X509Certificate[] certificates = null;
|
||||
if (remotingConnection != null) {
|
||||
Connection transportConnection = remotingConnection.getTransportConnection();
|
||||
if (transportConnection instanceof NettyConnection) {
|
||||
certificates = org.apache.activemq.artemis.utils.CertificateUtil.getCertsFromChannel(((NettyConnection) transportConnection).getChannel());
|
||||
certificates = getCertsFromChannel(((NettyConnection) transportConnection).getChannel());
|
||||
}
|
||||
}
|
||||
return certificates;
|
||||
|
@ -72,4 +88,47 @@ public class CertificateUtil {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static X509Certificate[] getCertsFromChannel(Channel channel) {
|
||||
Certificate[] plainCerts = null;
|
||||
ChannelHandler channelHandler = channel.pipeline().get("ssl");
|
||||
if (channelHandler != null && channelHandler instanceof SslHandler) {
|
||||
SslHandler sslHandler = (SslHandler) channelHandler;
|
||||
try {
|
||||
plainCerts = sslHandler.engine().getSession().getPeerCertificates();
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When using the OpenSSL provider on the broker the getPeerCertificates() method does *not* return a
|
||||
* X509Certificate[] so we need to convert the Certificate[] that is returned. This code is inspired by Tomcat's
|
||||
* org.apache.tomcat.util.net.jsse.JSSESupport class.
|
||||
*/
|
||||
X509Certificate[] x509Certs = null;
|
||||
if (plainCerts != null && plainCerts.length > 0) {
|
||||
x509Certs = new X509Certificate[plainCerts.length];
|
||||
for (int i = 0; i < plainCerts.length; i++) {
|
||||
if (plainCerts[i] instanceof X509Certificate) {
|
||||
x509Certs[i] = (X509Certificate) plainCerts[i];
|
||||
} else {
|
||||
try {
|
||||
x509Certs[i] = (X509Certificate) CertificateFactory
|
||||
.getInstance("X.509").generateCertificate(new ByteArrayInputStream(plainCerts[i].getEncoded()));
|
||||
} catch (Exception ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Failed to convert SSL cert", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Cert #" + i + " = " + x509Certs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return x509Certs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.apache.activemq.artemis.core.security.impl;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -203,15 +202,6 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getCertSubjectDN(RemotingConnection connection) {
|
||||
String certSubjectDN = "unavailable";
|
||||
X509Certificate[] certs = CertificateUtil.getCertsFromConnection(connection);
|
||||
if (certs != null && certs.length > 0 && certs[0] != null) {
|
||||
certSubjectDN = certs[0].getSubjectDN().getName();
|
||||
}
|
||||
return certSubjectDN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(final SimpleString address,
|
||||
final CheckType checkType,
|
||||
|
@ -356,7 +346,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
|||
}
|
||||
|
||||
private void authenticationFailed(String user, RemotingConnection connection) throws Exception {
|
||||
String certSubjectDN = getCertSubjectDN(connection);
|
||||
String certSubjectDN = CertificateUtil.getCertSubjectDN(connection);
|
||||
|
||||
if (notificationService != null) {
|
||||
TypedProperties props = new TypedProperties();
|
||||
|
@ -429,7 +419,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
|||
}
|
||||
|
||||
private String createAuthenticationCacheKey(String username, String password, RemotingConnection connection) {
|
||||
return username + password + getCertSubjectDN(connection);
|
||||
return username + password + CertificateUtil.getCertSubjectDN(connection);
|
||||
}
|
||||
|
||||
private String createAuthorizationCacheKey(String user, CheckType checkType) {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQException;
|
|||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.core.remoting.CertificateUtil;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.MessageReference;
|
||||
import org.apache.activemq.artemis.core.server.ServerConsumer;
|
||||
|
@ -170,8 +171,10 @@ public class NotificationActiveMQServerPlugin implements ActiveMQServerPlugin {
|
|||
|
||||
if (managementService != null && sendConnectionNotifications) {
|
||||
try {
|
||||
String certSubjectDN = CertificateUtil.getCertSubjectDN(connection);
|
||||
final TypedProperties props = new TypedProperties();
|
||||
props.putSimpleStringProperty(ManagementHelper.HDR_CONNECTION_NAME, SimpleString.toSimpleString(connection.getID().toString()));
|
||||
props.putSimpleStringProperty(ManagementHelper.HDR_CERT_SUBJECT_DN, SimpleString.toSimpleString(certSubjectDN));
|
||||
props.putSimpleStringProperty(ManagementHelper.HDR_REMOTE_ADDRESS, SimpleString.toSimpleString(connection.getRemoteAddress()));
|
||||
|
||||
managementService.sendNotification(new Notification(null, type, props));
|
||||
|
|
|
@ -40,6 +40,8 @@ import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
|||
import org.apache.activemq.artemis.core.security.Role;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
||||
import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerPlugin;
|
||||
import org.apache.activemq.artemis.core.server.plugin.impl.NotificationActiveMQServerPlugin;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||
import org.apache.activemq.artemis.tests.integration.security.SecurityTest;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
|
@ -48,6 +50,7 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.apache.activemq.artemis.api.core.management.CoreNotificationType.CONNECTION_CREATED;
|
||||
import static org.apache.activemq.artemis.api.core.management.CoreNotificationType.CONSUMER_CREATED;
|
||||
import static org.apache.activemq.artemis.api.core.management.CoreNotificationType.SECURITY_AUTHENTICATION_VIOLATION;
|
||||
|
||||
|
@ -77,7 +80,6 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase {
|
|||
|
||||
@Test
|
||||
public void testSECURITY_AUTHENTICATION_VIOLATION() throws Exception {
|
||||
SSLSecurityNotificationTest.flush(notifConsumer);
|
||||
|
||||
TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
|
||||
tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||
|
@ -89,6 +91,7 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase {
|
|||
ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
|
||||
ClientSessionFactory sf = addSessionFactory(createSessionFactory(locator));
|
||||
|
||||
SSLSecurityNotificationTest.flush(notifConsumer);
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
sf.createSession();
|
||||
|
@ -148,6 +151,36 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase {
|
|||
guestSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCONNECTION_CREATED() throws Exception {
|
||||
Role role = new Role("notif", true, true, true, true, false, true, true, true, true, true);
|
||||
Set<Role> roles = new HashSet<>();
|
||||
roles.add(role);
|
||||
server.getSecurityRepository().addMatch("#", roles);
|
||||
|
||||
TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
|
||||
tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||
tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
|
||||
tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "securepass");
|
||||
tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
|
||||
tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "securepass");
|
||||
|
||||
SSLSecurityNotificationTest.flush(notifConsumer);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
|
||||
ClientSessionFactory sf = addSessionFactory(createSessionFactory(locator));
|
||||
|
||||
ClientMessage notification = SecurityNotificationTest.consumeMessages(1, notifConsumer)[0];
|
||||
Assert.assertEquals(CONNECTION_CREATED.toString(), notification.getObjectProperty(ManagementHelper.HDR_NOTIFICATION_TYPE).toString());
|
||||
Assert.assertNotNull(notification.getObjectProperty(ManagementHelper.HDR_CERT_SUBJECT_DN));
|
||||
Assert.assertEquals("CN=ActiveMQ Artemis Client, OU=Artemis, O=ActiveMQ, L=AMQ, ST=AMQ, C=AMQ", notification.getObjectProperty(ManagementHelper.HDR_CERT_SUBJECT_DN).toString());
|
||||
Assert.assertTrue(notification.getObjectProperty(ManagementHelper.HDR_REMOTE_ADDRESS).toString().startsWith("/127.0.0.1"));
|
||||
Assert.assertTrue(notification.getTimestamp() >= start);
|
||||
Assert.assertTrue((long) notification.getObjectProperty(ManagementHelper.HDR_NOTIFICATION_TIMESTAMP) >= start);
|
||||
Assert.assertEquals(notification.getTimestamp(), (long) notification.getObjectProperty(ManagementHelper.HDR_NOTIFICATION_TIMESTAMP));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -165,6 +198,12 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase {
|
|||
|
||||
server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params));
|
||||
|
||||
ActiveMQServerPlugin plugin = new NotificationActiveMQServerPlugin();
|
||||
Map init = new HashMap();
|
||||
init.put(NotificationActiveMQServerPlugin.SEND_CONNECTION_NOTIFICATIONS, "true");
|
||||
plugin.init(init);
|
||||
server.registerBrokerPlugin(plugin);
|
||||
|
||||
server.start();
|
||||
|
||||
notifQueue = RandomUtil.randomSimpleString();
|
||||
|
|
Loading…
Reference in New Issue