Browse Source

Merge pull request #5930 from YevhenBondarenko/feature/californium-update

[3.3.3] updated Californium and Leshan versions
pull/5938/head
Andrew Shvayka 5 years ago
committed by GitHub
parent
commit
fc280254dd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java
  2. 6
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java
  3. 5
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java
  4. 6
      application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java
  5. 8
      application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java
  6. 8
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java
  7. 43
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java
  8. 19
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java
  9. 13
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java
  10. 6
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java
  11. 6
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java
  12. 12
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java
  13. 4
      application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java
  14. 4
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java
  15. 3
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java
  16. 37
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java
  17. 17
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java
  18. 11
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java
  19. 20
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java
  20. 3
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java
  21. 19
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
  22. 12
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java
  23. 6
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java
  24. 6
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java
  25. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java
  26. 35
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/TbLwM2MDtlsBootstrapCertificateVerifier.java
  27. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java
  28. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java
  29. 24
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java
  30. 42
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java
  31. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java
  32. 47
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java
  33. 19
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java
  34. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java
  35. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  36. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  37. 13
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  38. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java
  39. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java
  40. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java
  41. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java
  42. 4
      pom.xml

2
application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java

@ -52,6 +52,8 @@ import static org.junit.Assert.assertNotNull;
@Slf4j @Slf4j
public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest { public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest {
protected final byte[] EMPTY_PAYLOAD = new byte[0];
protected CoapClient client; protected CoapClient client;
@Override @Override

6
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java

@ -25,15 +25,13 @@ import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@Slf4j @Slf4j
@ -88,7 +86,7 @@ public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends
} }
protected void validateEmptyCurrentStateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException { protected void validateEmptyCurrentStateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
assertNull(callback.getPayloadBytes()); assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes());
assertNotNull(callback.getObserve()); assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode()); assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(0, callback.getObserve().intValue()); assertEquals(0, callback.getObserve().intValue());

5
application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java

@ -31,13 +31,12 @@ import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -186,7 +185,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
} }
private void validateCurrentStateNotification(TestCoapCallback callback) { private void validateCurrentStateNotification(TestCoapCallback callback) {
assertNull(callback.getPayloadBytes()); assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes());
assertNotNull(callback.getObserve()); assertNotNull(callback.getObserve());
assertEquals(callback.getResponseCode(), CoAP.ResponseCode.VALID); assertEquals(callback.getResponseCode(), CoAP.ResponseCode.VALID);
assertEquals(0, callback.getObserve().intValue()); assertEquals(0, callback.getObserve().intValue());

6
application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java

@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.client.object.Security;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
@ -174,7 +174,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
public void basicTestConnectionObserveTelemetry(Security security, public void basicTestConnectionObserveTelemetry(Security security,
LwM2MClientCredential credentials, LwM2MClientCredential credentials,
NetworkConfig coapConfig, Configuration coapConfig,
String endpoint) throws Exception { String endpoint) throws Exception {
createDeviceProfile(TRANSPORT_CONFIGURATION); createDeviceProfile(TRANSPORT_CONFIGURATION);
Device device = createDevice(credentials); Device device = createDevice(credentials);
@ -259,7 +259,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
this.resources = resources; this.resources = resources;
} }
public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc, String endpoint) throws Exception { public void createNewClient(Security security, Configuration coapConfig, boolean isRpc, String endpoint) throws Exception {
clientDestroy(); clientDestroy();
client = new LwM2MTestClient(this.executor, endpoint); client = new LwM2MTestClient(this.executor, endpoint);
int clientPort = SocketUtils.findAvailableTcpPort(); int clientPort = SocketUtils.findAvailableTcpPort();

8
application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java

@ -15,9 +15,11 @@
*/ */
package org.thingsboard.server.transport.lwm2m; package org.thingsboard.server.transport.lwm2m;
import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.client.object.Security;
import static org.eclipse.californium.core.config.CoapConfig.COAP_PORT;
import static org.eclipse.californium.core.config.CoapConfig.COAP_SECURE_PORT;
import static org.eclipse.leshan.client.object.Security.noSec; import static org.eclipse.leshan.client.object.Security.noSec;
public class Lwm2mTestHelper { public class Lwm2mTestHelper {
@ -32,10 +34,10 @@ public class Lwm2mTestHelper {
public static final int SHORT_SERVER_ID = 123; public static final int SHORT_SERVER_ID = 123;
public static final int SHORT_SERVER_ID_BS = 111; public static final int SHORT_SERVER_ID_BS = 111;
public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); public static final Configuration SECURE_COAP_CONFIG = new Configuration().set(COAP_SECURE_PORT, SECURE_PORT);
public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT; public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT;
public static final Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID); public static final Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID);
public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); public static final Configuration COAP_CONFIG = new Configuration().set(COAP_PORT, PORT);
// Models // Models
public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"}; public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"};

8
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java

@ -131,10 +131,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
scheduler.schedule(() -> { scheduler.schedule(() -> {
try { try {
state.set(1); state.set(1);
fireResourcesChange(3); fireResourceChange(3);
Thread.sleep(100); Thread.sleep(100);
state.set(2); state.set(2);
fireResourcesChange(3); fireResourceChange(3);
} catch (Exception e) { } catch (Exception e) {
} }
}, 100, TimeUnit.MILLISECONDS); }, 100, TimeUnit.MILLISECONDS);
@ -144,10 +144,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
scheduler.schedule(() -> { scheduler.schedule(() -> {
try { try {
state.set(3); state.set(3);
fireResourcesChange(3); fireResourceChange(3);
Thread.sleep(100); Thread.sleep(100);
updateResult.set(1); updateResult.set(1);
fireResourcesChange(5); fireResourceChange(5);
} catch (Exception e) { } catch (Exception e) {
} }
}, 100, TimeUnit.MILLISECONDS); }, 100, TimeUnit.MILLISECONDS);

43
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java

@ -17,10 +17,7 @@ package org.thingsboard.server.transport.lwm2m.client;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.core.observe.ObservationStore;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.leshan.client.californium.LeshanClient; import org.eclipse.leshan.client.californium.LeshanClient;
import org.eclipse.leshan.client.californium.LeshanClientBuilder; import org.eclipse.leshan.client.californium.LeshanClientBuilder;
@ -32,7 +29,6 @@ import org.eclipse.leshan.client.resource.DummyInstanceEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.client.servers.ServerIdentity; import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.californium.EndpointFactory;
import org.eclipse.leshan.core.model.InvalidDDFFileException; import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectLoader;
@ -44,15 +40,15 @@ import org.eclipse.leshan.core.request.BootstrapRequest;
import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.DeregisterRequest;
import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.RegisterRequest;
import org.eclipse.leshan.core.request.UpdateRequest; import org.eclipse.leshan.core.request.UpdateRequest;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import org.junit.Assert; import org.junit.Assert;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL;
import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.DEVICE;
import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE;
@ -61,10 +57,10 @@ import static org.eclipse.leshan.core.LwM2mId.SECURITY;
import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SERVER;
import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources;
@ -84,7 +80,7 @@ public class LwM2MTestClient {
private LwM2MLocationParams locationParams; private LwM2MLocationParams locationParams;
private LwM2mTemperatureSensor lwM2MTemperatureSensor; private LwM2mTemperatureSensor lwM2MTemperatureSensor;
public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { public void init(Security security, Configuration coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException {
Assert.assertNull("client already initialized", client); Assert.assertNull("client already initialized", client);
List<ObjectModel> models = new ArrayList<>(); List<ObjectModel> models = new ArrayList<>();
for (String resourceName : resources) { for (String resourceName : resources) {
@ -106,44 +102,19 @@ public class LwM2MTestClient {
initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, OBJECT_INSTANCE_ID_0)); initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, OBJECT_INSTANCE_ID_0));
initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_0), new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_12)); initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_0), new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_12));
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(coapConfig);
dtlsConfig.setRecommendedCipherSuitesOnly(true); dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true);
dtlsConfig.setClientOnly();
DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory(); DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory();
engineFactory.setReconnectOnUpdate(false); engineFactory.setReconnectOnUpdate(false);
engineFactory.setResumeOnConnect(true); engineFactory.setResumeOnConnect(true);
EndpointFactory endpointFactory = new EndpointFactory() {
@Override
public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig,
ObservationStore store) {
CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
builder.setInetSocketAddress(address);
builder.setNetworkConfig(coapConfig);
return builder.build();
}
@Override
public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig,
ObservationStore store) {
CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig);
builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build()));
builder.setNetworkConfig(coapConfig);
return builder.build();
}
};
LeshanClientBuilder builder = new LeshanClientBuilder(endpoint); LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
builder.setLocalAddress("0.0.0.0", port); builder.setLocalAddress("0.0.0.0", port);
builder.setObjects(initializer.createAll()); builder.setObjects(initializer.createAll());
builder.setCoapConfig(coapConfig); builder.setCoapConfig(coapConfig);
builder.setDtlsConfig(dtlsConfig); builder.setDtlsConfig(dtlsConfig);
builder.setRegistrationEngineFactory(engineFactory); builder.setRegistrationEngineFactory(engineFactory);
builder.setEndpointFactory(endpointFactory);
builder.setSharedExecutor(executor); builder.setSharedExecutor(executor);
builder.setDecoder(new DefaultLwM2mDecoder(false)); builder.setDecoder(new DefaultLwM2mDecoder(false));

19
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java

@ -81,8 +81,11 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements
public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) {
try { try {
if (id != null) this.setId(id); if (id != null) this.setId(id);
executorService.scheduleWithFixedDelay(() -> executorService.scheduleWithFixedDelay(() -> {
fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN fireResourceChange(0);
fireResourceChange(2);
}
, 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN
} catch (Throwable e) { } catch (Throwable e) {
log.error("[{}]Throwable", e.toString()); log.error("[{}]Throwable", e.toString());
e.printStackTrace(); e.printStackTrace();
@ -126,23 +129,23 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements
} }
case 1: case 1:
setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue())); setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue()));
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
case 2: case 2:
setTimestamp(((Date) value.getValue()).getTime()); setTimestamp(((Date) value.getValue()).getTime());
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
case 3: case 3:
setDescription((String) value.getValue()); setDescription((String) value.getValue());
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
case 4: case 4:
setDataFormat((String) value.getValue()); setDataFormat((String) value.getValue());
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
case 5: case 5:
setAppID((Integer) value.getValue()); setAppID((Integer) value.getValue());
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
default: default:
return super.write(identity, replace, resourceId, value); return super.write(identity, replace, resourceId, value);
@ -185,7 +188,7 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements
try { try {
if (value instanceof LwM2mMultipleResource) { if (value instanceof LwM2mMultipleResource) {
if (replace || this.data == null) { if (replace || this.data == null) {
this.data = new HashMap<>(); this.data = new HashMap<>();
} }
value.getInstances().values().forEach(v -> { value.getInstances().values().forEach(v -> {
this.data.put(v.getId(), (byte[]) v.getValue()); this.data.put(v.getId(), (byte[]) v.getValue());

13
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java

@ -74,8 +74,10 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable {
} }
this.scaleFactor = scaleFactor; this.scaleFactor = scaleFactor;
timestamp = new Date(); timestamp = new Date();
executorService.scheduleWithFixedDelay(() -> executorService.scheduleWithFixedDelay(() -> {
fireResourcesChange(0, 1), 10000, 10000, TimeUnit.MILLISECONDS); fireResourceChange(0);
fireResourceChange(1);
}, 10000, 10000, TimeUnit.MILLISECONDS);
} catch (Throwable e) { } catch (Throwable e) {
log.error("[{}]Throwable", e.toString()); log.error("[{}]Throwable", e.toString());
e.printStackTrace(); e.printStackTrace();
@ -117,13 +119,16 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable {
private void moveLatitude(float delta) { private void moveLatitude(float delta) {
latitude = latitude + delta * scaleFactor; latitude = latitude + delta * scaleFactor;
timestamp = new Date(); timestamp = new Date();
fireResourcesChange(0, 5); fireResourceChange(0);
fireResourceChange(5);
} }
private void moveLongitude(float delta) { private void moveLongitude(float delta) {
longitude = longitude + delta * scaleFactor; longitude = longitude + delta * scaleFactor;
timestamp = new Date(); timestamp = new Date();
fireResourcesChange(1, 5); fireResourceChange(1);
fireResourceChange(5);
} }
public float getLatitude() { public float getLatitude() {

6
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java

@ -93,10 +93,9 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr
float delta = (RANDOM.nextInt(20) - 10) / 10f; float delta = (RANDOM.nextInt(20) - 10) / 10f;
currentTemp += delta; currentTemp += delta;
Integer changedResource = adjustMinMaxMeasuredValue(currentTemp); Integer changedResource = adjustMinMaxMeasuredValue(currentTemp);
fireResourceChange(5700);
if (changedResource != null) { if (changedResource != null) {
fireResourcesChange(5700, changedResource); fireResourceChange(changedResource);
} else {
fireResourcesChange(5700);
} }
} }
@ -127,5 +126,4 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr
} }
} }

6
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java

@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.client;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity; import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.Destroyable;
import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResource;
@ -25,7 +26,6 @@ import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse; import org.eclipse.leshan.core.response.WriteResponse;
import javax.security.auth.Destroyable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
@ -103,11 +103,11 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
return WriteResponse.notFound(); return WriteResponse.notFound();
case 14: case 14:
setUtcOffset((String) value.getValue()); setUtcOffset((String) value.getValue());
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
case 15: case 15:
setTimezone((String) value.getValue()); setTimezone((String) value.getValue());
fireResourcesChange(resourceId); fireResourceChange(resourceId);
return WriteResponse.success(); return WriteResponse.success();
default: default:
return super.write(identity, replace, resourceId, value); return super.write(identity, replace, resourceId, value);

12
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java

@ -128,16 +128,17 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
try { try {
state.set(1); state.set(1);
updateResult.set(1); updateResult.set(1);
fireResourcesChange(7, 9); fireResourceChange(7);
fireResourceChange(9);
Thread.sleep(100); Thread.sleep(100);
state.set(2); state.set(2);
fireResourcesChange(7); fireResourceChange(7);
Thread.sleep(100); Thread.sleep(100);
state.set(3); state.set(3);
fireResourcesChange(7); fireResourceChange(7);
Thread.sleep(100); Thread.sleep(100);
updateResult.set(3); updateResult.set(3);
fireResourcesChange(9); fireResourceChange(9);
} catch (Exception e) { } catch (Exception e) {
} }
@ -148,7 +149,8 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
scheduler.schedule(() -> { scheduler.schedule(() -> {
state.set(4); state.set(4);
updateResult.set(2); updateResult.set(2);
fireResourcesChange(7, 9); fireResourceChange(7);
fireResourceChange(9);
}, 100, TimeUnit.MILLISECONDS); }, 100, TimeUnit.MILLISECONDS);
} }

4
application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java

@ -201,9 +201,9 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest {
@Test @Test
public void testSoftwareUpdateByObject9() throws Exception { public void testSoftwareUpdateByObject9() throws Exception {
createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9); NoSecClientCredential credentials = createNoSecClientCredentials(CLIENT_ENDPOINT_OTA9);
final Device device = createDevice(credentials); final Device device = createDevice(credentials);
createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA9); createNewClient(SECURITY, COAP_CONFIG, false, CLIENT_ENDPOINT_OTA9);
Thread.sleep(1000); Thread.sleep(1000);

4
application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java

@ -52,8 +52,8 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration
Set actualObjects = ConcurrentHashMap.newKeySet(); Set actualObjects = ConcurrentHashMap.newKeySet();
Set actualInstances = ConcurrentHashMap.newKeySet(); Set actualInstances = ConcurrentHashMap.newKeySet();
rpcActualValue.forEach(node -> { rpcActualValue.forEach(node -> {
if (!node.get("url").asText().equals("/")) { if (!node.get("uriReference").asText().equals("/")) {
LwM2mPath path = new LwM2mPath(node.get("url").asText()); LwM2mPath path = new LwM2mPath(node.get("uriReference").asText());
actualObjects.add("/" + path.getObjectId()); actualObjects.add("/" + path.getObjectId());
if (path.isObjectInstance()) { if (path.isObjectInstance()) {
actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId()); actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId());

3
common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.coapserver;
import org.eclipse.californium.core.CoapServer; import org.eclipse.californium.core.CoapServer;
import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -24,7 +25,7 @@ public interface CoapServerService {
CoapServer getCoapServer() throws UnknownHostException; CoapServer getCoapServer() throws UnknownHostException;
ConcurrentMap<String, TbCoapDtlsSessionInfo> getDtlsSessionsMap(); ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> getDtlsSessionsMap();
long getTimeout(); long getTimeout();

37
common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java

@ -18,8 +18,9 @@ package org.thingsboard.server.coapserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapServer; import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.server.resources.Resource; import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -37,7 +38,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS;
@Slf4j @Slf4j
@Component @Component
@ -78,8 +79,8 @@ public class DefaultCoapServerService implements CoapServerService {
} }
@Override @Override
public ConcurrentMap<String, TbCoapDtlsSessionInfo> getDtlsSessionsMap() { public ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> getDtlsSessionsMap() {
return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionIdsMap() : null; return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionsMap() : null;
} }
@Override @Override
@ -88,16 +89,16 @@ public class DefaultCoapServerService implements CoapServerService {
} }
private CoapServer createCoapServer() throws UnknownHostException { private CoapServer createCoapServer() throws UnknownHostException {
NetworkConfig networkConfig = new NetworkConfig(); Configuration networkConfig = new Configuration();
networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); networkConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); networkConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
networkConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); networkConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS);
networkConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); networkConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
networkConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); networkConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED);
networkConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); networkConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024);
networkConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); networkConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024);
networkConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4); networkConfig.set(CoapConfig.MAX_RETRANSMIT, 4);
networkConfig.setInt(NetworkConfig.Keys.COAP_PORT, coapServerContext.getPort()); networkConfig.set(CoapConfig.COAP_PORT, coapServerContext.getPort());
server = new CoapServer(networkConfig); server = new CoapServer(networkConfig);
CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder(); CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder();
@ -105,15 +106,15 @@ public class DefaultCoapServerService implements CoapServerService {
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort()); InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort());
noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr); noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr);
noSecCoapEndpointBuilder.setNetworkConfig(networkConfig); noSecCoapEndpointBuilder.setConfiguration(networkConfig);
CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build(); CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build();
server.addEndpoint(noSecCoapEndpoint); server.addEndpoint(noSecCoapEndpoint);
if (isDtlsEnabled()) { if (isDtlsEnabled()) {
CoapEndpoint.Builder dtlsCoapEndpointBuilder = new CoapEndpoint.Builder(); CoapEndpoint.Builder dtlsCoapEndpointBuilder = new CoapEndpoint.Builder();
TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings(); TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings();
DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(); DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(networkConfig);
networkConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort()); networkConfig.set(CoapConfig.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort());
dtlsCoapEndpointBuilder.setNetworkConfig(networkConfig); dtlsCoapEndpointBuilder.setConfiguration(networkConfig);
DTLSConnector connector = new DTLSConnector(dtlsConnectorConfig); DTLSConnector connector = new DTLSConnector(dtlsConnectorConfig);
dtlsCoapEndpointBuilder.setConnector(connector); dtlsCoapEndpointBuilder.setConnector(connector);
CoapEndpoint dtlsCoapEndpoint = dtlsCoapEndpointBuilder.build(); CoapEndpoint dtlsCoapEndpoint = dtlsCoapEndpointBuilder.build();

17
common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java

@ -23,7 +23,6 @@ import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
import org.eclipse.californium.scandium.dtls.ConnectionId; import org.eclipse.californium.scandium.dtls.ConnectionId;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
@ -34,13 +33,13 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.common.transport.util.SslUtil;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import java.net.InetSocketAddress;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateExpiredException;
@ -48,7 +47,6 @@ import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -71,12 +69,12 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
} }
@Override @Override
public List<CertificateType> getSupportedCertificateType() { public List<CertificateType> getSupportedCertificateTypes() {
return Collections.singletonList(CertificateType.X_509); return Collections.singletonList(CertificateType.X_509);
} }
@Override @Override
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, CertificateMessage message) {
try { try {
CertPath certpath = message.getCertificateChain(); CertPath certpath = message.getCertificateChain();
X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]); X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]);
@ -111,7 +109,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
if (msg != null && strCert.equals(msg.getCredentials())) { if (msg != null && strCert.equals(msg.getCredentials())) {
DeviceProfile deviceProfile = msg.getDeviceProfile(); DeviceProfile deviceProfile = msg.getDeviceProfile();
if (msg.hasDeviceInfo() && deviceProfile != null) { if (msg.hasDeviceInfo() && deviceProfile != null) {
tbCoapDtlsSessionInMemoryStorage.put(session.getSessionIdentifier().toString(), new TbCoapDtlsSessionInfo(msg, deviceProfile)); tbCoapDtlsSessionInMemoryStorage.put(remotePeer, new TbCoapDtlsSessionInfo(msg, deviceProfile));
} }
break; break;
} }
@ -120,8 +118,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
CertificateExpiredException | CertificateExpiredException |
CertificateNotYetValidException e) { CertificateNotYetValidException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE, AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE);
session.getPeer());
throw new HandshakeException("Certificate chain could not be validated", alert); throw new HandshakeException("Certificate chain could not be validated", alert);
} }
} }
@ -141,8 +138,8 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
public void setResultHandler(HandshakeResultHandler resultHandler) { public void setResultHandler(HandshakeResultHandler resultHandler) {
} }
public ConcurrentMap<String, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionIdsMap() { public ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionsMap() {
return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionIdMap(); return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionsMap();
} }
public void evictTimeoutSessions() { public void evictTimeoutSessions() {

11
common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java

@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -25,7 +26,7 @@ import java.util.concurrent.ConcurrentMap;
@Data @Data
public class TbCoapDtlsSessionInMemoryStorage { public class TbCoapDtlsSessionInMemoryStorage {
private final ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap = new ConcurrentHashMap<>(); private final ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> dtlsSessionsMap = new ConcurrentHashMap<>();
private long dtlsSessionInactivityTimeout; private long dtlsSessionInactivityTimeout;
private long dtlsSessionReportTimeout; private long dtlsSessionReportTimeout;
@ -35,14 +36,14 @@ public class TbCoapDtlsSessionInMemoryStorage {
this.dtlsSessionReportTimeout = dtlsSessionReportTimeout; this.dtlsSessionReportTimeout = dtlsSessionReportTimeout;
} }
public void put(String dtlsSessionId, TbCoapDtlsSessionInfo dtlsSessionInfo) { public void put(InetSocketAddress remotePeer, TbCoapDtlsSessionInfo dtlsSessionInfo) {
log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", dtlsSessionId, dtlsSessionInfo.getLastActivityTime()); log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", remotePeer, dtlsSessionInfo.getLastActivityTime());
dtlsSessionIdMap.putIfAbsent(dtlsSessionId, dtlsSessionInfo); dtlsSessionsMap.putIfAbsent(remotePeer, dtlsSessionInfo);
} }
public void evictTimeoutSessions() { public void evictTimeoutSessions() {
long expTime = System.currentTimeMillis() - dtlsSessionInactivityTimeout; long expTime = System.currentTimeMillis() - dtlsSessionInactivityTimeout;
dtlsSessionIdMap.entrySet().removeIf(entry -> { dtlsSessionsMap.entrySet().removeIf(entry -> {
if (entry.getValue().getLastActivityTime() < expTime) { if (entry.getValue().getLastActivityTime() < expTime) {
log.trace("DTLS session was removed from in-memory store: [{}]", entry.getKey()); log.trace("DTLS session was removed from in-memory store: [{}]", entry.getKey());
return true; return true;

20
common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java

@ -16,9 +16,13 @@
package org.thingsboard.server.coapserver; package org.thingsboard.server.coapserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.config.CertificateAuthenticationMode;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -26,17 +30,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.ResourceUtils;
import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.Collections; import java.util.Collections;
@Slf4j @Slf4j
@ -75,15 +76,14 @@ public class TbCoapDtlsSettings {
@Autowired @Autowired
private TbServiceInfoProvider serviceInfoProvider; private TbServiceInfoProvider serviceInfoProvider;
public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException { public DtlsConnectorConfig dtlsConnectorConfig(Configuration configuration) throws UnknownHostException {
DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(configuration);
configBuilder.setAddress(getInetSocketAddress()); configBuilder.setAddress(getInetSocketAddress());
SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials(); SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials();
SslContextUtil.Credentials serverCredentials = SslContextUtil.Credentials serverCredentials =
new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain()); new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain());
configBuilder.setServerOnly(true); configBuilder.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY);
configBuilder.setClientAuthenticationRequired(false); configBuilder.set(DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE, CertificateAuthenticationMode.WANTED);
configBuilder.setClientAuthenticationWanted(true);
configBuilder.setAdvancedCertificateVerifier( configBuilder.setAdvancedCertificateVerifier(
new TbCoapDtlsCertificateVerifier( new TbCoapDtlsCertificateVerifier(
transportService, transportService,
@ -93,8 +93,8 @@ public class TbCoapDtlsSettings {
skipValidityCheckForClientCert skipValidityCheckForClientCert
) )
); );
configBuilder.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), configBuilder.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(),
Collections.singletonList(CertificateType.X_509)); Collections.singletonList(CertificateType.X_509)));
return configBuilder.build(); return configBuilder.build();
} }

3
common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java

@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.coap.OptionSet;
import org.eclipse.californium.core.network.Exchange; import org.eclipse.californium.core.network.Exchange;
import org.eclipse.californium.core.server.DelivererException;
import org.eclipse.californium.core.server.ServerMessageDeliverer; import org.eclipse.californium.core.server.ServerMessageDeliverer;
import org.eclipse.californium.core.server.resources.Resource; import org.eclipse.californium.core.server.resources.Resource;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -32,7 +33,7 @@ public class TbCoapServerMessageDeliverer extends ServerMessageDeliverer {
} }
@Override @Override
protected Resource findResource(Exchange exchange) { protected Resource findResource(Exchange exchange) throws DelivererException {
validateUriPath(exchange); validateUriPath(exchange);
return findResource(exchange.getRequest().getOptions().getUriPath()); return findResource(exchange.getRequest().getOptions().getUriPath());
} }

19
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java

@ -30,7 +30,6 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
@ -48,6 +47,7 @@ import org.thingsboard.server.transport.coap.callback.ToServerRpcSyncSessionCall
import org.thingsboard.server.transport.coap.client.CoapClientContext; import org.thingsboard.server.transport.coap.client.CoapClientContext;
import org.thingsboard.server.transport.coap.client.TbCoapClientState; import org.thingsboard.server.transport.coap.client.TbCoapClientState;
import java.net.InetSocketAddress;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
@ -56,6 +56,8 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static org.eclipse.californium.elements.DtlsEndpointContext.KEY_SESSION_ID;
@Slf4j @Slf4j
public class CoapTransportResource extends AbstractCoapTransportResource { public class CoapTransportResource extends AbstractCoapTransportResource {
private static final int ACCESS_TOKEN_POSITION = 3; private static final int ACCESS_TOKEN_POSITION = 3;
@ -64,9 +66,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
private static final int FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST = 3; private static final int FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST = 3;
private static final int REQUEST_ID_POSITION_CERTIFICATE_REQUEST = 4; private static final int REQUEST_ID_POSITION_CERTIFICATE_REQUEST = 4;
private static final String DTLS_SESSION_ID_KEY = "DTLS_SESSION_ID";
private final ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap; private final ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> dtlsSessionsMap;
private final long timeout; private final long timeout;
private final CoapClientContext clients; private final CoapClientContext clients;
@ -74,7 +75,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
super(ctx, name); super(ctx, name);
this.setObservable(true); // enable observing this.setObservable(true); // enable observing
this.addObserver(new CoapResourceObserver()); this.addObserver(new CoapResourceObserver());
this.dtlsSessionIdMap = coapServerService.getDtlsSessionsMap(); this.dtlsSessionsMap = coapServerService.getDtlsSessionsMap();
this.timeout = coapServerService.getTimeout(); this.timeout = coapServerService.getTimeout();
this.clients = ctx.getClientContext(); this.clients = ctx.getClientContext();
long sessionReportTimeout = ctx.getSessionReportTimeout(); long sessionReportTimeout = ctx.getSessionReportTimeout();
@ -91,7 +92,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
if (relation == null || relation.isCanceled()) { if (relation == null || relation.isCanceled()) {
return; // because request did not try to establish a relation return; // because request did not try to establish a relation
} }
if (CoAP.ResponseCode.isSuccess(response.getCode())) { if (response.getCode().isSuccess()) {
if (!relation.isEstablished()) { if (!relation.isEstablished()) {
relation.setEstablished(); relation.setEstablished();
addObserveRelation(relation); addObserveRelation(relation);
@ -198,10 +199,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
Exchange advanced = exchange.advanced(); Exchange advanced = exchange.advanced();
Request request = advanced.getRequest(); Request request = advanced.getRequest();
String dtlsSessionIdStr = request.getSourceContext().get(DTLS_SESSION_ID_KEY); var dtlsSessionId = request.getSourceContext().get(KEY_SESSION_ID);
if (dtlsSessionIdMap != null && StringUtils.isNotEmpty(dtlsSessionIdStr)) { if (dtlsSessionsMap != null && dtlsSessionId != null && !dtlsSessionId.isEmpty()) {
TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionIdMap TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionsMap
.computeIfPresent(dtlsSessionIdStr, (dtlsSessionId, dtlsSessionInfo) -> { .computeIfPresent(request.getSourceContext().getPeerAddress(), (dtlsSessionIdStr, dtlsSessionInfo) -> {
dtlsSessionInfo.setLastActivityTime(System.currentTimeMillis()); dtlsSessionInfo.setLastActivityTime(System.currentTimeMillis());
return dtlsSessionInfo; return dtlsSessionInfo;
}); });

12
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java

@ -29,6 +29,11 @@ public class TbCoapMessageObserver implements MessageObserver {
private final Consumer<Integer> onAcknowledge; private final Consumer<Integer> onAcknowledge;
private final Consumer<Integer> onTimeout; private final Consumer<Integer> onTimeout;
@Override
public boolean isInternal() {
return false;
}
@Override @Override
public void onRetransmission() { public void onRetransmission() {
@ -86,13 +91,18 @@ public class TbCoapMessageObserver implements MessageObserver {
} }
@Override
public void onResponseHandlingError(Throwable cause) {
}
@Override @Override
public void onContextEstablished(EndpointContext endpointContext) { public void onContextEstablished(EndpointContext endpointContext) {
} }
@Override @Override
public void onComplete() { public void onTransferComplete() {
} }
} }

6
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java

@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.elements.DtlsEndpointContext; import org.eclipse.californium.elements.DtlsEndpointContext;
import org.eclipse.californium.elements.EndpointContext; import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.exception.ConnectorException; import org.eclipse.californium.elements.exception.ConnectorException;
import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
@ -118,7 +120,7 @@ public class SecureClientNoAuth {
String keyStorePassword = args[6]; String keyStorePassword = args[6];
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(); DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration());
setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword); setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword);
DTLSConnector dtlsConnector = new DTLSConnector(builder.build()); DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
SecureClientNoAuth client = new SecureClientNoAuth(dtlsConnector, host, port, accessToken, clientKeys, sharedKeys); SecureClientNoAuth client = new SecureClientNoAuth(dtlsConnector, host, port, accessToken, clientKeys, sharedKeys);
@ -134,7 +136,7 @@ public class SecureClientNoAuth {
keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray()); keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray());
trustBuilder.setTrustedCertificates(trustedCertificates); trustBuilder.setTrustedCertificates(trustedCertificates);
config.setAdvancedCertificateVerifier(trustBuilder.build()); config.setAdvancedCertificateVerifier(trustBuilder.build());
config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)); config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
System.err.println("certificates are invalid!"); System.err.println("certificates are invalid!");
throw new IllegalArgumentException(e.getMessage()); throw new IllegalArgumentException(e.getMessage());

6
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java

@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.elements.DtlsEndpointContext; import org.eclipse.californium.elements.DtlsEndpointContext;
import org.eclipse.californium.elements.EndpointContext; import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.exception.ConnectorException; import org.eclipse.californium.elements.exception.ConnectorException;
import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
@ -117,7 +119,7 @@ public class SecureClientX509 {
String keyStorePassword = args[5]; String keyStorePassword = args[5];
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(); DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration());
setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword); setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword);
DTLSConnector dtlsConnector = new DTLSConnector(builder.build()); DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
SecureClientX509 client = new SecureClientX509(dtlsConnector, host, port, clientKeys, sharedKeys); SecureClientX509 client = new SecureClientX509(dtlsConnector, host, port, clientKeys, sharedKeys);
@ -133,7 +135,7 @@ public class SecureClientX509 {
keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray()); keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray());
trustBuilder.setTrustedCertificates(trustedCertificates); trustBuilder.setTrustedCertificates(trustedCertificates);
config.setAdvancedCertificateVerifier(trustBuilder.build()); config.setAdvancedCertificateVerifier(trustBuilder.build());
config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)); config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
System.err.println("certificates are invalid!"); System.err.println("certificates are invalid!");
throw new IllegalArgumentException(e.getMessage()); throw new IllegalArgumentException(e.getMessage());

16
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
@ -37,6 +38,8 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY;
import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig;
@ -80,12 +83,11 @@ public class LwM2MTransportBootstrapService {
/* Create and Set DTLS Config */ /* Create and Set DTLS Config */
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig));
dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups()); dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups());
dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers()); dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers());
dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES);
/* Create credentials */ setServerWithCredentials(builder, dtlsConfig);
this.setServerWithCredentials(builder, dtlsConfig);
/* Set DTLS Config */ /* Set DTLS Config */
builder.setDtlsConfig(dtlsConfig); builder.setDtlsConfig(dtlsConfig);
@ -110,7 +112,7 @@ public class LwM2MTransportBootstrapService {
builder.setPublicKey(sslCredentials.getPublicKey()); builder.setPublicKey(sslCredentials.getPublicKey());
builder.setPrivateKey(sslCredentials.getPrivateKey()); builder.setPrivateKey(sslCredentials.getPrivateKey());
builder.setCertificateChain(sslCredentials.getCertificateChain()); builder.setCertificateChain(sslCredentials.getCertificateChain());
dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES);
dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
} else { } else {
/* by default trust all */ /* by default trust all */

35
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/TbLwM2MDtlsBootstrapCertificateVerifier.java

@ -17,19 +17,18 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.auth.RawPublicKeyIdentity;
import org.eclipse.californium.elements.util.CertPathUtil; import org.eclipse.californium.elements.util.CertPathUtil;
import org.eclipse.californium.scandium.dtls.AlertMessage; import org.eclipse.californium.scandium.dtls.AlertMessage;
import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
import org.eclipse.californium.scandium.dtls.ConnectionId; import org.eclipse.californium.scandium.dtls.ConnectionId;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.util.ServerNames; import org.eclipse.californium.scandium.util.ServerNames;
import org.eclipse.leshan.server.security.SecurityChecker;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
@ -39,14 +38,12 @@ import org.thingsboard.server.common.transport.util.SslUtil;
import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent;
import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import java.net.InetSocketAddress;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
@ -65,14 +62,13 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti
private final LwM2MTransportServerConfig config; private final LwM2MTransportServerConfig config;
private final LwM2MBootstrapSecurityStore bsSecurityStore; private final LwM2MBootstrapSecurityStore bsSecurityStore;
@SuppressWarnings("deprecation") private StaticNewAdvancedCertificateVerifier staticCertificateVerifier;
private StaticCertificateVerifier staticCertificateVerifier;
@Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}") @Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}")
private boolean skipValidityCheckForClientCert; private boolean skipValidityCheckForClientCert;
@Override @Override
public List<CertificateType> getSupportedCertificateType() { public List<CertificateType> getSupportedCertificateTypes() {
return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY); return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY);
} }
@ -83,17 +79,17 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti
/* by default trust all */ /* by default trust all */
if (config.getTrustSslCredentials() != null) { if (config.getTrustSslCredentials() != null) {
X509Certificate[] trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates(); X509Certificate[] trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates();
staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); staticCertificateVerifier = new StaticNewAdvancedCertificateVerifier(trustedCertificates, new RawPublicKeyIdentity[0], null);
} }
} catch (Exception e) { } catch (Exception e) {
log.info("Failed to initialize the certificate verifier", e); log.warn("ailed to initialize the LwM2M certificate verifier", e);
} }
} }
@Override @Override
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer,
boolean truncateCertificatePath, CertificateMessage message, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath,
DTLSSession session) { CertificateMessage message) {
CertPath certChain = message.getCertificateChain(); CertPath certChain = message.getCertificateChain();
if (certChain == null) { if (certChain == null) {
//We trust all RPK on this layer, and use TbLwM2MAuthorizer //We trust all RPK on this layer, and use TbLwM2MAuthorizer
@ -111,14 +107,14 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti
TbLwM2MSecurityInfo securityInfo = null; TbLwM2MSecurityInfo securityInfo = null;
// verify if trust // verify if trust
if (staticCertificateVerifier != null) { if (staticCertificateVerifier != null) {
try { HandshakeException exception = staticCertificateVerifier.verifyCertificate(cid, serverName, remotePeer, clientUsage, verifySubject, truncateCertificatePath, message).getException();
staticCertificateVerifier.verifyCertificate(message, session); if (exception == null) {
String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN");
if (StringUtils.isNotEmpty(endpoint)) { if (StringUtils.isNotEmpty(endpoint)) {
securityInfo = bsSecurityStore.getX509ByEndpoint(endpoint); securityInfo = bsSecurityStore.getX509ByEndpoint(endpoint);
} }
} catch (HandshakeException e) { } else {
log.trace("Certificate validation failed.", e); log.trace("Certificate validation failed.", exception);
} }
} }
// if not trust or cert trust securityInfo == null // if not trust or cert trust securityInfo == null
@ -143,8 +139,7 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti
} }
} }
if (!x509CredentialsFound) { if (!x509CredentialsFound) {
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR, AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR);
session.getPeer());
throw new HandshakeException("x509 verification not enabled!", alert); throw new HandshakeException("x509 verification not enabled!", alert);
} }
return new CertificateVerificationResult(cid, certChain, null); return new CertificateVerificationResult(cid, certChain, null);

16
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java

@ -16,7 +16,7 @@
package org.thingsboard.server.transport.lwm2m.bootstrap.store; package org.thingsboard.server.transport.lwm2m.bootstrap.store;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.request.BootstrapDeleteRequest; import org.eclipse.leshan.core.request.BootstrapDeleteRequest;
@ -134,18 +134,18 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi
log.info("Object after discover: [{}]", objectLinks); log.info("Object after discover: [{}]", objectLinks);
this.securityInstances = new HashMap<>(); this.securityInstances = new HashMap<>();
for (Link link : objectLinks) { for (Link link : objectLinks) {
if (link.getUrl().startsWith("/0/")) { if (link.getUriReference().startsWith("/0/")) {
try { try {
LwM2mPath path = new LwM2mPath(link.getUrl()); LwM2mPath path = new LwM2mPath(link.getUriReference());
if (path.isObjectInstance()) { if (path.isObjectInstance()) {
if (link.getAttributes().containsKey("ssid")) { if (link.getLinkParams().containsKey("ssid")) {
int serverId = Integer.parseInt(link.getAttributes().get("ssid")); int serverId = Integer.parseInt(link.getLinkParams().get("ssid").getUnquoted());
if (!this.securityInstances.containsKey(serverId)) { if (!this.securityInstances.containsKey(serverId)) {
this.securityInstances.put(serverId, path.getObjectInstanceId()); this.securityInstances.put(serverId, path.getObjectInstanceId());
} else { } else {
log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId()); log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId());
} }
this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId()); this.securityInstances.put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId());
} else { } else {
if (!this.securityInstances.containsKey(0)) { if (!this.securityInstances.containsKey(0)) {
this.securityInstances.put(0, path.getObjectInstanceId()); this.securityInstances.put(0, path.getObjectInstanceId());
@ -188,10 +188,10 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi
private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) { private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) {
Link[] links = response.getObjectLinks(); Link[] links = response.getObjectLinks();
Arrays.stream(links).forEach(link -> { Arrays.stream(links).forEach(link -> {
LwM2mPath path = new LwM2mPath(link.getUrl()); LwM2mPath path = new LwM2mPath(link.getUriReference());
if (!path.isRoot() && path.getObjectId() < 3) { if (!path.isRoot() && path.getObjectId() < 3) {
if (path.isObject()) { if (path.isObject()) {
String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0"; String ver = link.getLinkParams().get("ver") != null ? link.getLinkParams().get("ver").getUnquoted() : "1.0";
this.supportedObjects.put(path.getObjectId(), ver); this.supportedObjects.put(path.getObjectId(), ver);
} }
} }

11
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java

@ -80,7 +80,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, BOOTSTRAP); TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, BOOTSTRAP);
if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) {
/* add value to store from BootstrapJson */ /* add value to store from BootstrapJson */
this.setBootstrapConfigScurityInfo(store); this.setBootstrapConfigSecurityInfo(store);
BootstrapConfig bsConfig = store.getBootstrapConfig(); BootstrapConfig bsConfig = store.getBootstrapConfig();
if (bsConfig.security != null) { if (bsConfig.security != null) {
try { try {
@ -99,18 +99,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
} }
public TbLwM2MSecurityInfo getX509ByEndpoint(String endPoint) { public TbLwM2MSecurityInfo getX509ByEndpoint(String endPoint) {
try {
TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP);
this.addValueToStore(store, store.getEndpoint()); this.addValueToStore(store, store.getEndpoint());
return store; return store;
} catch (LwM2MAuthException e) {
log.trace("Failed find security info: {}", endPoint, e);
}
return null;
} }
private void setBootstrapConfigScurityInfo(TbLwM2MSecurityInfo store) { private void setBootstrapConfigSecurityInfo(TbLwM2MSecurityInfo store) {
/* BootstrapConfig */ /* BootstrapConfig */
LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store);
if (lwM2MBootstrapConfig != null) { if (lwM2MBootstrapConfig != null) {
@ -182,7 +177,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
SecurityInfo securityInfo = null; SecurityInfo securityInfo = null;
if (store != null && store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { if (store != null && store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) {
securityInfo = store.getSecurityInfo(); securityInfo = store.getSecurityInfo();
this.setBootstrapConfigScurityInfo(store); this.setBootstrapConfigSecurityInfo(store);
BootstrapConfig bsConfigNew = store.getBootstrapConfig(); BootstrapConfig bsConfigNew = store.getBootstrapConfig();
if (bsConfigNew != null) { if (bsConfigNew != null) {
try { try {

24
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java → common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java

@ -16,31 +16,31 @@
package org.thingsboard.server.transport.lwm2m.config; package org.thingsboard.server.transport.lwm2m.config;
import lombok.Getter; import lombok.Getter;
import org.eclipse.leshan.core.LwM2m.Version; import org.eclipse.leshan.core.LwM2m.LwM2mVersion;
import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.ContentFormat;
public enum LwM2mVersion { public enum TbLwM2mVersion {
VERSION_1_0(0, Version.V1_0, ContentFormat.TLV, false), VERSION_1_0(0, LwM2mVersion.V1_0, ContentFormat.TLV, false),
VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT, true); VERSION_1_1(1, LwM2mVersion.V1_1, ContentFormat.TEXT, true);
@Getter @Getter
private final int code; private final int code;
@Getter @Getter
private final Version version; private final LwM2mVersion version;
@Getter @Getter
private final ContentFormat contentFormat; private final ContentFormat contentFormat;
@Getter @Getter
private final boolean composite; private final boolean composite;
LwM2mVersion(int code, Version version, ContentFormat contentFormat, boolean composite) { TbLwM2mVersion(int code, LwM2mVersion version, ContentFormat contentFormat, boolean composite) {
this.code = code; this.code = code;
this.version = version; this.version = version;
this.contentFormat = contentFormat; this.contentFormat = contentFormat;
this.composite = composite; this.composite = composite;
} }
public static LwM2mVersion fromVersion(Version version) { public static TbLwM2mVersion fromVersion(LwM2mVersion version) {
for (LwM2mVersion to : LwM2mVersion.values()) { for (TbLwM2mVersion to : TbLwM2mVersion.values()) {
if (to.version.equals(version)) { if (to.version.equals(version)) {
return to; return to;
} }
@ -48,8 +48,8 @@ public enum LwM2mVersion {
throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %s", version)); throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %s", version));
} }
public static LwM2mVersion fromVersionStr(String versionStr) { public static TbLwM2mVersion fromVersionStr(String versionStr) {
for (LwM2mVersion to : LwM2mVersion.values()) { for (TbLwM2mVersion to : TbLwM2mVersion.values()) {
if (to.version.toString().equals(versionStr)) { if (to.version.toString().equals(versionStr)) {
return to; return to;
} }
@ -57,8 +57,8 @@ public enum LwM2mVersion {
throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %s", versionStr)); throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %s", versionStr));
} }
public static LwM2mVersion fromCode(int code) { public static TbLwM2mVersion fromCode(int code) {
for (LwM2mVersion to : LwM2mVersion.values()) { for (TbLwM2mVersion to : TbLwM2mVersion.values()) {
if (to.code == code) { if (to.code == code) {
return to; return to;
} }

42
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java

@ -17,17 +17,17 @@ package org.thingsboard.server.transport.lwm2m.secure;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.auth.RawPublicKeyIdentity;
import org.eclipse.californium.elements.util.CertPathUtil; import org.eclipse.californium.elements.util.CertPathUtil;
import org.eclipse.californium.scandium.dtls.AlertMessage; import org.eclipse.californium.scandium.dtls.AlertMessage;
import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
import org.eclipse.californium.scandium.dtls.ConnectionId; import org.eclipse.californium.scandium.dtls.ConnectionId;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.util.ServerNames; import org.eclipse.californium.scandium.util.ServerNames;
import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -49,6 +49,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import java.net.InetSocketAddress;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
@ -71,34 +72,33 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator;
private final TbMainSecurityStore securityStore; private final TbMainSecurityStore securityStore;
@SuppressWarnings("deprecation") private StaticNewAdvancedCertificateVerifier staticCertificateVerifier;
private StaticCertificateVerifier staticCertificateVerifier;
@Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}") @Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}")
private boolean skipValidityCheckForClientCert; private boolean skipValidityCheckForClientCert;
@Override @Override
public List<CertificateType> getSupportedCertificateType() { public List<CertificateType> getSupportedCertificateTypes() {
return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY); return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY);
} }
@SuppressWarnings("deprecation")
@PostConstruct @PostConstruct
public void init() { public void init() {
try { try {
/* by default trust all */ /* by default trust all */
if (config.getTrustSslCredentials() != null) { if (config.getTrustSslCredentials() != null) {
X509Certificate[] trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates(); X509Certificate[] trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates();
staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); staticCertificateVerifier = new StaticNewAdvancedCertificateVerifier(trustedCertificates, new RawPublicKeyIdentity[0], null);
} }
} catch (Exception e) { } catch (Exception e) {
log.info("Failed to initialize the "); log.warn("Failed to initialize the LwM2M certificate verifier", e);
} }
} }
@Override @Override
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer,
boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath,
CertificateMessage message) {
CertPath certChain = message.getCertificateChain(); CertPath certChain = message.getCertificateChain();
if (certChain == null) { if (certChain == null) {
//We trust all RPK on this layer, and use TbLwM2MAuthorizer //We trust all RPK on this layer, and use TbLwM2MAuthorizer
@ -115,21 +115,24 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
} }
TbLwM2MSecurityInfo securityInfo = null; TbLwM2MSecurityInfo securityInfo = null;
if (staticCertificateVerifier != null) { if (staticCertificateVerifier != null) {
try { HandshakeException exception = staticCertificateVerifier.verifyCertificate(cid, serverName, remotePeer, clientUsage, verifySubject, truncateCertificatePath, message).getException();
staticCertificateVerifier.verifyCertificate(message, session); if (exception == null) {
String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); try {
if (StringUtils.isNotEmpty(endpoint)) { String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN");
securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT); if (StringUtils.isNotEmpty(endpoint)) {
securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT);
}
} catch (LwM2MAuthException e) {
log.trace("Certificate trust validation failed.", e);
} }
} catch (HandshakeException | LwM2MAuthException e) { } else {
log.trace("Certificate trust validation failed.", e); log.trace("Certificate trust validation failed.", exception);
} }
} }
// if not trust or cert trust securityInfo == null // if not trust or cert trust securityInfo == null
String strCert = SslUtil.getCertificateString(cert); String strCert = SslUtil.getCertificateString(cert);
String sha3Hash = EncryptionUtil.getSha3Hash(strCert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
if (securityInfo == null || securityInfo.getMsg() == null) { if (securityInfo == null || securityInfo.getMsg() == null) {
try { try {
securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT); securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT);
} catch (LwM2MAuthException e) { } catch (LwM2MAuthException e) {
@ -168,8 +171,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
} }
} }
if (!x509CredentialsFound) { if (!x509CredentialsFound) {
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR, AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR);
session.getPeer());
throw new HandshakeException("x509 verification not enabled!", alert); throw new HandshakeException("x509 verification not enabled!", alert);
} }
return new CertificateVerificationResult(cid, certChain, null); return new CertificateVerificationResult(cid, certChain, null);

16
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder; import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder;
@ -40,6 +41,8 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
@ -121,11 +124,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
/* Create DTLS Config */ /* Create DTLS Config */
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(config.getPort(), config.getSecurePort(), config));
dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY);
dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, config.isRecommendedSupportedGroups());
dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, config.isRecommendedCiphers());
dtlsConfig.setServerOnly(true);
dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups());
dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers());
/* Create credentials */ /* Create credentials */
this.setServerWithCredentials(builder, dtlsConfig); this.setServerWithCredentials(builder, dtlsConfig);
@ -144,12 +148,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
builder.setCertificateChain(sslCredentials.getCertificateChain()); builder.setCertificateChain(sslCredentials.getCertificateChain());
dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
builder.setAuthorizer(authorizer); builder.setAuthorizer(authorizer);
dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, RPK_OR_X509_CIPHER_SUITES);
} else { } else {
/* by default trust all */ /* by default trust all */
builder.setTrustedCertificates(new X509Certificate[0]); builder.setTrustedCertificates(new X509Certificate[0]);
log.info("Unable to load X509 files for LWM2MServer"); log.info("Unable to load X509 files for LWM2MServer");
dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES); dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, PSK_CIPHER_SUITES);
} }
} }

47
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java

@ -15,27 +15,30 @@
*/ */
package org.thingsboard.server.transport.lwm2m.server; package org.thingsboard.server.transport.lwm2m.server;
import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.network.config.NetworkConfigDefaults; import org.eclipse.californium.elements.config.Configuration;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; import java.util.Properties;
import java.util.concurrent.TimeUnit;
import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS;
public class LwM2MNetworkConfig { public class LwM2MNetworkConfig {
public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { public static Configuration getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) {
NetworkConfig coapConfig = new NetworkConfig(); Configuration coapConfig = new Configuration();
coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, serverPortNoSec); coapConfig.set(CoapConfig.COAP_PORT, serverPortNoSec);
coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, serverSecurePort); coapConfig.set(CoapConfig.COAP_SECURE_PORT, serverSecurePort);
/** /**
Example:Property for large packet: Example:Property for large packet:
#NetworkConfig config = new NetworkConfig(); #NetworkConfig config = new NetworkConfig();
#config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32); #config.setInt(CoapConfig.MAX_MESSAGE_SIZE,32);
#config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32); #config.setInt(CoapConfig.PREFERRED_BLOCK_SIZE,32);
#config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048); #config.setInt(CoapConfig.MAX_RESOURCE_BODY_SIZE,2048);
#config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3); #config.setInt(CoapConfig.MAX_RETRANSMIT,3);
#config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000); #config.setInt(CoapConfig.MAX_TRANSMIT_WAIT,120000);
*/ */
/** /**
@ -46,14 +49,14 @@ public class LwM2MNetworkConfig {
CoAP client will try to use block mode CoAP client will try to use block mode
or adapt the block size when receiving a 4.13 Entity too large response code or adapt the block size when receiving a 4.13 Entity too large response code
*/ */
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); coapConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
/** /**
Property to indicate if the response should always include the Block2 option \ Property to indicate if the response should always include the Block2 option \
when client request early blockwise negociation but the response can be sent on one packet. when client request early blockwise negociation but the response can be sent on one packet.
- value of false indicate that the server will respond without block2 option if no further blocks are required. - value of false indicate that the server will respond without block2 option if no further blocks are required.
- value of true indicate that the server will response with block2 option event if no further blocks are required. - value of true indicate that the server will response with block2 option event if no further blocks are required.
*/ */
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); coapConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
/** /**
* The maximum amount of time (in milliseconds) allowed between * The maximum amount of time (in milliseconds) allowed between
* transfers of individual blocks in a blockwise transfer before the * transfers of individual blocks in a blockwise transfer before the
@ -62,7 +65,7 @@ public class LwM2MNetworkConfig {
* The default value of this property is * The default value of this property is
* {@link NetworkConfigDefaults#DEFAULT_BLOCKWISE_STATUS_LIFETIME} = 5 * 60 * 1000; // 5 mins [ms]. * {@link NetworkConfigDefaults#DEFAULT_BLOCKWISE_STATUS_LIFETIME} = 5 * 60 * 1000; // 5 mins [ms].
*/ */
coapConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); coapConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS);
/** /**
!!! REQUEST_ENTITY_TOO_LARGE CODE=4.13 !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
The maximum size of a resource body (in bytes) that will be accepted The maximum size of a resource body (in bytes) that will be accepted
@ -77,7 +80,7 @@ public class LwM2MNetworkConfig {
The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192 The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
A value of {@code 0} turns off transparent handling of blockwise transfers altogether. A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
*/ */
coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); coapConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
/** /**
The default DTLS response matcher. The default DTLS response matcher.
Supported values are STRICT, RELAXED, or PRINCIPAL. Supported values are STRICT, RELAXED, or PRINCIPAL.
@ -88,13 +91,13 @@ public class LwM2MNetworkConfig {
– true with address check, (STRICT, UDP) - if port Registration of client is changed - it is bad – true with address check, (STRICT, UDP) - if port Registration of client is changed - it is bad
- false, without - false, without
*/ */
coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); coapConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED);
/** /**
https://tools.ietf.org/html/rfc7959#section-2.9.3 https://tools.ietf.org/html/rfc7959#section-2.9.3
The block size (number of bytes) to use when doing a blockwise transfer. \ The block size (number of bytes) to use when doing a blockwise transfer. \
This value serves as the upper limit for block size in blockwise transfers This value serves as the upper limit for block size in blockwise transfers
*/ */
coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); coapConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024);
/** /**
The maximum payload size (in bytes) that can be transferred in a The maximum payload size (in bytes) that can be transferred in a
single message, i.e. without requiring a blockwise transfer. single message, i.e. without requiring a blockwise transfer.
@ -102,12 +105,14 @@ public class LwM2MNetworkConfig {
In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
DEFAULT_VALUE = 1024 DEFAULT_VALUE = 1024
*/ */
coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); coapConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024);
coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10); coapConfig.set(CoapConfig.MAX_RETRANSMIT, 10);
if (!CollectionUtils.isEmpty(config.getNetworkConfig())) { if (!CollectionUtils.isEmpty(config.getNetworkConfig())) {
config.getNetworkConfig().forEach(p -> coapConfig.setString(p.getKey(), p.getValue())); Properties networkProps = new Properties();
config.getNetworkConfig().forEach(p -> networkProps.put(p.getKey(), p.getValue()));
coapConfig.add(networkProps);
} }
return coapConfig; return coapConfig;

19
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java

@ -16,7 +16,10 @@
package org.thingsboard.server.transport.lwm2m.server; package org.thingsboard.server.transport.lwm2m.server;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.observation.CompositeObservation;
import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.response.ObserveCompositeResponse;
import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.core.response.ObserveResponse;
import org.eclipse.leshan.server.observation.ObservationListener; import org.eclipse.leshan.server.observation.ObservationListener;
import org.eclipse.leshan.server.queue.PresenceListener; import org.eclipse.leshan.server.queue.PresenceListener;
@ -86,26 +89,34 @@ public class LwM2mServerListener {
@Override @Override
public void cancelled(Observation observation) { public void cancelled(Observation observation) {
log.trace("Canceled Observation {}.", observation.getPath()); //TODO: should be able to use CompositeObservation
log.trace("Canceled Observation {}.", ((SingleObservation)observation).getPath());
} }
@Override @Override
public void onResponse(Observation observation, Registration registration, ObserveResponse response) { public void onResponse(SingleObservation observation, Registration registration, ObserveResponse response) {
if (registration != null) { if (registration != null) {
service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response); service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response);
} }
} }
@Override
public void onResponse(CompositeObservation observation, Registration registration, ObserveCompositeResponse response) {
throw new RuntimeException("Not implemented yet!");
}
@Override @Override
public void onError(Observation observation, Registration registration, Exception error) { public void onError(Observation observation, Registration registration, Exception error) {
if (error != null) { if (error != null) {
log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); //TODO: should be able to use CompositeObservation
log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), ((SingleObservation)observation).getPath(), error.getMessage());
} }
} }
@Override @Override
public void newObservation(Observation observation, Registration registration) { public void newObservation(Observation observation, Registration registration) {
log.trace("Successful start newObservation {}.", observation.getPath()); //TODO: should be able to use CompositeObservation
log.trace("Successful start newObservation {}.", ((SingleObservation)observation).getPath());
} }
}; };
} }

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java

@ -56,7 +56,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
if (relation == null || relation.isCanceled()) { if (relation == null || relation.isCanceled()) {
return; // because request did not try to establish a relation return; // because request did not try to establish a relation
} }
if (CoAP.ResponseCode.isSuccess(response.getCode())) { if (response.getCode().isSuccess()) {
if (!relation.isEstablished()) { if (!relation.isEstablished()) {
relation.setEstablished(); relation.setEstablished();

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
@ -423,14 +423,14 @@ public class LwM2mClient implements Serializable {
if (registration == null) { if (registration == null) {
return ContentFormat.DEFAULT; return ContentFormat.DEFAULT;
} else{ } else{
return LwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat(); return TbLwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat();
} }
} }
static private Set<ContentFormat> clientSupportContentFormat(Registration registration) { static private Set<ContentFormat> clientSupportContentFormat(Registration registration) {
Set<ContentFormat> contentFormats = new HashSet<>(); Set<ContentFormat> contentFormats = new HashSet<>();
contentFormats.add(ContentFormat.DEFAULT); contentFormats.add(ContentFormat.DEFAULT);
String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")).findFirst().get().getAttributes().get("ct"); String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUriReference().equals("/")).findFirst().get().getLinkParams().get("ct").getUnquoted();
if (code != null) { if (code != null) {
Set<ContentFormat> codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) Set<ContentFormat> codes = Stream.of(code.replaceAll("\"", "").split(" ", -1))
.map(String::trim) .map(String::trim)

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -393,9 +393,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
public Set<String> getSupportedIdVerInClient(LwM2mClient client) { public Set<String> getSupportedIdVerInClient(LwM2mClient client) {
Set<String> clientObjects = ConcurrentHashMap.newKeySet(); Set<String> clientObjects = ConcurrentHashMap.newKeySet();
Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
LwM2mPath pathIds = new LwM2mPath(link.getUrl()); LwM2mPath pathIds = new LwM2mPath(link.getUriReference());
if (!pathIds.isRoot()) { if (!pathIds.isRoot()) {
clientObjects.add(convertObjectIdToVersionedId(link.getUrl(), client.getRegistration())); clientObjects.add(convertObjectIdToVersionedId(link.getUriReference(), client.getRegistration()));
} }
}); });
return (clientObjects.size() > 0) ? clientObjects : null; return (clientObjects.size() > 0) ? clientObjects : null;

13
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java

@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.LwM2m; import org.eclipse.leshan.core.LwM2m;
import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.Attribute;
import org.eclipse.leshan.core.attributes.AttributeSet; import org.eclipse.leshan.core.attributes.AttributeSet;
@ -29,6 +29,7 @@ import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.request.CompositeDownlinkRequest; import org.eclipse.leshan.core.request.CompositeDownlinkRequest;
import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.CreateRequest;
@ -160,7 +161,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
validateVersionedId(client, request); validateVersionedId(client, request);
LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration()); Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { //TODO: should be able to use CompositeObservation
if (observations.stream().noneMatch(observation -> ((SingleObservation)observation).getPath().equals(resultIds))) {
ObserveRequest downlink; ObserveRequest downlink;
ContentFormat contentFormat = getReadRequestContentFormat(client, request, modelProvider); ContentFormat contentFormat = getReadRequestContentFormat(client, request, modelProvider);
if (resultIds.isResource()) { if (resultIds.isResource()) {
@ -183,7 +185,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
@Override @Override
public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback) { public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback) {
Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration()); Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
Set<String> paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); //TODO: should be able to use CompositeObservation
Set<String> paths = observations.stream().map(observation -> ((SingleObservation)observation).getPath().toString()).collect(Collectors.toUnmodifiableSet());
callback.onSuccess(request, paths); callback.onSuccess(request, paths);
} }
@ -620,9 +623,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
} }
private static ContentFormat getContentFormatForComplex(LwM2mClient client) { private static ContentFormat getContentFormatForComplex(LwM2mClient client) {
if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) { if (LwM2m.LwM2mVersion.V1_0.equals(client.getRegistration().getLwM2mVersion())) {
return ContentFormat.TLV; return ContentFormat.TLV;
} else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) { } else if (LwM2m.LwM2mVersion.V1_1.equals(client.getRegistration().getLwM2mVersion())) {
ContentFormat result = findFirst(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON); ContentFormat result = findFirst(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON);
if (result != null) { if (result != null) {
return result; return result;

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java

@ -15,7 +15,7 @@
*/ */
package org.thingsboard.server.transport.lwm2m.server.downlink; package org.thingsboard.server.transport.lwm2m.server.downlink;
import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.CreateRequest;
import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.request.DeleteRequest;

7
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java

@ -15,7 +15,8 @@
*/ */
package org.thingsboard.server.transport.lwm2m.server.rpc; package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.link.DefaultLinkSerializer;
import org.eclipse.leshan.core.link.LinkSerializer;
import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.request.DiscoverRequest;
import org.eclipse.leshan.core.response.DiscoverResponse; import org.eclipse.leshan.core.response.DiscoverResponse;
import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportService;
@ -27,12 +28,14 @@ import java.util.Optional;
public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback<DiscoverRequest, DiscoverResponse> { public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback<DiscoverRequest, DiscoverResponse> {
private final LinkSerializer serializer = new DefaultLinkSerializer();
public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) { public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) {
super(transportService, client, requestMsg, callback); super(transportService, client, requestMsg, callback);
} }
protected Optional<String> serializeSuccessfulResponse(DiscoverResponse response) { protected Optional<String> serializeSuccessfulResponse(DiscoverResponse response) {
return Optional.of(Link.serialize(response.getObjectLinks())); return Optional.of(serializer.serialize(response.getObjectLinks()));
} }
} }

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java

@ -22,10 +22,11 @@ import org.eclipse.leshan.core.Destroyable;
import org.eclipse.leshan.core.Startable; import org.eclipse.leshan.core.Startable;
import org.eclipse.leshan.core.Stoppable; import org.eclipse.leshan.core.Stoppable;
import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.core.request.Identity;
import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.core.util.Validate; import org.eclipse.leshan.core.util.Validate;
import org.eclipse.leshan.server.californium.observation.ObserveUtil; import org.eclipse.leshan.core.californium.ObserveUtil;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.redis.RedisRegistrationStore; import org.eclipse.leshan.server.redis.RedisRegistrationStore;
import org.eclipse.leshan.server.redis.serialization.IdentitySerDes; import org.eclipse.leshan.server.redis.serialization.IdentitySerDes;
@ -455,7 +456,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
// cancel existing observations for the same path and registration id. // cancel existing observations for the same path and registration id.
for (Observation obs : getObservations(connection, registrationId)) { for (Observation obs : getObservations(connection, registrationId)) {
if (observation.getPath().equals(obs.getPath()) //TODO: should be able to use CompositeObservation
if (((SingleObservation)observation).getPath().equals(((SingleObservation)obs).getPath())
&& !Arrays.equals(observation.getId(), obs.getId())) { && !Arrays.equals(observation.getId(), obs.getId())) {
removed.add(obs); removed.add(obs);
unsafeRemoveObservation(connection, registrationId, obs.getId()); unsafeRemoveObservation(connection, registrationId, obs.getId());

5
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java

@ -30,7 +30,6 @@ import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.node.codec.CodecException; import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest;
@ -44,7 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
@ -236,7 +235,7 @@ public class LwM2MTransportUtil {
public static String convertObjectIdToVersionedId(String path, Registration registration) { public static String convertObjectIdToVersionedId(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
ver = ver != null ? ver : LwM2mVersion.VERSION_1_0.getVersion().toString(); ver = ver != null ? ver : TbLwM2mVersion.VERSION_1_0.getVersion().toString();
try { try {
String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1) { if (keyArray.length > 1) {

4
pom.xml

@ -68,8 +68,8 @@
<jackson.version>2.12.1</jackson.version> <jackson.version>2.12.1</jackson.version>
<fasterxml-classmate.version>1.3.4</fasterxml-classmate.version> <fasterxml-classmate.version>1.3.4</fasterxml-classmate.version>
<json-schema-validator.version>2.2.6</json-schema-validator.version> <json-schema-validator.version>2.2.6</json-schema-validator.version>
<californium.version>2.6.1</californium.version> <californium.version>3.0.0</californium.version>
<leshan.version>2.0.0-M4</leshan.version> <leshan.version>2.0.0-M5</leshan.version>
<gson.version>2.6.2</gson.version> <gson.version>2.6.2</gson.version>
<freemarker.version>2.3.30</freemarker.version> <freemarker.version>2.3.30</freemarker.version>
<mail.version>1.6.2</mail.version> <mail.version>1.6.2</mail.version>

Loading…
Cancel
Save