Commit 7322afac0be4c15be9e47aae8e054367e5a17410

Authored by Andrii Shvaika
1 parent a8dd25a7

Implementation draft

Showing 15 changed files with 326 additions and 108 deletions
@@ -643,6 +643,7 @@ transport: @@ -643,6 +643,7 @@ transport:
643 private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" 643 private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
644 # Only Certificate_x509: 644 # Only Certificate_x509:
645 alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" 645 alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}"
  646 + skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
646 bootstrap: 647 bootstrap:
647 enable: "${LWM2M_ENABLED_BS:true}" 648 enable: "${LWM2M_ENABLED_BS:true}"
648 id: "${LWM2M_SERVER_ID_BS:111}" 649 id: "${LWM2M_SERVER_ID_BS:111}"
@@ -145,7 +145,6 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri @@ -145,7 +145,6 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
145 145
146 @Override 146 @Override
147 public void setResultHandler(HandshakeResultHandler resultHandler) { 147 public void setResultHandler(HandshakeResultHandler resultHandler) {
148 - // empty implementation  
149 } 148 }
150 149
151 public ConcurrentMap<String, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionIdsMap() { 150 public ConcurrentMap<String, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionIdsMap() {
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java
@@ -65,7 +65,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.g @@ -65,7 +65,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.g
65 @Component 65 @Component
66 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')") 66 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')")
67 @RequiredArgsConstructor 67 @RequiredArgsConstructor
68 -public class LwM2MTransportBootstrapServerConfiguration { 68 +//TODO: @ybondarenko please refactor this to be similar to DefaultLwM2mTransportService
  69 +public class LwM2MTransportBootstrapService {
69 private PublicKey publicKey; 70 private PublicKey publicKey;
70 private PrivateKey privateKey; 71 private PrivateKey privateKey;
71 private boolean pskMode = false; 72 private boolean pskMode = false;
@@ -103,7 +103,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @@ -103,7 +103,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
103 BootstrapConfig bsConfig = store.getBootstrapConfig(); 103 BootstrapConfig bsConfig = store.getBootstrapConfig();
104 if (bsConfig.security != null) { 104 if (bsConfig.security != null) {
105 try { 105 try {
106 - bootstrapConfigStore.add(store.getEndPoint(), bsConfig); 106 + bootstrapConfigStore.add(store.getEndpoint(), bsConfig);
107 } catch (InvalidConfigurationException e) { 107 } catch (InvalidConfigurationException e) {
108 log.error("", e); 108 log.error("", e);
109 } 109 }
@@ -121,22 +121,22 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @@ -121,22 +121,22 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
121 switch (SecurityMode.valueOf(lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode())) { 121 switch (SecurityMode.valueOf(lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode())) {
122 /* Use RPK only */ 122 /* Use RPK only */
123 case PSK: 123 case PSK:
124 - store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndPoint(), 124 + store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(),
125 lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), 125 lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(),
126 Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); 126 Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray())));
127 store.setSecurityMode(SecurityMode.PSK.code); 127 store.setSecurityMode(SecurityMode.PSK.code);
128 break; 128 break;
129 case RPK: 129 case RPK:
130 try { 130 try {
131 - store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndPoint(), 131 + store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(),
132 SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); 132 SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray()))));
133 store.setSecurityMode(SecurityMode.RPK.code); 133 store.setSecurityMode(SecurityMode.RPK.code);
134 break; 134 break;
135 } catch (IOException | GeneralSecurityException e) { 135 } catch (IOException | GeneralSecurityException e) {
136 - log.error("Unable to decode Client public key for [{}] [{}]", store.getEndPoint(), e.getMessage()); 136 + log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage());
137 } 137 }
138 case X509: 138 case X509:
139 - store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndPoint())); 139 + store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint()));
140 store.setSecurityMode(SecurityMode.X509.code); 140 store.setSecurityMode(SecurityMode.X509.code);
141 break; 141 break;
142 case NO_SEC: 142 case NO_SEC:
@@ -166,22 +166,22 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @@ -166,22 +166,22 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
166 if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { 166 if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {
167 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); 167 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
168 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); 168 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
169 - String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint()); 169 + String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndpoint());
170 helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo); 170 helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo);
171 return lwM2MBootstrapConfig; 171 return lwM2MBootstrapConfig;
172 } else { 172 } else {
173 - log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());  
174 - log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());  
175 - String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint()); 173 + log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint());
  174 + log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());
  175 + String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());
176 helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo); 176 helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo);
177 return null; 177 return null;
178 } 178 }
179 } 179 }
180 } catch (JsonProcessingException e) { 180 } catch (JsonProcessingException e) {
181 - log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndPoint(), e.getMessage()); 181 + log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndpoint(), e.getMessage());
182 return null; 182 return null;
183 } 183 }
184 - log.error("Unable to decode Json or Certificate for [{}]", store.getEndPoint()); 184 + log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint());
185 return null; 185 return null;
186 } 186 }
187 187
@@ -148,9 +148,7 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @@ -148,9 +148,7 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
148 keyStoreValue = KeyStore.getInstance(keyStoreType); 148 keyStoreValue = KeyStore.getInstance(keyStoreType);
149 keyStoreValue.load(inKeyStore, keyStorePassword == null ? null : keyStorePassword.toCharArray()); 149 keyStoreValue.load(inKeyStore, keyStorePassword == null ? null : keyStorePassword.toCharArray());
150 } catch (Exception e) { 150 } catch (Exception e) {
151 - log.warn("Unable to lookup LwM2M keystore. Reason: {}, {}" , uri, e.getMessage());  
152 -// Absence of the key store should not block user from using plain LwM2M  
153 -// throw new RuntimeException("Failed to lookup LwM2M keystore: " + (uri != null ? uri.toString() : ""), e); 151 + log.info("Unable to lookup LwM2M keystore. Reason: {}, {}" , uri, e.getMessage());
154 } 152 }
155 } 153 }
156 } 154 }
@@ -20,19 +20,20 @@ import lombok.Data; @@ -20,19 +20,20 @@ import lombok.Data;
20 import org.eclipse.leshan.server.bootstrap.BootstrapConfig; 20 import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
21 import org.eclipse.leshan.server.security.SecurityInfo; 21 import org.eclipse.leshan.server.security.SecurityInfo;
22 import org.thingsboard.server.common.data.DeviceProfile; 22 import org.thingsboard.server.common.data.DeviceProfile;
  23 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
23 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; 24 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
24 25
25 import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE; 26 import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE;
26 27
27 @Data 28 @Data
28 public class EndpointSecurityInfo { 29 public class EndpointSecurityInfo {
29 - private ValidateDeviceCredentialsResponseMsg msg; 30 + private ValidateDeviceCredentialsResponse msg;
30 private SecurityInfo securityInfo; 31 private SecurityInfo securityInfo;
31 private int securityMode = DEFAULT_MODE.code; 32 private int securityMode = DEFAULT_MODE.code;
32 33
33 /** bootstrap */ 34 /** bootstrap */
34 private DeviceProfile deviceProfile; 35 private DeviceProfile deviceProfile;
35 private JsonObject bootstrapJsonCredential; 36 private JsonObject bootstrapJsonCredential;
36 - private String endPoint; 37 + private String endpoint;
37 private BootstrapConfig bootstrapConfig; 38 private BootstrapConfig bootstrapConfig;
38 } 39 }
@@ -24,6 +24,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; @@ -24,6 +24,7 @@ import org.eclipse.leshan.server.security.SecurityInfo;
24 import org.springframework.stereotype.Component; 24 import org.springframework.stereotype.Component;
25 import org.thingsboard.server.common.data.DeviceProfile; 25 import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.transport.TransportServiceCallback; 26 import org.thingsboard.server.common.transport.TransportServiceCallback;
  27 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
27 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; 28 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
28 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; 29 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
29 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 30 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
@@ -59,12 +60,11 @@ public class LwM2mCredentialsSecurityInfoValidator { @@ -59,12 +60,11 @@ public class LwM2mCredentialsSecurityInfoValidator {
59 context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(), 60 context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(),
60 new TransportServiceCallback<>() { 61 new TransportServiceCallback<>() {
61 @Override 62 @Override
62 - public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) {  
63 - String credentialsBody = msg.getCredentialsBody(); 63 + public void onSuccess(ValidateDeviceCredentialsResponse msg) {
  64 + String credentialsBody = msg.getCredentials();
64 resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue); 65 resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue);
65 resultSecurityStore[0].setMsg(msg); 66 resultSecurityStore[0].setMsg(msg);
66 - Optional<DeviceProfile> deviceProfileOpt = LwM2mTransportUtil.decode(msg.getProfileBody().toByteArray());  
67 - deviceProfileOpt.ifPresent(profile -> resultSecurityStore[0].setDeviceProfile(profile)); 67 + resultSecurityStore[0].setDeviceProfile(msg.getDeviceProfile());
68 latch.countDown(); 68 latch.countDown();
69 } 69 }
70 70
@@ -105,7 +105,7 @@ public class LwM2mCredentialsSecurityInfoValidator { @@ -105,7 +105,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
105 if (object != null && !object.isJsonNull()) { 105 if (object != null && !object.isJsonNull()) {
106 if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { 106 if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) {
107 result.setBootstrapJsonCredential(object); 107 result.setBootstrapJsonCredential(object);
108 - result.setEndPoint(endpoint); 108 + result.setEndpoint(endpoint);
109 result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code); 109 result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code);
110 } else { 110 } else {
111 LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase()); 111 LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase());
  1 +/**
  2 + * Copyright © 2016-2021 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.transport.lwm2m.secure;
  17 +
  18 +import org.eclipse.leshan.core.request.Identity;
  19 +import org.eclipse.leshan.core.request.UplinkRequest;
  20 +import org.eclipse.leshan.server.registration.Registration;
  21 +import org.eclipse.leshan.server.security.Authorizer;
  22 +
  23 +public class TbLwM2MAuthorizer implements Authorizer {
  24 + @Override
  25 + public Registration isAuthorized(UplinkRequest<?> request, Registration registration, Identity senderIdentity) {
  26 + return null;
  27 + }
  28 +}
  1 +/**
  2 + * Copyright © 2016-2021 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.transport.lwm2m.secure;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.californium.elements.util.CertPathUtil;
  21 +import org.eclipse.californium.scandium.dtls.AlertMessage;
  22 +import org.eclipse.californium.scandium.dtls.CertificateMessage;
  23 +import org.eclipse.californium.scandium.dtls.CertificateType;
  24 +import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
  25 +import org.eclipse.californium.scandium.dtls.ConnectionId;
  26 +import org.eclipse.californium.scandium.dtls.DTLSSession;
  27 +import org.eclipse.californium.scandium.dtls.HandshakeException;
  28 +import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
  29 +import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
  30 +import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier;
  31 +import org.eclipse.californium.scandium.util.ServerNames;
  32 +import org.springframework.beans.factory.annotation.Value;
  33 +import org.springframework.stereotype.Component;
  34 +import org.springframework.util.StringUtils;
  35 +import org.thingsboard.server.common.data.DeviceProfile;
  36 +import org.thingsboard.server.common.msg.EncryptionUtil;
  37 +import org.thingsboard.server.common.transport.TransportService;
  38 +import org.thingsboard.server.common.transport.TransportServiceCallback;
  39 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  40 +import org.thingsboard.server.common.transport.util.SslUtil;
  41 +import org.thingsboard.server.gen.transport.TransportProtos;
  42 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  43 +
  44 +import javax.annotation.PostConstruct;
  45 +import javax.security.auth.x500.X500Principal;
  46 +import java.security.PublicKey;
  47 +import java.security.cert.CertPath;
  48 +import java.security.cert.CertificateEncodingException;
  49 +import java.security.cert.CertificateExpiredException;
  50 +import java.security.cert.CertificateNotYetValidException;
  51 +import java.security.cert.X509Certificate;
  52 +import java.util.Arrays;
  53 +import java.util.List;
  54 +import java.util.concurrent.CountDownLatch;
  55 +import java.util.concurrent.TimeUnit;
  56 +
  57 +@Slf4j
  58 +@Component
  59 +@RequiredArgsConstructor
  60 +public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier {
  61 +
  62 + private final TransportService transportService;
  63 + private final TbLwM2MDtlsSessionStorage sessionStorage;
  64 + private final LwM2MTransportServerConfig config;
  65 +
  66 + @SuppressWarnings("deprecation")
  67 + private StaticCertificateVerifier staticCertificateVerifier;
  68 +
  69 + @Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}")
  70 + private boolean skipValidityCheckForClientCert;
  71 +
  72 + @Override
  73 + public List<CertificateType> getSupportedCertificateType() {
  74 + return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY);
  75 + }
  76 +
  77 + @PostConstruct
  78 + public void init() {
  79 + try {
  80 + /* by default trust all */
  81 + X509Certificate[] trustedCertificates = new X509Certificate[0];
  82 + if (config.getKeyStoreValue() != null) {
  83 + X509Certificate rootCAX509Cert = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getRootCertificateAlias());
  84 + if (rootCAX509Cert != null) {
  85 + trustedCertificates = new X509Certificate[1];
  86 + trustedCertificates[0] = rootCAX509Cert;
  87 + }
  88 + }
  89 + staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates);
  90 + } catch (Exception e) {
  91 + log.info("Failed to initialize the ");
  92 + }
  93 + }
  94 +
  95 + @Override
  96 + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) {
  97 + CertPath certChain = message.getCertificateChain();
  98 + if (certChain == null) {
  99 + //We trust all RPK on this layer, and use TbLwM2MAuthorizer
  100 + PublicKey publicKey = message.getPublicKey();
  101 + return new CertificateVerificationResult(cid, publicKey, null);
  102 + } else {
  103 + try {
  104 + String credentialsBody = null;
  105 + CertPath certpath = message.getCertificateChain();
  106 + X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]);
  107 + for (X509Certificate cert : chain) {
  108 + try {
  109 + if (!skipValidityCheckForClientCert) {
  110 + cert.checkValidity();
  111 + }
  112 +
  113 + String strCert = SslUtil.getCertificateString(cert);
  114 + String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
  115 + final ValidateDeviceCredentialsResponse[] deviceCredentialsResponse = new ValidateDeviceCredentialsResponse[1];
  116 + CountDownLatch latch = new CountDownLatch(1);
  117 + transportService.process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(sha3Hash).build(),
  118 + new TransportServiceCallback<>() {
  119 + @Override
  120 + public void onSuccess(ValidateDeviceCredentialsResponse msg) {
  121 + if (!StringUtils.isEmpty(msg.getCredentials())) {
  122 + deviceCredentialsResponse[0] = msg;
  123 + }
  124 + latch.countDown();
  125 + }
  126 +
  127 + @Override
  128 + public void onError(Throwable e) {
  129 + log.error(e.getMessage(), e);
  130 + latch.countDown();
  131 + }
  132 + });
  133 + latch.await(10, TimeUnit.SECONDS);
  134 + ValidateDeviceCredentialsResponse msg = deviceCredentialsResponse[0];
  135 + if (msg != null && strCert.equals(msg.getCredentials())) {
  136 + credentialsBody = msg.getCredentials();
  137 + DeviceProfile deviceProfile = msg.getDeviceProfile();
  138 + if (msg.hasDeviceInfo() && deviceProfile != null) {
  139 + String endpoint = sha3Hash; //TODO: extract endpoint from credentials body and push to storage
  140 + sessionStorage.put(endpoint, msg);
  141 + }
  142 + break;
  143 + }
  144 + } catch (InterruptedException |
  145 + CertificateEncodingException |
  146 + CertificateExpiredException |
  147 + CertificateNotYetValidException e) {
  148 + log.error(e.getMessage(), e);
  149 + }
  150 + }
  151 + if (credentialsBody == null) {
  152 + if (staticCertificateVerifier != null) {
  153 + staticCertificateVerifier.verifyCertificate(message, session);
  154 + } else {
  155 + AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR,
  156 + session.getPeer());
  157 + throw new HandshakeException("x509 verification not enabled!", alert);
  158 + }
  159 + }
  160 + return new CertificateVerificationResult(cid, certpath, null);
  161 + } catch (HandshakeException e) {
  162 + log.trace("Certificate validation failed!", e);
  163 + return new CertificateVerificationResult(cid, e, null);
  164 + }
  165 + }
  166 + }
  167 +
  168 + @Override
  169 + public List<X500Principal> getAcceptedIssuers() {
  170 + return CertPathUtil.toSubjects(null);
  171 + }
  172 +
  173 + @Override
  174 + public void setResultHandler(HandshakeResultHandler resultHandler) {
  175 +
  176 + }
  177 +}
  1 +/**
  2 + * Copyright © 2016-2021 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.transport.lwm2m.secure;
  17 +
  18 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  19 +
  20 +public interface TbLwM2MDtlsSessionStorage {
  21 +
  22 + void put(String endpoint, ValidateDeviceCredentialsResponse msg);
  23 +
  24 + ValidateDeviceCredentialsResponse get(String endpoint);
  25 +
  26 +}
@@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server; @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server;
18 import lombok.RequiredArgsConstructor; 18 import lombok.RequiredArgsConstructor;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.eclipse.californium.scandium.config.DtlsConnectorConfig; 20 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
  21 +import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
21 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; 22 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder;
22 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; 23 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder;
23 import org.eclipse.leshan.core.util.Hex; 24 import org.eclipse.leshan.core.util.Hex;
@@ -25,14 +26,14 @@ import org.eclipse.leshan.server.californium.LeshanServer; @@ -25,14 +26,14 @@ import org.eclipse.leshan.server.californium.LeshanServer;
25 import org.eclipse.leshan.server.californium.LeshanServerBuilder; 26 import org.eclipse.leshan.server.californium.LeshanServerBuilder;
26 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; 27 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
27 import org.eclipse.leshan.server.model.LwM2mModelProvider; 28 import org.eclipse.leshan.server.model.LwM2mModelProvider;
28 -import org.eclipse.leshan.server.security.DefaultAuthorizer;  
29 import org.eclipse.leshan.server.security.EditableSecurityStore; 29 import org.eclipse.leshan.server.security.EditableSecurityStore;
30 -import org.eclipse.leshan.server.security.SecurityChecker;  
31 import org.springframework.stereotype.Component; 30 import org.springframework.stereotype.Component;
32 import org.thingsboard.server.common.data.StringUtils; 31 import org.thingsboard.server.common.data.StringUtils;
33 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
34 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 33 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
35 import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; 34 import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
  35 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
  36 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier;
36 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; 37 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
37 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 38 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
38 39
@@ -41,7 +42,6 @@ import javax.annotation.PreDestroy; @@ -41,7 +42,6 @@ import javax.annotation.PreDestroy;
41 import java.math.BigInteger; 42 import java.math.BigInteger;
42 import java.security.AlgorithmParameters; 43 import java.security.AlgorithmParameters;
43 import java.security.KeyFactory; 44 import java.security.KeyFactory;
44 -import java.security.KeyStoreException;  
45 import java.security.NoSuchAlgorithmException; 45 import java.security.NoSuchAlgorithmException;
46 import java.security.PrivateKey; 46 import java.security.PrivateKey;
47 import java.security.PublicKey; 47 import java.security.PublicKey;
@@ -70,9 +70,10 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.g @@ -70,9 +70,10 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.g
70 @RequiredArgsConstructor 70 @RequiredArgsConstructor
71 public class DefaultLwM2mTransportService implements LwM2MTransportService { 71 public class DefaultLwM2mTransportService implements LwM2MTransportService {
72 72
  73 + public static final CipherSuite[] RPK_OR_X509_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256};
  74 + public static final CipherSuite[] PSK_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256};
73 private PublicKey publicKey; 75 private PublicKey publicKey;
74 private PrivateKey privateKey; 76 private PrivateKey privateKey;
75 - private boolean pskMode = false;  
76 77
77 private final LwM2mTransportContext context; 78 private final LwM2mTransportContext context;
78 private final LwM2MTransportServerConfig config; 79 private final LwM2MTransportServerConfig config;
@@ -81,6 +82,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -81,6 +82,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
81 private final CaliforniumRegistrationStore registrationStore; 82 private final CaliforniumRegistrationStore registrationStore;
82 private final EditableSecurityStore securityStore; 83 private final EditableSecurityStore securityStore;
83 private final LwM2mClientContext lwM2mClientContext; 84 private final LwM2mClientContext lwM2mClientContext;
  85 + private final TbLwM2MDtlsCertificateVerifier certificateVerifier;
  86 + private final TbLwM2MAuthorizer authorizer;
84 87
85 private LeshanServer server; 88 private LeshanServer server;
86 89
@@ -128,9 +131,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -128,9 +131,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
128 config.setModelProvider(modelProvider); 131 config.setModelProvider(modelProvider);
129 builder.setObjectModelProvider(modelProvider); 132 builder.setObjectModelProvider(modelProvider);
130 133
131 - /* Create credentials */  
132 - this.setServerWithCredentials(builder);  
133 -  
134 /* Set securityStore with new registrationStore */ 134 /* Set securityStore with new registrationStore */
135 builder.setSecurityStore(securityStore); 135 builder.setSecurityStore(securityStore);
136 builder.setRegistrationStore(registrationStore); 136 builder.setRegistrationStore(registrationStore);
@@ -142,18 +142,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -142,18 +142,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
142 dtlsConfig.setServerOnly(true); 142 dtlsConfig.setServerOnly(true);
143 dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups()); 143 dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups());
144 dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers()); 144 dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers());
145 - if (this.pskMode) {  
146 - dtlsConfig.setSupportedCipherSuites(  
147 - TLS_PSK_WITH_AES_128_CCM_8,  
148 - TLS_PSK_WITH_AES_128_CBC_SHA256);  
149 - } else {  
150 - dtlsConfig.setSupportedCipherSuites(  
151 - TLS_PSK_WITH_AES_128_CCM_8,  
152 - TLS_PSK_WITH_AES_128_CBC_SHA256,  
153 - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,  
154 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);  
155 - }  
156 - 145 + /* Create credentials */
  146 + this.setServerWithCredentials(builder, dtlsConfig);
157 147
158 /* Set DTLS Config */ 148 /* Set DTLS Config */
159 builder.setDtlsConfig(dtlsConfig); 149 builder.setDtlsConfig(dtlsConfig);
@@ -162,40 +152,21 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -162,40 +152,21 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
162 return builder.build(); 152 return builder.build();
163 } 153 }
164 154
165 - private void setServerWithCredentials(LeshanServerBuilder builder) {  
166 - try {  
167 - if (config.getKeyStoreValue() != null) {  
168 - if (this.setBuilderX509(builder)) {  
169 - X509Certificate rootCAX509Cert = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getRootCertificateAlias());  
170 - if (rootCAX509Cert != null) {  
171 - X509Certificate[] trustedCertificates = new X509Certificate[1];  
172 - trustedCertificates[0] = rootCAX509Cert;  
173 - builder.setTrustedCertificates(trustedCertificates);  
174 - } else {  
175 - /* by default trust all */  
176 - builder.setTrustedCertificates(new X509Certificate[0]);  
177 - }  
178 - /* Set securityStore with registrationStore*/  
179 - builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() {  
180 - @Override  
181 - protected boolean matchX509Identity(String endpoint, String receivedX509CommonName,  
182 - String expectedX509CommonName) {  
183 - return endpoint.startsWith(expectedX509CommonName);  
184 - }  
185 - }));  
186 - }  
187 - } else if (this.setServerRPK(builder)) {  
188 - this.infoPramsUri("RPK");  
189 - this.infoParamsServerKey(this.publicKey, this.privateKey);  
190 - } else {  
191 - /* by default trust all */  
192 - builder.setTrustedCertificates(new X509Certificate[0]);  
193 - log.info("Unable to load X509 files for LWM2MServer");  
194 - this.pskMode = true;  
195 - this.infoPramsUri("PSK");  
196 - }  
197 - } catch (KeyStoreException ex) {  
198 - log.error("[{}] Unable to load X509 files server", ex.getMessage()); 155 + private void setServerWithCredentials(LeshanServerBuilder builder, DtlsConnectorConfig.Builder dtlsConfig) {
  156 + if (config.getKeyStoreValue() != null && this.setBuilderX509(builder)) {
  157 + dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
  158 + builder.setAuthorizer(authorizer);
  159 + dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
  160 + } else if (this.setServerRPK(builder)) {
  161 + this.infoPramsUri("RPK");
  162 + this.infoParamsServerKey(this.publicKey, this.privateKey);
  163 + dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
  164 + } else {
  165 + /* by default trust all */
  166 + builder.setTrustedCertificates(new X509Certificate[0]);
  167 + log.info("Unable to load X509 files for LWM2MServer");
  168 + dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES);
  169 + this.infoPramsUri("PSK");
199 } 170 }
200 } 171 }
201 172
@@ -241,7 +212,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -241,7 +212,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
241 212
242 private boolean setServerRPK(LeshanServerBuilder builder) { 213 private boolean setServerRPK(LeshanServerBuilder builder) {
243 try { 214 try {
244 - this.generateKeyForRPK(); 215 + this.loadOrGenerateRPKKeys();
245 if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && 216 if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&
246 this.privateKey != null && this.privateKey.getEncoded().length > 0) { 217 this.privateKey != null && this.privateKey.getEncoded().length > 0) {
247 builder.setPublicKey(this.publicKey); 218 builder.setPublicKey(this.publicKey);
@@ -254,7 +225,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -254,7 +225,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
254 return false; 225 return false;
255 } 226 }
256 227
257 - private void generateKeyForRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException { 228 + private void loadOrGenerateRPKKeys() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
258 /* Get Elliptic Curve Parameter spec for secp256r1 */ 229 /* Get Elliptic Curve Parameter spec for secp256r1 */
259 AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); 230 AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
260 algoParameters.init(new ECGenParameterSpec("secp256r1")); 231 algoParameters.init(new ECGenParameterSpec("secp256r1"));
@@ -40,6 +40,7 @@ import org.eclipse.leshan.core.model.ResourceModel; @@ -40,6 +40,7 @@ import org.eclipse.leshan.core.model.ResourceModel;
40 import org.eclipse.leshan.core.node.codec.CodecException; 40 import org.eclipse.leshan.core.node.codec.CodecException;
41 import org.springframework.stereotype.Component; 41 import org.springframework.stereotype.Component;
42 import org.thingsboard.server.common.transport.TransportServiceCallback; 42 import org.thingsboard.server.common.transport.TransportServiceCallback;
  43 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
43 import org.thingsboard.server.gen.transport.TransportProtos; 44 import org.thingsboard.server.gen.transport.TransportProtos;
44 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; 45 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
45 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; 46 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
@@ -106,21 +107,21 @@ public class LwM2mTransportServerHelper { @@ -106,21 +107,21 @@ public class LwM2mTransportServerHelper {
106 /** 107 /**
107 * @return - sessionInfo after access connect client 108 * @return - sessionInfo after access connect client
108 */ 109 */
109 - public SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) { 110 + public SessionInfoProto getValidateSessionInfo(ValidateDeviceCredentialsResponse msg, long mostSignificantBits, long leastSignificantBits) {
110 return SessionInfoProto.newBuilder() 111 return SessionInfoProto.newBuilder()
111 .setNodeId(context.getNodeId()) 112 .setNodeId(context.getNodeId())
112 .setSessionIdMSB(mostSignificantBits) 113 .setSessionIdMSB(mostSignificantBits)
113 .setSessionIdLSB(leastSignificantBits) 114 .setSessionIdLSB(leastSignificantBits)
114 - .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())  
115 - .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())  
116 - .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())  
117 - .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())  
118 - .setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())  
119 - .setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB()) 115 + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceId().getId().getMostSignificantBits())
  116 + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceId().getId().getLeastSignificantBits())
  117 + .setTenantIdMSB(msg.getDeviceInfo().getTenantId().getId().getMostSignificantBits())
  118 + .setTenantIdLSB(msg.getDeviceInfo().getTenantId().getId().getLeastSignificantBits())
  119 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerId().getId().getMostSignificantBits())
  120 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerId().getId().getLeastSignificantBits())
120 .setDeviceName(msg.getDeviceInfo().getDeviceName()) 121 .setDeviceName(msg.getDeviceInfo().getDeviceName())
121 .setDeviceType(msg.getDeviceInfo().getDeviceType()) 122 .setDeviceType(msg.getDeviceInfo().getDeviceType())
122 - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())  
123 - .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB()) 123 + .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits())
  124 + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileId().getId().getLeastSignificantBits())
124 .build(); 125 .build();
125 } 126 }
126 127
@@ -27,6 +27,7 @@ import org.eclipse.leshan.server.registration.Registration; @@ -27,6 +27,7 @@ import org.eclipse.leshan.server.registration.Registration;
27 import org.eclipse.leshan.server.security.SecurityInfo; 27 import org.eclipse.leshan.server.security.SecurityInfo;
28 import org.thingsboard.server.common.data.Device; 28 import org.thingsboard.server.common.data.Device;
29 import org.thingsboard.server.common.data.DeviceProfile; 29 import org.thingsboard.server.common.data.DeviceProfile;
  30 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
30 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 31 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
31 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 32 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
32 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; 33 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
@@ -79,7 +80,7 @@ public class LwM2mClient implements Cloneable { @@ -79,7 +80,7 @@ public class LwM2mClient implements Cloneable {
79 @Setter 80 @Setter
80 private Registration registration; 81 private Registration registration;
81 82
82 - private ValidateDeviceCredentialsResponseMsg credentialsResponse; 83 + private ValidateDeviceCredentialsResponse credentials;
83 @Getter 84 @Getter
84 private final Map<String, ResourceValue> resources; 85 private final Map<String, ResourceValue> resources;
85 @Getter 86 @Getter
@@ -98,11 +99,11 @@ public class LwM2mClient implements Cloneable { @@ -98,11 +99,11 @@ public class LwM2mClient implements Cloneable {
98 return super.clone(); 99 return super.clone();
99 } 100 }
100 101
101 - public LwM2mClient(String nodeId, String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponseMsg credentialsResponse, UUID profileId, UUID sessionId) { 102 + public LwM2mClient(String nodeId, String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) {
102 this.endpoint = endpoint; 103 this.endpoint = endpoint;
103 this.identity = identity; 104 this.identity = identity;
104 this.securityInfo = securityInfo; 105 this.securityInfo = securityInfo;
105 - this.credentialsResponse = credentialsResponse; 106 + this.credentials = credentials;
106 this.delayedRequests = new ConcurrentHashMap<>(); 107 this.delayedRequests = new ConcurrentHashMap<>();
107 this.pendingReadRequests = new CopyOnWriteArrayList<>(); 108 this.pendingReadRequests = new CopyOnWriteArrayList<>();
108 this.resources = new ConcurrentHashMap<>(); 109 this.resources = new ConcurrentHashMap<>();
@@ -112,8 +113,8 @@ public class LwM2mClient implements Cloneable { @@ -112,8 +113,8 @@ public class LwM2mClient implements Cloneable {
112 this.updateFw = false; 113 this.updateFw = false;
113 this.queuedRequests = new ConcurrentLinkedQueue<>(); 114 this.queuedRequests = new ConcurrentLinkedQueue<>();
114 this.frUpdate = new LwM2mFirmwareUpdate(); 115 this.frUpdate = new LwM2mFirmwareUpdate();
115 - if (this.credentialsResponse != null && this.credentialsResponse.hasDeviceInfo()) {  
116 - this.session = createSession(nodeId, sessionId, credentialsResponse); 116 + if (this.credentials != null && this.credentials.hasDeviceInfo()) {
  117 + this.session = createSession(nodeId, sessionId, credentials);
117 this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB()); 118 this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
118 this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB()); 119 this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());
119 this.deviceName = session.getDeviceName(); 120 this.deviceName = session.getDeviceName();
@@ -146,21 +147,21 @@ public class LwM2mClient implements Cloneable { @@ -146,21 +147,21 @@ public class LwM2mClient implements Cloneable {
146 builder.setDeviceType(this.deviceProfileName); 147 builder.setDeviceType(this.deviceProfileName);
147 } 148 }
148 149
149 - private SessionInfoProto createSession(String nodeId, UUID sessionId, ValidateDeviceCredentialsResponseMsg msg) { 150 + private SessionInfoProto createSession(String nodeId, UUID sessionId, ValidateDeviceCredentialsResponse msg) {
150 return SessionInfoProto.newBuilder() 151 return SessionInfoProto.newBuilder()
151 .setNodeId(nodeId) 152 .setNodeId(nodeId)
152 .setSessionIdMSB(sessionId.getMostSignificantBits()) 153 .setSessionIdMSB(sessionId.getMostSignificantBits())
153 .setSessionIdLSB(sessionId.getLeastSignificantBits()) 154 .setSessionIdLSB(sessionId.getLeastSignificantBits())
154 - .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())  
155 - .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())  
156 - .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())  
157 - .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())  
158 - .setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())  
159 - .setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB()) 155 + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceId().getId().getMostSignificantBits())
  156 + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceId().getId().getLeastSignificantBits())
  157 + .setTenantIdMSB(msg.getDeviceInfo().getTenantId().getId().getMostSignificantBits())
  158 + .setTenantIdLSB(msg.getDeviceInfo().getTenantId().getId().getLeastSignificantBits())
  159 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerId().getId().getMostSignificantBits())
  160 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerId().getId().getLeastSignificantBits())
160 .setDeviceName(msg.getDeviceInfo().getDeviceName()) 161 .setDeviceName(msg.getDeviceInfo().getDeviceName())
161 .setDeviceType(msg.getDeviceInfo().getDeviceType()) 162 .setDeviceType(msg.getDeviceInfo().getDeviceType())
162 - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())  
163 - .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB()) 163 + .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits())
  164 + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileId().getId().getLeastSignificantBits())
164 .build(); 165 .build();
165 } 166 }
166 167
@@ -79,7 +79,7 @@ public interface TransportService { @@ -79,7 +79,7 @@ public interface TransportService {
79 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); 79 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
80 80
81 void process(ValidateDeviceLwM2MCredentialsRequestMsg msg, 81 void process(ValidateDeviceLwM2MCredentialsRequestMsg msg,
82 - TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback); 82 + TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
83 83
84 void process(GetOrCreateDeviceFromGatewayRequestMsg msg, 84 void process(GetOrCreateDeviceFromGatewayRequestMsg msg,
85 TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse> callback); 85 TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse> callback);
@@ -348,11 +348,25 @@ public class DefaultTransportService implements TransportService { @@ -348,11 +348,25 @@ public class DefaultTransportService implements TransportService {
348 } 348 }
349 349
350 @Override 350 @Override
351 - public void process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg msg, TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> callback) {  
352 - log.trace("Processing msg: {}", msg);  
353 - TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateDeviceLwM2MCredentialsRequestMsg(msg).build());  
354 - AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg),  
355 - response -> callback.onSuccess(response.getValue().getValidateCredResponseMsg()), callback::onError, transportCallbackExecutor); 351 + public void process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg requestMsg, TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
  352 + log.trace("Processing msg: {}", requestMsg);
  353 + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateDeviceLwM2MCredentialsRequestMsg(requestMsg).build());
  354 + ListenableFuture<ValidateDeviceCredentialsResponse> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp -> {
  355 + TransportProtos.ValidateDeviceCredentialsResponseMsg msg = tmp.getValue().getValidateCredResponseMsg();
  356 + ValidateDeviceCredentialsResponse.ValidateDeviceCredentialsResponseBuilder result = ValidateDeviceCredentialsResponse.builder();
  357 + if (msg.hasDeviceInfo()) {
  358 + result.credentials(msg.getCredentialsBody());
  359 + TransportDeviceInfo tdi = getTransportDeviceInfo(msg.getDeviceInfo());
  360 + result.deviceInfo(tdi);
  361 + ByteString profileBody = msg.getProfileBody();
  362 + if (!profileBody.isEmpty()) {
  363 + DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody);
  364 + result.deviceProfile(profile);
  365 + }
  366 + }
  367 + return result.build();
  368 + }, MoreExecutors.directExecutor());
  369 + AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor);
356 } 370 }
357 371
358 @Override 372 @Override
@@ -372,7 +386,7 @@ public class DefaultTransportService implements TransportService { @@ -372,7 +386,7 @@ public class DefaultTransportService implements TransportService {
372 TransportDeviceInfo tdi = getTransportDeviceInfo(msg.getDeviceInfo()); 386 TransportDeviceInfo tdi = getTransportDeviceInfo(msg.getDeviceInfo());
373 result.deviceInfo(tdi); 387 result.deviceInfo(tdi);
374 ByteString profileBody = msg.getProfileBody(); 388 ByteString profileBody = msg.getProfileBody();
375 - if (profileBody != null && !profileBody.isEmpty()) { 389 + if (!profileBody.isEmpty()) {
376 DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody); 390 DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody);
377 if (transportType != DeviceTransportType.DEFAULT 391 if (transportType != DeviceTransportType.DEFAULT
378 && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) { 392 && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) {