diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java index 4760a024c1..2edc985301 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java @@ -22,6 +22,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Header; import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwts; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.hamcrest.Matcher; @@ -34,6 +35,7 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootContextLoader; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; diff --git a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java index 1b27fb6a62..3abd311aa3 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java @@ -54,7 +54,7 @@ public class TbTestWebSocketClient extends WebSocketClient { @Override public void onClose(int i, String s, boolean b) { - log.error("CLOSED:"); + log.info("CLOSED."); } @Override diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index fd4c748f85..67e17e3d8d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m; import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.eclipse.californium.elements.config.Configuration; import org.eclipse.leshan.client.object.Security; @@ -35,12 +36,22 @@ import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.NoSecLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; @@ -58,17 +69,157 @@ import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import static org.awaitility.Awaitility.await; +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.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_INIT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; +@Slf4j @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { + + // Lwm2m Server + public static final int port = 5685; + public static final int securityPort = 5686; + public static final int portBs = 5687; + public static final int securityPortBs = 5688; + + public static final String host = "localhost"; + public static final String hostBs = "localhost"; + public static final int shortServerId = 123; + public static final int shortServerIdBs = 111; + public static final String COAP = "coap://"; + public static final String COAPS = "coaps://"; + public static final String URI = COAP + host + ":" + port; + public static final String SECURE_URI = COAPS + host + ":" + securityPort; + public static final Configuration COAP_CONFIG = new Configuration().set(COAP_PORT, port).set(COAP_SECURE_PORT, securityPort); + public static final Security SECURITY_NO_SEC = noSec(URI, shortServerId); + + public static final Configuration SECURE_COAP_CONFIG = COAP_CONFIG.set(COAP_SECURE_PORT, securityPort); + public static final Configuration COAP_CONFIG_BS = new Configuration().set(COAP_PORT, portBs); + + + public static final String URI_BS = COAP + hostBs + ":" + portBs; + + public static final String SECURE_URI_BS = COAPS + hostBs + ":" + securityPortBs; + + protected final String OBSERVE_ATTRIBUTES_WITHOUT_PARAMS = + " {\n" + + " \"keyName\": {},\n" + + " \"observe\": [],\n" + + " \"attribute\": [],\n" + + " \"telemetry\": [],\n" + + " \"attributeLwm2m\": {}\n" + + " }"; + + protected final String OBSERVE_ATTRIBUTES_WITH_PARAMS = + + " {\n" + + " \"keyName\": {\n" + + " \"/3_1.0/0/9\": \"batteryLevel\"\n" + + " },\n" + + " \"observe\": [],\n" + + " \"attribute\": [\n" + + " ],\n" + + " \"telemetry\": [\n" + + " \"/3_1.0/0/9\"\n" + + " ],\n" + + " \"attributeLwm2m\": {}\n" + + " }"; + + protected final String CLIENT_LWM2M_SETTINGS = + " {\n" + + " \"edrxCycle\": null,\n" + + " \"powerMode\": \"DRX\",\n" + + " \"fwUpdateResource\": null,\n" + + " \"fwUpdateStrategy\": 1,\n" + + " \"psmActivityTimer\": null,\n" + + " \"swUpdateResource\": null,\n" + + " \"swUpdateStrategy\": 1,\n" + + " \"pagingTransmissionWindow\": null,\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + + " }"; + + + protected final String TRANSPORT_CONFIGURATION_NO_SEC_WITHOUT_ATTRIBUTES = "{\n" + + " \"type\": \"LWM2M\",\n" + + " \"observeAttr\": {\n" + + " \"keyName\": {},\n" + + " \"observe\": [],\n" + + " \"attribute\": [],\n" + + " \"telemetry\": [],\n" + + " \"attributeLwm2m\": {}\n" + + " },\n" + + " \"bootstrapServerUpdateEnable\": true,\n" + + " \"bootstrap\": [\n" + + " {\n" + + " \"host\": \"" + hostBs + "\",\n" + + " \"port\": " + portBs + ",\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"" + NO_SEC.name() + "\",\n" + + " \"shortServerId\": " + shortServerIdBs + ",\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " },\n" + + " {\n" + + " \"host\": \"" + host + "\",\n" + + " \"port\": " + port + ",\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"" + NO_SEC.name() + "\",\n" + + " \"shortServerId\": " + shortServerId + ",\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " }\n" + + " ],\n" + + " \"clientLwM2mSettings\": {\n" + + " \"edrxCycle\": null,\n" + + " \"powerMode\": \"DRX\",\n" + + " \"fwUpdateResource\": null,\n" + + " \"fwUpdateStrategy\": 1,\n" + + " \"psmActivityTimer\": null,\n" + + " \"swUpdateResource\": null,\n" + + " \"swUpdateStrategy\": 1,\n" + + " \"pagingTransmissionWindow\": null,\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + + " }\n" + + "}"; + + protected final String TRANSPORT_CONFIGURATION = "{\n" + " \"type\": \"LWM2M\",\n" + " \"observeAttr\": {\n" + @@ -86,12 +237,12 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest " \"bootstrapServerUpdateEnable\": true,\n" + " \"bootstrap\": [\n" + " {\n" + - " \"host\": \"0.0.0.0\",\n" + - " \"port\": 5687,\n" + + " \"host\": \"" + hostBs + "\",\n" + + " \"port\": " + portBs + ",\n" + " \"binding\": \"U\",\n" + " \"lifetime\": 300,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"shortServerId\": 111,\n" + + " \"securityMode\": \"" + NO_SEC.name() + "\",\n" + + " \"shortServerId\": " + shortServerIdBs + ",\n" + " \"notifIfDisabled\": true,\n" + " \"serverPublicKey\": \"\",\n" + " \"defaultMinPeriod\": 1,\n" + @@ -100,12 +251,12 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest " \"bootstrapServerAccountTimeout\": 0\n" + " },\n" + " {\n" + - " \"host\": \"0.0.0.0\",\n" + - " \"port\": 5685,\n" + + " \"host\": \"" + host + "\",\n" + + " \"port\": " + port + ",\n" + " \"binding\": \"U\",\n" + " \"lifetime\": 300,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"shortServerId\": 123,\n" + + " \"securityMode\": \"" + NO_SEC.name() + "\",\n" + + " \"shortServerId\": " + shortServerId + ",\n" + " \"notifIfDisabled\": true,\n" + " \"serverPublicKey\": \"\",\n" + " \"defaultMinPeriod\": 1,\n" + @@ -127,21 +278,20 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest " }\n" + "}"; + protected final Lwm2mDeviceProfileTransportConfiguration LWM2M_TRANSPORT_CONFIGURATION_NO_SEC_WITH_ATTRIBUTES = JacksonUtil.fromString(TRANSPORT_CONFIGURATION, Lwm2mDeviceProfileTransportConfiguration.class); + protected final Lwm2mDeviceProfileTransportConfiguration LWM2M_TRANSPORT_CONFIGURATION_NO_SEC_WITHOUT_ATTRIBUTES = JacksonUtil.fromString(TRANSPORT_CONFIGURATION_NO_SEC_WITHOUT_ATTRIBUTES, Lwm2mDeviceProfileTransportConfiguration.class); + protected final Set expectedStatusesRegistrationLwm2mSuccess = new HashSet<>(Arrays.asList(ON_INIT, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS)); + protected final Set expectedStatusesRegistrationBsSuccess = new HashSet<>(Arrays.asList(ON_INIT, ON_BOOTSTRAP_STARTED, ON_BOOTSTRAP_SUCCESS, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS)); protected DeviceProfile deviceProfile; protected ScheduledExecutorService executor; protected TbTestWebSocketClient wsClient; protected LwM2MTestClient client; - private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; private String[] resources; public AbstractLwM2MIntegrationTest() { - this.defaultBootstrapCredentials = new LwM2MBootstrapClientCredentials(); - NoSecBootstrapClientCredential serverCredentials = new NoSecBootstrapClientCredential(); - this.defaultBootstrapCredentials.setBootstrapServer(serverCredentials); - this.defaultBootstrapCredentials.setLwm2mServer(serverCredentials); } - public void init () throws Exception{ + public void init() throws Exception { executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-scheduled")); loginTenantAdmin(); @@ -167,17 +317,42 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest @After public void after() { - wsClient.close(); clientDestroy(); executor.shutdownNow(); } + public void basicTestConnection(Security security, + LwM2MDeviceCredentials deviceCredentials, + Configuration coapConfig, + String endpoint, + Lwm2mDeviceProfileTransportConfiguration transportConfiguration, + String awaitAlias, Set expectedStatuses, + boolean isBootstrap, LwM2MSecurityMode mode) throws Exception { + createDeviceProfile(transportConfiguration); + createDevice(deviceCredentials, endpoint); + createNewClient(security, coapConfig, false, endpoint, isBootstrap); + + await(awaitAlias) + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> ON_REGISTRATION_SUCCESS.equals(client.getClientState())); + Assert.assertEquals(expectedStatuses, client.getClientStates()); + + client.destroy(); + expectedStatuses.add(ON_DEREGISTRATION_STARTED); + expectedStatuses.add(ON_DEREGISTRATION_SUCCESS); + await(awaitAlias) + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> ON_DEREGISTRATION_SUCCESS.equals(client.getClientState())); + Assert.assertEquals(expectedStatuses, client.getClientStates()); + } + public void basicTestConnectionObserveTelemetry(Security security, - LwM2MClientCredential credentials, + LwM2MDeviceCredentials deviceCredentials, Configuration coapConfig, String endpoint) throws Exception { - createDeviceProfile(TRANSPORT_CONFIGURATION); - Device device = createDevice(credentials); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITH_PARAMS, getBootstrapServerCredentialsNoSec(NONE)); + createDeviceProfile(transportConfiguration); + Device device = createDevice(deviceCredentials, endpoint); SingleEntityFilter sef = new SingleEntityFilter(); sef.setSingleEntity(device.getId()); @@ -194,7 +369,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest wsClient.waitForReply(); wsClient.registerWaitForUpdate(); - createNewClient(security, coapConfig, false, endpoint); + createNewClient(security, coapConfig, false, endpoint, false); String msg = wsClient.waitForUpdate(); EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); @@ -208,7 +383,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); } - protected void createDeviceProfile(String transportConfiguration) throws Exception { + protected void createDeviceProfile(Lwm2mDeviceProfileTransportConfiguration transportConfiguration) throws Exception { deviceProfile = new DeviceProfile(); deviceProfile.setName("LwM2M"); deviceProfile.setType(DeviceProfileType.DEFAULT); @@ -220,16 +395,16 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest DeviceProfileData deviceProfileData = new DeviceProfileData(); deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); deviceProfileData.setProvisionConfiguration(new DisabledDeviceProfileProvisionConfiguration(null)); - deviceProfileData.setTransportConfiguration(JacksonUtil.fromString(transportConfiguration, Lwm2mDeviceProfileTransportConfiguration.class)); + deviceProfileData.setTransportConfiguration(transportConfiguration); deviceProfile.setProfileData(deviceProfileData); deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); Assert.assertNotNull(deviceProfile); } - protected Device createDevice(LwM2MClientCredential clientCredentials) throws Exception { + protected Device createDevice(LwM2MDeviceCredentials credentials, String endpoint) throws Exception { Device device = new Device(); - device.setName("Device A"); + device.setName(endpoint); device.setDeviceProfileId(deviceProfile.getId()); device.setTenantId(tenantId); device = doPost("/api/device", device, Device.class); @@ -239,11 +414,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); Assert.assertEquals(device.getId(), deviceCredentials.getDeviceId()); deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); - - LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials(); - credentials.setClient(clientCredentials); - credentials.setBootstrap(defaultBootstrapCredentials); - +// LwM2MDeviceCredentials credentials = getDeviceCredentials(clientCredentials, mode); deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); return device; @@ -259,11 +430,11 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.resources = resources; } - public void createNewClient(Security security, Configuration coapConfig, boolean isRpc, String endpoint) throws Exception { + public void createNewClient(Security security, Configuration coapConfig, boolean isRpc, String endpoint, boolean isBootstrap) throws Exception { clientDestroy(); client = new LwM2MTestClient(this.executor, endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(security, coapConfig, clientPort, isRpc); + client.init(security, coapConfig, clientPort, isRpc, isBootstrap, this.shortServerId, this.shortServerIdBs); } private void clientDestroy() { @@ -271,4 +442,54 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest client.destroy(); } } + + protected Lwm2mDeviceProfileTransportConfiguration getTransportConfiguration(String observeAttr, List bootstrapServerCredentials) { + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); + TelemetryMappingConfiguration observeAttrConfiguration = JacksonUtil.fromString(observeAttr, TelemetryMappingConfiguration.class); + OtherConfiguration clientLwM2mSettings = JacksonUtil.fromString(CLIENT_LWM2M_SETTINGS, OtherConfiguration.class); + transportConfiguration.setBootstrapServerUpdateEnable(true); + transportConfiguration.setObserveAttr(observeAttrConfiguration); + transportConfiguration.setClientLwM2mSettings(clientLwM2mSettings); + transportConfiguration.setBootstrap(bootstrapServerCredentials); + return transportConfiguration; + } + + protected List getBootstrapServerCredentialsNoSec(LwM2MProfileBootstrapConfigType bootstrapConfigType) { + List bootstrap = new ArrayList<>(); + switch (bootstrapConfigType) { + case BOTH: + bootstrap.add(getBootstrapServerCredentialNoSec(false)); + bootstrap.add(getBootstrapServerCredentialNoSec(true)); + break; + case BOOTSTRAP_ONLY: + bootstrap.add(getBootstrapServerCredentialNoSec(true)); + break; + case LWM2M_ONLY: + bootstrap.add(getBootstrapServerCredentialNoSec(false)); + break; + case NONE: + } + return bootstrap; + } + + private AbstractLwM2MBootstrapServerCredential getBootstrapServerCredentialNoSec(boolean isBootstrap) { + AbstractLwM2MBootstrapServerCredential bootstrapServerCredential = new NoSecLwM2MBootstrapServerCredential(); + bootstrapServerCredential.setServerPublicKey(""); + bootstrapServerCredential.setShortServerId(isBootstrap ? shortServerIdBs : shortServerId); + bootstrapServerCredential.setBootstrapServerIs(isBootstrap); + bootstrapServerCredential.setHost(isBootstrap ? hostBs : host); + bootstrapServerCredential.setPort(isBootstrap ? portBs : port); + return bootstrapServerCredential; + } + + protected LwM2MDeviceCredentials getDeviceCredentialsNoSec(LwM2MClientCredential clientCredentials) { + LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials(); + credentials.setClient(clientCredentials); + LwM2MBootstrapClientCredentials bootstrapCredentials = new LwM2MBootstrapClientCredentials(); + NoSecBootstrapClientCredential serverCredentials = new NoSecBootstrapClientCredential(); + bootstrapCredentials.setBootstrapServer(serverCredentials); + bootstrapCredentials.setLwm2mServer(serverCredentials); + credentials.setBootstrap(bootstrapCredentials); + return credentials; + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 2d10c50bc4..532b1920b2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -15,29 +15,34 @@ */ package org.thingsboard.server.transport.lwm2m; -import org.eclipse.californium.elements.config.Configuration; -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; - public class Lwm2mTestHelper { - // Server - public static final int SECURE_PORT = 5686; - public static final int SECURE_PORT_BS = 5688; - public static final int PORT = 5685; - public static final int PORT_BS = 5687; - public static final String HOST = "localhost"; - public static final String HOST_BS = "localhost"; - public static final int SHORT_SERVER_ID = 123; - public static final int SHORT_SERVER_ID_BS = 111; - - 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 Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID); - public static final Configuration COAP_CONFIG = new Configuration().set(COAP_PORT, PORT); +// // Server +// public static final int SECURE_PORT = 5686; +// public static final int SECURE_PORT_BS = 5688; +// +//// public static final String HOST = "localhost"; +//// public static final int PORT = 5685; +////public static final String URI = "coap://" + HOST + ":" + PORT; +//public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT; +// public static final Configuration COAP_CONFIG = new Configuration().set(EXCHANGE_LIFETIME , 200, TimeUnit.SECONDS).set(COAP_PORT, PORT).set(COAP_SECURE_PORT, SECURE_PORT); +// public static final Security SECURITY_NO_SEC = noSec(URI, SHORT_SERVER_ID); +// +// public static final int PORT_BS = 5687; +// +// public static final String HOST_BS = "localhost"; +// public static final int SHORT_SERVER_ID = 123; +// public static final int SHORT_SERVER_ID_BS = 111; +// +// +// public static final Configuration SECURE_COAP_CONFIG = COAP_CONFIG.set(COAP_SECURE_PORT, SECURE_PORT); +// public static final Configuration COAP_CONFIG_BS = new Configuration().set(COAP_PORT, PORT_BS); +// +// +// public static final String URI_BS = "coap://" + HOST_BS + ":" + PORT_BS; +// +// public static final String SECURE_URI_BS = "coaps://" + HOST_BS + ":" + SECURE_PORT_BS; + // 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"}; @@ -67,4 +72,86 @@ public class Lwm2mTestHelper { public static final String RESOURCE_ID_NAME_3_14 = "UtfOffset"; public static final String RESOURCE_ID_NAME_19_0_0 = "dataRead"; public static final String RESOURCE_ID_NAME_19_1_0 = "dataWrite"; + + public enum LwM2MClientState { + + ON_INIT(1, "onInit"), + ON_BOOTSTRAP_STARTED(1, "onBootstrapStarted"), + ON_BOOTSTRAP_SUCCESS(2, "onBootstrapSuccess"), + ON_BOOTSTRAP_FAILURE(3, "onBootstrapFailure"), + ON_BOOTSTRAP_TIMEOUT(4, "onBootstrapTimeout"), + ON_REGISTRATION_STARTED(5, "onRegistrationStarted"), + ON_REGISTRATION_SUCCESS(6, "onRegistrationSuccess"), + ON_REGISTRATION_FAILURE(7, "onRegistrationFailure"), + ON_REGISTRATION_TIMEOUT(7, "onRegistrationTimeout"), + ON_UPDATE_STARTED(8, "onUpdateStarted"), + ON_UPDATE_SUCCESS(9, "onUpdateSuccess"), + ON_UPDATE_FAILURE(10, "onUpdateFailure"), + ON_UPDATE_TIMEOUT(11, "onUpdateTimeout"), + ON_DEREGISTRATION_STARTED(12, "onDeregistrationStarted"), + ON_DEREGISTRATION_SUCCESS(13, "onDeregistrationSuccess"), + ON_DEREGISTRATION_FAILURE(14, "onDeregistrationFailure"), + ON_DEREGISTRATION_TIMEOUT(15, "onDeregistrationTimeout"), + ON_EXPECTED_ERROR(16, "onUnexpectedError"); + + public int code; + public String type; + + LwM2MClientState(int code, String type) { + this.code = code; + this.type = type; + } + + public static LwM2MClientState fromLwM2MClientStateByType(String type) { + for (LwM2MClientState to : LwM2MClientState.values()) { + if (to.type.equals(type)) { + return to; + } + } + throw new IllegalArgumentException(String.format("Unsupported Client State type : %s", type)); + } + + public static LwM2MClientState fromLwM2MClientStateByCode(int code) { + for (LwM2MClientState to : LwM2MClientState.values()) { + if (to.code == code) { + return to; + } + } + throw new IllegalArgumentException(String.format("Unsupported Client State code : %s", code)); + } + } + + public enum LwM2MProfileBootstrapConfigType { + + LWM2M_ONLY(1, "only Lwm2m Server"), + BOOTSTRAP_ONLY(2, "only Bootstrap Server"), + BOTH(3, "Lwm2m Server and Bootstrap Server"), + NONE(4, "Without Lwm2m Server and Bootstrap Server"); + + public int code; + public String type; + + LwM2MProfileBootstrapConfigType(int code, String type) { + this.code = code; + this.type = type; + } + + public static LwM2MProfileBootstrapConfigType fromLwM2MBootstrapConfigByType(String type) { + for (LwM2MProfileBootstrapConfigType to : LwM2MProfileBootstrapConfigType.values()) { + if (to.type.equals(type)) { + return to; + } + } + throw new IllegalArgumentException(String.format("Unsupported Profile Bootstrap Config type : %s", type)); + } + + public static LwM2MProfileBootstrapConfigType fromLwM2MBootstrapConfigByCode(int code) { + for (LwM2MProfileBootstrapConfigType to : LwM2MProfileBootstrapConfigType.values()) { + if (to.code == code) { + return to; + } + } + throw new IllegalArgumentException(String.format("Unsupported Profile Bootstrap Config code : %s", code)); + } + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 9180617846..bd3ca6ef9a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -45,7 +45,9 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.io.IOException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; @@ -57,6 +59,25 @@ import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SERVER; 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.LwM2MClientState; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_FAILURE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_TIMEOUT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_FAILURE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_TIMEOUT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_EXPECTED_ERROR; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_INIT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_FAILURE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_TIMEOUT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_FAILURE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_STARTED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_TIMEOUT; 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_12; @@ -79,18 +100,23 @@ public class LwM2MTestClient { private LwM2mBinaryAppDataContainer lwM2MBinaryAppDataContainer; private LwM2MLocationParams locationParams; private LwM2mTemperatureSensor lwM2MTemperatureSensor; + private LwM2MClientState clientState; + private Set clientStates; - public void init(Security security, Configuration coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { + public void init(Security security, Configuration coapConfig, int port, boolean isRpc, boolean isBootstrap, int shortServerId, int shortServerIdBs) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); List models = new ArrayList<>(); for (String resourceName : resources) { models.addAll(ObjectLoader.loadDdfFile(LwM2MTestClient.class.getClassLoader().getResourceAsStream("lwm2m/" + resourceName), resourceName)); } - LwM2mModel model = new StaticModel(models); ObjectsInitializer initializer = new ObjectsInitializer(model); initializer.setInstancesForObject(SECURITY, security); - initializer.setInstancesForObject(SERVER, lwm2mServer = new Server(123, 300)); + if (isBootstrap) { + initializer.setInstancesForObject(SERVER, lwm2mServer = new Server(shortServerIdBs, 300)); + } else { + initializer.setInstancesForObject(SERVER, lwm2mServer = new Server(shortServerId, 300)); + } initializer.setInstancesForObject(DEVICE, lwM2MDevice = new SimpleLwM2MDevice()); initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice()); initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice()); @@ -119,94 +145,128 @@ public class LwM2MTestClient { builder.setDecoder(new DefaultLwM2mDecoder(false)); builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false)); + clientState = ON_INIT; + clientStates = new HashSet<>(); + clientStates.add(clientState); client = builder.build(); LwM2mClientObserver observer = new LwM2mClientObserver() { @Override public void onBootstrapStarted(ServerIdentity bsserver, BootstrapRequest request) { - log.info("ClientObserver -> onBootstrapStarted..."); + clientState = ON_BOOTSTRAP_STARTED; + clientStates.add(clientState); +// log.info("ClientObserver -> onBootstrapStarted..."); } @Override public void onBootstrapSuccess(ServerIdentity bsserver, BootstrapRequest request) { - log.info("ClientObserver -> onBootstrapSuccess..."); + clientState = ON_BOOTSTRAP_SUCCESS; + clientStates.add(clientState); +// log.info("ClientObserver -> onBootstrapSuccess..."); } @Override public void onBootstrapFailure(ServerIdentity bsserver, BootstrapRequest request, ResponseCode responseCode, String errorMessage, Exception cause) { - log.info("ClientObserver -> onBootstrapFailure..."); + clientState = ON_BOOTSTRAP_FAILURE; + clientStates.add(clientState); +// log.info("ClientObserver -> onBootstrapFailure..."); } @Override public void onBootstrapTimeout(ServerIdentity bsserver, BootstrapRequest request) { - log.info("ClientObserver -> onBootstrapTimeout..."); + clientState = ON_BOOTSTRAP_TIMEOUT; + clientStates.add(clientState); +// log.info("ClientObserver -> onBootstrapTimeout..."); } @Override public void onRegistrationStarted(ServerIdentity server, RegisterRequest request) { + clientState = ON_REGISTRATION_STARTED; + clientStates.add(clientState); // log.info("ClientObserver -> onRegistrationStarted... EndpointName [{}]", request.getEndpointName()); } @Override public void onRegistrationSuccess(ServerIdentity server, RegisterRequest request, String registrationID) { - log.info("ClientObserver -> onRegistrationSuccess... EndpointName [{}] [{}]", request.getEndpointName(), registrationID); + clientState = ON_REGISTRATION_SUCCESS; + clientStates.add(clientState); +// log.info("ClientObserver -> onRegistrationSuccess... EndpointName [{}] [{}]", request.getEndpointName(), registrationID); } @Override public void onRegistrationFailure(ServerIdentity server, RegisterRequest request, ResponseCode responseCode, String errorMessage, Exception cause) { - log.info("ClientObserver -> onRegistrationFailure... ServerIdentity [{}]", server); + clientState = ON_REGISTRATION_FAILURE; + clientStates.add(clientState); +// log.info("ClientObserver -> onRegistrationFailure... ServerIdentity [{}]", server); } @Override public void onRegistrationTimeout(ServerIdentity server, RegisterRequest request) { - log.info("ClientObserver -> onRegistrationTimeout... RegisterRequest [{}]", request); + clientState = ON_REGISTRATION_TIMEOUT; + clientStates.add(clientState); +// log.info("ClientObserver -> onRegistrationTimeout... RegisterRequest [{}]", request); } @Override public void onUpdateStarted(ServerIdentity server, UpdateRequest request) { + clientState = ON_UPDATE_STARTED; + clientStates.add(clientState); // log.info("ClientObserver -> onUpdateStarted... UpdateRequest [{}]", request); } @Override public void onUpdateSuccess(ServerIdentity server, UpdateRequest request) { + clientState = ON_UPDATE_SUCCESS; + clientStates.add(clientState); // log.info("ClientObserver -> onUpdateSuccess... UpdateRequest [{}]", request); } @Override public void onUpdateFailure(ServerIdentity server, UpdateRequest request, ResponseCode responseCode, String errorMessage, Exception cause) { - + clientState = ON_UPDATE_FAILURE; + clientStates.add(clientState); } @Override public void onUpdateTimeout(ServerIdentity server, UpdateRequest request) { - + clientState = ON_UPDATE_TIMEOUT; + clientStates.add(clientState); } @Override public void onDeregistrationStarted(ServerIdentity server, DeregisterRequest request) { - log.info("ClientObserver ->onDeregistrationStarted... DeregisterRequest [{}]", request.getRegistrationId()); + clientState = ON_DEREGISTRATION_STARTED; + clientStates.add(clientState); +// log.info("ClientObserver ->onDeregistrationStarted... DeregisterRequest [{}]", request.getRegistrationId()); } @Override public void onDeregistrationSuccess(ServerIdentity server, DeregisterRequest request) { + clientState = ON_DEREGISTRATION_SUCCESS; + clientStates.add(clientState); log.info("ClientObserver ->onDeregistrationSuccess... DeregisterRequest [{}]", request.getRegistrationId()); } @Override public void onDeregistrationFailure(ServerIdentity server, DeregisterRequest request, ResponseCode responseCode, String errorMessage, Exception cause) { - log.info("ClientObserver ->onDeregistrationFailure... DeregisterRequest [{}] [{}]", request.getRegistrationId(), request.getRegistrationId()); + clientState = ON_DEREGISTRATION_FAILURE; + clientStates.add(clientState); +// log.info("ClientObserver ->onDeregistrationFailure... DeregisterRequest [{}] [{}]", request.getRegistrationId(), request.getRegistrationId()); } @Override public void onDeregistrationTimeout(ServerIdentity server, DeregisterRequest request) { - log.info("ClientObserver ->onDeregistrationTimeout... DeregisterRequest [{}] [{}]", request.getRegistrationId(), request.getRegistrationId()); + clientState = ON_DEREGISTRATION_TIMEOUT; + clientStates.add(clientState); +// log.info("ClientObserver ->onDeregistrationTimeout... DeregisterRequest [{}] [{}]", request.getRegistrationId(), request.getRegistrationId()); } @Override public void onUnexpectedError(Throwable unexpectedError) { - + clientState = ON_EXPECTED_ERROR; + clientStates.add(clientState); } }; this.client.addObserver(observer); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 3095f28f28..c05e5d6dda 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -20,7 +20,8 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Test; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; @@ -46,102 +47,59 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.QUEU import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; @Slf4j public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { public static final int TIMEOUT = 30; - private final String OTA_TRANSPORT_CONFIGURATION = "{\n" + - " \"type\": \"LWM2M\",\n" + - " \"observeAttr\": {\n" + - " \"keyName\": {\n" + - " \"/5_1.0/0/3\": \"state\",\n" + - " \"/5_1.0/0/5\": \"updateResult\",\n" + - " \"/5_1.0/0/6\": \"pkgname\",\n" + - " \"/5_1.0/0/7\": \"pkgversion\",\n" + - " \"/5_1.0/0/9\": \"firmwareUpdateDeliveryMethod\",\n" + - " \"/9_1.0/0/0\": \"pkgname\",\n" + - " \"/9_1.0/0/1\": \"pkgversion\",\n" + - " \"/9_1.0/0/7\": \"updateState\",\n" + - " \"/9_1.0/0/9\": \"updateResult\"\n" + - " },\n" + - " \"observe\": [\n" + - " \"/5_1.0/0/3\",\n" + - " \"/5_1.0/0/5\",\n" + - " \"/5_1.0/0/6\",\n" + - " \"/5_1.0/0/7\",\n" + - " \"/5_1.0/0/9\",\n" + - " \"/9_1.0/0/0\",\n" + - " \"/9_1.0/0/1\",\n" + - " \"/9_1.0/0/7\",\n" + - " \"/9_1.0/0/9\"\n" + - " ],\n" + - " \"attribute\": [],\n" + - " \"telemetry\": [\n" + - " \"/5_1.0/0/3\",\n" + - " \"/5_1.0/0/5\",\n" + - " \"/5_1.0/0/6\",\n" + - " \"/5_1.0/0/7\",\n" + - " \"/5_1.0/0/9\",\n" + - " \"/9_1.0/0/0\",\n" + - " \"/9_1.0/0/1\",\n" + - " \"/9_1.0/0/7\",\n" + - " \"/9_1.0/0/9\"\n" + - " ],\n" + - " \"attributeLwm2m\": {}\n" + - " },\n" + - " \"bootstrapServerUpdateEnable\": true,\n" + - " \"bootstrap\": [\n" + - " {\n" + - " \"host\": \"0.0.0.0\",\n" + - " \"port\": 5687,\n" + - " \"binding\": \"U\",\n" + - " \"lifetime\": 300,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"shortServerId\": 111,\n" + - " \"notifIfDisabled\": true,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"defaultMinPeriod\": 1,\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " {\n" + - " \"host\": \"0.0.0.0\",\n" + - " \"port\": 5685,\n" + - " \"binding\": \"U\",\n" + - " \"lifetime\": 300,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"shortServerId\": 123,\n" + - " \"notifIfDisabled\": true,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"defaultMinPeriod\": 1,\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " }\n" + - " ],\n" + - " \"clientLwM2mSettings\": {\n" + - " \"edrxCycle\": null,\n" + - " \"powerMode\": \"DRX\",\n" + - " \"fwUpdateResource\": null,\n" + - " \"fwUpdateStrategy\": 1,\n" + - " \"psmActivityTimer\": null,\n" + - " \"swUpdateResource\": null,\n" + - " \"swUpdateStrategy\": 1,\n" + - " \"pagingTransmissionWindow\": null,\n" + - " \"clientOnlyObserveAfterConnect\": 1\n" + - " }\n" + - "}"; - @Test + protected final String OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA = + + " {\n" + + " \"keyName\": {\n" + + " \"/5_1.0/0/3\": \"state\",\n" + + " \"/5_1.0/0/5\": \"updateResult\",\n" + + " \"/5_1.0/0/6\": \"pkgname\",\n" + + " \"/5_1.0/0/7\": \"pkgversion\",\n" + + " \"/5_1.0/0/9\": \"firmwareUpdateDeliveryMethod\",\n" + + " \"/9_1.0/0/0\": \"pkgname\",\n" + + " \"/9_1.0/0/1\": \"pkgversion\",\n" + + " \"/9_1.0/0/7\": \"updateState\",\n" + + " \"/9_1.0/0/9\": \"updateResult\"\n" + + " },\n" + + " \"observe\": [\n" + + " \"/5_1.0/0/3\",\n" + + " \"/5_1.0/0/5\",\n" + + " \"/5_1.0/0/6\",\n" + + " \"/5_1.0/0/7\",\n" + + " \"/5_1.0/0/9\",\n" + + " \"/9_1.0/0/0\",\n" + + " \"/9_1.0/0/1\",\n" + + " \"/9_1.0/0/7\",\n" + + " \"/9_1.0/0/9\"\n" + + " ],\n" + + " \"attribute\": [],\n" + + " \"telemetry\": [\n" + + " \"/5_1.0/0/3\",\n" + + " \"/5_1.0/0/5\",\n" + + " \"/5_1.0/0/6\",\n" + + " \"/5_1.0/0/7\",\n" + + " \"/5_1.0/0/9\",\n" + + " \"/9_1.0/0/0\",\n" + + " \"/9_1.0/0/1\",\n" + + " \"/9_1.0/0/7\",\n" + + " \"/9_1.0/0/9\"\n" + + " ],\n" + + " \"attributeLwm2m\": {}\n" + + " }"; + @Test public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { - createDeviceProfile(TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); - final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITH_PARAMS, getBootstrapServerCredentialsNoSec(NONE)); + createDeviceProfile(transportConfiguration); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(this.CLIENT_ENDPOINT_WITHOUT_FW_INFO)); + final Device device = createDevice(deviceCredentials, this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); + createNewClient(SECURITY_NO_SEC, COAP_CONFIG, false, this.CLIENT_ENDPOINT_WITHOUT_FW_INFO, false); Thread.sleep(1000); @@ -163,10 +121,11 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateByObject5() throws Exception { - createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA5); - final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA5); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA, getBootstrapServerCredentialsNoSec(NONE)); + createDeviceProfile(transportConfiguration); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA5)); + final Device device = createDevice(deviceCredentials, this.CLIENT_ENDPOINT_OTA5); + createNewClient(SECURITY_NO_SEC, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA5, false); Thread.sleep(1000); @@ -200,10 +159,11 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { * */ @Test public void testSoftwareUpdateByObject9() throws Exception { - createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(CLIENT_ENDPOINT_OTA9); - final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false, CLIENT_ENDPOINT_OTA9); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA, getBootstrapServerCredentialsNoSec(NONE)); + createDeviceProfile(transportConfiguration); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9)); + final Device device = createDevice(deviceCredentials, this.CLIENT_ENDPOINT_OTA9); + createNewClient(SECURITY_NO_SEC, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA9, false); Thread.sleep(1000); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 0252c77071..251fccb450 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -17,9 +17,11 @@ package org.thingsboard.server.transport.lwm2m.rpc; import org.junit.Before; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; + import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -31,8 +33,6 @@ import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; import static org.eclipse.leshan.core.LwM2mId.SERVER; 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.COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; @@ -45,12 +45,12 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_14; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; @DaoSqlTest public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - protected String RPC_TRANSPORT_CONFIGURATION; - + protected String OBSERVE_ATTRIBUTES_WITH_PARAMS_RPC; protected String deviceId; public Set expectedObjects; public Set expectedObjectIdVers; @@ -71,7 +71,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected static AtomicInteger endpointSequence = new AtomicInteger(); protected static String DEVICE_ENDPOINT_RPC_PREF = "deviceEndpointRpc"; - public AbstractRpcLwM2MIntegrationTest(){ + public AbstractRpcLwM2MIntegrationTest() { setResources(resources); } @@ -79,7 +79,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg public void beforeTest() throws Exception { String endpoint = DEVICE_ENDPOINT_RPC_PREF + endpointSequence.incrementAndGet(); init(); - createNewClient (SECURITY, COAP_CONFIG, true, endpoint); + createNewClient(SECURITY_NO_SEC, COAP_CONFIG, true, endpoint, false); expectedObjects = ConcurrentHashMap.newKeySet(); expectedObjectIdVers = ConcurrentHashMap.newKeySet(); @@ -103,8 +103,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg String ver_Id_0 = client.getClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_0).version; if ("1.0".equals(ver_Id_0)) { objectIdVer_0 = "/" + OBJECT_ID_0; - } - else { + } else { objectIdVer_0 = "/" + OBJECT_ID_0 + "_" + ver_Id_0; } objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + ACCESS_CONTROL)).findFirst().get(); @@ -116,86 +115,44 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get(); objectInstanceIdVer_9 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + SOFTWARE_MANAGEMENT)).findFirst().get(); - RPC_TRANSPORT_CONFIGURATION = "{\n" + - " \"type\": \"LWM2M\",\n" + - " \"observeAttr\": {\n" + - " \"keyName\": {\n" + - " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\": \"" + RESOURCE_ID_NAME_3_9 + "\",\n" + - " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_14 + "\": \"" + RESOURCE_ID_NAME_3_14 + "\",\n" + - " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\": \"" + RESOURCE_ID_NAME_19_0_0 + "\",\n" + - " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "\": \"" + RESOURCE_ID_NAME_19_1_0 + "\"\n" + - " },\n" + - " \"observe\": [\n" + - " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\",\n" + - " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\"\n" + - " ],\n" + - " \"attribute\": [\n" + - " ],\n" + - " \"telemetry\": [\n" + - " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\",\n" + - " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_14 + "\",\n" + - " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\",\n" + - " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "\"\n" + - " ],\n" + - " \"attributeLwm2m\": {}\n" + - " },\n" + - " \"bootstrapServerUpdateEnable\": true,\n" + - " \"bootstrap\": [\n" + + OBSERVE_ATTRIBUTES_WITH_PARAMS_RPC = " {\n" + - " \"host\": \"0.0.0.0\",\n" + - " \"port\": 5687,\n" + - " \"binding\": \"U\",\n" + - " \"lifetime\": 300,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"shortServerId\": 111,\n" + - " \"notifIfDisabled\": true,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"defaultMinPeriod\": 1,\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " {\n" + - " \"host\": \"0.0.0.0\",\n" + - " \"port\": 5685,\n" + - " \"binding\": \"U\",\n" + - " \"lifetime\": 300,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"shortServerId\": 123,\n" + - " \"notifIfDisabled\": true,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"defaultMinPeriod\": 1,\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " }\n" + - " ],\n" + - " \"clientLwM2mSettings\": {\n" + - " \"edrxCycle\": null,\n" + - " \"powerMode\": \"DRX\",\n" + - " \"fwUpdateResource\": null,\n" + - " \"fwUpdateStrategy\": 1,\n" + - " \"psmActivityTimer\": null,\n" + - " \"swUpdateResource\": null,\n" + - " \"swUpdateStrategy\": 1,\n" + - " \"pagingTransmissionWindow\": null,\n" + - " \"clientOnlyObserveAfterConnect\": 1\n" + - " }\n" + - "}"; - createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); + " \"keyName\": {\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\": \"" + RESOURCE_ID_NAME_3_9 + "\",\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_14 + "\": \"" + RESOURCE_ID_NAME_3_14 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\": \"" + RESOURCE_ID_NAME_19_0_0 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "\": \"" + RESOURCE_ID_NAME_19_1_0 + "\"\n" + + " },\n" + + " \"observe\": [\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\"\n" + + " ],\n" + + " \"attribute\": [\n" + + " ],\n" + + " \"telemetry\": [\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\",\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_14 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "\"\n" + + " ],\n" + + " \"attributeLwm2m\": {}\n" + + " }"; + + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITH_PARAMS_RPC, getBootstrapServerCredentialsNoSec(NONE)); + createDeviceProfile(transportConfiguration); - NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); - final Device device = createDevice(credentials); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(endpoint)); + final Device device = createDevice(deviceCredentials, endpoint); deviceId = device.getId().getId().toString(); client.start(); - } + } protected String pathIdVerToObjectId(String pathIdVer) { - if (pathIdVer.contains("_")){ - String [] objVer = pathIdVer.split("/"); - objVer[1] = objVer[1].split("_")[0]; - return String.join("/", objVer); + if (pathIdVer.contains("_")) { + String[] objVer = pathIdVer.split("/"); + objVer[1] = objVer[1].split("_")[0]; + return String.join("/", objVer); } return pathIdVer; } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index c4108a2921..1e22748676 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -15,10 +15,25 @@ */ package org.thingsboard.server.transport.lwm2m.security; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509BootstrapClientCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.PSKLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapServerCredential; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import java.io.IOException; @@ -27,28 +42,39 @@ import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; @DaoSqlTest +@Slf4j public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - protected final String CREDENTIALS_PATH = "lwm2m/credentials/"; // client public key or id used for PSK + protected final String CREDENTIALS_PATH = "lwm2m/credentials/"; // client public key or id used for PSK // Get keys PSK - protected final String CLIENT_PSK_IDENTITY = "SOME_PSK_ID"; // client public key or id used for PSK + protected final String CLIENT_PSK_IDENTITY = "SOME_PSK_ID"; // client public key or id used for PSK + protected final String CLIENT_PSK_IDENTITY_BS = "SOME_PSK_ID_BS"; // client public key or id used for PSK protected final String CLIENT_PSK_KEY = "73656372657450534b73656372657450"; // client private/secret key used for PSK // Server protected static final String SERVER_JKS_FOR_TEST = "lwm2mserver"; protected static final String SERVER_STORE_PWD = "server_ks_password"; protected static final String SERVER_CERT_ALIAS = "server"; -protected final X509Certificate serverX509Cert; // server certificate signed by rootCA - protected final PublicKey serverPublicKeyFromCert; // server public key used for RPK + protected static final String SERVER_CERT_ALIAS_BS = "bootstrap"; + protected final X509Certificate serverX509Cert; // server certificate signed by rootCA + protected final X509Certificate serverX509CertBs; // serverBs certificate signed by rootCA + protected final PublicKey serverPublicKeyFromCert; // server public key used for RPK + protected final PublicKey serverPublicKeyFromCertBs; // serverBs public key used for RPK // Client protected LwM2MTestClient client; protected static final String CLIENT_ENDPOINT_NO_SEC = "LwNoSec00000000"; + protected static final String CLIENT_ENDPOINT_NO_SEC_BS = "LwNoSecBs00000000"; protected static final String CLIENT_ENDPOINT_PSK = "LwPsk00000000"; + protected static final String CLIENT_ENDPOINT_PSK_BS = "LwPskBs00000000"; protected static final String CLIENT_ENDPOINT_RPK = "LwRpk00000000"; + protected static final String CLIENT_ENDPOINT_RPK_BS = "LwRpkBs00000000"; protected static final String CLIENT_ENDPOINT_X509_TRUST = "LwX50900000000"; protected static final String CLIENT_ENDPOINT_X509_TRUST_NO = "LwX509TrustNo"; protected static final String CLIENT_JKS_FOR_TEST = "lwm2mclient"; @@ -56,19 +82,16 @@ protected final X509Certificate serverX509Cert; protected static final String CLIENT_ALIAS_CERT_TRUST = "client_alias_00000000"; protected static final String CLIENT_ALIAS_CERT_TRUST_NO = "client_alias_trust_no"; - protected final X509Certificate clientX509CertTrust; // client certificate signed by intermediate, rootCA with a good CN ("host name") - protected final PrivateKey clientPrivateKeyFromCertTrust; // client private key used for X509 and RPK - protected final PublicKey clientPublicKeyFromCertTrust; // client public key used for RPK - protected final X509Certificate clientX509CertTrustNo; // client certificate signed by intermediate, rootCA with a good CN ("host name") - protected final PrivateKey clientPrivateKeyFromCertTrustNo; // client private key used for X509 and RPK - protected final PublicKey clientPublicKeyFromCertTrustNo; // client public key used for RPK - private final String[] RESOURCES_SECURITY = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; + protected final X509Certificate clientX509CertTrust; // client certificate signed by intermediate, rootCA with a good CN ("host name") + protected final PrivateKey clientPrivateKeyFromCertTrust; // client private key used for X509 and RPK + protected final X509Certificate clientX509CertTrustNo; // client certificate signed by intermediate, rootCA with a good CN ("host name") + protected final PrivateKey clientPrivateKeyFromCertTrustNo; // client private key used for X509 and RPK + private final String[] RESOURCES_SECURITY = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; - public AbstractSecurityLwM2MIntegrationTest() { // create client credentials setResources(this.RESOURCES_SECURITY); @@ -82,12 +105,9 @@ protected final X509Certificate serverX509Cert; // Trust clientPrivateKeyFromCertTrust = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST, clientKeyStorePwd); clientX509CertTrust = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST); - clientPublicKeyFromCertTrust = clientX509CertTrust != null ? clientX509CertTrust.getPublicKey() : null; // No trust clientPrivateKeyFromCertTrustNo = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST_NO, clientKeyStorePwd); clientX509CertTrustNo = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST_NO); - clientPublicKeyFromCertTrustNo = clientX509CertTrustNo != null ? clientX509CertTrustNo.getPublicKey() : null; - } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } @@ -103,6 +123,9 @@ protected final X509Certificate serverX509Cert; serverX509Cert = (X509Certificate) serverKeyStore.getCertificate(SERVER_CERT_ALIAS); serverPublicKeyFromCert = serverX509Cert.getPublicKey(); + serverX509CertBs = (X509Certificate) serverKeyStore.getCertificate(SERVER_CERT_ALIAS_BS); + serverPublicKeyFromCertBs = serverX509CertBs.getPublicKey(); + } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } @@ -114,4 +137,125 @@ protected final X509Certificate serverX509Cert; defaultBootstrapCredentials.setBootstrapServer(serverCredentials); defaultBootstrapCredentials.setLwm2mServer(serverCredentials); } + + + protected List getBootstrapServerCredentialsSecure(LwM2MSecurityMode mode, LwM2MProfileBootstrapConfigType bootstrapConfigType) { + List bootstrap = new ArrayList<>(); + switch (bootstrapConfigType) { + case BOTH: + bootstrap.add(getBootstrapServerCredential(mode, false)); + bootstrap.add(getBootstrapServerCredential(mode, true)); + break; + case BOOTSTRAP_ONLY: + bootstrap.add(getBootstrapServerCredential(mode, true)); + break; + case LWM2M_ONLY: + bootstrap.add(getBootstrapServerCredential(mode, false)); + break; + case NONE: + } + return bootstrap; + } + + private AbstractLwM2MBootstrapServerCredential getBootstrapServerCredential(LwM2MSecurityMode mode, boolean isBootstrap) { + AbstractLwM2MBootstrapServerCredential bootstrapServerCredential; + switch (mode) { + case PSK: + bootstrapServerCredential = new PSKLwM2MBootstrapServerCredential(); + bootstrapServerCredential.setServerPublicKey(""); + break; + case RPK: + bootstrapServerCredential = new RPKLwM2MBootstrapServerCredential(); + if (isBootstrap) { + bootstrapServerCredential.setServerPublicKey(Base64.encodeBase64String(serverPublicKeyFromCertBs.getEncoded())); + } else { + bootstrapServerCredential.setServerPublicKey(Base64.encodeBase64String(serverPublicKeyFromCert.getEncoded())); + } + break; + case X509: + bootstrapServerCredential = new X509LwM2MBootstrapServerCredential(); + try { + if (isBootstrap) { + bootstrapServerCredential.setServerPublicKey(Base64.encodeBase64String(serverX509CertBs.getEncoded())); + } else { + bootstrapServerCredential.setServerPublicKey(Base64.encodeBase64String(serverX509Cert.getEncoded())); + } + } catch (CertificateEncodingException e) { + e.printStackTrace(); + } + break; + default: + throw new IllegalStateException("Unexpected value: " + mode); + } + bootstrapServerCredential.setShortServerId(isBootstrap ? shortServerIdBs : shortServerId); + bootstrapServerCredential.setBootstrapServerIs(isBootstrap); + bootstrapServerCredential.setHost(isBootstrap ? hostBs : host); + bootstrapServerCredential.setPort(isBootstrap ? securityPortBs : securityPort); + return bootstrapServerCredential; + } + + + protected LwM2MDeviceCredentials getDeviceCredentialsSecure(LwM2MClientCredential clientCredentials, + PrivateKey privateKey, + X509Certificate certificate, + LwM2MSecurityMode mode) { + LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials(); + credentials.setClient(clientCredentials); + LwM2MBootstrapClientCredentials bootstrapCredentials; + switch (mode) { + case PSK: + bootstrapCredentials = getBootstrapClientCredentialsPsk(clientCredentials); + break; + case RPK: + bootstrapCredentials = getBootstrapClientCredentialsRpk(certificate, privateKey); + break; + case X509: + bootstrapCredentials = getBootstrapClientCredentialsX509(certificate, privateKey); + break; + default: + throw new IllegalStateException("Unexpected value: " + mode); + } + credentials.setBootstrap(bootstrapCredentials); + return credentials; + } + + private LwM2MBootstrapClientCredentials getBootstrapClientCredentialsPsk(LwM2MClientCredential clientCredentials) { + LwM2MBootstrapClientCredentials bootstrapCredentials = new LwM2MBootstrapClientCredentials(); + PSKBootstrapClientCredential serverCredentials = new PSKBootstrapClientCredential(); + if (clientCredentials != null) { + serverCredentials.setClientSecretKey(((PSKClientCredential) clientCredentials).getKey()); + serverCredentials.setClientPublicKeyOrId(((PSKClientCredential) clientCredentials).getIdentity()); + } + bootstrapCredentials.setBootstrapServer(serverCredentials); + bootstrapCredentials.setLwm2mServer(serverCredentials); + return bootstrapCredentials; + } + + private LwM2MBootstrapClientCredentials getBootstrapClientCredentialsRpk(X509Certificate certificate, PrivateKey privateKey) { + LwM2MBootstrapClientCredentials bootstrapCredentials = new LwM2MBootstrapClientCredentials(); + RPKBootstrapClientCredential serverCredentials = new RPKBootstrapClientCredential(); + if (certificate != null && certificate.getPublicKey() != null && privateKey != null) { + serverCredentials.setClientPublicKeyOrId(Base64.encodeBase64String(certificate.getPublicKey().getEncoded())); + serverCredentials.setClientSecretKey(Base64.encodeBase64String(privateKey.getEncoded())); + } + bootstrapCredentials.setBootstrapServer(serverCredentials); + bootstrapCredentials.setLwm2mServer(serverCredentials); + return bootstrapCredentials; + } + + private LwM2MBootstrapClientCredentials getBootstrapClientCredentialsX509(X509Certificate certificate, PrivateKey privateKey) { + LwM2MBootstrapClientCredentials bootstrapCredentials = new LwM2MBootstrapClientCredentials(); + X509BootstrapClientCredential serverCredentials = new X509BootstrapClientCredential(); + if (certificate != null) { + try { + serverCredentials.setClientPublicKeyOrId(Base64.encodeBase64String(certificate.getEncoded())); + serverCredentials.setClientSecretKey(Base64.encodeBase64String(privateKey.getEncoded())); + } catch (CertificateEncodingException e) { + log.error("Client`s certificate [{}] is bad. [{}]", certificate, e.getMessage()); + } + } + bootstrapCredentials.setBootstrapServer(serverCredentials); + bootstrapCredentials.setLwm2mServer(serverCredentials); + return bootstrapCredentials; + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index c324480e17..56874f57aa 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -15,21 +15,41 @@ */ package org.thingsboard.server.transport.lwm2m.security.sql; -import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.client.object.Security; import org.junit.Test; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; +import static org.eclipse.leshan.client.object.Security.noSecBootstap; +import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; -@Slf4j public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + //Lwm2m only @Test - public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredential clientCredentials = createNoSecClientCredentials(CLIENT_ENDPOINT_NO_SEC); - super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, CLIENT_ENDPOINT_NO_SEC); + public void testWithNoSecConnectLwm2mSuccessAndObserveTelemetry() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC; + LwM2MDeviceCredentials clientCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(clientEndpoint)); + super.basicTestConnectionObserveTelemetry(SECURITY_NO_SEC, clientCredentials, COAP_CONFIG, clientEndpoint); } + // Bootstrap + Lwm2m + @Test + public void testWithNoSecConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS; + Security securityBs = noSecBootstap(URI_BS); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsNoSec(BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(clientEndpoint)); + this.basicTestConnection(securityBs, + deviceCredentials, + COAP_CONFIG_BS, + clientEndpoint, + transportConfiguration, + "await on client state (NoSecBS two section)", + expectedStatusesRegistrationBsSuccess, + true, + NO_SEC); + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index f93ab67db9..9afa25c0b3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -18,28 +18,70 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; import org.junit.Test; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import java.nio.charset.StandardCharsets; import static org.eclipse.leshan.client.object.Security.psk; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; +import static org.eclipse.leshan.client.object.Security.pskBootstrap; +import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.PSK; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + //Lwm2m only @Test - public void testConnectWithPSKAndObserveTelemetry() throws Exception { + public void testWithPskConnectLwm2mSuccessAndObserveTelemetry() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_PSK; + String identity = CLIENT_PSK_IDENTITY; + String keyPsk = CLIENT_PSK_KEY; PSKClientCredential clientCredentials = new PSKClientCredential(); - clientCredentials.setEndpoint(CLIENT_ENDPOINT_PSK); - clientCredentials.setKey(CLIENT_PSK_KEY); - clientCredentials.setIdentity(CLIENT_PSK_IDENTITY); - Security security = psk(SECURE_URI, - SHORT_SERVER_ID, - CLIENT_PSK_IDENTITY.getBytes(StandardCharsets.UTF_8), - Hex.decodeHex(CLIENT_PSK_KEY.toCharArray())); - super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_PSK); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setIdentity(identity); + clientCredentials.setKey(keyPsk); + Security securityBs = psk(SECURE_URI, + shortServerId, + identity.getBytes(StandardCharsets.UTF_8), + Hex.decodeHex(keyPsk.toCharArray())); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(PSK, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, null, null, PSK); + this.basicTestConnection(securityBs, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (Psk_Lwm2m)", + expectedStatusesRegistrationLwm2mSuccess, + false, + PSK); + } + + // Bootstrap + Lwm2m + @Test + public void testWithPskConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_PSK_BS; + String identity = CLIENT_PSK_IDENTITY_BS; + String keyPsk = CLIENT_PSK_KEY; + PSKClientCredential clientCredentials = new PSKClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setIdentity(identity); + clientCredentials.setKey(keyPsk); + Security securityBs = pskBootstrap(SECURE_URI_BS, + identity.getBytes(StandardCharsets.UTF_8), + Hex.decodeHex(keyPsk.toCharArray())); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(PSK, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, null, null, PSK); + this.basicTestConnection(securityBs, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (PskBS two section)", + expectedStatusesRegistrationBsSuccess, + true, + PSK); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 880d436e69..a28d72117a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -15,30 +15,74 @@ */ package org.thingsboard.server.transport.lwm2m.security.sql; +import org.apache.commons.codec.binary.Base64; import org.eclipse.leshan.client.object.Security; import org.junit.Test; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; -import org.apache.commons.codec.binary.Base64;; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; import static org.eclipse.leshan.client.object.Security.rpk; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; +import static org.eclipse.leshan.client.object.Security.rpkBootstrap; +import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.RPK; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + //Lwm2m only @Test - public void testConnectWithRPKAndObserveTelemetry() throws Exception { - RPKClientCredential rpkClientCredentials = new RPKClientCredential(); - rpkClientCredentials.setEndpoint(CLIENT_ENDPOINT_RPK); - rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKeyFromCertTrust.getEncoded()))); - Security security = rpk(SECURE_URI, - SHORT_SERVER_ID, - clientPublicKeyFromCertTrust.getEncoded(), - clientPrivateKeyFromCertTrust.getEncoded(), - serverPublicKeyFromCert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_RPK); + public void testWithRpkConnectLwm2mSuccessAndObserveTelemetry() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_RPK; + X509Certificate certificate = clientX509CertTrust; + PrivateKey privateKey = clientPrivateKeyFromCertTrust; + RPKClientCredential clientCredentials = new RPKClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setKey(Base64.encodeBase64String(certificate.getPublicKey().getEncoded())); + Security securityBs = rpk(SECURE_URI, + shortServerId, + certificate.getPublicKey().getEncoded(), + privateKey.getEncoded(), + serverX509Cert.getPublicKey().getEncoded()); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(RPK, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, privateKey, certificate, RPK); + this.basicTestConnection(securityBs, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (Rpk_Lwm2m)", + expectedStatusesRegistrationLwm2mSuccess, + false, + RPK); + } + + // Bootstrap + Lwm2m + @Test + public void testWithRpkConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_RPK_BS; + X509Certificate certificate = clientX509CertTrust; + PrivateKey privateKey = clientPrivateKeyFromCertTrust; + RPKClientCredential clientCredentials = new RPKClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setKey(Base64.encodeBase64String(certificate.getPublicKey().getEncoded())); + Security securityBs = rpkBootstrap(SECURE_URI_BS, + certificate.getPublicKey().getEncoded(), + privateKey.getEncoded(), + serverX509CertBs.getPublicKey().getEncoded()); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(RPK, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, clientPrivateKeyFromCertTrust, certificate, RPK); + this.basicTestConnection(securityBs, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (RpkBS two section)", + expectedStatusesRegistrationBsSuccess, + true, + RPK); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index c7cc24d7ee..1281adc36a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -17,27 +17,72 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.junit.Test; +import org.springframework.util.Base64Utils; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; -import org.thingsboard.server.common.transport.util.SslUtil; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + import static org.eclipse.leshan.client.object.Security.x509; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; +import static org.eclipse.leshan.client.object.Security.x509Bootstrap; +import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.X509; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + //Lwm2m only @Test - public void testConnectWithCertAndObserveTelemetry() throws Exception { - X509ClientCredential credentials = new X509ClientCredential(); - credentials.setEndpoint(CLIENT_ENDPOINT_X509_TRUST_NO); - credentials.setCert(SslUtil.getCertificateString(clientX509CertTrustNo)); + public void testWithX509NoTrustConnectLwm2mSuccessAndObserveTelemetry() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_X509_TRUST_NO; + X509Certificate certificate = clientX509CertTrustNo; + PrivateKey privateKey = clientPrivateKeyFromCertTrustNo; + X509ClientCredential clientCredentials = new X509ClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setCert(Base64Utils.encodeToString(certificate.getEncoded())); Security security = x509(SECURE_URI, - SHORT_SERVER_ID, - clientX509CertTrustNo.getEncoded(), - clientPrivateKeyFromCertTrustNo.getEncoded(), + shortServerId, + certificate.getEncoded(), + privateKey.getEncoded(), serverX509Cert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_X509_TRUST_NO); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(X509, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, privateKey, certificate, X509); + this.basicTestConnection(security, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (X509_Trust_Lwm2m)", + expectedStatusesRegistrationLwm2mSuccess, + false, + X509); + } + + // Bootstrap + Lwm2m + @Test + public void testWithX509NoTrustConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_X509_TRUST_NO; + X509Certificate certificate = clientX509CertTrustNo; + PrivateKey privateKey = clientPrivateKeyFromCertTrustNo; + X509ClientCredential clientCredentials = new X509ClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setCert(Base64Utils.encodeToString(certificate.getEncoded())); + Security security = x509Bootstrap(SECURE_URI_BS, + certificate.getEncoded(), + privateKey.getEncoded(), + serverX509CertBs.getEncoded()); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(X509, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, privateKey, certificate, X509); + this.basicTestConnection(security, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (X509NoTrust two section)", + expectedStatusesRegistrationBsSuccess, + true, + X509); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index d59f6ee4ea..40f094a96a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -17,26 +17,71 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.junit.Test; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + import static org.eclipse.leshan.client.object.Security.x509; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; +import static org.eclipse.leshan.client.object.Security.x509Bootstrap; +import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.X509; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; public class X509_TrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + //Lwm2m only @Test - public void testConnectAndObserveTelemetry() throws Exception { - X509ClientCredential credentials = new X509ClientCredential(); - credentials.setEndpoint(CLIENT_ENDPOINT_X509_TRUST); + public void testWithX509TrustConnectLwm2mSuccessAndObserveTelemetry() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_X509_TRUST; + X509Certificate certificate = clientX509CertTrust; + PrivateKey privateKey = clientPrivateKeyFromCertTrust; + X509ClientCredential clientCredentials = new X509ClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setCert(""); Security security = x509(SECURE_URI, - SHORT_SERVER_ID, - clientX509CertTrust.getEncoded(), - clientPrivateKeyFromCertTrust.getEncoded(), + shortServerId, + certificate.getEncoded(), + privateKey.getEncoded(), serverX509Cert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_X509_TRUST); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(X509, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, privateKey, certificate, X509); + this.basicTestConnection(security, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (X509_Trust_Lwm2m)", + expectedStatusesRegistrationLwm2mSuccess, + false, + X509); } + // Bootstrap + Lwm2m + @Test + public void testWithX509TrustConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_X509_TRUST; + X509Certificate certificate = clientX509CertTrust; + PrivateKey privateKey = clientPrivateKeyFromCertTrust; + X509ClientCredential clientCredentials = new X509ClientCredential(); + clientCredentials.setEndpoint(clientEndpoint); + clientCredentials.setCert(""); + Security security = x509Bootstrap(SECURE_URI_BS, + certificate.getEncoded(), + privateKey.getEncoded(), + serverX509CertBs.getEncoded()); + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(X509, BOTH)); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, privateKey, certificate, X509); + this.basicTestConnection(security, + deviceCredentials, + COAP_CONFIG, + clientEndpoint, + transportConfiguration, + "await on client state (X509Trust two section)", + expectedStatusesRegistrationBsSuccess, + true, + X509); + } } diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 7f7cb6e8b9..d919319096 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -1,20 +1,12 @@ transport.lwm2m.server.security.credentials.enabled=true transport.lwm2m.server.security.credentials.type=KEYSTORE transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credentials/lwm2mserver.jks -#transport.lwm2m.server.security.credentials.keystore.store_password=server -#transport.lwm2m.server.security.credentials.keystore.key_alias=server -#transport.lwm2m.server.security.credentials.keystore.key_password=server -transport.lwm2m.bootstrap.enabled=false transport.lwm2m.bootstrap.security.credentials.enabled=true transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/lwm2mserver.jks -#transport.lwm2m.bootstrap.security.credentials.keystore.store_password=server -#transport.lwm2m.bootstrap.security.credentials.keystore.key_alias=server -#transport.lwm2m.bootstrap.security.credentials.keystore.key_password=server transport.lwm2m.security.trust-credentials.enabled=true transport.lwm2m.security.trust-credentials.type=KEYSTORE transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials/lwm2mtruststorechain.jks -#transport.lwm2m.security.trust-credentials.keystore.store_password=server edges.enabled=true edges.storage.no_read_records_sleep=500 diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index 0582ff5450..0bcf65fd70 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -33,6 +33,8 @@ import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; import org.eclipse.leshan.server.bootstrap.BootstrapUtil; +import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -43,6 +45,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; @Slf4j @@ -164,9 +167,14 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi protected void findServerInstanceId(BootstrapReadResponse readResponse) { this.serverInstances = new HashMap<>(); - ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { - serverInstances.put(((Long) instance.getResource(0).getValue()).intValue(), instance.getId()); - }); + try { + ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { + Integer shortId = OPAQUE.equals(instance.getResource(0).getType()) ? new BigInteger((byte[]) instance.getResource(0).getValue()).intValue() : (Integer) instance.getResource(0).getValue(); + serverInstances.put(shortId, instance.getId()); + }); + } catch (Exception e) { + log.error("", e); + } if (this.securityInstances != null && this.securityInstances.size() > 0 && this.serverInstances != null && this.serverInstances.size() > 0) { this.findBootstrapServerId(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java index b47e548b56..f3ab8d2cb8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java @@ -33,12 +33,12 @@ public class LwM2MNetworkConfig { coapConfig.set(CoapConfig.COAP_SECURE_PORT, serverSecurePort); /** Example:Property for large packet: - #NetworkConfig config = new NetworkConfig(); - #config.setInt(CoapConfig.MAX_MESSAGE_SIZE,32); - #config.setInt(CoapConfig.PREFERRED_BLOCK_SIZE,32); - #config.setInt(CoapConfig.MAX_RESOURCE_BODY_SIZE,2048); - #config.setInt(CoapConfig.MAX_RETRANSMIT,3); - #config.setInt(CoapConfig.MAX_TRANSMIT_WAIT,120000); + #NetworkConfig config = new Configuration(); + #config.sett(CoapConfig.MAX_MESSAGE_SIZE,32); + #config.set(CoapConfig.PREFERRED_BLOCK_SIZE,32); + #config.set(CoapConfig.MAX_RESOURCE_BODY_SIZE,2048); + #config.set(CoapConfig.MAX_RETRANSMIT,3); + #config.set(CoapConfig.MAX_TRANSMIT_WAIT,120000); */ /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java index 40514577c3..8f754bc142 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java @@ -85,7 +85,11 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { this.registration = registration; this.tenantId = lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()).getTenantId(); this.modelsLock = new ReentrantLock(); - models.computeIfAbsent(tenantId, t -> new ConcurrentHashMap<>()); + log.info("tenantId: [{}]", tenantId); + log.info("models: [{}]", models); + if (tenantId != null) { + models.computeIfAbsent(tenantId, t -> new ConcurrentHashMap<>()); + } } @Override @@ -127,8 +131,8 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { private ObjectModel getObjectModelDynamic(Integer objectId, String version) { String key = getKeyIdVer(objectId, version); - ObjectModel objectModel = models.get(tenantId).get(key); - if (objectModel == null) { + ObjectModel objectModel = tenantId != null ? models.get(tenantId).get(key) : null; + if (tenantId != null && objectModel == null) { modelsLock.lock(); try { objectModel = models.get(tenantId).get(key);