Showing
15 changed files
with
326 additions
and
108 deletions
... | ... | @@ -643,6 +643,7 @@ transport: |
643 | 643 | private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" |
644 | 644 | # Only Certificate_x509: |
645 | 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 | 647 | bootstrap: |
647 | 648 | enable: "${LWM2M_ENABLED_BS:true}" |
648 | 649 | id: "${LWM2M_SERVER_ID_BS:111}" | ... | ... |
... | ... | @@ -145,7 +145,6 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri |
145 | 145 | |
146 | 146 | @Override |
147 | 147 | public void setResultHandler(HandshakeResultHandler resultHandler) { |
148 | - // empty implementation | |
149 | 148 | } |
150 | 149 | |
151 | 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 | 65 | @Component |
66 | 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 | 67 | @RequiredArgsConstructor |
68 | -public class LwM2MTransportBootstrapServerConfiguration { | |
68 | +//TODO: @ybondarenko please refactor this to be similar to DefaultLwM2mTransportService | |
69 | +public class LwM2MTransportBootstrapService { | |
69 | 70 | private PublicKey publicKey; |
70 | 71 | private PrivateKey privateKey; |
71 | 72 | private boolean pskMode = false; | ... | ... |
... | ... | @@ -103,7 +103,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { |
103 | 103 | BootstrapConfig bsConfig = store.getBootstrapConfig(); |
104 | 104 | if (bsConfig.security != null) { |
105 | 105 | try { |
106 | - bootstrapConfigStore.add(store.getEndPoint(), bsConfig); | |
106 | + bootstrapConfigStore.add(store.getEndpoint(), bsConfig); | |
107 | 107 | } catch (InvalidConfigurationException e) { |
108 | 108 | log.error("", e); |
109 | 109 | } |
... | ... | @@ -121,22 +121,22 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { |
121 | 121 | switch (SecurityMode.valueOf(lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode())) { |
122 | 122 | /* Use RPK only */ |
123 | 123 | case PSK: |
124 | - store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndPoint(), | |
124 | + store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), | |
125 | 125 | lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), |
126 | 126 | Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); |
127 | 127 | store.setSecurityMode(SecurityMode.PSK.code); |
128 | 128 | break; |
129 | 129 | case RPK: |
130 | 130 | try { |
131 | - store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndPoint(), | |
131 | + store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), | |
132 | 132 | SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); |
133 | 133 | store.setSecurityMode(SecurityMode.RPK.code); |
134 | 134 | break; |
135 | 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 | 138 | case X509: |
139 | - store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndPoint())); | |
139 | + store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); | |
140 | 140 | store.setSecurityMode(SecurityMode.X509.code); |
141 | 141 | break; |
142 | 142 | case NO_SEC: |
... | ... | @@ -166,22 +166,22 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { |
166 | 166 | if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { |
167 | 167 | lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); |
168 | 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 | 170 | helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo); |
171 | 171 | return lwM2MBootstrapConfig; |
172 | 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 | 176 | helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo); |
177 | 177 | return null; |
178 | 178 | } |
179 | 179 | } |
180 | 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 | 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 | 185 | return null; |
186 | 186 | } |
187 | 187 | ... | ... |
... | ... | @@ -148,9 +148,7 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { |
148 | 148 | keyStoreValue = KeyStore.getInstance(keyStoreType); |
149 | 149 | keyStoreValue.load(inKeyStore, keyStorePassword == null ? null : keyStorePassword.toCharArray()); |
150 | 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 | 20 | import org.eclipse.leshan.server.bootstrap.BootstrapConfig; |
21 | 21 | import org.eclipse.leshan.server.security.SecurityInfo; |
22 | 22 | import org.thingsboard.server.common.data.DeviceProfile; |
23 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
23 | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
24 | 25 | |
25 | 26 | import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE; |
26 | 27 | |
27 | 28 | @Data |
28 | 29 | public class EndpointSecurityInfo { |
29 | - private ValidateDeviceCredentialsResponseMsg msg; | |
30 | + private ValidateDeviceCredentialsResponse msg; | |
30 | 31 | private SecurityInfo securityInfo; |
31 | 32 | private int securityMode = DEFAULT_MODE.code; |
32 | 33 | |
33 | 34 | /** bootstrap */ |
34 | 35 | private DeviceProfile deviceProfile; |
35 | 36 | private JsonObject bootstrapJsonCredential; |
36 | - private String endPoint; | |
37 | + private String endpoint; | |
37 | 38 | private BootstrapConfig bootstrapConfig; |
38 | 39 | } | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; |
24 | 24 | import org.springframework.stereotype.Component; |
25 | 25 | import org.thingsboard.server.common.data.DeviceProfile; |
26 | 26 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
27 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
27 | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
28 | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; |
29 | 30 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
... | ... | @@ -59,12 +60,11 @@ public class LwM2mCredentialsSecurityInfoValidator { |
59 | 60 | context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(), |
60 | 61 | new TransportServiceCallback<>() { |
61 | 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 | 65 | resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue); |
65 | 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 | 68 | latch.countDown(); |
69 | 69 | } |
70 | 70 | |
... | ... | @@ -105,7 +105,7 @@ public class LwM2mCredentialsSecurityInfoValidator { |
105 | 105 | if (object != null && !object.isJsonNull()) { |
106 | 106 | if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { |
107 | 107 | result.setBootstrapJsonCredential(object); |
108 | - result.setEndPoint(endpoint); | |
108 | + result.setEndpoint(endpoint); | |
109 | 109 | result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code); |
110 | 110 | } else { |
111 | 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 | 18 | import lombok.RequiredArgsConstructor; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | 20 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
21 | +import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; | |
21 | 22 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; |
22 | 23 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; |
23 | 24 | import org.eclipse.leshan.core.util.Hex; |
... | ... | @@ -25,14 +26,14 @@ import org.eclipse.leshan.server.californium.LeshanServer; |
25 | 26 | import org.eclipse.leshan.server.californium.LeshanServerBuilder; |
26 | 27 | import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; |
27 | 28 | import org.eclipse.leshan.server.model.LwM2mModelProvider; |
28 | -import org.eclipse.leshan.server.security.DefaultAuthorizer; | |
29 | 29 | import org.eclipse.leshan.server.security.EditableSecurityStore; |
30 | -import org.eclipse.leshan.server.security.SecurityChecker; | |
31 | 30 | import org.springframework.stereotype.Component; |
32 | 31 | import org.thingsboard.server.common.data.StringUtils; |
33 | 32 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
34 | 33 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
35 | 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 | 37 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; |
37 | 38 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; |
38 | 39 | |
... | ... | @@ -41,7 +42,6 @@ import javax.annotation.PreDestroy; |
41 | 42 | import java.math.BigInteger; |
42 | 43 | import java.security.AlgorithmParameters; |
43 | 44 | import java.security.KeyFactory; |
44 | -import java.security.KeyStoreException; | |
45 | 45 | import java.security.NoSuchAlgorithmException; |
46 | 46 | import java.security.PrivateKey; |
47 | 47 | import java.security.PublicKey; |
... | ... | @@ -70,9 +70,10 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.g |
70 | 70 | @RequiredArgsConstructor |
71 | 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 | 75 | private PublicKey publicKey; |
74 | 76 | private PrivateKey privateKey; |
75 | - private boolean pskMode = false; | |
76 | 77 | |
77 | 78 | private final LwM2mTransportContext context; |
78 | 79 | private final LwM2MTransportServerConfig config; |
... | ... | @@ -81,6 +82,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
81 | 82 | private final CaliforniumRegistrationStore registrationStore; |
82 | 83 | private final EditableSecurityStore securityStore; |
83 | 84 | private final LwM2mClientContext lwM2mClientContext; |
85 | + private final TbLwM2MDtlsCertificateVerifier certificateVerifier; | |
86 | + private final TbLwM2MAuthorizer authorizer; | |
84 | 87 | |
85 | 88 | private LeshanServer server; |
86 | 89 | |
... | ... | @@ -128,9 +131,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
128 | 131 | config.setModelProvider(modelProvider); |
129 | 132 | builder.setObjectModelProvider(modelProvider); |
130 | 133 | |
131 | - /* Create credentials */ | |
132 | - this.setServerWithCredentials(builder); | |
133 | - | |
134 | 134 | /* Set securityStore with new registrationStore */ |
135 | 135 | builder.setSecurityStore(securityStore); |
136 | 136 | builder.setRegistrationStore(registrationStore); |
... | ... | @@ -142,18 +142,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
142 | 142 | dtlsConfig.setServerOnly(true); |
143 | 143 | dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups()); |
144 | 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 | 148 | /* Set DTLS Config */ |
159 | 149 | builder.setDtlsConfig(dtlsConfig); |
... | ... | @@ -162,40 +152,21 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
162 | 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 | 212 | |
242 | 213 | private boolean setServerRPK(LeshanServerBuilder builder) { |
243 | 214 | try { |
244 | - this.generateKeyForRPK(); | |
215 | + this.loadOrGenerateRPKKeys(); | |
245 | 216 | if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && |
246 | 217 | this.privateKey != null && this.privateKey.getEncoded().length > 0) { |
247 | 218 | builder.setPublicKey(this.publicKey); |
... | ... | @@ -254,7 +225,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
254 | 225 | return false; |
255 | 226 | } |
256 | 227 | |
257 | - private void generateKeyForRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException { | |
228 | + private void loadOrGenerateRPKKeys() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException { | |
258 | 229 | /* Get Elliptic Curve Parameter spec for secp256r1 */ |
259 | 230 | AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); |
260 | 231 | algoParameters.init(new ECGenParameterSpec("secp256r1")); | ... | ... |
... | ... | @@ -40,6 +40,7 @@ import org.eclipse.leshan.core.model.ResourceModel; |
40 | 40 | import org.eclipse.leshan.core.node.codec.CodecException; |
41 | 41 | import org.springframework.stereotype.Component; |
42 | 42 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
43 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
43 | 44 | import org.thingsboard.server.gen.transport.TransportProtos; |
44 | 45 | import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; |
45 | 46 | import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; |
... | ... | @@ -106,21 +107,21 @@ public class LwM2mTransportServerHelper { |
106 | 107 | /** |
107 | 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 | 111 | return SessionInfoProto.newBuilder() |
111 | 112 | .setNodeId(context.getNodeId()) |
112 | 113 | .setSessionIdMSB(mostSignificantBits) |
113 | 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 | 121 | .setDeviceName(msg.getDeviceInfo().getDeviceName()) |
121 | 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 | 125 | .build(); |
125 | 126 | } |
126 | 127 | ... | ... |
... | ... | @@ -27,6 +27,7 @@ import org.eclipse.leshan.server.registration.Registration; |
27 | 27 | import org.eclipse.leshan.server.security.SecurityInfo; |
28 | 28 | import org.thingsboard.server.common.data.Device; |
29 | 29 | import org.thingsboard.server.common.data.DeviceProfile; |
30 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
30 | 31 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
31 | 32 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
32 | 33 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
... | ... | @@ -79,7 +80,7 @@ public class LwM2mClient implements Cloneable { |
79 | 80 | @Setter |
80 | 81 | private Registration registration; |
81 | 82 | |
82 | - private ValidateDeviceCredentialsResponseMsg credentialsResponse; | |
83 | + private ValidateDeviceCredentialsResponse credentials; | |
83 | 84 | @Getter |
84 | 85 | private final Map<String, ResourceValue> resources; |
85 | 86 | @Getter |
... | ... | @@ -98,11 +99,11 @@ public class LwM2mClient implements Cloneable { |
98 | 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 | 103 | this.endpoint = endpoint; |
103 | 104 | this.identity = identity; |
104 | 105 | this.securityInfo = securityInfo; |
105 | - this.credentialsResponse = credentialsResponse; | |
106 | + this.credentials = credentials; | |
106 | 107 | this.delayedRequests = new ConcurrentHashMap<>(); |
107 | 108 | this.pendingReadRequests = new CopyOnWriteArrayList<>(); |
108 | 109 | this.resources = new ConcurrentHashMap<>(); |
... | ... | @@ -112,8 +113,8 @@ public class LwM2mClient implements Cloneable { |
112 | 113 | this.updateFw = false; |
113 | 114 | this.queuedRequests = new ConcurrentLinkedQueue<>(); |
114 | 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 | 118 | this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB()); |
118 | 119 | this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB()); |
119 | 120 | this.deviceName = session.getDeviceName(); |
... | ... | @@ -146,21 +147,21 @@ public class LwM2mClient implements Cloneable { |
146 | 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 | 151 | return SessionInfoProto.newBuilder() |
151 | 152 | .setNodeId(nodeId) |
152 | 153 | .setSessionIdMSB(sessionId.getMostSignificantBits()) |
153 | 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 | 161 | .setDeviceName(msg.getDeviceInfo().getDeviceName()) |
161 | 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 | 165 | .build(); |
165 | 166 | } |
166 | 167 | ... | ... |
... | ... | @@ -79,7 +79,7 @@ public interface TransportService { |
79 | 79 | TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); |
80 | 80 | |
81 | 81 | void process(ValidateDeviceLwM2MCredentialsRequestMsg msg, |
82 | - TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback); | |
82 | + TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); | |
83 | 83 | |
84 | 84 | void process(GetOrCreateDeviceFromGatewayRequestMsg msg, |
85 | 85 | TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse> callback); | ... | ... |
... | ... | @@ -348,11 +348,25 @@ public class DefaultTransportService implements TransportService { |
348 | 348 | } |
349 | 349 | |
350 | 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 | 372 | @Override |
... | ... | @@ -372,7 +386,7 @@ public class DefaultTransportService implements TransportService { |
372 | 386 | TransportDeviceInfo tdi = getTransportDeviceInfo(msg.getDeviceInfo()); |
373 | 387 | result.deviceInfo(tdi); |
374 | 388 | ByteString profileBody = msg.getProfileBody(); |
375 | - if (profileBody != null && !profileBody.isEmpty()) { | |
389 | + if (!profileBody.isEmpty()) { | |
376 | 390 | DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody); |
377 | 391 | if (transportType != DeviceTransportType.DEFAULT |
378 | 392 | && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) { | ... | ... |