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 ddf8bca43f..50051c08d5 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 @@ -147,7 +147,6 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte public static final Integer shortServerId = 123; public static final Integer shortServerIdBs0 = 0; public static final int serverId = 1; - public static final int serverIdBs = 0; public static final String COAP = "coap://"; public static final String COAPS = "coaps://"; @@ -705,7 +704,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte return bootstrap; } - private AbstractLwM2MBootstrapServerCredential getBootstrapServerCredentialNoSec(boolean isBootstrap) { + protected AbstractLwM2MBootstrapServerCredential getBootstrapServerCredentialNoSec(boolean isBootstrap) { AbstractLwM2MBootstrapServerCredential bootstrapServerCredential = new NoSecLwM2MBootstrapServerCredential(); bootstrapServerCredential.setServerPublicKey(""); bootstrapServerCredential.setShortServerId(isBootstrap ? shortServerIdBs0 : shortServerId); 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 6159400bb6..ce073d137d 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 @@ -24,8 +24,6 @@ public class Lwm2mTestHelper { public static final int TEMPERATURE_SENSOR = 3303; // Ids in Client - public static final int OBJECT_ID_0 = 0; - public static final int OBJECT_ID_1 = 1; public static final int OBJECT_INSTANCE_ID_0 = 0; public static final int OBJECT_INSTANCE_ID_1 = 1; public static final int OBJECT_INSTANCE_ID_2 = 2; 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 2ae1432cac..7c5e2973ac 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 @@ -88,10 +88,7 @@ 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.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder.getDefaultPathEncoder; -import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.serverId; -import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.serverIdBs; import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.shortServerId; -import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.shortServerIdBs0; 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; @@ -169,31 +166,29 @@ public class LwM2MTestClient { LwM2mModel model = new StaticModel(models); ObjectsInitializer initializer = new ObjectsInitializer(model); if (securityBs != null && security != null) { - // SECURITY - security.setId(serverId); - securityBs.setId(serverIdBs); + // SECURITIES + securityBs.setId(0); + security.setId(1); LwM2mInstanceEnabler[] instances = new LwM2mInstanceEnabler[]{securityBs, security}; - initializer.setClassForObject(SECURITY, Security.class); initializer.setInstancesForObject(SECURITY, instances); // SERVER Server lwm2mServer = new Server(shortServerId, TimeUnit.MINUTES.toSeconds(60)); - lwm2mServer.setId(serverId); - Server serverBs = new Server(shortServerIdBs0, TimeUnit.MINUTES.toSeconds(60)); - serverBs.setId(serverIdBs); - instances = new LwM2mInstanceEnabler[]{serverBs, lwm2mServer}; - initializer.setClassForObject(SERVER, Server.class); + lwm2mServer.setId(0); + instances = new LwM2mInstanceEnabler[]{lwm2mServer}; + initializer.setInstancesForObject(SERVER, instances); } else if (securityBs != null) { // SECURITY - initializer.setInstancesForObject(SECURITY, securityBs); - // SERVER + securityBs.setId(0); initializer.setClassForObject(SERVER, Server.class); + initializer.setInstancesForObject(SECURITY, securityBs); } else { // SECURITY + security.setId(0); initializer.setInstancesForObject(SECURITY, security); // SERVER Server lwm2mServer = new Server(shortServerId, TimeUnit.MINUTES.toSeconds(60)); - lwm2mServer.setId(serverId); + lwm2mServer.setId(0); initializer.setInstancesForObject(SERVER, lwm2mServer); } 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 be85294f08..1253993e08 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 @@ -43,12 +43,11 @@ import static org.awaitility.Awaitility.await; import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; +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.LwM2MProfileBootstrapConfigType.NONE; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_1; 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; @@ -140,10 +139,10 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg }); } }); - String ver_Id_0 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_0).version; - String ver_Id_1 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_1).version; - objectIdVer_0 = "/" + OBJECT_ID_0 + "_" + ver_Id_0; - objectIdVer_1 = "/" + OBJECT_ID_1 + "_" + ver_Id_1; + String ver_Id_0 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(SECURITY).version; + String ver_Id_1 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(SERVER).version; + objectIdVer_0 = "/" + SECURITY + "_" + ver_Id_0; + objectIdVer_1 = "/" + SERVER + "_" + ver_Id_1; objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).startsWith("/" + ACCESS_CONTROL)).findFirst().get(); objectIdVer_3 = (String) expectedObjectIdVers.stream().filter(PREDICATE_3).findFirst().get(); objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).startsWith("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java index 90b373b16c..c0779ad944 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -21,8 +21,10 @@ import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.node.LwM2mPath; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; +import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -53,18 +55,18 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest try { expectedObjectIdVers.forEach(expected -> { try { - String actualResult = sendRPCById((String) expected); String expectedObjectId = pathIdVerToObjectId((String) expected); LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); - ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); - assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String expectedObjectInstances = "LwM2mObject [id=" + expectedPath.getObjectId() + ", instances={0=LwM2mObjectInstance [id=0, resources="; - if (expectedPath.getObjectId() == 1) { - expectedObjectInstances = "LwM2mObject [id=1, instances={1="; - } else if (expectedPath.getObjectId() == 2) { - expectedObjectInstances = "LwM2mObject [id=2, instances={}]"; + if (expectedPath.getObjectId() > ACCESS_CONTROL) { + String actualResult = sendRPCByIdSync((String) expected); + if (StringUtils.isNoneBlank(actualResult)) { + log.warn(" expectedPath: [{}]", expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expectedObjectInstances = "LwM2mObject [id=" + expectedPath.getObjectId() + ", instances={0=LwM2mObjectInstance [id=0, resources="; + assertTrue(rpcActualResult.get("value").asText().contains(expectedObjectInstances)); + } } - assertTrue(rpcActualResult.get("value").asText().contains(expectedObjectInstances)); } catch (Exception e) { e.printStackTrace(); } @@ -83,7 +85,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest public void testReadAllInstancesInClientById_Result_CONTENT_Value_IsInstances_IsResources() throws Exception { expectedObjectIdVerInstances.forEach(expected -> { try { - String actualResult = sendRPCById((String) expected); + String actualResult = sendRPCByIdAsync((String) expected); String expectedObjectId = pathIdVerToObjectId((String) expected); LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -104,7 +106,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest @Test public void testReadMultipleResourceById_Result_CONTENT_Value_IsLwM2mMultipleResource() throws Exception { String expectedIdVer = objectInstanceIdVer_3 + "/" + RESOURCE_ID_11; - String actualResult = sendRPCById(expectedIdVer); + String actualResult = sendRPCByIdAsync(expectedIdVer); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); String expected = "LwM2mMultipleResource [id=" + RESOURCE_ID_11 + ", values={"; @@ -117,7 +119,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest @Test public void testReadSingleResourceById_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { String expectedIdVer = objectInstanceIdVer_3 + "/" + RESOURCE_ID_14; - String actualResult = sendRPCById(expectedIdVer); + String actualResult = sendRPCByIdAsync(expectedIdVer); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value="; @@ -228,10 +230,14 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest assertEquals(actualValue, expectedValue); } - private String sendRPCById(String path) throws Exception { + private String sendRPCByIdAsync(String path) throws Exception { String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + path + "\"}}"; return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); } + private String sendRPCByIdSync(String path) throws Exception { + String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + path + "\"}}"; + return doPost("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); + } private String sendRPCByKey(String key) throws Exception { String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"key\": \"" + key + "\"}}"; 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 6dda2de9fe..264c3b84c7 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 @@ -69,6 +69,7 @@ import java.util.concurrent.TimeUnit; import static org.awaitility.Awaitility.await; import static org.eclipse.leshan.client.object.Security.noSecBootstrap; import static org.eclipse.leshan.client.object.Security.psk; +import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.junit.Assert.assertEquals; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode.PSK; @@ -77,7 +78,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClient 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_UPDATE_SUCCESS; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; @DaoSqlTest @@ -191,7 +192,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M transportConfiguration, awaitAlias, expectedStatuses, - true, + false, finishState, false); } @@ -231,8 +232,15 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M } - public void basicTestConnectionBootstrapRequestTriggerBefore(String clientEndpoint, String awaitAlias, LwM2MProfileBootstrapConfigType type) throws Exception { - Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsNoSec(type)); + public void basicTestConnectionBootstrapRequestTriggerBefore(String clientEndpoint, String awaitAlias, LwM2MProfileBootstrapConfigType type, int cnt) throws Exception { + List bootstrapServerCredentialsNoSec = getBootstrapServerCredentialsNoSec(type); + for (int i = 2; i <= cnt; i++) { + AbstractLwM2MBootstrapServerCredential bsCredential = getBootstrapServerCredentialNoSec(false); + bsCredential.setHost("0.0.0." + i); + bsCredential.setShortServerId(bsCredential.getShortServerId() + i); + bootstrapServerCredentialsNoSec.add(bsCredential); + } + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, bootstrapServerCredentialsNoSec); LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(clientEndpoint)); this.basicTestConnectionBootstrapRequestTrigger( SECURITY_NO_SEC, @@ -275,8 +283,8 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M }); Assert.assertTrue(lwM2MTestClient.getClientStates().containsAll(expectedStatusesLwm2m)); - String executedPath = "/" + OBJECT_ID_1 + "_" + lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_1).version - + "/" +serverId + "/" + RESOURCE_ID_9; + String executedPath = "/" + SERVER + "_" + lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(SERVER).version + + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9; lwM2MTestClient.setClientStates(new HashSet<>()); String actualResult = sendRPCSecurityExecuteById(executedPath, deviceIdStr, endpoint); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSNoTriggerTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSNoTriggerTest.java new file mode 100644 index 0000000000..2622cac18c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSNoTriggerTest.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.security.sql; + +import org.junit.Test; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; + +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_SUCCESS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.LWM2M_ONLY; + +public class NoSecLwM2MIntegrationBSNoTriggerTest extends AbstractSecurityLwM2MIntegrationTest { + + @Test + public void testWithNoSecConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "NoTrigger" + BOTH.name(); + String awaitAlias = "await on client state (NoSecBS two section)"; + basicTestConnectionBefore(clientEndpoint, awaitAlias, BOTH, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); + } + + @Test + public void testWithNoSecConnectBsSuccess_UpdateLwm2mSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "NoTrigger" + LWM2M_ONLY.name(); + String awaitAlias = "await on client state (NoSecBS Lwm2m section)"; + basicTestConnectionBefore(clientEndpoint, awaitAlias, LWM2M_ONLY, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSTriggerTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSTriggerTest.java new file mode 100644 index 0000000000..af5571864f --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSTriggerTest.java @@ -0,0 +1,61 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.security.sql; + +import org.junit.Test; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; + +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOOTSTRAP_ONLY; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.LWM2M_ONLY; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; + +public class NoSecLwM2MIntegrationBSTriggerTest extends AbstractSecurityLwM2MIntegrationTest { + + @Test + public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateBootstrapSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + BOOTSTRAP_ONLY.name(); + String awaitAlias = "await on client state (NoSecBS Trigger Bootstrap section)"; + basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, BOOTSTRAP_ONLY, 1); + } + + @Test + public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateTwoSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + BOTH.name(); + String awaitAlias = "await on client state (NoSecBS Trigger Two section)"; + basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, BOTH, 1); + } + + @Test + public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateLwm2mSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + LWM2M_ONLY.name(); + String awaitAlias = "await on client state (NoSecBS Trigger Lwm2m section)"; + basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, LWM2M_ONLY, 1); + } + @Test + public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateLwm2mSection_3_AndLm2m_1_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + LWM2M_ONLY.name(); + String awaitAlias = "await on client state (NoSecBS Trigger Lwm2m section)"; + basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, LWM2M_ONLY, 3); + } + + @Test + public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateNoneSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { + String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + NONE.name(); + String awaitAlias = "await on client state (NoSecBS Trigger None section)"; + basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, NONE, 1); + } +} 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 d4a464b9c6..50bb87467f 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 @@ -19,12 +19,6 @@ import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_SUCCESS; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOOTSTRAP_ONLY; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.BOTH; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.LWM2M_ONLY; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; - public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { //Lwm2m only @@ -34,48 +28,4 @@ public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationT LwM2MDeviceCredentials clientCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(clientEndpoint)); super.basicTestConnectionObserveSingleTelemetry(SECURITY_NO_SEC, clientCredentials, clientEndpoint, false, false); } - - // Bootstrap + Lwm2m - @Test - public void testWithNoSecConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + BOTH.name(); - String awaitAlias = "await on client state (NoSecBS two section)"; - basicTestConnectionBefore(clientEndpoint, awaitAlias, BOTH, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); - } - - @Test - public void testWithNoSecConnectBsSuccess_UpdateLwm2mSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + LWM2M_ONLY.name(); - String awaitAlias = "await on client state (NoSecBS Lwm2m section)"; - basicTestConnectionBefore(clientEndpoint, awaitAlias, LWM2M_ONLY, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); - } - - // Bs trigger - @Test - public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateTwoSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + BOTH.name(); - String awaitAlias = "await on client state (NoSecBS Trigger Two section)"; - basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, BOTH); - } - - @Test - public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateBootstrapSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + BOOTSTRAP_ONLY.name(); - String awaitAlias = "await on client state (NoSecBS Trigger Bootstrap section)"; - basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, BOOTSTRAP_ONLY); - } - - @Test - public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateLwm2mSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + LWM2M_ONLY.name(); - String awaitAlias = "await on client state (NoSecBS Trigger Lwm2m section)"; - basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, LWM2M_ONLY); - } - - @Test - public void testWithNoSecConnectLwm2mSuccessBootstrapRequestTriggerConnectBsSuccess_UpdateNoneSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + "Trigger" + NONE.name(); - String awaitAlias = "await on client state (NoSecBS Trigger None section)"; - basicTestConnectionBootstrapRequestTriggerBefore(clientEndpoint, awaitAlias, NONE); - } } 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 3b61dfe49f..e4bf935306 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 @@ -175,12 +175,12 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes clientCredentials.setEndpoint(clientEndpoint); clientCredentials.setIdentity(identity); clientCredentials.setKey(keyPsk); - Security securityBs = pskBootstrap(SECURE_URI_BS, + Security securityPskBs = 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, false); - this.basicTestConnection(null, securityBs, + this.basicTestConnection(null, securityPskBs, deviceCredentials, clientEndpoint, transportConfiguration, 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 e94b8a6319..fbe84a28b2 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 @@ -113,13 +113,13 @@ public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTes RPKClientCredential clientCredentials = new RPKClientCredential(); clientCredentials.setEndpoint(clientEndpoint); clientCredentials.setKey(Base64.encodeBase64String(certificate.getPublicKey().getEncoded())); - Security securityBs = rpkBootstrap(SECURE_URI_BS, + Security securityRpkBs = 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, false); - this.basicTestConnection(null, securityBs, + this.basicTestConnection(null, securityRpkBs, deviceCredentials, clientEndpoint, transportConfiguration, 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 1ba408ac70..d1576ede1b 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 @@ -51,15 +51,14 @@ public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MInteg X509ClientCredential clientCredentials = new X509ClientCredential(); clientCredentials.setEndpoint(clientEndpoint); clientCredentials.setCert(Base64.getEncoder().encodeToString(certificate.getEncoded())); - Security security = x509(SECURE_URI, + Security securityX509 = x509(SECURE_URI, shortServerId, certificate.getEncoded(), privateKey.getEncoded(), serverX509Cert.getEncoded()); Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(X509, NONE)); LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, privateKey, certificate, X509, false); - this.basicTestConnection(security, - null, + this.basicTestConnection(securityX509, null, deviceCredentials, clientEndpoint, transportConfiguration, diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 516f118630..9adceb2860 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.core.coap.Request; import org.eclipse.leshan.core.peer.IpPeer; import org.eclipse.leshan.core.peer.LwM2mPeer; import org.eclipse.leshan.core.peer.PskIdentity; @@ -112,8 +113,10 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } catch (InvalidConfigurationException e){ log.error("Failed put to lwM2MBootstrapSessionClients by endpoint [{}]", request.getEndpointName(), e); } + String msg = String.format("Bootstrap session started... %s", ((Request) request.getCoapRequest()).getLocalAddress().toString()); + log.warn(String.format("%s: %s", request.getEndpointName(), msg)); this.sendLogs(request.getEndpointName(), - String.format("%s: Bootstrap session started...", LOG_LWM2M_INFO, request.getEndpointName())); + String.format("%s: %s", LOG_LWM2M_INFO, msg)); } return session; } @@ -135,7 +138,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession session.setModel(modelProvider.getObjectModel(session, tasks.supportedObjects)); // set Requests to Send - log.info("tasks.requestsToSend = [{}]", tasks.requestsToSend); + log.warn("tasks.requestsToSend = [{}]", tasks.requestsToSend); session.setRequests(tasks.requestsToSend); // prepare list where we will store Responses @@ -182,14 +185,16 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession session.getResponses().add(response); String msg = String.format("%s: receives success response for: %s %s %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), request.getPath().toString(), response.toString()); + log.warn(msg); this.sendLogs(bsSession.getEndpoint(), msg); // on success for NOT bootstrap finish request we send next request return BootstrapPolicy.continueWith(nextRequest(bsSession)); } else { // on success for bootstrap finish request we stop the session - this.sendLogs(bsSession.getEndpoint(), - String.format("%s: receives success response for bootstrap finish.", LOG_LWM2M_INFO)); + String msg = String.format("%s: receives success response for bootstrap finish.", LOG_LWM2M_INFO); + log.info(msg); + this.sendLogs(bsSession.getEndpoint(), msg); this.tasksProvider.remove(bsSession.getEndpoint()); return BootstrapPolicy.finished(); } @@ -228,7 +233,9 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public void end(BootstrapSession bsSession) { - this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session finished.", LOG_LWM2M_INFO)); + String msg = String.format("%s: Bootstrap session finished.", LOG_LWM2M_INFO); + log.warn(msg); + this.sendLogs(bsSession.getEndpoint(), msg); this.tasksProvider.remove(bsSession.getEndpoint()); } 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 f24f068365..3223179486 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 @@ -17,15 +17,12 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.link.Link; -import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.request.BootstrapDeleteRequest; import org.eclipse.leshan.core.request.BootstrapDiscoverRequest; import org.eclipse.leshan.core.request.BootstrapDownlinkRequest; -import org.eclipse.leshan.core.request.BootstrapReadRequest; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; -import org.eclipse.leshan.core.response.BootstrapReadResponse; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; @@ -33,7 +30,6 @@ import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.BootstrapUtil; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -43,14 +39,18 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.stream.Collectors; -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; +import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; +import static org.eclipse.leshan.core.LwM2mId.SECURITY; +import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.BOOTSTRAP_DEFAULT_SHORT_ID_0; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LWM2M_DEFAULT_SHORT_ID_1; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LWM2M_DEFAULT_SHORT_ID_65534; @Slf4j public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTaskProvider { @@ -77,11 +77,11 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask @Override public Tasks getTasks(BootstrapSession session, List previousResponse) { // BootstrapConfig config = store.get(session.getEndpoint(), session.getClientTransportData().getIdentity(), session); - BootstrapConfig config = store.get(session); - if (config == null) { + BootstrapConfig configNew = store.get(session); + if (configNew == null) { return null; } - if (previousResponse == null && shouldStartWithDiscover(config)) { + if (previousResponse == null && shouldStartWithDiscover(configNew)) { Tasks tasks = new Tasks(); tasks.requestsToSend = new ArrayList<>(1); tasks.requestsToSend.add(new BootstrapDiscoverRequest()); @@ -96,47 +96,25 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask tasks.supportedObjects = this.supportedObjects; // handle bootstrap discover response if (previousResponse != null) { - if (previousResponse.get(0) instanceof BootstrapDiscoverResponse) { - BootstrapDiscoverResponse discoverResponse = (BootstrapDiscoverResponse) previousResponse.get(0); + if (previousResponse.get(0) instanceof BootstrapDiscoverResponse discoverResponse) { if (discoverResponse.isSuccess()) { this.initAfterBootstrapDiscover(discoverResponse); - findSecurityInstanceId(discoverResponse.getObjectLinks(), session.getEndpoint()); + /// Short Server Ids - in old config + findInstancesIdOldByServerId(discoverResponse, session.getEndpoint()); } else { - log.warn( - "Bootstrap Discover return error {} : to continue bootstrap session without autoIdForSecurityObject mode. {}", - discoverResponse, session); - } - if (this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID_0) == null) { log.error( "Unable to find bootstrap server instance in Security Object (0) in response {}: unable to continue bootstrap session with autoIdForSecurityObject mode. {}", discoverResponse, session); return null; } - tasks.requestsToSend = new ArrayList<>(1); - tasks.requestsToSend.add(new BootstrapReadRequest("/1")); - tasks.last = false; - return tasks; - } - BootstrapReadResponse readResponse = (BootstrapReadResponse) previousResponse.get(0); - Integer bootstrapServerIdOld = null; - if (readResponse.isSuccess()) { - findServerInstanceId(readResponse, session.getEndpoint()); - if (this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getSecurityInstances().size() > 0 && this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getServerInstances().size() > 0) { - bootstrapServerIdOld = this.findBootstrapServerId(session.getEndpoint()); - } - } else { - log.warn( - "Bootstrap ReadResponse return error {} : to continue bootstrap session without find Server Instance Id. {}", - readResponse, session); } // create requests from config - tasks.requestsToSend = this.toRequests(config, - config.contentFormat != null ? config.contentFormat : session.getContentFormat(), - bootstrapServerIdOld, session.getEndpoint()); + tasks.requestsToSend = this.toRequests(configNew, + configNew.contentFormat != null ? configNew.contentFormat : session.getContentFormat(), session.getEndpoint()); } else { // create requests from config - tasks.requestsToSend = BootstrapUtil.toRequests(config, - config.contentFormat != null ? config.contentFormat : session.getContentFormat()); + tasks.requestsToSend = BootstrapUtil.toRequests(configNew, + configNew.contentFormat != null ? configNew.contentFormat : session.getContentFormat()); } return tasks; } @@ -148,81 +126,57 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask /** * "Short Server ID": This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. - * The values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server. - * "Short Server ID": + * "Short Lwm2m Server ID": * - Link Instance (lwm2m Server) hase linkParams with key = "ssid" value = "shortId" (ver lvm2m = 1.1). - * - Link Instance (bootstrap Server) hase not linkParams with key = "ssid" (ver lvm2m = 1.0). + * The values ID:0 values MUST NOT be used for identifying the LwM2M Server only BS. */ - protected void findSecurityInstanceId(Link[] objectLinks, String endpoint) { - log.info("Object after discover: [{}]", objectLinks); - for (Link link : objectLinks) { - if (link.getUriReference().startsWith("/0/")) { - try { - LwM2mPath path = new LwM2mPath(link.getUriReference()); - if (path.isObjectInstance()) { - if (link.getAttributes().get("ssid") != null) { - int serverId = Integer.parseInt(link.getAttributes().get("ssid").getCoreLinkValue()); - if (!lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(serverId)) { - lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(serverId, path.getObjectInstanceId()); - } else { - log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId()); - } - lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(serverId, path.getObjectInstanceId()); + protected void findInstancesIdOldByServerId(BootstrapDiscoverResponse discoverResponses, String endpoint) { + log.info("Object after discover: [{}]", Arrays.toString(discoverResponses.getObjectLinks())); + for (Link link : discoverResponses.getObjectLinks()) { + LwM2mPath path = new LwM2mPath(link.getUriReference()); + if (path.isObjectInstance()) { + int lwm2mShortServerId = 0; + if (path.getObjectId() == 0) { + if (link.getAttributes().get("ssid") != null) { + lwm2mShortServerId = Integer.parseInt(link.getAttributes().get("ssid").getCoreLinkValue()); + if (validateLwm2mShortServerId(lwm2mShortServerId)) { + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().putIfAbsent(lwm2mShortServerId, path.getObjectInstanceId()); + } else { + log.error("Invalid lwm2mSecurityInstance [{}] by short server id [{}]", path.getObjectInstanceId(), lwm2mShortServerId); + } + } else { + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().putIfAbsent(BOOTSTRAP_DEFAULT_SHORT_ID_0, path.getObjectInstanceId()); + } + } else if (path.getObjectId() == 1) { + if (link.getAttributes().get("ssid") != null) { + lwm2mShortServerId = Integer.parseInt(link.getAttributes().get("ssid").getCoreLinkValue()); + if (validateLwm2mShortServerId(lwm2mShortServerId)) { + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().putIfAbsent(lwm2mShortServerId, path.getObjectInstanceId()); } else { - if (!this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(0)) { - this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(BOOTSTRAP_DEFAULT_SHORT_ID_0, path.getObjectInstanceId()); - } else { - log.error("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId()); - } + log.error("Invalid lwm2mServerInstance [{}] by short server id [{}]", path.getObjectInstanceId(), lwm2mShortServerId); } } - } catch (Exception e) { - // ignore if this is not a LWM2M path - log.error("Invalid LwM2MPath starting by \"/0/\""); } } } } - protected void findServerInstanceId(BootstrapReadResponse readResponse, String endpoint) { - try { - ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { - var shId = OPAQUE.equals(instance.getResource(0).getType()) ? new BigInteger((byte[]) instance.getResource(0).getValue()).intValue() : instance.getResource(0).getValue(); - int shortId; - if (shId instanceof Long) { - shortId = ((Long) shId).intValue(); - } else { - shortId = (int) shId; - } - this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().put(shortId, instance.getId()); - }); - } catch (Exception e) { - log.error("Failed find Server Instance Id. ", e); - } - } - - protected Integer findBootstrapServerId(String endpoint) { - Integer bootstrapServerIdOld = null; - Map filteredMap = this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().entrySet() - .stream().filter(x -> !this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(x.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - if (filteredMap.size() > 0) { - bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); - } - return bootstrapServerIdOld; - } - public BootstrapConfigStore getStore() { return this.store; } private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) { Link[] links = response.getObjectLinks(); + AtomicReference verDefault = new AtomicReference<>("1.0"); Arrays.stream(links).forEach(link -> { LwM2mPath path = new LwM2mPath(link.getUriReference()); - if (!path.isRoot() && path.getObjectId() < 3) { + if (path.isRoot()) { + if (link.hasAttribute() && link.getAttributes().get("lwm2m") != null) { + verDefault.set(link.getAttributes().get("lwm2m").getValue().toString()); + } + } else if (path.getObjectId() <= ACCESS_CONTROL) { if (path.isObject()) { - String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver").getCoreLinkValue() : "1.0"; + String ver = (link.hasAttribute() && link.getAttributes().get("ver") != null) ? link.getAttributes().get("ver").getCoreLinkValue() : verDefault.get(); this.supportedObjects.put(path.getObjectId(), ver); } } @@ -230,84 +184,103 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask } - public List> toRequests(BootstrapConfig bootstrapConfig, + /** Map + * 1) Only Lwm2m Server + * - Short Server ID == 1 - 65534 lwm2m) + * SECURITY = 0; InstanceId = 0 + * SERVER = 1; InstanceId = 0 + * 2) Both + * - Short Server ID == 0 or 65535 bs) + * SECURITY = 0; InstanceId = 0 + * SERVER = 1; InstanceId = null + * - Short Server ID == 1 - 65534 lwm2m) + * SECURITY = 0; InstanceId = 1 + * SERVER = 1; InstanceId = 0 + * */ + public List> toRequests(BootstrapConfig bootstrapConfigNew, ContentFormat contentFormat, - Integer bootstrapServerIdOld, String endpoint) { + Integer bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID_0); List> requests = new ArrayList<>(); Set pathsDelete = new HashSet<>(); - List> requestsWrite = new ArrayList<>(); - boolean isBsServer = false; - boolean isLwServer = false; - /** Map */ - Map instances = new HashMap<>(); - Integer bootstrapServerIdNew = null; - // handle security - int lwm2mSecurityInstanceId = 0; - int bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID_0); - for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { - if (security.bootstrapServer) { - requestsWrite.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); - isBsServer = true; - bootstrapServerIdNew = security.serverId; - instances.put(security.serverId, bootstrapSecurityInstanceId); - } else { - if (lwm2mSecurityInstanceId == bootstrapSecurityInstanceId) { - lwm2mSecurityInstanceId++; - } - requestsWrite.add(toWriteRequest(lwm2mSecurityInstanceId, security, contentFormat)); - instances.put(security.serverId, lwm2mSecurityInstanceId); - isLwServer = true; - if (!isBsServer && this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(security.serverId) && - lwm2mSecurityInstanceId != this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)) { - pathsDelete.add("/0/" + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)); - } - /** - * If there is an instance in the serverInstances with serverId which we replace in the securityInstances - */ - // find serverId in securityInstances by id (instance) - Integer serverIdOld = null; - for (Map.Entry entry : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().entrySet()) { - if (entry.getValue().equals(lwm2mSecurityInstanceId)) { - serverIdOld = entry.getKey(); - } - } - if (!isBsServer && serverIdOld != null && this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().containsKey(serverIdOld)) { - pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(serverIdOld)); - } - lwm2mSecurityInstanceId++; + ConcurrentHashMap> requestsWrite = new ConcurrentHashMap<>(); + + /// handle security & handle + int lwm2mSecurityInstanceIdMax = -1; + int lwm2mServerInstanceIdMax = -1; + // bootstrap Security new - There can only be one instance of bootstrap at a time. + /// bs: handle security only + for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfigNew.security).values()) { + if (security.bootstrapServer && security.serverId == BOOTSTRAP_DEFAULT_SHORT_ID_0) { + // delete old bootstrap Security + String path = "/" + SECURITY + "/" + bootstrapSecurityInstanceId; + pathsDelete.add(path); + // add new bootstrap Security + requestsWrite.put(path, toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); } } - // handle server - for (Map.Entry server : bootstrapConfig.servers.entrySet()) { - int securityInstanceId = instances.get(server.getValue().shortId); - requestsWrite.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); - if (!isBsServer) { - /** Delete instance if bootstrapServerIdNew not equals bootstrapServerIdOld or securityInstanceBsIdNew not equals serverInstanceBsIdOld */ - if (bootstrapServerIdNew != null && server.getValue().shortId == bootstrapServerIdNew && - (bootstrapServerIdNew != bootstrapServerIdOld || securityInstanceId != this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(bootstrapServerIdOld))) { - pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(bootstrapServerIdOld)); - /** Delete instance if serverIdNew is present in serverInstances and securityInstanceIdOld by serverIdNew not equals serverInstanceIdOld */ - } else if (this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().containsKey(server.getValue().shortId) && - securityInstanceId != this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(server.getValue().shortId)) { - pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(server.getValue().shortId)); - } + + /** lwm2m servers: Multiple instances of lwm2m servers can run simultaneously by SHORT_ID + if update -> delete and write by InstanceId + if new -> only write with InstanceIdMax++ + */ + + /// lwm2m server: handle security & server + //max Lwm2m Security instance old id if new + for (Integer shortId : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().keySet()) { + if (shortId >= BOOTSTRAP_DEFAULT_SHORT_ID_0 && shortId <= LWM2M_DEFAULT_SHORT_ID_65534) { + lwm2mSecurityInstanceIdMax = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(shortId) > + lwm2mSecurityInstanceIdMax ? this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(shortId) : + lwm2mSecurityInstanceIdMax; } } - // handle acl - for (Map.Entry acl : bootstrapConfig.acls.entrySet()) { - requestsWrite.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); + //max Lwm2m Server instance old id if new + for (Integer shortId : this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().keySet()) { + if (shortId >= LWM2M_DEFAULT_SHORT_ID_1 && shortId <= LWM2M_DEFAULT_SHORT_ID_65534) { + lwm2mServerInstanceIdMax = this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(shortId) > + lwm2mServerInstanceIdMax ? this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(shortId) : + lwm2mServerInstanceIdMax; + } } - // handle delete - if (isBsServer && isLwServer) { - requests.add(new BootstrapDeleteRequest("/0")); - requests.add(new BootstrapDeleteRequest("/1")); - } else { - pathsDelete.forEach(pathDelete -> requests.add(new BootstrapDeleteRequest(pathDelete))); + // Lwm2m update or new + for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfigNew.security).values()) { + if (!security.bootstrapServer) { + // Security + boolean isUpdate = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(security.serverId); + Integer secureInstanceId; + Integer serverInstanceId; + if (isUpdate) { + secureInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId); + serverInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(security.serverId); + pathsDelete.add("/" + SECURITY + "/" + secureInstanceId); + pathsDelete.add("/" + SERVER + "/" + serverInstanceId); + } else { + secureInstanceId = ++lwm2mSecurityInstanceIdMax; + serverInstanceId = ++lwm2mServerInstanceIdMax; + } + requestsWrite.put("/" + SECURITY + "/" + secureInstanceId, toWriteRequest(secureInstanceId, security, contentFormat)); + new TreeMap<>(bootstrapConfigNew.servers).values().stream() + .filter(server -> server.shortId == security.serverId) + .findFirst() + .ifPresent(server -> + requestsWrite.put( + "/" + SERVER + "/" + serverInstanceId, + toWriteRequest(serverInstanceId, server, contentFormat) + ) + ); + } } - // handle write - if (requestsWrite.size() > 0) { - requests.addAll(requestsWrite); + + /// handle acl + for (Map.Entry acl : bootstrapConfigNew.acls.entrySet()) { + requestsWrite.put("/" + ACCESS_CONTROL + "/" + acl.getKey(), toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); + } + /// handle delete + pathsDelete.forEach(pathDelete -> requests.add(new BootstrapDeleteRequest(pathDelete))); + + /// handle write + if (!requestsWrite.isEmpty()) { + requests.addAll(requestsWrite.values()); } return (requests); } @@ -315,9 +288,13 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask private void initSupportedObjectsDefault() { this.supportedObjects = new HashMap<>(); - this.supportedObjects.put(0, "1.1"); - this.supportedObjects.put(1, "1.1"); - this.supportedObjects.put(2, "1.0"); + this.supportedObjects.put(SECURITY, "1.1"); + this.supportedObjects.put(SERVER, "1.1"); + this.supportedObjects.put(ACCESS_CONTROL, "1.0"); + } + + private boolean validateLwm2mShortServerId(int id){ + return id >= LWM2M_DEFAULT_SHORT_ID_1 && id <= LWM2M_DEFAULT_SHORT_ID_65534; } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 160ca3d905..7464361c24 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -82,6 +82,8 @@ public class LwM2MTransportUtil { public static final String LOG_LWM2M_ERROR = "error"; public static final String LOG_LWM2M_WARN = "warn"; public static final int BOOTSTRAP_DEFAULT_SHORT_ID_0 = 0; + public static final int LWM2M_DEFAULT_SHORT_ID_1 = 1; + public static final int LWM2M_DEFAULT_SHORT_ID_65534 = 65534; public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) { String path = fromVersionedIdToObjectId(pathIdVer); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 1630a1d220..6756ea2874 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -104,7 +104,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], shortServerId: ['', this.isBootstrap ? [Validators.required, Validators.pattern('^(' + this.shortServerIdBsMin+ '|' + this.shortServerIdBsMax + ')$' )] - : [Validators.required, Validators.pattern('[0-9]*'),Validators.min(this.shortServerIdMin), Validators.max(this.shortServerIdMax)] + : [Validators.required, Validators.pattern('[0-9]*'), Validators.min(this.shortServerIdMin), Validators.max(this.shortServerIdMax)] ], bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], binding: [''],