Add ability to upgrade device credentials if chain match with uploaded device profile certificate.
This commit is contained in:
parent
dccc19a9b6
commit
5d35fa1f26
@ -65,8 +65,8 @@ import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgDataType;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
|
||||
import org.thingsboard.server.dao.device.DeviceCredentialsService;
|
||||
import org.thingsboard.server.dao.device.DeviceProfileService;
|
||||
import org.thingsboard.server.dao.device.DeviceProvisionService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
|
||||
@ -90,11 +90,15 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesRespon
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.UpdateOrCreateDeviceX509CertRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceProfileCredentialsResponseMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceProfileX509CertRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
|
||||
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
||||
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
|
||||
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
|
||||
@ -108,6 +112,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.PASSWORD_MISMATCH;
|
||||
@ -128,6 +134,7 @@ public class DefaultTransportApiService implements TransportApiService {
|
||||
private final TbTenantProfileCache tenantProfileCache;
|
||||
private final TbApiUsageStateService apiUsageStateService;
|
||||
private final DeviceService deviceService;
|
||||
private final DeviceProfileService deviceProfileService;
|
||||
private final RelationService relationService;
|
||||
private final DeviceCredentialsService deviceCredentialsService;
|
||||
private final DbCallbackExecutorService dbCallbackExecutorService;
|
||||
@ -159,6 +166,13 @@ public class DefaultTransportApiService implements TransportApiService {
|
||||
} else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) {
|
||||
ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg();
|
||||
result = validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE);
|
||||
} else if (transportApiRequestMsg.hasValidateProfileX509CertRequestMsg()) {
|
||||
ValidateDeviceProfileX509CertRequestMsg msg = transportApiRequestMsg.getValidateProfileX509CertRequestMsg();
|
||||
result = validateDeviceProfileCertificate(msg.getHash());
|
||||
} else if (transportApiRequestMsg.hasUpdateOrCreateDeviceCertRequestMsg()) {
|
||||
UpdateOrCreateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getUpdateOrCreateDeviceCertRequestMsg();
|
||||
DeviceProfile deviceProfile = deviceProfileCache.find(new DeviceProfileId(new UUID(msg.getDeviceProfileIdMSB(), msg.getDeviceProfileIdLSB())));
|
||||
result = updateOrCreateDeviceCredentials(msg.getHash(), msg.getValue(), msg.getCommonName(), deviceProfile, DeviceCredentialsType.X509_CERTIFICATE);
|
||||
} else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) {
|
||||
result = handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg());
|
||||
} else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) {
|
||||
@ -226,6 +240,31 @@ public class DefaultTransportApiService implements TransportApiService {
|
||||
}
|
||||
}
|
||||
|
||||
private ListenableFuture<TransportApiResponseMsg> validateDeviceProfileCertificate(String credentialsId) {
|
||||
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileByCertificateHash(credentialsId);
|
||||
if (deviceProfile != null) {
|
||||
return getDeviceProfileInfo(deviceProfile);
|
||||
}
|
||||
return getEmptyTransportApiResponseFuture();
|
||||
}
|
||||
|
||||
private ListenableFuture<TransportApiResponseMsg> updateOrCreateDeviceCredentials(String credentialsId,
|
||||
String credentialsValue,
|
||||
String deviceCN,
|
||||
DeviceProfile deviceProfile,
|
||||
DeviceCredentialsType credentialsType) {
|
||||
String deviceName = extractRegex(deviceCN, deviceProfile.getCertificateRegexPattern());
|
||||
// find deviceCredentials by deviceName (device exists)
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByTenantIdAndDeviceName(deviceProfile.getTenantId(), deviceName);
|
||||
if (deviceCredentials != null && deviceCredentials.getCredentialsType() == credentialsType) {
|
||||
deviceCredentials.setCredentialsId(credentialsId);
|
||||
deviceCredentials.setCredentialsValue(credentialsValue);
|
||||
deviceCredentialsService.updateDeviceCredentials(deviceProfile.getTenantId(), deviceCredentials);
|
||||
return getDeviceInfo(deviceCredentials);
|
||||
}
|
||||
return getEmptyTransportApiResponseFuture();
|
||||
}
|
||||
|
||||
private ListenableFuture<TransportApiResponseMsg> validateUserNameCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) {
|
||||
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName());
|
||||
if (credentials != null) {
|
||||
@ -507,6 +546,18 @@ public class DefaultTransportApiService implements TransportApiService {
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private ListenableFuture<TransportApiResponseMsg> getDeviceProfileInfo(DeviceProfile deviceProfile) {
|
||||
ValidateDeviceProfileCredentialsResponseMsg.Builder builder = ValidateDeviceProfileCredentialsResponseMsg.newBuilder()
|
||||
.setDeviceProfileIdMSB(deviceProfile.getId().getId().getMostSignificantBits())
|
||||
.setDeviceProfileIdLSB(deviceProfile.getId().getId().getLeastSignificantBits())
|
||||
.setIsDeviceProfileFound(true);
|
||||
|
||||
return Futures.immediateFuture(
|
||||
TransportApiResponseMsg.newBuilder()
|
||||
.setValidateDeviceProfileResponseMsg(builder.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
private DeviceInfoProto getDeviceInfoProto(Device device) throws JsonProcessingException {
|
||||
DeviceInfoProto.Builder builder = DeviceInfoProto.newBuilder()
|
||||
.setTenantIdMSB(device.getTenantId().getId().getMostSignificantBits())
|
||||
@ -664,4 +715,13 @@ public class DefaultTransportApiService implements TransportApiService {
|
||||
private Long checkLong(Long l) {
|
||||
return l != null ? l : 0;
|
||||
}
|
||||
|
||||
private String extractRegex(String commonName, String regex) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(commonName);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(0);
|
||||
}
|
||||
return commonName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,6 +169,18 @@ message ValidateDeviceX509CertRequestMsg {
|
||||
string hash = 1;
|
||||
}
|
||||
|
||||
message ValidateDeviceProfileX509CertRequestMsg {
|
||||
string hash = 1;
|
||||
}
|
||||
|
||||
message UpdateOrCreateDeviceX509CertRequestMsg {
|
||||
string hash = 1;
|
||||
string value = 2;
|
||||
string commonName = 3;
|
||||
int64 deviceProfileIdMSB = 4;
|
||||
int64 deviceProfileIdLSB = 5;
|
||||
}
|
||||
|
||||
message ValidateBasicMqttCredRequestMsg {
|
||||
string clientId = 1;
|
||||
string userName = 2;
|
||||
@ -181,6 +193,12 @@ message ValidateDeviceCredentialsResponseMsg {
|
||||
bytes profileBody = 3;
|
||||
}
|
||||
|
||||
message ValidateDeviceProfileCredentialsResponseMsg {
|
||||
int64 deviceProfileIdMSB = 1;
|
||||
int64 deviceProfileIdLSB = 2;
|
||||
bool isDeviceProfileFound = 3;
|
||||
}
|
||||
|
||||
message GetOrCreateDeviceFromGatewayRequestMsg {
|
||||
int64 gatewayIdMSB = 1;
|
||||
int64 gatewayIdLSB = 2;
|
||||
@ -885,33 +903,36 @@ message VersionControlResponseMsg {
|
||||
message TransportApiRequestMsg {
|
||||
ValidateDeviceTokenRequestMsg validateTokenRequestMsg = 1;
|
||||
ValidateDeviceX509CertRequestMsg validateX509CertRequestMsg = 2;
|
||||
GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3;
|
||||
GetEntityProfileRequestMsg entityProfileRequestMsg = 4;
|
||||
LwM2MRequestMsg lwM2MRequestMsg = 5;
|
||||
ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6;
|
||||
ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7;
|
||||
ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8;
|
||||
GetResourceRequestMsg resourceRequestMsg = 9;
|
||||
GetOtaPackageRequestMsg otaPackageRequestMsg = 10;
|
||||
GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11;
|
||||
GetDeviceRequestMsg deviceRequestMsg = 12;
|
||||
GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13;
|
||||
GetAllQueueRoutingInfoRequestMsg getAllQueueRoutingInfoRequestMsg = 14;
|
||||
ValidateDeviceProfileX509CertRequestMsg validateProfileX509CertRequestMsg = 3;
|
||||
GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 4;
|
||||
GetEntityProfileRequestMsg entityProfileRequestMsg = 5;
|
||||
LwM2MRequestMsg lwM2MRequestMsg = 6;
|
||||
ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 7;
|
||||
ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 8;
|
||||
ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 9;
|
||||
GetResourceRequestMsg resourceRequestMsg = 10;
|
||||
GetOtaPackageRequestMsg otaPackageRequestMsg = 11;
|
||||
GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 12;
|
||||
GetDeviceRequestMsg deviceRequestMsg = 13;
|
||||
GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 14;
|
||||
GetAllQueueRoutingInfoRequestMsg getAllQueueRoutingInfoRequestMsg = 15;
|
||||
UpdateOrCreateDeviceX509CertRequestMsg updateOrCreateDeviceCertRequestMsg = 16;
|
||||
}
|
||||
|
||||
/* Response from ThingsBoard Core Service to Transport Service */
|
||||
message TransportApiResponseMsg {
|
||||
ValidateDeviceCredentialsResponseMsg validateCredResponseMsg = 1;
|
||||
GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2;
|
||||
GetEntityProfileResponseMsg entityProfileResponseMsg = 3;
|
||||
ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4;
|
||||
GetSnmpDevicesResponseMsg snmpDevicesResponseMsg = 5;
|
||||
LwM2MResponseMsg lwM2MResponseMsg = 6;
|
||||
GetResourceResponseMsg resourceResponseMsg = 7;
|
||||
GetOtaPackageResponseMsg otaPackageResponseMsg = 8;
|
||||
GetDeviceResponseMsg deviceResponseMsg = 9;
|
||||
GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10;
|
||||
repeated GetQueueRoutingInfoResponseMsg getQueueRoutingInfoResponseMsgs = 11;
|
||||
ValidateDeviceProfileCredentialsResponseMsg validateDeviceProfileResponseMsg = 2;
|
||||
GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 3;
|
||||
GetEntityProfileResponseMsg entityProfileResponseMsg = 4;
|
||||
ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 5;
|
||||
GetSnmpDevicesResponseMsg snmpDevicesResponseMsg = 6;
|
||||
LwM2MResponseMsg lwM2MResponseMsg = 7;
|
||||
GetResourceResponseMsg resourceResponseMsg = 8;
|
||||
GetOtaPackageResponseMsg otaPackageResponseMsg = 9;
|
||||
GetDeviceResponseMsg deviceResponseMsg = 10;
|
||||
GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 11;
|
||||
repeated GetQueueRoutingInfoResponseMsg getQueueRoutingInfoResponseMsgs = 12;
|
||||
}
|
||||
|
||||
/* Messages that are handled by ThingsBoard Core Service */
|
||||
|
||||
@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.device;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public interface DeviceCredentialsService {
|
||||
|
||||
@ -26,6 +26,8 @@ public interface DeviceCredentialsService {
|
||||
|
||||
DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId);
|
||||
|
||||
DeviceCredentials findDeviceCredentialsByTenantIdAndDeviceName(TenantId tenantId, String deviceName);
|
||||
|
||||
DeviceCredentials updateDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
|
||||
|
||||
DeviceCredentials createDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
|
||||
|
||||
@ -39,6 +39,8 @@ public interface DeviceProfileService extends EntityDaoService {
|
||||
|
||||
PageData<DeviceProfileInfo> findDeviceProfileInfos(TenantId tenantId, PageLink pageLink, String transportType);
|
||||
|
||||
DeviceProfile findDeviceProfileByCertificateHash(String credentialsId);
|
||||
|
||||
DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String profileName);
|
||||
|
||||
DeviceProfile createDefaultDeviceProfile(TenantId tenantId);
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
package org.thingsboard.server.common.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -28,7 +27,6 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
|
||||
import org.thingsboard.server.common.data.id.DashboardId;
|
||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
|
||||
import org.thingsboard.server.common.data.id.OtaPackageId;
|
||||
import org.thingsboard.server.common.data.id.QueueId;
|
||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.validation.Length;
|
||||
@ -68,6 +66,13 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
|
||||
private DeviceTransportType transportType;
|
||||
@ApiModelProperty(position = 15, value = "Provisioning strategy.")
|
||||
private DeviceProfileProvisionType provisionType;
|
||||
@ApiModelProperty(position = 16, value = "CA certificate value")
|
||||
private String certificateValue;
|
||||
@ApiModelProperty(position = 17, value = "CA certificate hash")
|
||||
private String certificateHash;
|
||||
@ApiModelProperty(position = 18, value = "Regex for fetch deviceName from CN")
|
||||
private String certificateRegexPattern;
|
||||
|
||||
@ApiModelProperty(position = 7, value = "Reference to the rule chain. " +
|
||||
"If present, the specified rule chain will be used to process all messages related to device, including telemetry, attribute updates, etc. " +
|
||||
"Otherwise, the root rule chain will be used to process those messages.")
|
||||
|
||||
@ -24,12 +24,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.data.DeviceTransportType;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
import org.thingsboard.server.common.transport.TransportService;
|
||||
import org.thingsboard.server.common.transport.TransportServiceCallback;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceProfileCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
|
||||
import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
|
||||
import org.thingsboard.server.common.transport.util.SslUtil;
|
||||
@ -142,8 +143,15 @@ public class MqttSslHandlerProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
String deviceCN = SslUtil.parseCommonName(chain[0]);
|
||||
String deviceCert;
|
||||
String deviceCredentialsValue = SslUtil.getCertificateString(chain[0]);
|
||||
try {
|
||||
deviceCert = EncryptionUtil.getSha3Hash(SslUtil.getCertificateString(chain[0]));
|
||||
} catch (CertificateEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String credentialsBody = null;
|
||||
for (X509Certificate cert : chain) {
|
||||
try {
|
||||
@ -152,13 +160,53 @@ public class MqttSslHandlerProvider {
|
||||
final String[] credentialsBodyHolder = new String[1];
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
transportService.process(DeviceTransportType.MQTT, TransportProtos.ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
|
||||
new TransportServiceCallback<ValidateDeviceCredentialsResponse>() {
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
|
||||
if (!StringUtils.isEmpty(msg.getCredentials())) {
|
||||
credentialsBodyHolder[0] = msg.getCredentials();
|
||||
latch.countDown();
|
||||
} else {
|
||||
transportService.process(DeviceTransportType.MQTT,
|
||||
TransportProtos.ValidateDeviceProfileX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceProfileCredentialsResponse msg) {
|
||||
if (msg.isDeviceProfileFound()) {
|
||||
transportService.process(DeviceTransportType.MQTT,
|
||||
TransportProtos.UpdateOrCreateDeviceX509CertRequestMsg.newBuilder()
|
||||
.setHash(deviceCert)
|
||||
.setCommonName(deviceCN)
|
||||
.setDeviceProfileIdMSB(msg.getDeviceProfileId().getId().getMostSignificantBits())
|
||||
.setDeviceProfileIdLSB(msg.getDeviceProfileId().getId().getLeastSignificantBits())
|
||||
.build(),
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
|
||||
System.out.println("msg.getCredentials() = " + msg.getCredentials());
|
||||
credentialsBodyHolder[0] = msg.getCredentials();
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,7 +216,7 @@ public class MqttSslHandlerProvider {
|
||||
}
|
||||
});
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
if (strCert.equals(credentialsBodyHolder[0])) {
|
||||
if (deviceCredentialsValue.equals(credentialsBodyHolder[0])) {
|
||||
credentialsBody = credentialsBodyHolder[0];
|
||||
break;
|
||||
}
|
||||
|
||||
@ -21,7 +21,6 @@ import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.mqtt.MqttConnAckMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttConnAckVariableHeader;
|
||||
import io.netty.handler.codec.mqtt.MqttConnectMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
|
||||
import io.netty.handler.codec.mqtt.MqttFixedHeader;
|
||||
@ -63,12 +62,12 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException;
|
||||
import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
|
||||
import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceProfileCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.service.DefaultTransportService;
|
||||
import org.thingsboard.server.common.transport.service.SessionMetaData;
|
||||
import org.thingsboard.server.common.transport.util.SslUtil;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
|
||||
import org.thingsboard.server.queue.scheduler.SchedulerComponent;
|
||||
import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
|
||||
import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
|
||||
@ -80,7 +79,7 @@ import org.thingsboard.server.transport.mqtt.util.ReturnCodeResolver;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -90,16 +89,15 @@ import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.amazonaws.util.StringUtils.UTF8;
|
||||
import static io.netty.handler.codec.mqtt.MqttMessageType.CONNACK;
|
||||
import static io.netty.handler.codec.mqtt.MqttMessageType.CONNECT;
|
||||
import static io.netty.handler.codec.mqtt.MqttMessageType.PINGRESP;
|
||||
import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK;
|
||||
import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK;
|
||||
import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE;
|
||||
import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;
|
||||
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED;
|
||||
@ -810,9 +808,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
|
||||
deviceSessionCtx.setProvisionOnly(true);
|
||||
ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SUCCESS, msg));
|
||||
} else {
|
||||
X509Certificate cert;
|
||||
if (sslHandler != null && (cert = getX509Certificate()) != null) {
|
||||
processX509CertConnect(ctx, cert, msg);
|
||||
X509Certificate[] chain;
|
||||
if (sslHandler != null && (chain = getX509Certificate()) != null) {
|
||||
processX509CertConnect(ctx, chain, msg);
|
||||
} else {
|
||||
processAuthTokenConnect(ctx, msg);
|
||||
}
|
||||
@ -848,27 +846,82 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
|
||||
});
|
||||
}
|
||||
|
||||
private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert, MqttConnectMessage connectMessage) {
|
||||
private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate[] chain, MqttConnectMessage connectMessage) {
|
||||
try {
|
||||
if (!context.isSkipValidityCheckForClientCert()) {
|
||||
cert.checkValidity();
|
||||
}
|
||||
String strCert = SslUtil.getCertificateString(cert);
|
||||
String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
|
||||
transportService.process(DeviceTransportType.MQTT, ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
|
||||
onValidateDeviceResponse(msg, ctx, connectMessage);
|
||||
}
|
||||
String deviceCN = SslUtil.parseCommonName(chain[0]);
|
||||
String deviceCertHash = EncryptionUtil.getSha3Hash(SslUtil.getCertificateString(chain[0]));
|
||||
for (X509Certificate cert : chain) {
|
||||
try {
|
||||
String strCert = SslUtil.getCertificateString(cert);
|
||||
String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
|
||||
final ValidateDeviceCredentialsResponse[] validateDeviceCredentialsResponses = new ValidateDeviceCredentialsResponse[1];
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
transportService.process(DeviceTransportType.MQTT, TransportProtos.ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
|
||||
if (!StringUtils.isEmpty(msg.getCredentials())) {
|
||||
validateDeviceCredentialsResponses[0] = msg;
|
||||
latch.countDown();
|
||||
} else {
|
||||
transportService.process(DeviceTransportType.MQTT,
|
||||
TransportProtos.ValidateDeviceProfileX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceProfileCredentialsResponse msg) {
|
||||
if (msg.isDeviceProfileFound()) {
|
||||
transportService.process(DeviceTransportType.MQTT,
|
||||
TransportProtos.UpdateOrCreateDeviceX509CertRequestMsg.newBuilder()
|
||||
.setHash(deviceCertHash)
|
||||
.setCommonName(deviceCN)
|
||||
.setDeviceProfileIdMSB(msg.getDeviceProfileId().getId().getMostSignificantBits())
|
||||
.setDeviceProfileIdLSB(msg.getDeviceProfileId().getId().getLeastSignificantBits())
|
||||
.build(),
|
||||
new TransportServiceCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
|
||||
if (!StringUtils.isEmpty(msg.getCredentials())) {
|
||||
validateDeviceCredentialsResponses[0] = msg;
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
log.trace("[{}] Failed to process credentials: {}", address, sha3Hash, e);
|
||||
ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SERVER_UNAVAILABLE_5, connectMessage));
|
||||
ctx.close();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
if (validateDeviceCredentialsResponses[0] != null && validateDeviceCredentialsResponses[0].hasDeviceInfo()) {
|
||||
onValidateDeviceResponse(validateDeviceCredentialsResponses[0], ctx, connectMessage);
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException | CertificateEncodingException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
context.onAuthFailure(address);
|
||||
ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.NOT_AUTHORIZED_5, connectMessage));
|
||||
@ -877,17 +930,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate getX509Certificate() {
|
||||
private X509Certificate[] getX509Certificate() {
|
||||
try {
|
||||
Certificate[] certChain = sslHandler.engine().getSession().getPeerCertificates();
|
||||
if (certChain.length > 0) {
|
||||
return (X509Certificate) certChain[0];
|
||||
}
|
||||
return (X509Certificate[]) sslHandler.engine().getSession().getPeerCertificates();
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
log.warn(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MqttConnAckMessage createMqttConnAckMsg(ReturnCode returnCode, MqttConnectMessage msg) {
|
||||
|
||||
@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.DeviceTransportType;
|
||||
import org.thingsboard.server.common.data.rpc.RpcStatus;
|
||||
import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceProfileCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.service.SessionMetaData;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
|
||||
@ -52,8 +53,10 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMs
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.UpdateOrCreateDeviceX509CertRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceProfileX509CertRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
|
||||
|
||||
@ -87,6 +90,12 @@ public interface TransportService {
|
||||
void process(DeviceTransportType transportType, ValidateDeviceX509CertRequestMsg msg,
|
||||
TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
|
||||
|
||||
void process(DeviceTransportType transportType, ValidateDeviceProfileX509CertRequestMsg msg,
|
||||
TransportServiceCallback<ValidateDeviceProfileCredentialsResponse> callback);
|
||||
|
||||
void process(DeviceTransportType transportType, UpdateOrCreateDeviceX509CertRequestMsg msg,
|
||||
TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
|
||||
|
||||
void process(ValidateDeviceLwM2MCredentialsRequestMsg msg,
|
||||
TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
|
||||
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 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.server.common.transport.auth;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class ValidateDeviceProfileCredentialsResponse {
|
||||
|
||||
private final DeviceProfileId deviceProfileId;
|
||||
private final boolean isDeviceProfileFound;
|
||||
}
|
||||
@ -71,8 +71,8 @@ import org.thingsboard.server.common.transport.TransportTenantProfileCache;
|
||||
import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
|
||||
import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceProfileCredentialsResponse;
|
||||
import org.thingsboard.server.common.transport.limits.TransportRateLimitService;
|
||||
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
|
||||
import org.thingsboard.server.common.transport.util.JsonUtils;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
|
||||
@ -97,6 +97,7 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
|
||||
import org.thingsboard.server.queue.provider.TbTransportQueueFactory;
|
||||
import org.thingsboard.server.queue.scheduler.SchedulerComponent;
|
||||
import org.thingsboard.server.queue.util.AfterStartUp;
|
||||
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
|
||||
import org.thingsboard.server.queue.util.TbTransportComponent;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@ -427,6 +428,32 @@ public class DefaultTransportService implements TransportService {
|
||||
AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceProfileX509CertRequestMsg requestMsg,
|
||||
TransportServiceCallback<ValidateDeviceProfileCredentialsResponse> callback) {
|
||||
log.trace("Processing msg: {}", requestMsg);
|
||||
TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(),
|
||||
TransportApiRequestMsg.newBuilder().setValidateProfileX509CertRequestMsg(requestMsg).build());
|
||||
ListenableFuture<ValidateDeviceProfileCredentialsResponse> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp -> {
|
||||
TransportProtos.ValidateDeviceProfileCredentialsResponseMsg msg = tmp.getValue().getValidateDeviceProfileResponseMsg();
|
||||
ValidateDeviceProfileCredentialsResponse.ValidateDeviceProfileCredentialsResponseBuilder result = ValidateDeviceProfileCredentialsResponse.builder();
|
||||
DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(msg.getDeviceProfileIdMSB(), msg.getDeviceProfileIdLSB()));
|
||||
result.deviceProfileId(deviceProfileId);
|
||||
result.isDeviceProfileFound(msg.getIsDeviceProfileFound());
|
||||
return result.build();
|
||||
}, MoreExecutors.directExecutor());
|
||||
AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(DeviceTransportType transportType, TransportProtos.UpdateOrCreateDeviceX509CertRequestMsg requestMsg,
|
||||
TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
|
||||
log.trace("Processing msg: {}", requestMsg);
|
||||
TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder()
|
||||
.setUpdateOrCreateDeviceCertRequestMsg(requestMsg).build());
|
||||
doProcess(transportType, protoMsg, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
|
||||
log.trace("Processing msg: {}", msg);
|
||||
|
||||
@ -16,11 +16,17 @@
|
||||
package org.thingsboard.server.common.transport.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.asn1.x500.RDN;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||
import org.bouncycastle.asn1.x500.style.IETFUtils;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* @author Valerii Sosliuk
|
||||
@ -35,4 +41,15 @@ public class SslUtil {
|
||||
throws CertificateEncodingException {
|
||||
return EncryptionUtil.certTrimNewLines(Base64Utils.encodeToString(cert.getEncoded()));
|
||||
}
|
||||
|
||||
public static String parseCommonName(X509Certificate certificate) {
|
||||
X500Name x500name;
|
||||
try {
|
||||
x500name = new JcaX509CertificateHolder(certificate).getSubject();
|
||||
} catch (CertificateEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
RDN cn = x500name.getRDNs(BCStyle.CN)[0];
|
||||
return IETFUtils.valueToString(cn.getFirst().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,4 +53,12 @@ public interface DeviceCredentialsDao extends Dao<DeviceCredentials> {
|
||||
*/
|
||||
DeviceCredentials findByCredentialsId(TenantId tenantId, String credentialsId);
|
||||
|
||||
/**
|
||||
* Find device credentials by device name.
|
||||
*
|
||||
* @param deviceName the device name
|
||||
* @return the device credentials object
|
||||
*/
|
||||
DeviceCredentials findByTenantIdAndDeviceName(TenantId tenantId, String deviceName);
|
||||
|
||||
}
|
||||
|
||||
@ -16,15 +16,12 @@
|
||||
package org.thingsboard.server.dao.device;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.leshan.core.SecurityMode;
|
||||
import org.eclipse.leshan.core.util.SecurityUtil;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
@ -86,6 +83,13 @@ public class DeviceCredentialsServiceImpl extends AbstractCachedEntityService<St
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceCredentials findDeviceCredentialsByTenantIdAndDeviceName(TenantId tenantId, String deviceName) {
|
||||
log.trace("Executing findDeviceCredentialsByDeviceName [{}]", deviceName);
|
||||
validateString(deviceName, "Incorrect deviceName " + deviceName);
|
||||
return deviceCredentialsDao.findByTenantIdAndDeviceName(tenantId, deviceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceCredentials updateDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials) {
|
||||
return saveOrUpdate(tenantId, deviceCredentials);
|
||||
|
||||
@ -29,25 +29,31 @@ public class DeviceProfileCacheKey implements Serializable {
|
||||
private final TenantId tenantId;
|
||||
private final String name;
|
||||
private final DeviceProfileId deviceProfileId;
|
||||
private final String certificateHash;
|
||||
private final boolean defaultProfile;
|
||||
|
||||
private DeviceProfileCacheKey(TenantId tenantId, String name, DeviceProfileId deviceProfileId, boolean defaultProfile) {
|
||||
private DeviceProfileCacheKey(TenantId tenantId, String name, DeviceProfileId deviceProfileId, String certificateHash, boolean defaultProfile) {
|
||||
this.tenantId = tenantId;
|
||||
this.name = name;
|
||||
this.deviceProfileId = deviceProfileId;
|
||||
this.certificateHash = certificateHash;
|
||||
this.defaultProfile = defaultProfile;
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey fromName(TenantId tenantId, String name) {
|
||||
return new DeviceProfileCacheKey(tenantId, name, null, false);
|
||||
return new DeviceProfileCacheKey(tenantId, name, null, null, false);
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey fromId(DeviceProfileId id) {
|
||||
return new DeviceProfileCacheKey(null, null, id, false);
|
||||
return new DeviceProfileCacheKey(null, null, id, null, false);
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey fromCertificateHash(String certificateHash) {
|
||||
return new DeviceProfileCacheKey(null, null, null, certificateHash, false);
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey defaultProfile(TenantId tenantId) {
|
||||
return new DeviceProfileCacheKey(tenantId, null, null, true);
|
||||
return new DeviceProfileCacheKey(tenantId, null, null, null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -45,4 +45,6 @@ public interface DeviceProfileDao extends Dao<DeviceProfile>, ExportableEntityDa
|
||||
DeviceProfile findByProvisionDeviceKey(String provisionDeviceKey);
|
||||
|
||||
DeviceProfile findByName(TenantId tenantId, String profileName);
|
||||
|
||||
DeviceProfile findByCertificateHash(String certificateHash);
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
|
||||
@Service("DeviceProfileDaoService")
|
||||
@Slf4j
|
||||
@ -61,6 +62,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||
private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId ";
|
||||
private static final String INCORRECT_DEVICE_PROFILE_NAME = "Incorrect deviceProfileName ";
|
||||
private static final String INCORRECT_DEVICE_PROFILE_CREDENTIALS_HASH = "Incorrect deviceProfileCredentialsHash ";
|
||||
private static final String DEVICE_PROFILE_WITH_SUCH_NAME_ALREADY_EXISTS = "Device profile with such name already exists!";
|
||||
|
||||
@Autowired
|
||||
@ -197,6 +199,14 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink, transportType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceProfile findDeviceProfileByCertificateHash(String certificateHash) {
|
||||
log.trace("Executing findDeviceProfileIdByCredentialsId credentialId [{}]", certificateHash);
|
||||
validateString(certificateHash, INCORRECT_DEVICE_PROFILE_CREDENTIALS_HASH + certificateHash);
|
||||
return cache.getAndPutInTransaction(DeviceProfileCacheKey.fromCertificateHash(certificateHash),
|
||||
() -> deviceProfileDao.findByCertificateHash(certificateHash), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String name) {
|
||||
log.trace("Executing findOrCreateDefaultDeviceProfile");
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
package org.thingsboard.server.dao.sql.device;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.thingsboard.server.dao.model.sql.DeviceCredentialsEntity;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -28,4 +30,7 @@ public interface DeviceCredentialsRepository extends JpaRepository<DeviceCredent
|
||||
DeviceCredentialsEntity findByDeviceId(UUID deviceId);
|
||||
|
||||
DeviceCredentialsEntity findByCredentialsId(String credentialsId);
|
||||
|
||||
@Query("SELECT dc FROM DeviceCredentialsEntity dc INNER JOIN DeviceEntity de ON dc.deviceId = de.id WHERE de.tenantId = :tenantId AND de.name = :deviceName ")
|
||||
DeviceCredentialsEntity findByTenantIdAndDeviceName(@Param("tenantId") UUID tenantId, @Param("deviceName") String deviceName);
|
||||
}
|
||||
|
||||
@ -64,6 +64,8 @@ public interface DeviceProfileRepository extends JpaRepository<DeviceProfileEnti
|
||||
"WHERE d.tenantId = :tenantId AND d.isDefault = true")
|
||||
DeviceProfileInfo findDefaultDeviceProfileInfo(@Param("tenantId") UUID tenantId);
|
||||
|
||||
DeviceProfileEntity findDeviceProfileByCertificateHash(String certificateHash);
|
||||
|
||||
DeviceProfileEntity findByTenantIdAndName(UUID id, String profileName);
|
||||
|
||||
DeviceProfileEntity findByProvisionDeviceKey(@Param("provisionDeviceKey") String provisionDeviceKey);
|
||||
|
||||
@ -66,4 +66,9 @@ public class JpaDeviceCredentialsDao extends JpaAbstractDao<DeviceCredentialsEnt
|
||||
public DeviceCredentials findByCredentialsId(TenantId tenantId, String credentialsId) {
|
||||
return DaoUtil.getData(deviceCredentialsRepository.findByCredentialsId(credentialsId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceCredentials findByTenantIdAndDeviceName(TenantId tenantId, String deviceName) {
|
||||
return DaoUtil.getData(deviceCredentialsRepository.findByTenantIdAndDeviceName(tenantId, deviceName));
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,6 +115,11 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE
|
||||
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndName(tenantId.getId(), profileName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceProfile findByCertificateHash(String certificateHash) {
|
||||
return DaoUtil.getData(deviceProfileRepository.findDeviceProfileByCertificateHash(certificateHash));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
|
||||
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user