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) { |