X.509 Certificate Based Authentication
X.509 Certificate Based Authentication is used in Two-Way SSL connection. In this case, the certificate itself is the client’s ID, thus, Access Token is no longer needed.
Instructions below will describe how to generate a client-side certificate and connect to the server that is running MQTT over SSL.
You will need to have the public key of the server certificate in PEM format.
See following instructions for more details on server-side configuration.
Update keygen.properties file
Open the keygen.properties file, and update the values if needed:
DOMAIN_SUFFIX="$(hostname)"
ORGANIZATIONAL_UNIT=ThingsBoard
ORGANIZATION=ThingsBoard
CITY=San Francisco
STATE_OR_PROVINCE=CA
TWO_LETTER_COUNTRY_CODE=US
SERVER_KEYSTORE_PASSWORD=server_ks_password
SERVER_KEY_PASSWORD=server_key_password
SERVER_KEY_ALIAS="serveralias"
SERVER_FILE_PREFIX="mqttserver"
SERVER_KEYSTORE_DIR="/etc/thingsboard/conf/"
CLIENT_KEYSTORE_PASSWORD=password
CLIENT_KEY_PASSWORD=password
CLIENT_KEY_ALIAS="clientalias"
CLIENT_FILE_PREFIX="mqttclient"
Run Client keygen script
Download and launch the client.keygen.sh script.
chmod +x client.keygen.sh
./client.keygen.sh
The script outputs the following files:
- CLIENT_FILE_PREFIX.jks - Java Keystore file with the server certificate imported
- CLIENT_FILE_PREFIX.nopass.pem - Client certificate file in PEM format to be used by non-java client
- CLIENT_FILE_PREFIX.pub.pem - Client public key
Provision Client Public Key as Device Credentials
Go to ThingsBoard Web UI -> Devices -> Your Device -> Device Credentials. Select X.509 Certificate device credentials, insert the contents of CLIENT_FILE_PREFIX.pub.pem file and click save.
Alternatively, the same can be done through the REST API.
Run Two-Way MQTT SSL Python Client
Download Python client example two-way-ssl-mqtt-client.py.
Specify your client-side certificate and path to the public key of the server certificate.
# Some code omitted
client.tls_set(ca_certs="mqttserver.pub.pem", certfile="mqttclient.nopass.pem", keyfile=None, cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1, ciphers=None);
# Some code omitted
Note Script uses 8883 MQTT port and requires paho-mqtt library that you can install using the following command: pip install paho-mqtt
Run the script:
If everything was configured correctly, the output should be like:
To run Java client, import CLIENT_FILE_PREFIX.jks file as follows:
resources/MqttSslClient.java |
import com.google.common.io.Resources;
import org.eclipse.paho.client.mqttv3.*;
import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
public class MqttSslClient {
private static final String MQTT_URL = "ssl://localhost:8883";
private static final String clientId = "MQTT_SSL_JAVA_CLIENT";
private static final String keyStoreFile = "mqttclient.jks";
private static final String JKS="JKS";
private static final String TLS="TLS";
private static final String CLIENT_KEYSTORE_PASSWORD = "password";
private static final String CLIENT_KEY_PASSWORD = "password";
public static void main(String[] args) {
try {
URL ksUrl = Resources.getResource(keyStoreFile);
File ksFile = new File(ksUrl.toURI());
URL tsUrl = Resources.getResource(keyStoreFile);
File tsFile = new File(tsUrl.toURI());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance(JKS);
trustStore.load(new FileInputStream(tsFile), CLIENT_KEYSTORE_PASSWORD.toCharArray());
tmf.init(trustStore);
KeyStore ks = KeyStore.getInstance(JKS);
ks.load(new FileInputStream(ksFile), CLIENT_KEYSTORE_PASSWORD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, CLIENT_KEY_PASSWORD.toCharArray());
KeyManager[] km = kmf.getKeyManagers();
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance(TLS);
sslContext.init(km, tm, null);
MqttConnectOptions options = new MqttConnectOptions();
options.setSocketFactory(sslContext.getSocketFactory());
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);
client.connect(options);
Thread.sleep(3000);
MqttMessage message = new MqttMessage();
message.setPayload("{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4}".getBytes());
client.publish("v1/devices/me/telemetry", message);
client.disconnect();
System.out.println("Disconnected");
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
|