All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sitewhere.communication.mqtt.MqttConfigurer Maven / Gradle / Ivy

/**
 * Copyright © 2014-2021 The SiteWhere Authors
 *
 * Licensed 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 com.sitewhere.communication.mqtt;

import java.io.File;
import java.io.FileInputStream;
import java.net.URISyntaxException;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.lang3.StringUtils;
import org.fusesource.mqtt.client.MQTT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sitewhere.spi.SiteWhereException;

/**
 * Common MQTT configuration functionality.
 */
public class MqttConfigurer {

    /** Static logger instance */
    private static Logger LOGGER = LoggerFactory.getLogger(MqttConfigurer.class);

    /**
     * Configures MQTT connectivity based on configuration.
     * 
     * @return
     * @throws SiteWhereException
     */
    public static MQTT configure(IMqttConfiguration configuration) throws SiteWhereException {
	MQTT mqtt = new MQTT();

	boolean usingSSL = configuration.getProtocol().startsWith("ssl");
	boolean usingTLS = configuration.getProtocol().startsWith("tls");

	// Optionally set client id.
	if (configuration.getClientId() != null) {
	    mqtt.setClientId(configuration.getClientId());
	    LOGGER.info("MQTT connection will use client id '" + configuration.getClientId() + "'.");
	}
	// Set flag for clean session.
	mqtt.setCleanSession(configuration.isCleanSession());
	LOGGER.info("MQTT clean session flag being set to '" + configuration.isCleanSession() + "'.");

	if (usingSSL || usingTLS) {
	    handleSecureTransport(mqtt, configuration);
	}
	// Set username if provided.
	if (!StringUtils.isEmpty(configuration.getUsername())) {
	    mqtt.setUserName(configuration.getUsername());
	}
	// Set password if provided.
	if (!StringUtils.isEmpty(configuration.getPassword())) {
	    mqtt.setPassword(configuration.getPassword());
	}
	try {
	    mqtt.setHost(
		    configuration.getProtocol() + "://" + configuration.getHostname() + ":" + configuration.getPort());
	    return mqtt;
	} catch (URISyntaxException e) {
	    throw new SiteWhereException("Invalid hostname for MQTT server.", e);
	}
    }

    /**
     * Handle configuration of secure transport.
     * 
     * @param mqtt
     * @throws SiteWhereException
     */
    protected static void handleSecureTransport(MQTT mqtt, IMqttConfiguration configuration) throws SiteWhereException {
	LOGGER.info("MQTT client using secure protocol '" + configuration.getProtocol() + "'.");
	boolean trustStoreConfigured = (configuration.getTrustStorePath() != null)
		&& (configuration.getTrustStorePassword() != null);
	boolean keyStoreConfigured = (configuration.getKeyStorePath() != null)
		&& (configuration.getKeyStorePassword() != null);
	try {
	    SSLContext sslContext = SSLContext.getInstance("TLS");
	    TrustManagerFactory tmf = null;
	    KeyManagerFactory kmf;

	    // Handle trust store configuration.
	    if (trustStoreConfigured) {
		tmf = configureTrustStore(sslContext, configuration.getTrustStorePath(),
			configuration.getTrustStorePassword());
	    } else {
		LOGGER.info("No trust store configured for MQTT client.");
	    }

	    // Handle key store configuration.
	    if (keyStoreConfigured) {
		kmf = configureKeyStore(sslContext, configuration.getKeyStorePath(),
			configuration.getKeyStorePassword());
		sslContext.init(kmf.getKeyManagers(), tmf != null ? tmf.getTrustManagers() : null, null);
	    } else if (trustStoreConfigured) {
		sslContext.init(null, tmf != null ? tmf.getTrustManagers() : null, null);
	    }

	    mqtt.setSslContext(sslContext);
	    LOGGER.info("Created SSL context for MQTT receiver.");
	} catch (Throwable t) {
	    throw new SiteWhereException("Unable to configure secure transport.", t);
	}
    }

    /**
     * Configure trust store.
     * 
     * @param sslContext
     * @param trustStorePath
     * @param trustStorePassword
     * @return
     * @throws Exception
     */
    protected static TrustManagerFactory configureTrustStore(SSLContext sslContext, String trustStorePath,
	    String trustStorePassword) throws Exception {
	LOGGER.info("MQTT client using truststore path: " + trustStorePath);
	TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
	KeyStore tks = KeyStore.getInstance("JKS");
	File trustFile = new File(trustStorePath);
	tks.load(new FileInputStream(trustFile), trustStorePassword.toCharArray());
	tmf.init(tks);
	return tmf;
    }

    /**
     * Configure key store.
     * 
     * @param sslContext
     * @param keyStorePath
     * @param keyStorePassword
     * @return
     * @throws Exception
     */
    protected static KeyManagerFactory configureKeyStore(SSLContext sslContext, String keyStorePath,
	    String keyStorePassword) throws Exception {
	LOGGER.info("MQTT client using keystore path: " + keyStorePath);
	KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
	KeyStore ks = KeyStore.getInstance("JKS");
	File keyFile = new File(keyStorePath);
	ks.load(new FileInputStream(keyFile), keyStorePassword.toCharArray());
	kmf.init(ks, keyStorePassword.toCharArray());
	return kmf;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy