Commit a3326b4464705b125fab923040d8564c98777b3c

Authored by Andrii Shvaika
1 parent 6e492c78

New type of credentials: MQTT

... ... @@ -23,12 +23,14 @@ import com.google.common.util.concurrent.ListenableFuture;
23 23 import com.google.common.util.concurrent.MoreExecutors;
24 24 import com.google.protobuf.ByteString;
25 25 import lombok.extern.slf4j.Slf4j;
  26 +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
26 27 import org.springframework.stereotype.Service;
27 28 import org.springframework.util.StringUtils;
28 29 import org.thingsboard.server.common.data.DataConstants;
29 30 import org.thingsboard.server.common.data.Device;
30 31 import org.thingsboard.server.common.data.DeviceProfile;
31 32 import org.thingsboard.server.common.data.TenantProfile;
  33 +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
32 34 import org.thingsboard.server.common.data.id.CustomerId;
33 35 import org.thingsboard.server.common.data.id.DeviceId;
34 36 import org.thingsboard.server.common.data.id.DeviceProfileId;
... ... @@ -36,6 +38,7 @@ import org.thingsboard.server.common.data.id.TenantId;
36 38 import org.thingsboard.server.common.data.relation.EntityRelation;
37 39 import org.thingsboard.server.common.data.security.DeviceCredentials;
38 40 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
  41 +import org.thingsboard.server.common.msg.EncryptionUtil;
39 42 import org.thingsboard.server.common.msg.TbMsg;
40 43 import org.thingsboard.server.common.msg.TbMsgDataType;
41 44 import org.thingsboard.server.common.msg.TbMsgMetaData;
... ... @@ -46,6 +49,7 @@ import org.thingsboard.server.dao.device.DeviceService;
46 49 import org.thingsboard.server.dao.relation.RelationService;
47 50 import org.thingsboard.server.dao.tenant.TenantProfileService;
48 51 import org.thingsboard.server.dao.tenant.TenantService;
  52 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
49 53 import org.thingsboard.server.gen.transport.TransportProtos;
50 54 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
51 55 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
... ... @@ -91,6 +95,7 @@ public class DefaultTransportApiService implements TransportApiService {
91 95 private final TbClusterService tbClusterService;
92 96 private final DataDecodingEncodingService dataDecodingEncodingService;
93 97
  98 +
94 99 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
95 100
96 101 public DefaultTransportApiService(DeviceProfileService deviceProfileService, TenantService tenantService,
... ... @@ -117,6 +122,10 @@ public class DefaultTransportApiService implements TransportApiService {
117 122 ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg();
118 123 return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN),
119 124 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
  125 + } else if (transportApiRequestMsg.hasValidateBasicMqttCredRequestMsg()) {
  126 + TransportProtos.ValidateBasicMqttCredRequestMsg msg = transportApiRequestMsg.getValidateBasicMqttCredRequestMsg();
  127 + return Futures.transform(validateCredentials(msg),
  128 + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
120 129 } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) {
121 130 ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg();
122 131 return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE),
... ... @@ -130,7 +139,6 @@ public class DefaultTransportApiService implements TransportApiService {
130 139 } else if (transportApiRequestMsg.hasGetDeviceProfileRequestMsg()) {
131 140 return Futures.transform(handle(transportApiRequestMsg.getGetDeviceProfileRequestMsg()),
132 141 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
133   -
134 142 }
135 143 return Futures.transform(getEmptyTransportApiResponseFuture(),
136 144 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
... ... @@ -146,6 +154,62 @@ public class DefaultTransportApiService implements TransportApiService {
146 154 }
147 155 }
148 156
  157 + private ListenableFuture<TransportApiResponseMsg> validateCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) {
  158 + DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName());
  159 + if (credentials != null) {
  160 + if (credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) {
  161 + return getDeviceInfo(credentials.getDeviceId(), credentials);
  162 + } else if (credentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) {
  163 + if (!checkMqttCredentials(mqtt, credentials)) {
  164 + credentials = null;
  165 + }
  166 + }
  167 + }
  168 + if (credentials == null) {
  169 + credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName()));
  170 + if (credentials == null) {
  171 + credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId()));
  172 + }
  173 + }
  174 + if (credentials != null) {
  175 + return getDeviceInfo(credentials.getDeviceId(), credentials);
  176 + } else {
  177 + return getEmptyTransportApiResponseFuture();
  178 + }
  179 + }
  180 +
  181 + private DeviceCredentials checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, String credId) {
  182 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credId);
  183 + if (deviceCredentials != null && deviceCredentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) {
  184 + if (!checkMqttCredentials(clientCred, deviceCredentials)) {
  185 + return null;
  186 + } else {
  187 + return deviceCredentials;
  188 + }
  189 + }
  190 + return null;
  191 + }
  192 +
  193 + private boolean checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) {
  194 + BasicMqttCredentials dbCred = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), BasicMqttCredentials.class);
  195 + if (!StringUtils.isEmpty(dbCred.getClientId()) && !dbCred.getClientId().equals(clientCred.getClientId())) {
  196 + return false;
  197 + }
  198 + if (!StringUtils.isEmpty(dbCred.getUserName()) && !dbCred.getUserName().equals(clientCred.getUserName())) {
  199 + return false;
  200 + }
  201 + if (!StringUtils.isEmpty(dbCred.getPassword())) {
  202 + if (StringUtils.isEmpty(clientCred.getPassword())) {
  203 + return false;
  204 + } else {
  205 + if (!dbCred.getPassword().equals(clientCred.getPassword())) {
  206 + return false;
  207 + }
  208 + }
  209 + }
  210 + return true;
  211 + }
  212 +
149 213 private ListenableFuture<TransportApiResponseMsg> handle(GetOrCreateDeviceFromGatewayRequestMsg requestMsg) {
150 214 DeviceId gatewayId = new DeviceId(new UUID(requestMsg.getGatewayIdMSB(), requestMsg.getGatewayIdLSB()));
151 215 ListenableFuture<Device> gatewayFuture = deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, gatewayId);
... ... @@ -237,7 +301,7 @@ public class DefaultTransportApiService implements TransportApiService {
237 301 builder.setCredentialsBody(credentials.getCredentialsValue());
238 302 }
239 303 return TransportApiResponseMsg.newBuilder()
240   - .setValidateTokenResponseMsg(builder.build()).build();
  304 + .setValidateCredResponseMsg(builder.build()).build();
241 305 } catch (JsonProcessingException e) {
242 306 log.warn("[{}] Failed to lookup device by id", deviceId, e);
243 307 return getEmptyTransportApiResponse();
... ... @@ -265,6 +329,6 @@ public class DefaultTransportApiService implements TransportApiService {
265 329
266 330 private TransportApiResponseMsg getEmptyTransportApiResponse() {
267 331 return TransportApiResponseMsg.newBuilder()
268   - .setValidateTokenResponseMsg(ValidateDeviceCredentialsResponseMsg.getDefaultInstance()).build();
  332 + .setValidateCredResponseMsg(ValidateDeviceCredentialsResponseMsg.getDefaultInstance()).build();
269 333 }
270 334 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.device.credentials;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class BasicMqttCredentials {
  22 +
  23 + private String clientId;
  24 + private String userName;
  25 + private String password;
  26 +
  27 +}
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.common.msg;
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.bouncycastle.crypto.digests.SHA3Digest;
20 20 import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
  21 +
21 22 /**
22 23 * @author Valerii Sosliuk
23 24 */
... ... @@ -30,8 +31,8 @@ public class EncryptionUtil {
30 31 public static String trimNewLines(String input) {
31 32 return input.replaceAll("-----BEGIN CERTIFICATE-----", "")
32 33 .replaceAll("-----END CERTIFICATE-----", "")
33   - .replaceAll("\n","")
34   - .replaceAll("\r","");
  34 + .replaceAll("\n", "")
  35 + .replaceAll("\r", "");
35 36 }
36 37
37 38 public static String getSha3Hash(String data) {
... ... @@ -45,4 +46,20 @@ public class EncryptionUtil {
45 46 String sha3Hash = ByteUtils.toHexString(hashedBytes);
46 47 return sha3Hash;
47 48 }
  49 +
  50 + public static String getSha3Hash(String delim, String... tokens) {
  51 + StringBuilder sb = new StringBuilder();
  52 + boolean first = true;
  53 + for (String token : tokens) {
  54 + if (token != null && !token.isEmpty()) {
  55 + if (first) {
  56 + first = false;
  57 + } else {
  58 + sb.append(delim);
  59 + }
  60 + sb.append(token);
  61 + }
  62 + }
  63 + return getSha3Hash(sb.toString());
  64 + }
48 65 }
... ...
... ... @@ -147,6 +147,12 @@ message ValidateDeviceX509CertRequestMsg {
147 147 string hash = 1;
148 148 }
149 149
  150 +message ValidateBasicMqttCredRequestMsg {
  151 + string clientId = 1;
  152 + string userName = 2;
  153 + string password = 3;
  154 +}
  155 +
150 156 message ValidateDeviceCredentialsResponseMsg {
151 157 DeviceInfoProto deviceInfo = 1;
152 158 string credentialsBody = 2;
... ... @@ -429,11 +435,12 @@ message TransportApiRequestMsg {
429 435 GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3;
430 436 GetTenantRoutingInfoRequestMsg getTenantRoutingInfoRequestMsg = 4;
431 437 GetDeviceProfileRequestMsg getDeviceProfileRequestMsg = 5;
  438 + ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6;
432 439 }
433 440
434 441 /* Response from ThingsBoard Core Service to Transport Service */
435 442 message TransportApiResponseMsg {
436   - ValidateDeviceCredentialsResponseMsg validateTokenResponseMsg = 1;
  443 + ValidateDeviceCredentialsResponseMsg validateCredResponseMsg = 1;
437 444 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2;
438 445 GetTenantRoutingInfoResponseMsg getTenantRoutingInfoResponseMsg = 4;
439 446 GetDeviceProfileResponseMsg getDeviceProfileResponseMsg = 5;
... ...
... ... @@ -66,6 +66,7 @@ import javax.net.ssl.SSLPeerUnverifiedException;
66 66 import javax.security.cert.X509Certificate;
67 67 import java.io.IOException;
68 68 import java.net.InetSocketAddress;
  69 +import java.nio.charset.StandardCharsets;
69 70 import java.util.ArrayList;
70 71 import java.util.List;
71 72 import java.util.UUID;
... ... @@ -365,25 +366,27 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
365 366 private void processAuthTokenConnect(ChannelHandlerContext ctx, MqttConnectMessage msg) {
366 367 String userName = msg.payload().userName();
367 368 log.info("[{}] Processing connect msg for client with user name: {}!", sessionId, userName);
368   - if (StringUtils.isEmpty(userName)) {
369   - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD));
370   - ctx.close();
371   - } else {
372   - transportService.process(DeviceTransportType.MQTT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(userName).build(),
373   - new TransportServiceCallback<ValidateDeviceCredentialsResponse>() {
374   - @Override
375   - public void onSuccess(ValidateDeviceCredentialsResponse msg) {
376   - onValidateDeviceResponse(msg, ctx);
377   - }
378   -
379   - @Override
380   - public void onError(Throwable e) {
381   - log.trace("[{}] Failed to process credentials: {}", address, userName, e);
382   - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE));
383   - ctx.close();
384   - }
385   - });
  369 + TransportProtos.ValidateBasicMqttCredRequestMsg.Builder request = TransportProtos.ValidateBasicMqttCredRequestMsg.newBuilder()
  370 + .setClientId(msg.payload().clientIdentifier())
  371 + .setUserName(userName);
  372 + String password = msg.payload().password();
  373 + if (password != null) {
  374 + request.setPassword(password);
386 375 }
  376 + transportService.process(DeviceTransportType.MQTT, request.build(),
  377 + new TransportServiceCallback<ValidateDeviceCredentialsResponse>() {
  378 + @Override
  379 + public void onSuccess(ValidateDeviceCredentialsResponse msg) {
  380 + onValidateDeviceResponse(msg, ctx);
  381 + }
  382 +
  383 + @Override
  384 + public void onError(Throwable e) {
  385 + log.trace("[{}] Failed to process credentials: {}", address, userName, e);
  386 + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE));
  387 + ctx.close();
  388 + }
  389 + });
387 390 }
388 391
389 392 private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert) {
... ...
... ... @@ -23,7 +23,6 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
23 23 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
24 24 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
25 25 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
26   -import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg;
27 26 import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg;
28 27 import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg;
29 28 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
... ... @@ -35,7 +34,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg;
35 34 import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProto;
36 35 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
37 36 import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg;
38   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
  37 +import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg;
39 38 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
40 39 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
41 40
... ... @@ -49,6 +48,9 @@ public interface TransportService {
49 48 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg,
50 49 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
51 50
  51 + void process(DeviceTransportType transportType, ValidateBasicMqttCredRequestMsg msg,
  52 + TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
  53 +
52 54 void process(DeviceTransportType transportType, ValidateDeviceX509CertRequestMsg msg,
53 55 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
54 56
... ...
... ... @@ -252,9 +252,20 @@ public class DefaultTransportService implements TransportService {
252 252 }
253 253
254 254 @Override
255   - public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
  255 + public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg,
  256 + TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
256 257 log.trace("Processing msg: {}", msg);
257   - TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateTokenRequestMsg(msg).build());
  258 + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(),
  259 + TransportApiRequestMsg.newBuilder().setValidateTokenRequestMsg(msg).build());
  260 + doProcess(transportType, protoMsg, callback);
  261 + }
  262 +
  263 + @Override
  264 + public void process(DeviceTransportType transportType, TransportProtos.ValidateBasicMqttCredRequestMsg msg,
  265 + TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
  266 + log.trace("Processing msg: {}", msg);
  267 + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(),
  268 + TransportApiRequestMsg.newBuilder().setValidateBasicMqttCredRequestMsg(msg).build());
258 269 doProcess(transportType, protoMsg, callback);
259 270 }
260 271
... ... @@ -265,9 +276,10 @@ public class DefaultTransportService implements TransportService {
265 276 doProcess(transportType, protoMsg, callback);
266 277 }
267 278
268   - private void doProcess(DeviceTransportType transportType, TbProtoQueueMsg<TransportApiRequestMsg> protoMsg, TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
  279 + private void doProcess(DeviceTransportType transportType, TbProtoQueueMsg<TransportApiRequestMsg> protoMsg,
  280 + TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
269 281 ListenableFuture<ValidateDeviceCredentialsResponse> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp -> {
270   - TransportProtos.ValidateDeviceCredentialsResponseMsg msg = tmp.getValue().getValidateTokenResponseMsg();
  282 + TransportProtos.ValidateDeviceCredentialsResponseMsg msg = tmp.getValue().getValidateCredResponseMsg();
271 283 ValidateDeviceCredentialsResponse.ValidateDeviceCredentialsResponseBuilder result = ValidateDeviceCredentialsResponse.builder();
272 284 if (msg.hasDeviceInfo()) {
273 285 result.credentials(msg.getCredentialsBody());
... ...
... ... @@ -21,18 +21,20 @@ import org.hibernate.exception.ConstraintViolationException;
21 21 import org.springframework.beans.factory.annotation.Autowired;
22 22 import org.springframework.cache.annotation.CacheEvict;
23 23 import org.springframework.cache.annotation.Cacheable;
  24 +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
24 25 import org.springframework.stereotype.Service;
25 26 import org.springframework.util.StringUtils;
26 27 import org.thingsboard.server.common.data.Device;
  28 +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
27 29 import org.thingsboard.server.common.data.id.DeviceId;
28 30 import org.thingsboard.server.common.data.id.EntityId;
29 31 import org.thingsboard.server.common.data.id.TenantId;
30 32 import org.thingsboard.server.common.data.security.DeviceCredentials;
31   -import org.thingsboard.server.common.data.security.DeviceCredentialsType;
32 33 import org.thingsboard.server.common.msg.EncryptionUtil;
33 34 import org.thingsboard.server.dao.entity.AbstractEntityService;
34 35 import org.thingsboard.server.dao.exception.DataValidationException;
35 36 import org.thingsboard.server.dao.service.DataValidator;
  37 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
36 38
37 39 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE;
38 40 import static org.thingsboard.server.dao.service.Validator.validateId;
... ... @@ -75,8 +77,16 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
75 77 }
76 78
77 79 private DeviceCredentials saveOrUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) {
78   - if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) {
79   - formatCertData(deviceCredentials);
  80 + if(deviceCredentials.getCredentialsType() == null){
  81 + throw new DataValidationException("Device credentials type should be specified");
  82 + }
  83 + switch (deviceCredentials.getCredentialsType()) {
  84 + case X509_CERTIFICATE:
  85 + formatCertData(deviceCredentials);
  86 + break;
  87 + case MQTT_BASIC:
  88 + formatSimpleMqttCredentials(deviceCredentials);
  89 + break;
80 90 }
81 91 log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials);
82 92 credentialsValidator.validate(deviceCredentials, id -> tenantId);
... ... @@ -93,6 +103,32 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
93 103 }
94 104 }
95 105
  106 + private void formatSimpleMqttCredentials(DeviceCredentials deviceCredentials) {
  107 + BasicMqttCredentials mqttCredentials;
  108 + try {
  109 + mqttCredentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), BasicMqttCredentials.class);
  110 + if (mqttCredentials == null) {
  111 + throw new IllegalArgumentException();
  112 + }
  113 + } catch (IllegalArgumentException e) {
  114 + throw new DataValidationException("Invalid credentials body for simple mqtt credentials!");
  115 + }
  116 + if (StringUtils.isEmpty(mqttCredentials.getClientId()) && StringUtils.isEmpty(mqttCredentials.getUserName())) {
  117 + throw new DataValidationException("Both mqtt client id and user name are empty!");
  118 + }
  119 + if (StringUtils.isEmpty(mqttCredentials.getClientId())) {
  120 + deviceCredentials.setCredentialsId(mqttCredentials.getUserName());
  121 + } else if (StringUtils.isEmpty(mqttCredentials.getUserName())) {
  122 + deviceCredentials.setCredentialsId(EncryptionUtil.getSha3Hash(mqttCredentials.getClientId()));
  123 + } else {
  124 + deviceCredentials.setCredentialsId(EncryptionUtil.getSha3Hash("|", mqttCredentials.getClientId(), mqttCredentials.getUserName()));
  125 + }
  126 + if (!StringUtils.isEmpty(mqttCredentials.getPassword())) {
  127 + mqttCredentials.setPassword(mqttCredentials.getPassword());
  128 + }
  129 + deviceCredentials.setCredentialsValue(JacksonUtil.toString(mqttCredentials));
  130 + }
  131 +
96 132 private void formatCertData(DeviceCredentials deviceCredentials) {
97 133 String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
98 134 String sha3Hash = EncryptionUtil.getSha3Hash(cert);
... ...