Merge pull request #5631 from thingsboard/lwm2m_include_bootstrap_update
[3.3.3] lwm2m - includes bootstrap update
This commit is contained in:
commit
2eb16eac01
@ -82,6 +82,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
|
||||
" ],\n" +
|
||||
" \"attributeLwm2m\": {}\n" +
|
||||
" },\n" +
|
||||
" \"bootstrapServerUpdateEnable\": true,\n" +
|
||||
" \"bootstrap\": [\n" +
|
||||
" {\n" +
|
||||
" \"host\": \"0.0.0.0\",\n" +
|
||||
|
||||
@ -92,6 +92,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest {
|
||||
" ],\n" +
|
||||
" \"attributeLwm2m\": {}\n" +
|
||||
" },\n" +
|
||||
" \"bootstrapServerUpdateEnable\": true,\n" +
|
||||
" \"bootstrap\": [\n" +
|
||||
" {\n" +
|
||||
" \"host\": \"0.0.0.0\",\n" +
|
||||
|
||||
@ -142,6 +142,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg
|
||||
" ],\n" +
|
||||
" \"attributeLwm2m\": {}\n" +
|
||||
" },\n" +
|
||||
" \"bootstrapServerUpdateEnable\": true,\n" +
|
||||
" \"bootstrap\": [\n" +
|
||||
" {\n" +
|
||||
" \"host\": \"0.0.0.0\",\n" +
|
||||
|
||||
@ -24,6 +24,7 @@ import org.eclipse.leshan.server.security.SecurityInfo;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode;
|
||||
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig;
|
||||
@ -36,6 +37,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -75,6 +77,18 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
BootstrapConfig bsConfigNew = store.getBootstrapConfig();
|
||||
if (bsConfigNew != null) {
|
||||
try {
|
||||
boolean bootstrapServerUpdateEnable = ((Lwm2mDeviceProfileTransportConfiguration)store.getDeviceProfile().getProfileData().getTransportConfiguration()).isBootstrapServerUpdateEnable();
|
||||
if (!bootstrapServerUpdateEnable) {
|
||||
Optional<Map.Entry<Integer, BootstrapConfig.ServerSecurity>> securities = bsConfigNew.security.entrySet().stream().filter(sec -> ((BootstrapConfig.ServerSecurity)sec.getValue()).bootstrapServer==true).findAny();
|
||||
if (securities.isPresent()) {
|
||||
bsConfigNew.security.entrySet().remove(securities.get());
|
||||
int serverSortId = securities.get().getValue().serverId;
|
||||
Optional<Map.Entry<Integer, BootstrapConfig.ServerConfig>> serverConfigs = bsConfigNew.servers.entrySet().stream().filter(serv -> ((BootstrapConfig.ServerConfig)serv.getValue()).shortId==serverSortId).findAny();
|
||||
if (serverConfigs.isPresent()) {
|
||||
bsConfigNew.servers.entrySet().remove(serverConfigs.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String config : bootstrapConfigStore.getAll().keySet()) {
|
||||
if (config.equals(endPoint)) {
|
||||
bootstrapConfigStore.remove(config);
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* 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.bootstrap.store;
|
||||
|
||||
import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
|
||||
import org.eclipse.leshan.server.bootstrap.ConfigurationChecker;
|
||||
import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException;
|
||||
import java.util.Map;
|
||||
|
||||
public class LwM2MConfigurationChecker extends ConfigurationChecker {
|
||||
|
||||
@Override
|
||||
public void verify(BootstrapConfig config) throws InvalidConfigurationException {
|
||||
// check security configurations
|
||||
for (Map.Entry<Integer, BootstrapConfig.ServerSecurity> e : config.security.entrySet()) {
|
||||
BootstrapConfig.ServerSecurity sec = e.getValue();
|
||||
|
||||
// checks security config
|
||||
switch (sec.securityMode) {
|
||||
case NO_SEC:
|
||||
checkNoSec(sec);
|
||||
break;
|
||||
case PSK:
|
||||
checkPSK(sec);
|
||||
break;
|
||||
case RPK:
|
||||
checkRPK(sec);
|
||||
break;
|
||||
case X509:
|
||||
checkX509(sec);
|
||||
break;
|
||||
case EST:
|
||||
throw new InvalidConfigurationException("EST is not currently supported.", e);
|
||||
}
|
||||
|
||||
validateMandatoryField(sec);
|
||||
}
|
||||
|
||||
// does each server have a corresponding security entry?
|
||||
validateOneSecurityByServer(config);
|
||||
}
|
||||
|
||||
protected void validateOneSecurityByServer(BootstrapConfig config) throws InvalidConfigurationException {
|
||||
for (Map.Entry<Integer, BootstrapConfig.ServerConfig> e : config.servers.entrySet()) {
|
||||
BootstrapConfig.ServerConfig srvCfg = e.getValue();
|
||||
|
||||
// shortId checks
|
||||
if (srvCfg.shortId == 0) {
|
||||
throw new InvalidConfigurationException("short ID must not be 0");
|
||||
}
|
||||
|
||||
// look for security entry
|
||||
BootstrapConfig.ServerSecurity security = getSecurityEntry(config, srvCfg.shortId);
|
||||
|
||||
if (security == null) {
|
||||
throw new InvalidConfigurationException("no security entry for server instance: " + e.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static BootstrapConfig.ServerSecurity getSecurityEntry(BootstrapConfig config, int shortId) {
|
||||
for (Map.Entry<Integer, BootstrapConfig.ServerSecurity> es : config.security.entrySet()) {
|
||||
if (es.getValue().serverId == shortId) {
|
||||
return es.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.leshan.core.request.Identity;
|
||||
import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
|
||||
import org.eclipse.leshan.server.bootstrap.BootstrapSession;
|
||||
import org.eclipse.leshan.server.bootstrap.ConfigurationChecker;
|
||||
import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore;
|
||||
import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
@ -36,6 +37,7 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt
|
||||
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||
private final Lock readLock = readWriteLock.readLock();
|
||||
private final Lock writeLock = readWriteLock.writeLock();
|
||||
protected final ConfigurationChecker configChecker = new LwM2MConfigurationChecker();
|
||||
|
||||
@Override
|
||||
public BootstrapConfig get(String endpoint, Identity deviceIdentity, BootstrapSession session) {
|
||||
@ -73,6 +75,26 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt
|
||||
}
|
||||
|
||||
public void addToStore(String endpoint, BootstrapConfig config) throws InvalidConfigurationException {
|
||||
super.add(endpoint, config);
|
||||
|
||||
configChecker.verify(config);
|
||||
// Check PSK identity uniqueness for bootstrap server:
|
||||
PskByServer pskToAdd = getBootstrapPskIdentity(config);
|
||||
if (pskToAdd != null) {
|
||||
BootstrapConfig existingConfig = bootstrapByPskId.get(pskToAdd);
|
||||
if (existingConfig != null) {
|
||||
// check if this config will be replace by the new one.
|
||||
BootstrapConfig previousConfig = bootstrapByEndpoint.get(endpoint);
|
||||
if (previousConfig != existingConfig) {
|
||||
throw new InvalidConfigurationException(
|
||||
"Psk identity [%s] already used for this bootstrap server [%s]", pskToAdd.identity,
|
||||
pskToAdd.serverUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bootstrapByEndpoint.put(endpoint, config);
|
||||
if (pskToAdd != null) {
|
||||
bootstrapByPskId.put(pskToAdd, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,7 +420,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
|
||||
}
|
||||
} else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) {
|
||||
List<LwM2MBootstrapServerCredential> lwM2MBootstrapServersConfigurations = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap();
|
||||
validateLwm2mServersConfigOfBootstrapForClient(lwM2MBootstrapServersConfigurations);
|
||||
validateLwm2mServersConfigOfBootstrapForClient(lwM2MBootstrapServersConfigurations,
|
||||
((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).isBootstrapServerUpdateEnable());
|
||||
for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) {
|
||||
validateLwm2mServersCredentialOfBootstrapForClient(bootstrapServerCredential);
|
||||
}
|
||||
@ -707,11 +708,14 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLwm2mServersConfigOfBootstrapForClient(List<LwM2MBootstrapServerCredential> lwM2MBootstrapServersConfigurations) {
|
||||
private void validateLwm2mServersConfigOfBootstrapForClient(List<LwM2MBootstrapServerCredential> lwM2MBootstrapServersConfigurations, boolean isBootstrapServerUpdateEnable) {
|
||||
Set <String> uris = new HashSet<>();
|
||||
Set <Integer> shortServerIds = new HashSet<>();
|
||||
for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) {
|
||||
AbstractLwM2MBootstrapServerCredential serverConfig = (AbstractLwM2MBootstrapServerCredential) bootstrapServerCredential;
|
||||
if (!isBootstrapServerUpdateEnable && serverConfig.isBootstrapServerIs()) {
|
||||
throw new DeviceCredentialsValidationException("Bootstrap config must not include \"Bootstrap Server\". \"Include Bootstrap Server updates\" is " + isBootstrapServerUpdateEnable + "." );
|
||||
}
|
||||
String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server" + " shortServerId: " + serverConfig.getShortServerId() + ":";
|
||||
if (serverConfig.getShortServerId() < 1 || serverConfig.getShortServerId() > 65534) {
|
||||
throw new DeviceCredentialsValidationException(server + " ShortServerId must not be less than 1 and more than 65534!");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user