Browse Source

lwm2m: bootstrap new

pull/14084/head
nickAS21 12 months ago
parent
commit
f19a1ba2a7
  1. 3
      application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java
  2. 2
      application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java
  3. 25
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java
  4. 11
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java
  5. 32
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java
  6. 20
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java
  7. 40
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSNoTriggerTest.java
  8. 61
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationBSTriggerTest.java
  9. 50
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java
  10. 4
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java
  11. 4
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java
  12. 5
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java
  13. 17
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java
  14. 307
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java
  15. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java
  16. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts

3
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);

2
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;

25
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);
}

11
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();

32
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 + "\"}}";

20
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<LwM2MBootstrapServerCredential> 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);

40
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);
}
}

61
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);
}
}

50
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);
}
}

4
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,

4
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,

5
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,

17
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());
}

307
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<LwM2mResponse> 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<Integer, Integer> 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<String> 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<BootstrapDownlinkRequest<? extends LwM2mResponse>> toRequests(BootstrapConfig bootstrapConfig,
/** Map<serverId ("Short Server ID"), InstanceId>
* 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<BootstrapDownlinkRequest<? extends LwM2mResponse>> toRequests(BootstrapConfig bootstrapConfigNew,
ContentFormat contentFormat,
Integer bootstrapServerIdOld,
String endpoint) {
Integer bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID_0);
List<BootstrapDownlinkRequest<? extends LwM2mResponse>> requests = new ArrayList<>();
Set<String> pathsDelete = new HashSet<>();
List<BootstrapDownlinkRequest<? extends LwM2mResponse>> requestsWrite = new ArrayList<>();
boolean isBsServer = false;
boolean isLwServer = false;
/** Map<serverId ("Short Server ID"), InstanceId> */
Map<Integer, Integer> 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<Integer, Integer> 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<String, BootstrapDownlinkRequest<? extends LwM2mResponse>> 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<Integer, BootstrapConfig.ServerConfig> 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<Integer, BootstrapConfig.ACLConfig> 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<Integer, BootstrapConfig.ACLConfig> 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

2
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);

2
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: [''],

Loading…
Cancel
Save