Category Archives: Java

Connecting remote JVM over JMX using VisualVM or JConsole

There are many posts over the Internet on how to do it right, but unfortunately none worked for me (debian behind firewall on the server side, reached over VPN from my local Mac). Therefore, i’m sharing below the solution that worked for me.

 

1. Check server ip

hostname -i

 

2. use JVM params:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=[jmx port]
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=[server ip from step 1]

 

3. Run application

 

4. Find pid of the running java process

 

5. Check all ports used by JMX/RMI

netstat -lp | grep [pid from step 4]

 

6. Open all ports from step 5 on the firewall

 

Connecting remote JVM over JMX using VisualVM or JConsole

 

Cheers!

Token-based Authentication Plugin for ActiveMQ

This post is a part of ActiveMQ Custom Security Plugins series.

 

Similarly to how we did in case of the IP-based Authentication Plugin for ActiveMQ, in order to limit the connectivity to the ActiveMQ server based on Token (assuming the connecting client, eg. a browser through a JavaScript over STOMP protocol) is providing such token when trying to establish a connection with the broker), we’ll need to override the addConnection() method of the BrokerFilter.class.

 

For the purpose of this example, i’ll be using Redis as the data store against which i’ll be checking the Tokens of connecting clients; to make a decision whether a client is allowed to establish a connection with the broker (Token exists in Redis) or not (otherwise). To hit Redis from Java i’ll be using the Jedis driver.

 

Step1: Implementation of the plugin logic:

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import java.util.Map;

public class TokenAuthenticationBroker extends BrokerFilter {

  private final Logger logger = LoggerFactory.getLogger(getClass());
  public final static String REDIS_KEY = "authentication:activemq:tokens";

  Map<String, String> redisConfig;

  public TokenAuthenticationBroker(Broker next, Map<String, String> redisConfig) {
    super(next);
    this.redisConfig = redisConfig;
  }

  @Override
  public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
    String host = redisConfig.get("host");
    int port = Integer.parseInt(redisConfig.get("port"));

    logger.debug("Establishing Redis connection using [host={}, port={}] ", host, port);
    Jedis jedis = new Jedis(host, port);

    String token = context.getUserName();

    logger.debug("Querying Redis using [key={}, token={}] ", REDIS_KEY, token);
    String response = jedis.hget(REDIS_KEY, token);

    if(response == null) {
      throw new SecurityException("Token not not found in the data store");
    } else {
      logger.debug("Found token [{}] belonging to user: {}. Allowing connection", token, response);
    super.addConnection(context, info);
    }
  }
}

 

As you can see in the example above, the token provided by the connecting client can be read in ActiveMQ directly from the context (by using the getUserName() method; assuming the client is sending the token as a query parameter named “username”). Having the token, next thing we need to do is to query the Redis store (under the REDIS_KEY) and check whether the token exists (hget() method invoked on jedis object/driver). Depending on the value of response, we’re making the decision whether to addConnection() or throw an SecurityException.

 

Also, after the actual plug-in logic has been implemented, the plug-in must be configured and installed. For this purpose, we need an implementation of the BrokerPlugin.class, which is used to expose the configuration of a plug-in and to install the plug-in into the ActiveMQ broker.

 

Step2: Implementation of the plugin “installer”:

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;
import java.util.Map;

public class TokenAuthenticationPlugin implements BrokerPlugin {

  Map<String, String> redisConfig;

  @Override
  public Broker installPlugin(Broker broker) throws Exception {
    return new TokenAuthenticationBroker(broker, redisConfig);
  }

  public Map<String, String> getRedisConfig() {
    return redisConfig;
  }

  public void setRedisConfig(Map<String, String> redisConfig) {
    this.redisConfig = redisConfig;
  }
}

 

The installPlugin() method above is used to instantiate the plug-in and return a new intercepted broker for the next plug-in in the chain. The TokenAuthenticationPlugin.class also contains getter and setter methods used to configure the TokenAuthenticationBroker. These setter and getter methods are available via a Spring beans–style XML configuration in the ActiveMQ XML configuration file (example below).

 

Step3: Configuring the plugin in activemq.xml:

// "/apache-activemq/conf/activemq.xml"
<broker brokerName="localhost" dataDirectory="${activemq.base}/data" xmlns="http://activemq.apache.org/schema/core">
  <plugins>
    <bean id="tokenAuthenticationPlugin" class="com.mycompany.mysystem.activemq.TokenAuthenticationPlugin" xmlns="http://www.springframework.org/schema/beans">
      <property name="redisConfig">
        <map>
          <entry key="host" value="localhost" />
          <entry key="port" value="6379" />
        </map>
      </property>
    </bean>
  </plugins>
</broker>

 

That’s all there is to it 🙂

 

Happy Coding!

 

 

Resources:

IP-based Authentication Plugin for ActiveMQ

To limit the connectivity to the ActiveMQ server based on IP address, we’ll need to override the addConnection() method of the BrokerFilter.class, mentioned in my initial post on ActiveMQ Custom Security Plugins.

 

Example implementation (from the book “ActiveMQ in Action”):

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IPAuthenticationBroker extends BrokerFilter {

  List<String> allowedIPAddresses;
  Pattern pattern = Pattern.compile("^/([0-9\\.]*):(.*)");

  public IPAuthenticationBroker(Broker next, List<String> allowedIPAddresses) {
    super(next);
    this.allowedIPAddresses = allowedIPAddresses;
  }

  public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
    String remoteAddress = context.getConnection().getRemoteAddress();
    Matcher matcher = pattern.matcher(remoteAddress);
    if (matcher.matches()) {
      String ip = matcher.group(1);
        if (!allowedIPAddresses.contains(ip)) {
          throw new SecurityException("Connecting from IP address " + ip + " is not allowed" );
        }
    } else {
      throw new SecurityException("Invalid remote address " + remoteAddress);
    }
    super.addConnection(context, info);
  }
}

As you can see, the implementation above performs a simple check of the IP address using a regular expression to determine the ability to connect. If that IP address is allowed to connect, the call is delegated to the BrokerFilter.addConnection() method. If that IP address isn’t allowed to connect, an exception is thrown.

 

After the actual plug-in logic has been implemented, the plug-in must be configured and installed. For this purpose, we need an implementation of the BrokerPlugin.class, which is used to expose the configuration of a plug-in and to install the plug-in into the ActiveMQ broker.

 

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;
import java.util.List;

public class IPAuthenticationPlugin implements BrokerPlugin {

  List<String> allowedIPAddresses;

  public Broker installPlugin(Broker broker) throws Exception {
    return new IPAuthenticationBroker(broker, allowedIPAddresses);
  }

  public List<String> getAllowedIPAddresses() {
    return allowedIPAddresses;
  }

  public void setAllowedIPAddresses(List<String> allowedIPAddresses) {
    this.allowedIPAddresses = allowedIPAddresses;
  }
}

The installPlugin() method above is used to instantiate the plug-in and return a new intercepted broker for the next plug-in in the chain. The IPAuthenticationPlugin.class also contains getter and setter methods used to configure the IPAuthenticationBroker. These setter and getter methods are available via a Spring beans–style XML configuration in the ActiveMQ XML configuration file (example below).

 

// "\apache-activemq\conf\activemq.xml"
<broker brokerName="localhost" dataDirectory="${activemq.base}/data" xmlns="http://activemq.apache.org/schema/core">
  <plugins>
    <bean id="ipAuthenticationPlugin" class="com.mycompany.mysystem.activemq.IPAuthenticationPlugin" xmlns="http://www.springframework.org/schema/beans">
      <property name="allowedIPAddresses">
        <list>
          <value>127.0.0.1</value>
        </list>
      </property>
    </bean>
  </plugins>
</broker>

To summarize, creating custom security plugins using ActiveMQ plugin API, consists of following three steps:

  1. Implementing the plugin logic (overriding methods of the BrokerFilter.class – first code snippet above)
  2. Coding the plugin “installer” (implementing the BrokerPlugin.class – second code snippet)
  3. Configuring the plugin in activemq.xml file (Spring beans-style XML – third code snippet)

 

Happy coding!

 

 

Resources: