Browse Source

Merge branch 'feature/rest_api_node_ssl' of https://github.com/vkukhtyn/thingsboard

pull/3985/head
Andrii Shvaika 6 years ago
parent
commit
e97c742828
  1. 21
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java
  2. 23
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java
  3. 32
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java
  4. 26
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java
  5. 29
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CredentialsType.java
  6. 36
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java
  7. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java
  8. 16
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java
  9. 45
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java
  10. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeConfiguration.java
  11. 20
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java
  12. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java
  13. 2
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  14. 34
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/BasicCredentialsTest.java

21
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/AnonymousCredentials.java → rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java

@ -13,23 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.mqtt.credentials; package org.thingsboard.rule.engine.credentials;
import io.netty.handler.ssl.SslContext; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.thingsboard.mqtt.MqttClientConfig;
import java.util.Optional;
public class AnonymousCredentials implements MqttClientCredentials {
@JsonIgnoreProperties(ignoreUnknown = true)
public class AnonymousCredentials implements ClientCredentials {
@Override @Override
public Optional<SslContext> initSslContext() { public CredentialsType getType() {
return Optional.empty(); return CredentialsType.ANONYMOUS;
}
@Override
public void configure(MqttClientConfig config) {
} }
} }

23
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/BasicCredentials.java → rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java

@ -13,30 +13,19 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.mqtt.credentials; package org.thingsboard.rule.engine.credentials;
import io.netty.handler.ssl.SslContext; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data; import lombok.Data;
import org.thingsboard.mqtt.MqttClientConfig;
import java.util.Optional;
@Data @Data
public class BasicCredentials implements MqttClientCredentials { @JsonIgnoreProperties(ignoreUnknown = true)
public class BasicCredentials implements ClientCredentials {
private String username; private String username;
private String password; private String password;
@Override @Override
public Optional<SslContext> initSslContext() { public CredentialsType getType() {
return Optional.empty(); return CredentialsType.BASIC;
} }
@Override
public void configure(MqttClientConfig config) {
config.setUsername(username);
config.setPassword(password);
}
} }

32
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java → rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java

@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.mqtt.credentials; package org.thingsboard.rule.engine.credentials;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslContextBuilder;
import lombok.Data; import lombok.Data;
@ -29,7 +28,6 @@ import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.mqtt.MqttClientConfig;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.EncryptedPrivateKeyInfo; import javax.crypto.EncryptedPrivateKeyInfo;
@ -51,13 +49,11 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.spec.KeySpec; import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Optional;
@Data @Data
@Slf4j @Slf4j
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class CertPemClientCredentials implements MqttClientCredentials { public class CertPemCredentials implements ClientCredentials {
private static final String TLS_VERSION = "TLSv1.2"; private static final String TLS_VERSION = "TLSv1.2";
private String caCert; private String caCert;
@ -66,25 +62,27 @@ public class CertPemClientCredentials implements MqttClientCredentials {
private String password; private String password;
@Override @Override
public Optional<SslContext> initSslContext() { public CredentialsType getType() {
return CredentialsType.CERT_PEM;
}
public SslContext initSslContext() {
try { try {
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
return Optional.of(SslContextBuilder.forClient() SslContextBuilder builder = SslContextBuilder.forClient();
.keyManager(createAndInitKeyManagerFactory()) if (StringUtils.hasLength(caCert)) {
.trustManager(createAndInitTrustManagerFactory()) builder.trustManager(createAndInitTrustManagerFactory());
.clientAuth(ClientAuth.REQUIRE) }
.build()); if (StringUtils.hasLength(cert) && StringUtils.hasLength(privateKey)) {
builder.keyManager(createAndInitKeyManagerFactory());
}
return builder.build();
} catch (Exception e) { } catch (Exception e) {
log.error("[{}:{}] Creating TLS factory failed!", caCert, cert, e); log.error("[{}:{}] Creating TLS factory failed!", caCert, cert, e);
throw new RuntimeException("Creating TLS factory failed!", e); throw new RuntimeException("Creating TLS factory failed!", e);
} }
} }
@Override
public void configure(MqttClientConfig config) {
}
private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception {
X509Certificate certHolder = readCertFile(cert); X509Certificate certHolder = readCertFile(cert);
Object keyObject = readPrivateKeyFile(privateKey); Object keyObject = readPrivateKeyFile(privateKey);

26
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java → rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java

@ -13,29 +13,29 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.rule.engine.mqtt.credentials; package org.thingsboard.rule.engine.credentials;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import org.thingsboard.mqtt.MqttClientConfig; import io.netty.handler.ssl.SslContextBuilder;
import org.thingsboard.rule.engine.mqtt.azure.AzureIotHubSasCredentials; import org.thingsboard.rule.engine.mqtt.azure.AzureIotHubSasCredentials;
import java.util.Optional; import javax.net.ssl.SSLException;
@JsonTypeInfo( @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({ @JsonSubTypes({
@JsonSubTypes.Type(value = AnonymousCredentials.class, name = "anonymous"), @JsonSubTypes.Type(value = AnonymousCredentials.class, name = "anonymous"),
@JsonSubTypes.Type(value = BasicCredentials.class, name = "basic"), @JsonSubTypes.Type(value = BasicCredentials.class, name = "basic"),
@JsonSubTypes.Type(value = AzureIotHubSasCredentials.class, name = "sas"), @JsonSubTypes.Type(value = AzureIotHubSasCredentials.class, name = "sas"),
@JsonSubTypes.Type(value = CertPemClientCredentials.class, name = "cert.PEM")}) @JsonSubTypes.Type(value = CertPemCredentials.class, name = "cert.PEM")})
public interface MqttClientCredentials { public interface ClientCredentials {
@JsonIgnore
CredentialsType getType();
Optional<SslContext> initSslContext(); @JsonIgnore
default SslContext initSslContext() throws SSLException{
void configure(MqttClientConfig config); return SslContextBuilder.forClient().build();
}
} }

29
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CredentialsType.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2021 The Thingsboard 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 org.thingsboard.rule.engine.credentials;
public enum CredentialsType {
ANONYMOUS("anonymous"),
BASIC("basic"),
SAS("sas"),
CERT_PEM("cert.PEM");
private final String label;
CredentialsType(String label) {
this.label = label;
}
}

36
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java

@ -18,22 +18,27 @@ package org.thingsboard.rule.engine.mqtt;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.codec.mqtt.MqttQoS;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClient;
import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.mqtt.MqttClientConfig;
import org.thingsboard.mqtt.MqttConnectResult; import org.thingsboard.mqtt.MqttConnectResult;
import org.springframework.util.StringUtils; import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.credentials.BasicCredentials;
import org.thingsboard.rule.engine.credentials.ClientCredentials;
import org.thingsboard.rule.engine.credentials.CredentialsType;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -97,13 +102,18 @@ public class TbMqttNode implements TbNode {
} }
protected MqttClient initClient(TbContext ctx) throws Exception { protected MqttClient initClient(TbContext ctx) throws Exception {
Optional<SslContext> sslContextOpt = initSslContext(); MqttClientConfig config = new MqttClientConfig(getSslContext());
MqttClientConfig config = sslContextOpt.isPresent() ? new MqttClientConfig(sslContextOpt.get()) : new MqttClientConfig();
if (!StringUtils.isEmpty(this.mqttNodeConfiguration.getClientId())) { if (!StringUtils.isEmpty(this.mqttNodeConfiguration.getClientId())) {
config.setClientId(this.mqttNodeConfiguration.getClientId()); config.setClientId(this.mqttNodeConfiguration.getClientId());
} }
config.setCleanSession(this.mqttNodeConfiguration.isCleanSession()); config.setCleanSession(this.mqttNodeConfiguration.isCleanSession());
this.mqttNodeConfiguration.getCredentials().configure(config);
ClientCredentials credentials = this.mqttNodeConfiguration.getCredentials();
if (credentials.getType() == CredentialsType.BASIC) {
config.setUsername(((BasicCredentials) credentials).getUsername());
config.setPassword(((BasicCredentials) credentials).getPassword());
}
MqttClient client = MqttClient.create(config, null); MqttClient client = MqttClient.create(config, null);
client.setEventLoop(ctx.getSharedEventLoop()); client.setEventLoop(ctx.getSharedEventLoop());
Future<MqttConnectResult> connectFuture = client.connect(this.mqttNodeConfiguration.getHost(), this.mqttNodeConfiguration.getPort()); Future<MqttConnectResult> connectFuture = client.connect(this.mqttNodeConfiguration.getHost(), this.mqttNodeConfiguration.getPort());
@ -125,12 +135,14 @@ public class TbMqttNode implements TbNode {
return client; return client;
} }
private Optional<SslContext> initSslContext() throws SSLException { private SslContext getSslContext() throws SSLException {
Optional<SslContext> result = this.mqttNodeConfiguration.getCredentials().initSslContext(); ClientCredentials credentials = this.mqttNodeConfiguration.getCredentials();
if (this.mqttNodeConfiguration.isSsl() && !result.isPresent()) { SslContext sslContext = credentials.initSslContext();
result = Optional.of(SslContextBuilder.forClient().build()); if (!this.mqttNodeConfiguration.isSsl() &&
(credentials.getType() == CredentialsType.ANONYMOUS || credentials.getType() == CredentialsType.BASIC)) {
sslContext = null;
} }
return result; return sslContext;
} }
} }

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java

@ -17,8 +17,8 @@ package org.thingsboard.rule.engine.mqtt;
import lombok.Data; import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.mqtt.credentials.AnonymousCredentials; import org.thingsboard.rule.engine.credentials.AnonymousCredentials;
import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; import org.thingsboard.rule.engine.credentials.ClientCredentials;
@Data @Data
public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConfiguration> { public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConfiguration> {
@ -31,7 +31,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConf
private boolean cleanSession; private boolean cleanSession;
private boolean ssl; private boolean ssl;
private MqttClientCredentials credentials; private ClientCredentials credentials;
@Override @Override
public TbMqttNodeConfiguration defaultConfiguration() { public TbMqttNodeConfiguration defaultConfiguration() {

16
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java

@ -24,8 +24,8 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.thingsboard.common.util.AzureIotHubUtil; import org.thingsboard.common.util.AzureIotHubUtil;
import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.rule.engine.credentials.CertPemCredentials;
import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; import org.thingsboard.rule.engine.credentials.CredentialsType;
import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -33,26 +33,25 @@ import java.security.KeyStore;
import java.security.Security; import java.security.Security;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Optional;
@Data @Data
@Slf4j @Slf4j
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class AzureIotHubSasCredentials implements MqttClientCredentials { public class AzureIotHubSasCredentials extends CertPemCredentials {
private String sasKey; private String sasKey;
private String caCert; private String caCert;
@Override @Override
public Optional<SslContext> initSslContext() { public SslContext initSslContext() {
try { try {
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
if (caCert == null || caCert.isEmpty()) { if (caCert == null || caCert.isEmpty()) {
caCert = AzureIotHubUtil.getDefaultCaCert(); caCert = AzureIotHubUtil.getDefaultCaCert();
} }
return Optional.of(SslContextBuilder.forClient() return SslContextBuilder.forClient()
.trustManager(createAndInitTrustManagerFactory()) .trustManager(createAndInitTrustManagerFactory())
.clientAuth(ClientAuth.REQUIRE) .clientAuth(ClientAuth.REQUIRE)
.build()); .build();
} catch (Exception e) { } catch (Exception e) {
log.error("[{}] Creating TLS factory failed!", caCert, e); log.error("[{}] Creating TLS factory failed!", caCert, e);
throw new RuntimeException("Creating TLS factory failed!", e); throw new RuntimeException("Creating TLS factory failed!", e);
@ -60,7 +59,8 @@ public class AzureIotHubSasCredentials implements MqttClientCredentials {
} }
@Override @Override
public void configure(MqttClientConfig config) { public CredentialsType getType() {
return CredentialsType.SAS;
} }
private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception {

45
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java

@ -15,23 +15,22 @@
*/ */
package org.thingsboard.rule.engine.mqtt.azure; package org.thingsboard.rule.engine.mqtt.azure;
import io.netty.handler.codec.mqtt.MqttVersion;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.AzureIotHubUtil; import org.thingsboard.common.util.AzureIotHubUtil;
import org.thingsboard.mqtt.MqttClientConfig;
import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.credentials.CertPemCredentials;
import org.thingsboard.rule.engine.credentials.ClientCredentials;
import org.thingsboard.rule.engine.credentials.CredentialsType;
import org.thingsboard.rule.engine.mqtt.TbMqttNode; import org.thingsboard.rule.engine.mqtt.TbMqttNode;
import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration;
import org.thingsboard.rule.engine.mqtt.credentials.CertPemClientCredentials;
import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import java.util.Optional; import javax.net.ssl.SSLException;
@Slf4j @Slf4j
@RuleNode( @RuleNode(
@ -50,17 +49,22 @@ public class TbAzureIotHubNode extends TbMqttNode {
this.mqttNodeConfiguration = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class); this.mqttNodeConfiguration = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class);
mqttNodeConfiguration.setPort(8883); mqttNodeConfiguration.setPort(8883);
mqttNodeConfiguration.setCleanSession(true); mqttNodeConfiguration.setCleanSession(true);
MqttClientCredentials credentials = mqttNodeConfiguration.getCredentials(); ClientCredentials credentials = mqttNodeConfiguration.getCredentials();
mqttNodeConfiguration.setCredentials(new MqttClientCredentials() { mqttNodeConfiguration.setCredentials(new ClientCredentials() {
@Override @Override
public Optional<SslContext> initSslContext() { public CredentialsType getType() {
return credentials.getType();
}
@Override
public SslContext initSslContext() throws SSLException {
if (credentials instanceof AzureIotHubSasCredentials) { if (credentials instanceof AzureIotHubSasCredentials) {
AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials; AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials;
if (sasCredentials.getCaCert() == null || sasCredentials.getCaCert().isEmpty()) { if (sasCredentials.getCaCert() == null || sasCredentials.getCaCert().isEmpty()) {
sasCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert()); sasCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert());
} }
} else if (credentials instanceof CertPemClientCredentials) { } else if (credentials instanceof CertPemCredentials) {
CertPemClientCredentials pemCredentials = (CertPemClientCredentials) credentials; CertPemCredentials pemCredentials = (CertPemCredentials) credentials;
if (pemCredentials.getCaCert() == null || pemCredentials.getCaCert().isEmpty()) { if (pemCredentials.getCaCert() == null || pemCredentials.getCaCert().isEmpty()) {
pemCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert()); pemCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert());
} }
@ -68,19 +72,20 @@ public class TbAzureIotHubNode extends TbMqttNode {
return credentials.initSslContext(); return credentials.initSslContext();
} }
@Override // @Override
public void configure(MqttClientConfig config) { // public void configure(MqttClientConfig config) {
config.setProtocolVersion(MqttVersion.MQTT_3_1_1); // config.setProtocolVersion(MqttVersion.MQTT_3_1_1);
config.setUsername(AzureIotHubUtil.buildUsername(mqttNodeConfiguration.getHost(), config.getClientId())); // config.setUsername(AzureIotHubUtil.buildUsername(mqttNodeConfiguration.getHost(), config.getClientId()));
if (credentials instanceof AzureIotHubSasCredentials) { // if (credentials instanceof AzureIotHubSasCredentials) {
AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials; // AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials;
config.setPassword(AzureIotHubUtil.buildSasToken(mqttNodeConfiguration.getHost(), sasCredentials.getSasKey())); // config.setPassword(AzureIotHubUtil.buildSasToken(mqttNodeConfiguration.getHost(), sasCredentials.getSasKey()));
} // }
} // }
}); });
this.mqttClient = initClient(ctx); this.mqttClient = initClient(ctx);
} catch (Exception e) { } catch (Exception e) {
throw new TbNodeException(e); throw new TbNodeException(e);
} } }
}
} }

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeConfiguration.java

@ -16,10 +16,7 @@
package org.thingsboard.rule.engine.mqtt.azure; package org.thingsboard.rule.engine.mqtt.azure;
import lombok.Data; import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration;
import org.thingsboard.rule.engine.mqtt.credentials.AnonymousCredentials;
import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials;
@Data @Data
public class TbAzureIotHubNodeConfiguration extends TbMqttNodeConfiguration { public class TbAzureIotHubNodeConfiguration extends TbMqttNodeConfiguration {

20
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java

@ -17,9 +17,9 @@ package org.thingsboard.rule.engine.rest;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.ssl.SslContextBuilder;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.auth.UsernamePasswordCredentials;
@ -44,6 +44,9 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.credentials.BasicCredentials;
import org.thingsboard.rule.engine.credentials.ClientCredentials;
import org.thingsboard.rule.engine.credentials.CredentialsType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -51,8 +54,10 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import java.net.Authenticator; import java.net.Authenticator;
import java.net.PasswordAuthentication; import java.net.PasswordAuthentication;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Deque; import java.util.Deque;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -133,7 +138,7 @@ public class TbHttpClient {
} else { } else {
this.eventLoopGroup = new NioEventLoopGroup(); this.eventLoopGroup = new NioEventLoopGroup();
Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(this.eventLoopGroup); Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(this.eventLoopGroup);
nettyFactory.setSslContext(SslContextBuilder.forClient().build()); nettyFactory.setSslContext(config.getCredentials().initSslContext());
nettyFactory.setReadTimeout(config.getReadTimeoutMs()); nettyFactory.setReadTimeout(config.getReadTimeoutMs());
httpClient = new AsyncRestTemplate(nettyFactory); httpClient = new AsyncRestTemplate(nettyFactory);
} }
@ -226,6 +231,7 @@ public class TbHttpClient {
private HttpHeaders prepareHeaders(TbMsgMetaData metaData) { private HttpHeaders prepareHeaders(TbMsgMetaData metaData) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData))); config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData)));
getBasicAuthHeaderValue(config.getCredentials()).ifPresent(authString -> headers.add("Authorization", authString));
return headers; return headers;
} }
@ -259,4 +265,14 @@ public class TbHttpClient {
throw new TbNodeException("Proxy port out of range:" + proxyPort); throw new TbNodeException("Proxy port out of range:" + proxyPort);
} }
} }
public static Optional<String> getBasicAuthHeaderValue(ClientCredentials credentials) {
if (CredentialsType.BASIC == credentials.getType()) {
BasicCredentials basicCredentials = (BasicCredentials) credentials;
String authString = basicCredentials.getUsername() + ":" + basicCredentials.getPassword();
String encodedAuthString = new String(Base64.encodeBase64(authString.getBytes(StandardCharsets.UTF_8)));
return Optional.of("Basic " + encodedAuthString);
}
return Optional.empty();
}
} }

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java

@ -18,6 +18,8 @@ package org.thingsboard.rule.engine.rest;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data; import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.credentials.AnonymousCredentials;
import org.thingsboard.rule.engine.credentials.ClientCredentials;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -42,6 +44,7 @@ public class TbRestApiCallNodeConfiguration implements NodeConfiguration<TbRestA
private String proxyUser; private String proxyUser;
private String proxyPassword; private String proxyPassword;
private String proxyScheme; private String proxyScheme;
private ClientCredentials credentials;
@Override @Override
public TbRestApiCallNodeConfiguration defaultConfiguration() { public TbRestApiCallNodeConfiguration defaultConfiguration() {
@ -55,6 +58,7 @@ public class TbRestApiCallNodeConfiguration implements NodeConfiguration<TbRestA
configuration.setUseRedisQueueForMsgPersistence(false); configuration.setUseRedisQueueForMsgPersistence(false);
configuration.setTrimQueue(false); configuration.setTrimQueue(false);
configuration.setEnableProxy(false); configuration.setEnableProxy(false);
configuration.setCredentials(new AnonymousCredentials());
return configuration; return configuration;
} }
} }

2
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

34
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/BasicCredentialsTest.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2021 The Thingsboard 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 org.thingsboard.rule.engine.rest.credentials;
import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.rule.engine.credentials.BasicCredentials;
import org.thingsboard.rule.engine.rest.TbHttpClient;
public class BasicCredentialsTest {
@Test
public void getBasicAuthHeaderValueTest() {
BasicCredentials credentials = new BasicCredentials();
credentials.setUsername("testUser");
credentials.setPassword("testPwd");
String actualHeaderValue = TbHttpClient.getBasicAuthHeaderValue(credentials).get();
String expectedHeaderValue = "Basic dGVzdFVzZXI6dGVzdFB3ZA==";
Assert.assertEquals(expectedHeaderValue, actualHeaderValue);
}
}
Loading…
Cancel
Save