diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index a12887db81..41d99a682b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -719,7 +719,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { void processCredentialsUpdate(TbActorMsg msg) { if (((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials().getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { sessions.forEach((k, v) -> { - notifyTransportAboutProfileUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); + notifyTransportAboutDeviceCredentialsUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); }); } else { sessions.forEach((sessionId, sessionMd) -> notifyTransportAboutClosedSession(sessionId, sessionMd, "device credentials updated!")); @@ -747,7 +747,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); } - void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { + void notifyTransportAboutDeviceCredentialsUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { ToTransportUpdateCredentialsProto.Builder notification = ToTransportUpdateCredentialsProto.newBuilder(); notification.addCredentialsId(deviceCredentials.getCredentialsId()); notification.addCredentialsValue(deviceCredentials.getCredentialsValue()); 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 0e6d2933e4..097b69f806 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 @@ -34,6 +34,7 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.ArrayList; import java.util.Iterator; @@ -79,17 +80,19 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public BootstrapSession begin(BootstrapRequest request, Identity clientIdentity) { - boolean authorized; + boolean authorized = true; Iterator securityInfos; - if (bsSecurityStore != null && securityChecker != null) { - if (clientIdentity.isSecure() && clientIdentity.isPSK()) { - securityInfos = bsSecurityStore.getAllByEndpoint(clientIdentity.getPskIdentity()); - } else { - securityInfos = bsSecurityStore.getAllByEndpoint(request.getEndpointName()); + try { + if (bsSecurityStore != null && securityChecker != null) { + if (clientIdentity.isSecure() && clientIdentity.isPSK()) { + securityInfos = bsSecurityStore.getAllByEndpoint(clientIdentity.getPskIdentity()); + } else { + securityInfos = bsSecurityStore.getAllByEndpoint(request.getEndpointName()); + } + authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); } - authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); - } else { - authorized = true; + } catch (LwM2MAuthException e) { + authorized = false; } DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized); if (authorized) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index 5cb8390ef9..a836eae27e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -29,7 +29,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; -import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import java.util.Arrays; @@ -40,7 +40,7 @@ import java.util.Arrays; public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; - private final TbSecurityStore securityStore; + private final TbMainSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); private final LwM2mClientContext clientContext; @@ -60,8 +60,7 @@ public class TbLwM2MAuthorizer implements Authorizer { } // If session info is not found, this may be the trusted certificate, so we still need to check all other options below. } - SecurityInfo expectedSecurityInfo = null; - if (securityStore != null) { + SecurityInfo expectedSecurityInfo; try { expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); if (expectedSecurityInfo != null && expectedSecurityInfo.usePSK() && expectedSecurityInfo.getEndpoint().equals(SecurityMode.NO_SEC.toString()) @@ -73,10 +72,10 @@ public class TbLwM2MAuthorizer implements Authorizer { log.info("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint()); return null; } - } if (securityChecker.checkSecurityInfo(registration.getEndpoint(), senderIdentity, expectedSecurityInfo)) { return registration; } else { + securityStore.remove(registration.getEndpoint(), registration.getId()); return null; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index c4b9ea3f27..b5b682ed0d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -25,7 +25,6 @@ import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; -import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.springframework.stereotype.Component; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.DataConstants; @@ -33,7 +32,6 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index b3c07c91b9..3e0ad17925 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java @@ -19,10 +19,10 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.ResourceType; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.transport.SessionMsgListener; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; @@ -108,4 +108,10 @@ public class LwM2mSessionMsgListener implements GenericFutureListener 0) { + if (otaData != null && otaData.length > 0) { + log.debug("Read ota data (length): [{}]", otaData.length); response.setPayload(otaData); if (exchange.getRequestOptions().getBlock2() != null) { int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); @@ -150,6 +150,8 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { log.trace("With block1 Send currentId: [{}], length: [{}], ", currentId.toString(), otaData.length); } exchange.respond(response); + } else { + log.trace("Ota packaged currentId: [{}] is not found.", currentId.toString()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index 8d97e775c6..239becdda3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -57,8 +57,6 @@ public interface LwM2mClientContext { void update(LwM2mClient lwM2MClient); - void removeCredentials(TransportProtos.SessionInfoProto sessionInfo); - void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); void onUplink(LwM2mClient client); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 827152db7b..b0fea97205 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -328,11 +328,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } } - @Override - public void removeCredentials(TransportProtos.SessionInfoProto sessionInfo) { - //TODO: implement - } - @Override public void sendMsgsAfterSleeping(LwM2mClient lwM2MClient) { if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 0a30f2df72..0b253ecc20 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -399,6 +399,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); startUpdateUsingBinary(client, fwInfo); } + } else { + log.debug("[{}] failed to process firmware update: [{}]. Previous update failed.", client.getEndpoint(), fwInfo); + logService.log(client, "Failed to process firmware update: " + fwInfo + ". Previous update failed."); } } catch (Exception e) { log.info("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e); @@ -424,6 +427,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startUpdateUsingBinary(client, swInfo); } } + } else { + log.debug("[{}] failed to update client: [{}], previous update failed.", client.getEndpoint(), swInfo); + logService.log(client, "Failed to process software update: " + swInfo + ". Previous update failed."); } } catch (Exception e) { log.info("[{}] failed to update client: {}", client.getEndpoint(), swInfo, e); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index e60680e5fb..7732948c27 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -42,6 +42,7 @@ import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.registration.RegistrationStore; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.DonAsynchron; @@ -52,6 +53,7 @@ import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.OtaPackageUtil; import org.thingsboard.server.common.transport.TransportService; @@ -85,10 +87,10 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; -import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -147,6 +149,8 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl private final LwM2mClientContext clientContext; private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; private final LwM2mVersionedModelProvider modelProvider; + private final RegistrationStore registrationStore; + private final TbLwM2mSecurityStore securityStore; public DefaultLwM2mUplinkMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, @@ -159,7 +163,9 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore, - LwM2mVersionedModelProvider modelProvider) { + LwM2mVersionedModelProvider modelProvider, + RegistrationStore registrationStore, + TbLwM2mSecurityStore securityStore) { this.transportService = transportService; this.sessionManager = sessionManager; this.attributesService = attributesService; @@ -172,6 +178,8 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl this.context = context; this.sessionStore = sessionStore; this.modelProvider = modelProvider; + this.registrationStore = registrationStore; + this.securityStore = securityStore; } @PostConstruct @@ -277,26 +285,27 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param observations - !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect */ public void unReg(Registration registration, Collection observations) { - executor.submit(() -> { - LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); - try { - logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); - clientContext.unregister(client, registration); - SessionInfoProto sessionInfo = client.getSession(); - if (sessionInfo != null) { - sessionManager.deregister(sessionInfo); - sessionStore.remove(registration.getEndpoint()); - log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); - } else { - log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } - } catch (LwM2MClientStateException stateException) { - log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); - } catch (Throwable t) { - log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); - logService.log(client, LOG_LWM2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage())); + executor.submit(() -> doUnReg(registration, clientContext.getClientByEndpoint(registration.getEndpoint()))); + } + + private void doUnReg(Registration registration, LwM2mClient client) { + try { + logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); + clientContext.unregister(client, registration); + SessionInfoProto sessionInfo = client.getSession(); + if (sessionInfo != null) { + sessionManager.deregister(sessionInfo); + sessionStore.remove(registration.getEndpoint()); + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } - }); + } catch (LwM2MClientStateException stateException) { + log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); + logService.log(client, LOG_LWM2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage())); + } } @Override @@ -394,6 +403,11 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl } } + @Override + public void onDeviceDelete(DeviceId deviceId) { + clearAndUnregister(clientContext.getClientByDeviceId(deviceId.getId())); + } + @Override public void onResourceUpdate(TransportProtos.ResourceUpdateMsg resourceUpdateMsgOpt) { String idVer = resourceUpdateMsgOpt.getResourceKey(); @@ -902,8 +916,8 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl */ @Override public void onToTransportUpdateCredentials(SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials) { - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList()); - this.clientContext.removeCredentials(sessionInfo); + log.info("[{}] updateCredentials", sessionInfo); + clearAndUnregister(clientContext.getClientBySessionInfo(sessionInfo)); } /** @@ -980,4 +994,16 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl .setLastActivityTime(System.currentTimeMillis()) .build(), TransportServiceCallback.EMPTY); } + + private void clearAndUnregister(LwM2mClient client) { + client.lock(); + try { + Registration registration = client.getRegistration(); + doUnReg(registration, client); + securityStore.remove(registration.getEndpoint(), registration.getId()); + registrationStore.removeRegistration(registration.getId()); + } finally { + client.unlock(); + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index 2d8139bf9b..ca706c8138 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -24,6 +24,7 @@ import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -49,6 +50,8 @@ public interface LwM2mUplinkMsgHandler { void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt); + void onDeviceDelete(DeviceId deviceId); + void onResourceUpdate(TransportProtos.ResourceUpdateMsg resourceUpdateMsgOpt); void onResourceDelete(TransportProtos.ResourceDeleteMsg resourceDeleteMsgOpt); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 7a778762b8..3e4d49b21b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.util.SecurityUtil; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; @@ -89,7 +90,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen private DeviceCredentials saveOrUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) { if (deviceCredentials.getCredentialsType() == null) { - throw new DataValidationException("Device credentials type should be specified"); + throw new DataValidationException("Device credentials type must be specified"); } formatCredentials(deviceCredentials); log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); @@ -199,36 +200,36 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen private void validateLwM2MDeviceCredentials(LwM2MDeviceCredentials lwM2MCredentials) { if (lwM2MCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M credentials must be specified!"); } LwM2MClientCredentials clientCredentials = lwM2MCredentials.getClient(); if (clientCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M client credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client credentials must be specified!"); } validateLwM2MClientCredentials(clientCredentials); LwM2MBootstrapCredentials bootstrapCredentials = lwM2MCredentials.getBootstrap(); if (bootstrapCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M bootstrap credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M bootstrap credentials must be specified!"); } LwM2MServerCredentials bootstrapServerCredentials = bootstrapCredentials.getBootstrapServer(); if (bootstrapServerCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M bootstrap server credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M bootstrap server credentials must be specified!"); } validateServerCredentials(bootstrapServerCredentials, "Bootstrap server"); LwM2MServerCredentials lwm2mServerCredentials = bootstrapCredentials.getLwm2mServer(); if (lwm2mServerCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M lwm2m server credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M lwm2m server credentials must be specified!"); } validateServerCredentials(lwm2mServerCredentials, "LwM2M server"); } private void validateLwM2MClientCredentials(LwM2MClientCredentials clientCredentials) { if (StringUtils.isBlank(clientCredentials.getEndpoint())) { - throw new DeviceCredentialsValidationException("LwM2M client endpoint should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client endpoint must be specified!"); } switch (clientCredentials.getSecurityConfigClientMode()) { @@ -237,26 +238,31 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKClientCredentials pskCredentials = (PSKClientCredentials) clientCredentials; if (StringUtils.isBlank(pskCredentials.getIdentity())) { - throw new DeviceCredentialsValidationException("LwM2M client PSK identity should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified!"); + } + // SecurityMode.NO_SEC.toString() == "NO_SEC"; + if (pskCredentials.getIdentity().equals(SecurityMode.NO_SEC.toString())) { + throw new DeviceCredentialsValidationException("The PSK ID of the LwM2M client must not be '" + SecurityMode.NO_SEC + "'!"); } String pskKey = pskCredentials.getKey(); if (StringUtils.isBlank(pskKey)) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key must be specified!"); } if (!pskKey.matches("-?[0-9a-fA-F]+")) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key should be random sequence in hex encoding!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key must be random sequence in hex encoding!"); } if (pskKey.length()% 32 != 0 || pskKey.length() > 128) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key length = " + pskKey.length() + ". Key must be HexDec format: 32, 64, 128 characters!"); } + break; case RPK: RPKClientCredentials rpkCredentials = (RPKClientCredentials) clientCredentials; if (StringUtils.isBlank(rpkCredentials.getKey())) { - throw new DeviceCredentialsValidationException("LwM2M client RPK key should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client RPK key must be specified!"); } try { @@ -264,7 +270,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkCredentials.setKey(pubkClient); SecurityUtil.publicKey.decode(rpkCredentials.getDecoded()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException("LwM2M client RPK key must be in standard [RFC7250] and support only EC algorithm and then encoded to Base64 format!"); } break; case X509: @@ -275,7 +281,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509CCredentials.setCert(certClient); SecurityUtil.certificate.decode(x509CCredentials.getDecoded()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException("LwM2M client X509 certificate must be in DER-encoded X509v3 format and support only EC algorithm and then encoded to Base64 format!"); } } break; @@ -289,37 +295,42 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKServerCredentials pskCredentials = (PSKServerCredentials) serverCredentials; if (StringUtils.isBlank(pskCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client PSK public key or id should be specified!"); + throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified!"); + } + + // SecurityMode.NO_SEC.toString() == "NO_SEC"; + if (pskCredentials.getClientPublicKeyOrId().equals(SecurityMode.NO_SEC.toString())) { + throw new DeviceCredentialsValidationException(server + " client PSK public key or id must not be '" + SecurityMode.NO_SEC + "'!"); } String pskKey = pskCredentials.getClientSecretKey(); if (StringUtils.isBlank(pskKey)) { - throw new DeviceCredentialsValidationException(server + " client PSK key should be specified!"); + throw new DeviceCredentialsValidationException(server + " client PSK key must be specified!"); } if (!pskKey.matches("-?[0-9a-fA-F]+")) { - throw new DeviceCredentialsValidationException(server + " client PSK key should be random sequence in hex encoding!"); + throw new DeviceCredentialsValidationException(server + " client PSK key must be random sequence in hex encoding!"); } if (pskKey.length() % 32 != 0 || pskKey.length() > 128) { - throw new DeviceCredentialsValidationException(server + " client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); + throw new DeviceCredentialsValidationException(server + " client PSK key length = " + pskKey.length() + ". Key must be HexDec format: 32, 64, 128 characters!"); } break; case RPK: RPKServerCredentials rpkServerCredentials = (RPKServerCredentials) serverCredentials; if (StringUtils.isEmpty(rpkServerCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be specified!"); + throw new DeviceCredentialsValidationException(server + " client RPK public key or id must be specified!"); } try { String pubkRpkSever = EncryptionUtil.pubkTrimNewLines(rpkServerCredentials.getClientPublicKeyOrId()); rpkServerCredentials.setClientPublicKeyOrId(pubkRpkSever); SecurityUtil.publicKey.decode(rpkServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client RPK public key or id must be in standard [RFC7250 ] and then encoded to Base64 format!"); } if (StringUtils.isEmpty(rpkServerCredentials.getClientSecretKey())) { - throw new DeviceCredentialsValidationException(server + " client RPK secret key should be specified!"); + throw new DeviceCredentialsValidationException(server + " client RPK secret key must be specified!"); } try { @@ -327,13 +338,13 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkServerCredentials.setClientSecretKey(prikRpkSever); SecurityUtil.privateKey.decode(rpkServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client RPK secret key must be in PKCS#8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!"); } break; case X509: X509ServerCredentials x509ServerCredentials = (X509ServerCredentials) serverCredentials; if (StringUtils.isBlank(x509ServerCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be specified!"); + throw new DeviceCredentialsValidationException(server + " client X509 public key or id must be specified!"); } try { @@ -341,10 +352,10 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509ServerCredentials.setClientPublicKeyOrId(certServer); SecurityUtil.certificate.decode(x509ServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 public key or id must be in DER-encoded X509v3 format and support only EC algorithm and then encoded to Base64 format!"); } if (StringUtils.isBlank(x509ServerCredentials.getClientSecretKey())) { - throw new DeviceCredentialsValidationException(server + " client X509 secret key should be specified!"); + throw new DeviceCredentialsValidationException(server + " client X509 secret key must be specified!"); } try { @@ -352,7 +363,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509ServerCredentials.setClientSecretKey(prikX509Sever); SecurityUtil.privateKey.decode(x509ServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 secret key must be in PKCS#8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!"); } break; }