16 changed files with 413 additions and 26 deletions
@ -0,0 +1,205 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 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; |
||||
|
|
||||
|
import org.eclipse.californium.core.network.config.NetworkConfig; |
||||
|
import org.eclipse.leshan.client.object.Security; |
||||
|
import org.jetbrains.annotations.NotNull; |
||||
|
import org.junit.Assert; |
||||
|
import org.junit.Test; |
||||
|
import org.thingsboard.common.util.JacksonUtil; |
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.common.data.query.EntityData; |
||||
|
import org.thingsboard.server.common.data.query.EntityDataPageLink; |
||||
|
import org.thingsboard.server.common.data.query.EntityDataQuery; |
||||
|
import org.thingsboard.server.common.data.query.EntityKey; |
||||
|
import org.thingsboard.server.common.data.query.EntityKeyType; |
||||
|
import org.thingsboard.server.common.data.query.SingleEntityFilter; |
||||
|
import org.thingsboard.server.common.data.security.DeviceCredentials; |
||||
|
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
||||
|
import org.thingsboard.server.common.transport.util.SslUtil; |
||||
|
import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper; |
||||
|
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; |
||||
|
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; |
||||
|
import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd; |
||||
|
import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; |
||||
|
import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; |
||||
|
import org.thingsboard.server.transport.lwm2m.secure.credentials.X509ClientCredentialsConfig; |
||||
|
|
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
|
||||
|
import static org.eclipse.leshan.client.object.Security.x509; |
||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
||||
|
|
||||
|
public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { |
||||
|
|
||||
|
protected final String TRANSPORT_CONFIGURATION = "{\n" + |
||||
|
" \"type\": \"LWM2M\",\n" + |
||||
|
" \"observeAttr\": {\n" + |
||||
|
" \"keyName\": {\n" + |
||||
|
" \"/3_1.0/0/9\": \"batteryLevel\"\n" + |
||||
|
" },\n" + |
||||
|
" \"observe\": [],\n" + |
||||
|
" \"attribute\": [\n" + |
||||
|
" ],\n" + |
||||
|
" \"telemetry\": [\n" + |
||||
|
" \"/3_1.0/0/9\"\n" + |
||||
|
" ],\n" + |
||||
|
" \"attributeLwm2m\": {}\n" + |
||||
|
" },\n" + |
||||
|
" \"bootstrap\": {\n" + |
||||
|
" \"servers\": {\n" + |
||||
|
" \"binding\": \"UQ\",\n" + |
||||
|
" \"shortId\": 123,\n" + |
||||
|
" \"lifetime\": 300,\n" + |
||||
|
" \"notifIfDisabled\": true,\n" + |
||||
|
" \"defaultMinPeriod\": 1\n" + |
||||
|
" },\n" + |
||||
|
" \"lwm2mServer\": {\n" + |
||||
|
" \"host\": \"localhost\",\n" + |
||||
|
" \"port\": 5686,\n" + |
||||
|
" \"serverId\": 123,\n" + |
||||
|
" \"serverPublicKey\": \"\",\n" + |
||||
|
" \"bootstrapServerIs\": false,\n" + |
||||
|
" \"clientHoldOffTime\": 1,\n" + |
||||
|
" \"bootstrapServerAccountTimeout\": 0\n" + |
||||
|
" },\n" + |
||||
|
" \"bootstrapServer\": {\n" + |
||||
|
" \"host\": \"localhost\",\n" + |
||||
|
" \"port\": 5687,\n" + |
||||
|
" \"serverId\": 111,\n" + |
||||
|
" \"securityMode\": \"NO_SEC\",\n" + |
||||
|
" \"serverPublicKey\": \"\",\n" + |
||||
|
" \"bootstrapServerIs\": true,\n" + |
||||
|
" \"clientHoldOffTime\": 1,\n" + |
||||
|
" \"bootstrapServerAccountTimeout\": 0\n" + |
||||
|
" }\n" + |
||||
|
" },\n" + |
||||
|
" \"clientLwM2mSettings\": {\n" + |
||||
|
" \"clientOnlyObserveAfterConnect\": 1\n" + |
||||
|
" }\n" + |
||||
|
"}"; |
||||
|
|
||||
|
|
||||
|
private final int port = 5686; |
||||
|
private final NetworkConfig coapConfig = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(port)); |
||||
|
private final String endpoint = "deviceAEndpoint"; |
||||
|
private final String serverUri = "coaps://localhost:" + port; |
||||
|
|
||||
|
@NotNull |
||||
|
private Device createDevice(String credentialsId, X509ClientCredentialsConfig credentialsConfig) throws Exception { |
||||
|
Device device = new Device(); |
||||
|
device.setName("Device A"); |
||||
|
device.setDeviceProfileId(deviceProfile.getId()); |
||||
|
device.setTenantId(tenantId); |
||||
|
device = doPost("/api/device", device, Device.class); |
||||
|
Assert.assertNotNull(device); |
||||
|
|
||||
|
DeviceCredentials deviceCredentials = |
||||
|
doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
||||
|
Assert.assertEquals(device.getId(), deviceCredentials.getDeviceId()); |
||||
|
deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); |
||||
|
|
||||
|
deviceCredentials.setCredentialsId(credentialsId); |
||||
|
|
||||
|
LwM2MCredentials X509Credentials = new LwM2MCredentials(); |
||||
|
|
||||
|
X509Credentials.setClient(credentialsConfig); |
||||
|
|
||||
|
deviceCredentials.setCredentialsValue(JacksonUtil.toString(X509Credentials)); |
||||
|
doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); |
||||
|
return device; |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testConnectAndObserveTelemetry() throws Exception { |
||||
|
createDeviceProfile(TRANSPORT_CONFIGURATION); |
||||
|
|
||||
|
Device device = createDevice(endpoint, new X509ClientCredentialsConfig(null, null)); |
||||
|
|
||||
|
SingleEntityFilter sef = new SingleEntityFilter(); |
||||
|
sef.setSingleEntity(device.getId()); |
||||
|
LatestValueCmd latestCmd = new LatestValueCmd(); |
||||
|
latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); |
||||
|
EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), |
||||
|
Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); |
||||
|
|
||||
|
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); |
||||
|
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); |
||||
|
wrapper.setEntityDataCmds(Collections.singletonList(cmd)); |
||||
|
|
||||
|
wsClient.send(mapper.writeValueAsString(wrapper)); |
||||
|
wsClient.waitForReply(); |
||||
|
|
||||
|
wsClient.registerWaitForUpdate(); |
||||
|
LwM2MTestClient client = new LwM2MTestClient(executor, endpoint); |
||||
|
Security security = x509(serverUri, 123, clientX509Cert.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); |
||||
|
client.init(security, coapConfig); |
||||
|
String msg = wsClient.waitForUpdate(); |
||||
|
|
||||
|
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); |
||||
|
Assert.assertEquals(1, update.getCmdId()); |
||||
|
List<EntityData> eData = update.getUpdate(); |
||||
|
Assert.assertNotNull(eData); |
||||
|
Assert.assertEquals(1, eData.size()); |
||||
|
Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); |
||||
|
Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); |
||||
|
var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); |
||||
|
Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); |
||||
|
client.destroy(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testConnectWithCertAndObserveTelemetry() throws Exception { |
||||
|
createDeviceProfile(TRANSPORT_CONFIGURATION); |
||||
|
Device device = createDevice(null, new X509ClientCredentialsConfig(SslUtil.getCertificateString(clientX509CertNotTrusted), endpoint)); |
||||
|
|
||||
|
SingleEntityFilter sef = new SingleEntityFilter(); |
||||
|
sef.setSingleEntity(device.getId()); |
||||
|
LatestValueCmd latestCmd = new LatestValueCmd(); |
||||
|
latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); |
||||
|
EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), |
||||
|
Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); |
||||
|
|
||||
|
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); |
||||
|
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); |
||||
|
wrapper.setEntityDataCmds(Collections.singletonList(cmd)); |
||||
|
|
||||
|
wsClient.send(mapper.writeValueAsString(wrapper)); |
||||
|
wsClient.waitForReply(); |
||||
|
|
||||
|
wsClient.registerWaitForUpdate(); |
||||
|
LwM2MTestClient client = new LwM2MTestClient(executor, endpoint); |
||||
|
|
||||
|
Security security = x509(serverUri, 123, clientX509CertNotTrusted.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); |
||||
|
|
||||
|
client.init(security, coapConfig); |
||||
|
String msg = wsClient.waitForUpdate(); |
||||
|
|
||||
|
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); |
||||
|
Assert.assertEquals(1, update.getCmdId()); |
||||
|
List<EntityData> eData = update.getUpdate(); |
||||
|
Assert.assertNotNull(eData); |
||||
|
Assert.assertEquals(1, eData.size()); |
||||
|
Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); |
||||
|
Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); |
||||
|
var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); |
||||
|
Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); |
||||
|
client.destroy(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
transport.lwm2m.security.key_store=lwm2m/credentials/serverKeyStore.jks |
||||
|
transport.lwm2m.security.key_store_password=server |
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue