diff --git a/dc3-center/dc3-auth/src/main/resources/application.yml b/dc3-center/dc3-auth/src/main/resources/application.yml
index 4079b7a72..3027073b4 100644
--- a/dc3-center/dc3-auth/src/main/resources/application.yml
+++ b/dc3-center/dc3-auth/src/main/resources/application.yml
@@ -12,8 +12,6 @@ spring:
- mysql
- redis
- feign
- #用于本地启动
- #- dev
main:
allow-bean-definition-overriding: true
mvc:
diff --git a/dc3-center/dc3-data/src/main/resources/application.yml b/dc3-center/dc3-data/src/main/resources/application.yml
index a15863713..3a47fb2ff 100644
--- a/dc3-center/dc3-data/src/main/resources/application.yml
+++ b/dc3-center/dc3-data/src/main/resources/application.yml
@@ -20,8 +20,6 @@ spring:
- mongo
- redis
- feign
- #用于本地启动
- #- dev
main:
allow-bean-definition-overriding: true
mvc:
diff --git a/dc3-common/dc3-base/pom.xml b/dc3-common/dc3-base/pom.xml
index 46df2fbe4..a54288e6a 100644
--- a/dc3-common/dc3-base/pom.xml
+++ b/dc3-common/dc3-base/pom.xml
@@ -32,6 +32,7 @@
0.9.1
5.6.3
1.2.76
+ 1.46
@@ -96,10 +97,10 @@
${fastjson.version}
-
org.bouncycastle
- bcpkix-jdk15on
+ bcprov-jdk16
+ ${bouncycastle.version}
diff --git a/dc3-common/dc3-base/src/main/java/com/dc3/common/utils/KeyUtil.java b/dc3-common/dc3-base/src/main/java/com/dc3/common/utils/KeyUtil.java
index b6015b8e5..9ec823b54 100644
--- a/dc3-common/dc3-base/src/main/java/com/dc3/common/utils/KeyUtil.java
+++ b/dc3-common/dc3-base/src/main/java/com/dc3/common/utils/KeyUtil.java
@@ -19,13 +19,25 @@ import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMReader;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.security.*;
+import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.KeySpec;
@@ -39,6 +51,7 @@ import java.util.Date;
*
* @author pnoker
*/
+@Slf4j
public class KeyUtil {
/**
@@ -182,4 +195,49 @@ public class KeyUtil {
.getBody();
}
+ public static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile, final String keyFile, final String password) {
+ try {
+ Security.addProvider(new BouncyCastleProvider());
+
+ // load CA certificate
+ PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
+ X509Certificate caCert = (X509Certificate) reader.readObject();
+ reader.close();
+
+ // load client certificate
+ reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
+ X509Certificate cert = (X509Certificate) reader.readObject();
+ reader.close();
+
+ // load client private key
+ reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))), password::toCharArray);
+ KeyPair key = (KeyPair) reader.readObject();
+ reader.close();
+
+ // CA certificate is used to authenticate server
+ KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
+ caKs.load(null, null);
+ caKs.setCertificateEntry("cacertfile", caCert);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(caKs);
+
+ // client key and certificates are sent to server so it can authenticate us
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null, null);
+ ks.setCertificateEntry("certfile", cert);
+ ks.setKeyEntry("keyfile", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, password.toCharArray());
+
+ // finally, create SSL socket factory
+ SSLContext context = SSLContext.getInstance("TLSv1.2");
+ context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+ return context.getSocketFactory();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
}
diff --git a/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/bean/MqttProperty.java b/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/bean/MqttProperty.java
index 0cfa9c4f8..b238a93ad 100644
--- a/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/bean/MqttProperty.java
+++ b/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/bean/MqttProperty.java
@@ -33,25 +33,49 @@ import java.util.List;
@Validated({Insert.class, Update.class})
@ConfigurationProperties(prefix = "driver.mqtt")
public class MqttProperty {
+ @NotBlank(message = "url can't be empty")
+ private String url;
+
+ @NotBlank(message = "auth type can't be empty")
+ private AuthTypeEnum authType;
+
@NotBlank(message = "username can't be empty")
private String username;
@NotBlank(message = "password can't be empty")
private String password;
- @NotBlank(message = "url can't be empty")
- private String url;
+ private String caCrt = "/home/mi/Code/mi/emqx-docker/certs/ca.crt";
+ private String clientKeyPass = "";
+ private String clientKey = "/home/mi/Code/mi/emqx-docker/certs/server.key";
+ private String clientCrt = "/home/mi/Code/mi/emqx-docker/certs/server.crt";
@Size(min = 1, message = "at least one qos")
private List qos;
+ @Size(min = 1, message = "at least one topic")
+ private List topics;
+
@NotNull(message = "keep alive interval can't be empty")
private Integer keepAlive;
@NotNull(message = "completion timeout can't be empty")
private Integer completionTimeout;
- @Size(min = 1, message = "at least one topic")
- private List topics;
+ public enum AuthTypeEnum {
+
+ NONE("none"),
+ CLIENT_ID("clientId"),
+ USERNAME("username"),
+ X509("x509");
+
+ @Getter
+ @Setter
+ private String authType;
+
+ AuthTypeEnum(String authType) {
+ this.authType = authType;
+ }
+ }
}
diff --git a/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/config/MqttConfig.java b/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/config/MqttConfig.java
index 2d1d8b681..dc81c6c07 100644
--- a/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/config/MqttConfig.java
+++ b/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/config/MqttConfig.java
@@ -13,6 +13,8 @@
package com.dc3.driver.config;
+import cn.hutool.core.util.StrUtil;
+import com.dc3.common.utils.KeyUtil;
import com.dc3.driver.bean.MqttProperty;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
@@ -55,16 +57,6 @@ public class MqttConfig {
@Resource
private MqttProperty mqttProperty;
- @Bean
- public MqttConnectOptions getMqttConnectOptions() {
- MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
- mqttConnectOptions.setUserName(mqttProperty.getUsername());
- mqttConnectOptions.setPassword(mqttProperty.getPassword().toCharArray());
- mqttConnectOptions.setServerURIs(new String[]{mqttProperty.getUrl()});
- mqttConnectOptions.setKeepAliveInterval(mqttProperty.getKeepAlive());
- return mqttConnectOptions;
- }
-
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
@@ -72,6 +64,36 @@ public class MqttConfig {
return factory;
}
+ @Bean
+ public MqttConnectOptions getMqttConnectOptions() {
+ MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
+
+
+ // username & password
+ if (mqttProperty.getAuthType().equals(MqttProperty.AuthTypeEnum.USERNAME)) {
+ mqttConnectOptions.setUserName(mqttProperty.getUsername());
+ mqttConnectOptions.setPassword(mqttProperty.getPassword().toCharArray());
+ }
+
+ // tls x509
+ if (mqttProperty.getAuthType().equals(MqttProperty.AuthTypeEnum.X509)) {
+ mqttConnectOptions.setSocketFactory(KeyUtil.getSocketFactory(
+ mqttProperty.getCaCrt(),
+ mqttProperty.getClientCrt(),
+ mqttProperty.getClientKey(),
+ StrUtil.isBlank(mqttProperty.getClientKeyPass()) ? "" : mqttProperty.getClientKeyPass()
+ ));
+ if (!StrUtil.isBlank(mqttProperty.getUsername()) && !StrUtil.isBlank(mqttProperty.getPassword())) {
+ mqttConnectOptions.setUserName(mqttProperty.getUsername());
+ mqttConnectOptions.setPassword(mqttProperty.getPassword().toCharArray());
+ }
+ }
+
+ mqttConnectOptions.setServerURIs(new String[]{mqttProperty.getUrl()});
+ mqttConnectOptions.setKeepAliveInterval(mqttProperty.getKeepAlive());
+ return mqttConnectOptions;
+ }
+
@Bean
public MessageChannel defaultMqttInputChannel() {
return new DirectChannel();
@@ -104,6 +126,11 @@ public class MqttConfig {
return new DirectChannel();
}
+ @Bean
+ public MessageChannel mqttOutputChannel() {
+ return new DirectChannel();
+ }
+
@Bean
public MessageProducer inbound() {
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
@@ -119,12 +146,7 @@ public class MqttConfig {
}
@Bean
- public MessageChannel mqttOutChannel() {
- return new DirectChannel();
- }
-
- @Bean
- @ServiceActivator(inputChannel = "mqttOutChannel")
+ @ServiceActivator(inputChannel = "mqttOutputChannel")
public MessageHandler outbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId, mqttClientFactory());
messageHandler.setAsync(true);
diff --git a/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/service/mqtt/MqttSendHandler.java b/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/service/mqtt/MqttSendHandler.java
index 9ed6e9003..e867ef6bf 100644
--- a/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/service/mqtt/MqttSendHandler.java
+++ b/dc3-driver/dc3-driver-mqtt/src/main/java/com/dc3/driver/service/mqtt/MqttSendHandler.java
@@ -20,7 +20,7 @@ import org.springframework.messaging.handler.annotation.Header;
/**
* @author pnoker
*/
-@MessagingGateway(defaultRequestChannel = "mqttOutChannel")
+@MessagingGateway(defaultRequestChannel = "mqttOutputChannel")
public interface MqttSendHandler {
/**
* 使用 Default Topic & Default Qos 发送数据
diff --git a/dc3-driver/dc3-driver-mqtt/src/main/resources/META-INF/spring-configuration-metadata.json b/dc3-driver/dc3-driver-mqtt/src/main/resources/META-INF/spring-configuration-metadata.json
new file mode 100644
index 000000000..f4e22e0d3
--- /dev/null
+++ b/dc3-driver/dc3-driver-mqtt/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,9 @@
+{
+ "properties": [
+ {
+ "name": "driver.mqtt.auth-type",
+ "type": "com.dc3.driver.bean.MqttProperty.AuthTypeEnum",
+ "description": "mqtt auth type."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/dc3-driver/dc3-driver-mqtt/src/main/resources/application.yml b/dc3-driver/dc3-driver-mqtt/src/main/resources/application.yml
index b917c37bf..50d121d62 100644
--- a/dc3-driver/dc3-driver-mqtt/src/main/resources/application.yml
+++ b/dc3-driver/dc3-driver-mqtt/src/main/resources/application.yml
@@ -35,11 +35,14 @@ driver:
data-type: static/url
data: jsonString
mqtt:
+ url: tcp://dc3-emqx:8883
+ auth-type: X509
username: dc3
password: dc3
- url: tcp://dc3-rabbitmq:1883
- #也可以连接到其他的mqtt服务器,例如:emqx,你可以在docker-compose.yml中找到,并启动它
- #url: tcp://dc3-emqx:1884
+ ca-crt: ./certs/ca.crt
+ client-key-pass: emqx-mqtt
+ client-key: ./certs/client.key
+ client-crt: ./certs/client.crt
qos:
- 0
topics:
diff --git a/pom.xml b/pom.xml
index f6aef1f1d..c9200c36a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -348,10 +348,17 @@
org.springframework.boot
spring-boot-maven-plugin
- ${spring-boot.version}
+ 2.3.8.RELEASE
${project.build.finalName}
+
+
+
+ repackage
+
+
+