2626import java .rmi .RemoteException ;
2727import java .rmi .registry .LocateRegistry ;
2828import java .rmi .registry .Registry ;
29+ import java .rmi .server .RMIClientSocketFactory ;
30+ import java .rmi .server .RMIServerSocketFactory ;
2931import java .rmi .server .UnicastRemoteObject ;
3032import java .util .LinkedList ;
3133import java .util .List ;
5052import javax .management .remote .JMXServiceURL ;
5153import javax .management .remote .rmi .RMIConnectorServer ;
5254import javax .management .remote .rmi .RMIJRMPServerImpl ;
55+ import javax .rmi .ssl .SslRMIClientSocketFactory ;
56+ import javax .rmi .ssl .SslRMIServerSocketFactory ;
5357
5458import org .apache .activemq .Service ;
59+ import org .apache .activemq .broker .SslContext ;
5560import org .slf4j .Logger ;
5661import org .slf4j .LoggerFactory ;
5762import org .slf4j .MDC ;
@@ -115,6 +120,7 @@ public class ManagementContext implements Service {
115120 private List <ObjectName > suppressMBeanList ;
116121 private Remote serverStub ;
117122 private RMIJRMPServerImpl server ;
123+ private SslContext sslContext ;
118124
119125 public ManagementContext () {
120126 this (null );
@@ -549,11 +555,28 @@ protected MBeanServer createMBeanServer() throws MalformedObjectNameException, I
549555 }
550556
551557 private void createConnector (MBeanServer mbeanServer ) throws IOException {
558+ // Resolve SSL socket factories first, so they can be shared by registry and connector
559+ final RMIClientSocketFactory csf ;
560+ final RMIServerSocketFactory ssf ;
561+ if (sslContext != null ) {
562+ try {
563+ final javax .net .ssl .SSLContext ctx = sslContext .getSSLContext ();
564+ csf = new SslRMIClientSocketFactory ();
565+ ssf = new SslRMIServerSocketFactory (ctx , null , null , false );
566+ LOG .info ("JMX connector will use SSL from configured sslContext" );
567+ } catch (Exception e ) {
568+ throw new IOException ("Failed to initialize SSL for JMX connector" , e );
569+ }
570+ } else {
571+ csf = null ;
572+ ssf = null ;
573+ }
574+
552575 // Create the NamingService, needed by JSR 160
553576 try {
554577 if (registry == null ) {
555578 LOG .debug ("Creating RMIRegistry on port {}" , connectorPort );
556- registry = jmxRegistry (connectorPort );
579+ registry = jmxRegistry (connectorPort , csf , ssf );
557580 }
558581
559582 namingServiceObjectName = ObjectName .getInstance ("naming:type=rmiregistry" );
@@ -579,7 +602,7 @@ private void createConnector(MBeanServer mbeanServer) throws IOException {
579602 rmiServer = "" +getConnectorHost ()+":" + rmiServerPort ;
580603 }
581604
582- server = new RMIJRMPServerImpl (connectorPort , null , null , environment );
605+ server = new RMIJRMPServerImpl (connectorPort , csf , ssf , environment );
583606
584607 final String serviceURL = "service:jmx:rmi://" + rmiServer + "/jndi/rmi://" +getConnectorHost ()+":" + connectorPort + connectorPath ;
585608 final JMXServiceURL url = new JMXServiceURL (serviceURL );
@@ -659,6 +682,28 @@ public void setEnvironment(Map<String, ?> environment) {
659682 this .environment = environment ;
660683 }
661684
685+ /**
686+ * Get the SSL context used for the JMX connector.
687+ */
688+ public SslContext getSslContext () {
689+ return sslContext ;
690+ }
691+
692+ /**
693+ * Set the SSL context to use for the JMX connector.
694+ * When configured, the JMX RMI connector will use SSL with the
695+ * keyStore and trustStore from this context, allowing reuse of
696+ * the broker's {@code <sslContext>} configuration.
697+ *
698+ * Example XML configuration:
699+ * <pre>
700+ * <managementContext createConnector="true" sslContext="#brokerSslContext"/>
701+ * </pre>
702+ */
703+ public void setSslContext (SslContext sslContext ) {
704+ this .sslContext = sslContext ;
705+ }
706+
662707 public boolean isAllowRemoteAddressInMBeanNames () {
663708 return allowRemoteAddressInMBeanNames ;
664709 }
@@ -683,9 +728,11 @@ public String getSuppressMBean() {
683728 }
684729
685730 // do not use sun.rmi.registry.RegistryImpl! it is not always easily available
686- private Registry jmxRegistry (final int port ) throws RemoteException {
731+ private Registry jmxRegistry (final int port , final RMIClientSocketFactory csf , final RMIServerSocketFactory ssf ) throws RemoteException {
687732 final var loader = Thread .currentThread ().getContextClassLoader ();
688- final var delegate = LocateRegistry .createRegistry (port );
733+ final var delegate = (csf != null && ssf != null )
734+ ? LocateRegistry .createRegistry (port , csf , ssf )
735+ : LocateRegistry .createRegistry (port );
689736 return Registry .class .cast (Proxy .newProxyInstance (
690737 loader == null ? getSystemClassLoader () : loader ,
691738 new Class <?>[]{Registry .class }, (proxy , method , args ) -> {
0 commit comments