Showing
8 changed files
with
201 additions
and
33 deletions
... | ... | @@ -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); | ... | ... |