From f703254518fa8d365be170145e07721aaf9815e4 Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Thu, 03 Oct 2013 18:00:04 +0000
Subject: [PATCH] Fix OPENDJ-1161 - Allow configuration of RMI port in JMX connector. These changes are adding a new optional configuration parameter : rmi-port, to allow specifying a fixed port for the RMI connection underlying JMX. This is required when managing applications need to connect to OpenDJ through a firewall. CR-2429.

---
 opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java             |   97 ++++++++++++++++++-------------
 opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java                     |    9 +-
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml |   34 ++++++++++
 opendj-sdk/opends/src/admin/messages/JMXConnectionHandlerCfgDefn.properties                        |    4 +
 opendj-sdk/opends/resource/schema/02-config.ldif                                                   |    8 ++
 5 files changed, 103 insertions(+), 49 deletions(-)

diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index eb2a3a4..f628927 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -3749,6 +3749,11 @@
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.132
+  NAME 'ds-cfg-rmi-port' EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler'
   SUP top
@@ -4456,7 +4461,8 @@
   MAY ( ds-cfg-listen-address $
         ds-cfg-ssl-cert-nickname $
         ds-cfg-use-ssl $
-        ds-cfg-key-manager-provider )
+        ds-cfg-key-manager-provider $
+        ds-cfg-rmi-port )
   X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.63
   NAME 'ds-task-import'
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
index 2f00ff9..7f52580 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
@@ -24,6 +24,7 @@
   !
   !
   !      Copyright 2007-2009 Sun Microsystems, Inc.
+  !      Portions Copyright 2013 ForgeRock AS.
   ! -->
 <adm:managed-object name="jmx-connection-handler"
   plural-name="jmx-connection-handlers"
@@ -67,11 +68,12 @@
       </adm:defined>
     </adm:default-behavior>
   </adm:property-override>
-     <adm:property name="listen-address" multi-valued="true" read-only="true">
+  <adm:property name="listen-address" multi-valued="true" read-only="true">
     <adm:synopsis>
       Specifies the address or set of addresses on which this
       <adm:user-friendly-name />
-      should listen for connections from SNMP clients.
+      should listen for connections from JMX clients. However JMX/RMI
+      doesn't allow this, and this property cannot be set.
     </adm:synopsis>
     <adm:description>
       Multiple addresses may be provided as separate values for this
@@ -146,4 +148,32 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="rmi-port">
+    <adm:synopsis>
+        Specifies the port number on which the JMX RMI service
+        will listen for connections from clients. A value of 0
+        indicates the service to choose a port of its own.
+    </adm:synopsis>
+    <adm:description>
+        If the value provided is different than 0, the value
+        will be used as the RMI port. Otherwise, the RMI service
+        will choose a port of its own.
+    </adm:description>
+    <adm:requires-admin-action>
+      <adm:component-restart />
+    </adm:requires-admin-action>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>0</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer lower-limit="0" upper-limit="65535" />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-rmi-port</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
 </adm:managed-object>
diff --git a/opendj-sdk/opends/src/admin/messages/JMXConnectionHandlerCfgDefn.properties b/opendj-sdk/opends/src/admin/messages/JMXConnectionHandlerCfgDefn.properties
index d4b2078..3544453 100644
--- a/opendj-sdk/opends/src/admin/messages/JMXConnectionHandlerCfgDefn.properties
+++ b/opendj-sdk/opends/src/admin/messages/JMXConnectionHandlerCfgDefn.properties
@@ -15,10 +15,12 @@
 property.key-manager-provider.synopsis=Specifies the name of the key manager that should be used with this JMX Connection Handler .
 property.key-manager-provider.requires-admin-action.synopsis=Changes to this property take effect immediately, but only for subsequent attempts to access the key manager provider for associated client connections.
 property.key-manager-provider.syntax.aggregation.constraint-synopsis=The referenced key manager provider must be enabled when the JMX Connection Handler is enabled and configured to use SSL.
-property.listen-address.synopsis=Specifies the address or set of addresses on which this JMX Connection Handler should listen for connections from SNMP clients.
+property.listen-address.synopsis=Specifies the address or set of addresses on which this JMX Connection Handler should listen for connections from JMX clients. However JMX/RMI doesn't allow this, and this property cannot be set.
 property.listen-address.description=Multiple addresses may be provided as separate values for this attribute. If no values are provided, then the JMX Connection Handler listens on all interfaces.
 property.listen-port.synopsis=Specifies the port number on which the JMX Connection Handler will listen for connections from clients.
 property.listen-port.description=Only a single port number may be provided.
+property.rmi-port.synopsis=Specifies the port number on which the JMX RMI service will listen for connections from clients. A value of 0 indicates the service to choose a port of its own.
+property.rmi-port.description=If the value provided is different than 0, the value will be used as the RMI port. Otherwise, the RMI service will choose a port of its own.
 property.ssl-cert-nickname.synopsis=Specifies the nickname (also called the alias) of the certificate that the JMX Connection Handler should use when performing SSL communication.
 property.ssl-cert-nickname.description=This is only applicable when the JMX Connection Handler is configured to use SSL.
 property.ssl-cert-nickname.default-behavior.alias.synopsis=Let the server decide.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
index 8b85df8..3f902ca 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
@@ -122,6 +122,10 @@
       portChanged = true;
     }
 
+    if (currentConfig.getRmiPort() != config.getRmiPort())
+    {
+      rmiConnectorRestart = true;
+    }
     if (currentConfig.isUseSSL() != config.isUseSSL()) {
       rmiConnectorRestart = true;
     }
@@ -205,9 +209,7 @@
   @Override
   public Map<String, String> getAlerts()
   {
-    Map<String, String> alerts = new LinkedHashMap<String, String>();
-
-    return alerts;
+    return new LinkedHashMap<String, String>();
   }
 
 
@@ -280,6 +282,14 @@
     return currentConfig.getListenPort();
   }
 
+  /**
+   * Get the JMX connection handler's rmi port.
+   *
+   * @return Returns the JMX connection handler's rmi port.
+   */
+  public int getRmiPort() {
+    return currentConfig.getRmiPort();
+  }
 
 
   /**
@@ -326,22 +336,11 @@
     // Configuration is ok.
     currentConfig = config;
 
-    // Attempt to bind to the listen port to verify whether the connection
-    // handler will be able to start.
-    try
+    List<Message> reasons = new LinkedList<Message>();
+    if (!isPortConfigurationAcceptable(String.valueOf(config.dn()),
+        config.getListenPort(), reasons))
     {
-      if (StaticUtils.isAddressInUse(
-        new InetSocketAddress(config.getListenPort()).getAddress(),
-        config.getListenPort(), true)) {
-        throw new IOException(
-          ERR_CONNHANDLER_ADDRESS_INUSE.get().toString());
-      }
-    }
-    catch (Exception e)
-    {
-      Message message =
-          ERR_CONNHANDLER_CANNOT_BIND.get("JMX", String.valueOf(config.dn()),
-              WILDCARD_ADDRESS, config.getListenPort(), getExceptionMessage(e));
+      Message message = reasons.get(0);
       logError(message);
       throw new InitializationException(message);
     }
@@ -399,7 +398,6 @@
   }
 
 
-
   /**
    * {@inheritDoc}
    */
@@ -409,32 +407,48 @@
   {
     JMXConnectionHandlerCfg config = (JMXConnectionHandlerCfg) configuration;
 
-    if ((currentConfig == null) ||
+    if (currentConfig == null ||
         (!currentConfig.isEnabled() && config.isEnabled()) ||
-        (currentConfig.getListenPort() != config.getListenPort())) {
-      // Attempt to bind to the listen port to verify whether the connection
-      // handler will be able to start.
-      try {
-        if (StaticUtils.isAddressInUse(
-          new InetSocketAddress(config.getListenPort()).getAddress(),
-          config.getListenPort(), true)) {
-          throw new IOException(
-            ERR_CONNHANDLER_ADDRESS_INUSE.get().toString());
-        }
-      } catch (Exception e) {
-        Message message =
-            ERR_CONNHANDLER_CANNOT_BIND.get("JMX", String.valueOf(config.dn()),
-                WILDCARD_ADDRESS, config.getListenPort(),
-                getExceptionMessage(e));
-        unacceptableReasons.add(message);
-        return false;
-      }
+        currentConfig.getListenPort() != config.getListenPort() &&
+        !isPortConfigurationAcceptable(String.valueOf(config.dn()),
+          config.getListenPort(), unacceptableReasons))
+    {
+      return false;
+    }
+
+    if (config.getRmiPort() != 0 &&
+        (currentConfig == null ||
+        (!currentConfig.isEnabled() && config.isEnabled()) ||
+        currentConfig.getRmiPort() != config.getRmiPort()) &&
+        !isPortConfigurationAcceptable(String.valueOf(config.dn()),
+          config.getRmiPort(), unacceptableReasons))
+    {
+      return false;
     }
 
     return isConfigurationChangeAcceptable(config, unacceptableReasons);
   }
 
-
+  /**
+   * Attempt to bind to the port to verify whether the connection
+   * handler will be able to start.
+   * @return true is the port is free to use, false otherwise.
+   */
+  private boolean isPortConfigurationAcceptable(String configDN,
+                      int newPort, List<Message> unacceptableReasons) {
+    try {
+      if (StaticUtils.isAddressInUse(
+          new InetSocketAddress(newPort).getAddress(), newPort, true)) {
+        throw new IOException(ERR_CONNHANDLER_ADDRESS_INUSE.get().toString());
+      }
+    } catch (Exception e) {
+      Message message = ERR_CONNHANDLER_CANNOT_BIND.get("JMX", configDN,
+              WILDCARD_ADDRESS, newPort, getExceptionMessage(e));
+      unacceptableReasons.add(message);
+      return false;
+    }
+    return true;
+  }
 
   /**
    * {@inheritDoc}
@@ -453,7 +467,7 @@
    * Determines whether or not clients are allowed to connect over JMX
    * using SSL.
    *
-   * @return Returns <code>true</code> if clients are allowed to
+   * @return Returns {@code true} if clients are allowed to
    *         connect over JMX using SSL.
    */
   public boolean isUseSSL() {
@@ -494,8 +508,9 @@
     {
       rmiConnector.initialize();
     }
-    catch (RuntimeException e)
+    catch (RuntimeException ignore)
     {
+      // Already caught and logged
     }
   }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
index 3858b65..f296fb5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2013 ForgeRock AS.
  */
 package org.opends.server.protocols.jmx;
 
@@ -127,7 +128,7 @@
   private OpendsRmiServerSocketFactory rmiSsf;
 
   /**
-   * The RMI protocol verison used by this connector.
+   * The RMI protocol version used by this connector.
    */
   private String rmiVersion;
 
@@ -271,7 +272,7 @@
 
   /**
    * Starts a secure RMI connector, with a client that doesn't have to
-   * present a certificate, on the local mbean server.
+   * present a certificate, on the local MBean server.
    * This method assumes that the common registry was successfully
    * started.
    * <p>
@@ -386,8 +387,8 @@
         TRACER.debugVerbose("Create and start the JMX RMI connector");
       }
       OpendsRMIJRMPServerImpl opendsRmiConnectorServer =
-          new OpendsRMIJRMPServerImpl(
-              0, rmiClientSockeyFactory, rmiServerSockeyFactory, env);
+          new OpendsRMIJRMPServerImpl(jmxConnectionHandler.getRmiPort(),
+              rmiClientSockeyFactory, rmiServerSockeyFactory, env);
       jmxRmiConnectorNoClientCertificate = new RMIConnectorServer(url, env,
           opendsRmiConnectorServer, mbs);
       jmxRmiConnectorNoClientCertificate.start();

--
Gitblit v1.10.0