From 626b6620dd1fcad12ea25f6b410899a7b5ff45b9 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 7 Jun 2021 15:59:30 +0300 Subject: [PATCH 1/2] Refactoring to avoid race conditions on device registration --- .../DefaultLwM2MTransportMsgHandler.java | 202 +++++++++--------- .../lwm2m/server/LwM2mServerListener.java | 4 +- .../server/LwM2mTransportMsgHandler.java | 5 +- .../lwm2m/server/LwM2mTransportRequest.java | 46 ++-- .../lwm2m/server/client/LwM2MClientState.java | 22 ++ .../client/LwM2MClientStateException.java | 31 +++ .../lwm2m/server/client/LwM2mClient.java | 56 +++-- .../server/client/LwM2mClientContext.java | 21 +- .../server/client/LwM2mClientContextImpl.java | 172 ++++++++------- .../lwm2m/server/client/LwM2mFwSwUpdate.java | 4 +- .../server/store/TbLwM2mSecurityStore.java | 4 +- 11 files changed, 328 insertions(+), 239 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 04dec8965a..41fcb1c9cb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -58,6 +58,8 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper; import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; @@ -91,7 +93,6 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWN import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_ID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID; @@ -184,9 +185,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler registrationExecutor.submit(() -> { try { log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); - LwM2mClient lwM2MClient = this.clientContext.registerOrUpdate(registration); + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); if (lwM2MClient != null) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + this.clientContext.register(lwM2MClient, registration); + SessionInfoProto sessionInfo = lwM2MClient.getSession(); if (sessionInfo != null) { transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() @@ -199,13 +201,19 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.getInfoFirmwareUpdate(lwM2MClient, null); this.getInfoSoftwareUpdate(lwM2MClient, null); this.initLwM2mFromClientValue(registration, lwM2MClient); - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId()); + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_INFO + ": Client create after Registration"); } else { log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } } else { log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); } + } catch (LwM2MClientStateException stateException) { + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) { + log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState()); + // Race condition detected and the client was in progress of unregistration while new registration arrived. Let's try again. + onRegistered(registration, previousObservations); + } } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); } @@ -219,25 +227,26 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public void updatedReg(Registration registration) { updateRegistrationExecutor.submit(() -> { + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); try { - LwM2mClient client = clientContext.getOrRegister(registration); - if (client != null && client.getSession() != null) { - SessionInfoProto sessionInfo = client.getSession(); - this.reportActivityAndRegister(sessionInfo); - if (registration.getQueueMode()) { - LwM2mQueuedRequest request; - while ((request = client.getQueuedRequests().poll()) != null) { - request.send(); - } + clientContext.updateRegistration(lwM2MClient, registration); + TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession(); + this.reportActivityAndRegister(sessionInfo); + if (registration.getQueueMode()) { + LwM2mQueuedRequest request; + while ((request = lwM2MClient.getQueuedRequests().poll()) != null) { + request.send(); } - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client update Registration", registration.getId()); + } + } catch (LwM2MClientStateException stateException) { + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) { + log.info("[{}] update registration failed because client was already unregistered: [{}].", registration.getEndpoint(), stateException.getState()); } else { - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - this.sendLogsToThingsboard(LOG_LW2M_ERROR + ": Client update Registration", registration.getId()); + log.info("[{}] update registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); } } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t); - this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()), registration.getId()); + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage())); } }); } @@ -248,34 +257,32 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public void unReg(Registration registration, Collection observations) { unRegistrationExecutor.submit(() -> { + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); try { - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); - this.closeClientSession(registration); + this.sendLogsToThingsboard(client, LOG_LW2M_INFO + ": Client unRegistration"); + clientContext.unregister(client, registration); + SessionInfoProto sessionInfo = client.getSession(); + if (sessionInfo != null) { + transportService.deregisterSession(sessionInfo); + sessionStore.remove(registration.getEndpoint()); + this.doCloseSession(sessionInfo); + 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); - this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()), registration.getId()); + this.sendLogsToThingsboard(client, LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage())); } }); } - private void closeClientSession(Registration registration) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration); - if (sessionInfo != null) { - transportService.deregisterSession(sessionInfo); - sessionStore.remove(registration.getEndpoint()); - this.doCloseSession(sessionInfo); - clientContext.removeClientByRegistrationId(registration.getId()); - 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); - } - } - @Override public void onSleepingDev(Registration registration) { log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration.getId()); - + this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is sleeping!"); //TODO: associate endpointId with device information. } @@ -300,7 +307,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { if (response.getContent() != null) { - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider()); if (objectModelVersion != null) { if (response.getContent() instanceof LwM2mObject) { @@ -332,7 +339,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } String msg = String.format("%s: type operation %s path - %s value - %s", LOG_LW2M_INFO, READ, pathIdVer, value); - this.sendLogsToThingsboard(msg, registration.getId()); + this.sendLogsToThingsboard(lwM2MClient, msg); rpcRequest.setValueMsg(String.format("%s", value)); this.sentRpcResponse(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE); } @@ -352,7 +359,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo); if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { - log.warn ("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList()); + log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList()); msg.getSharedUpdatedList().forEach(tsKvProto -> { String pathName = tsKvProto.getKv().getKey(); String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); @@ -377,13 +384,13 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew); String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", LOG_LW2M_ERROR, pathIdVer, valueNew); - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sendLogsToThingsboard(lwM2MClient, logMsg); } } else if (!isFwSwWords(pathName)) { log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew); String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", LOG_LW2M_ERROR, pathName, valueNew); - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sendLogsToThingsboard(lwM2MClient, logMsg); } }); @@ -396,9 +403,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } }); log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); - } - else if (lwM2MClient == null) { - log.error ("OnAttributeUpdate, lwM2MClient is null"); + } else if (lwM2MClient == null) { + log.error("OnAttributeUpdate, lwM2MClient is null"); } } @@ -408,12 +414,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ @Override public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { - Set clients = clientContext.getLwM2mClients() - .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toSet()); + List clients = clientContext.getLwM2mClients() + .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList()); clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); - Set registrationIds = clients.stream().map(LwM2mClient::getRegistration).map(Registration::getId).collect(Collectors.toSet()); - if (registrationIds.size() > 0) { - this.onDeviceProfileUpdate(registrationIds, deviceProfile); + if (clients.size() > 0) { + this.onDeviceProfileUpdate(clients, deviceProfile); } } @@ -446,7 +451,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) { // #1 this.checkRpcRequestTimeout(); - log.warn ("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); + log.warn("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); String bodyParams = StringUtils.trimToNull(toDeviceRpcRequestMsg.getParams()) != null ? toDeviceRpcRequestMsg.getParams() : "null"; LwM2mTypeOper lwM2mTypeOper = setValidTypeOper(toDeviceRpcRequestMsg.getMethodName()); UUID requestUUID = new UUID(toDeviceRpcRequestMsg.getRequestIdMSB(), toDeviceRpcRequestMsg.getRequestIdLSB()); @@ -506,7 +511,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, SessionInfoProto sessionInfo) { - log.warn ("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); + log.warn("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); transportService.process(sessionInfo, toDeviceResponse, null); } @@ -558,7 +563,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void onAwakeDev(Registration registration) { log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId()); + this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is awake!"); //TODO: associate endpointId with device information. } @@ -567,13 +572,17 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param registrationId - Id of Registration LwM2M Client */ @Override - public void sendLogsToThingsboard(String logMsg, String registrationId) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registrationId); - if (logMsg != null && sessionInfo != null) { + public void sendLogsToThingsboard2(String registrationId, String logMsg) { + sendLogsToThingsboard(clientContext.getClientByRegistrationId(registrationId), logMsg); + } + + @Override + public void sendLogsToThingsboard(LwM2mClient client, String logMsg) { + if (logMsg != null && client != null && client.getSession() != null) { if (logMsg.length() > 1024) { logMsg = logMsg.substring(0, 1024); } - this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo); + this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), client.getSession()); } } @@ -645,7 +654,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param path - resource */ private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) { /** version != null * set setClient_fw_info... = value @@ -798,7 +807,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional deviceProfileOpt) { - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singleton(lwM2MClient.getRegistration().getId()), deviceProfile)); + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile)); lwM2MClient.onDeviceUpdate(device, deviceProfileOpt); } @@ -843,7 +852,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) { - LwM2mClient lwM2MClient = this.clientContext.getClientByRegistrationId(registration.getId()); + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); JsonObject names = clientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile(); if (names != null && names.has(pathIdVer)) { String resourceName = names.get(pathIdVer).getAsString(); @@ -892,9 +901,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); - } - - else { + } else { return null; } } @@ -955,10 +962,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * #6.1 - update WriteAttribute * #6.2 - del WriteAttribute * - * @param registrationIds - - * @param deviceProfile - + * @param clients - + * @param deviceProfile - */ - private void onDeviceProfileUpdate(Set registrationIds, DeviceProfile deviceProfile) { + private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); if (clientContext.profileUpdate(deviceProfile) != null) { // #1 @@ -1009,15 +1016,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // #3.4, #6 if (!attributeLwm2mOld.equals(attributeLwm2mNew)) { - this.getAnalyzerAttributeLwm2m(registrationIds, attributeLwm2mOld, attributeLwm2mNew); + this.getAnalyzerAttributeLwm2m(clients, attributeLwm2mOld, attributeLwm2mNew); } // #4.1 add if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) { // update value in Resources - registrationIds.forEach(registrationId -> { - Registration registration = clientContext.getRegistration(registrationId); - this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); + clients.forEach(client -> { + this.readObserveFromProfile(client.getRegistration(), sendAttrToThingsboard.getPathPostParametersAdd(), READ); }); } // #4.2 del @@ -1041,8 +1047,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // does not include oldObserve ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd()); // send Request observe to Client - registrationIds.forEach(registrationId -> { - Registration registration = clientContext.getRegistration(registrationId); + clients.forEach(client -> { + Registration registration = client.getRegistration(); if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) { this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); } @@ -1124,7 +1130,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param attributeLwm2mNew - * @return */ - private void getAnalyzerAttributeLwm2m(Set registrationIds, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) { + private void getAnalyzerAttributeLwm2m(List clients, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) { ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); ConcurrentHashMap lwm2mAttributesOld = new Gson().fromJson(attributeLwm2mOld.toString(), new TypeToken>() { @@ -1146,8 +1152,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // #6 // #6.2 if (analyzerParameters.getPathPostParametersAdd().size() > 0) { - registrationIds.forEach(registrationId -> { - Registration registration = this.clientContext.getRegistration(registrationId); + clients.forEach(client -> { + Registration registration = client.getRegistration(); Set clientObjects = clientContext.getSupportedIdVerInClient(registration); Set pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) .collect(Collectors.toUnmodifiableSet()); @@ -1160,8 +1166,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } // #6.2 if (analyzerParameters.getPathPostParametersDel().size() > 0) { - registrationIds.forEach(registrationId -> { - Registration registration = this.clientContext.getRegistration(registrationId); + clients.forEach(client -> { + Registration registration = client.getRegistration(); Set clientObjects = clientContext.getSupportedIdVerInClient(registration); Set pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) .collect(Collectors.toUnmodifiableSet()); @@ -1180,7 +1186,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } private void cancelObserveFromProfile(Registration registration, Set paramAnallyzer) { - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); paramAnallyzer.forEach(pathIdVer -> { if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) { lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null, @@ -1199,7 +1205,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler log.error("Failed update resource [{}] [{}]", path, valueNew); String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad", LOG_LW2M_ERROR, path, valueNew); - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sendLogsToThingsboard(lwM2MClient, logMsg); log.info("Failed update resource [{}] [{}]", path, valueNew); } } @@ -1275,8 +1281,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), getValueFromKvProto(tsKvProto.getKv()), pathIdVer); }); - } - else { + } else { log.error("UpdateAttributeFromThingsboard, lwM2MClient is null"); } } @@ -1285,14 +1290,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param lwM2MClient - * @return SessionInfoProto - */ - private SessionInfoProto getSessionInfoOrCloseSession(LwM2mClient lwM2MClient) { - if (lwM2MClient != null) { - SessionInfoProto sessionInfoProto = lwM2MClient.getSession(); - if (sessionInfoProto == null) { - log.info("[{}] [{}]", lwM2MClient.getEndpoint(), CLIENT_NOT_AUTHORIZED); - this.closeClientSession(lwM2MClient.getRegistration()); - } - return sessionInfoProto; + private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) { + if (lwM2MClient != null && lwM2MClient.getSession() != null) { + return lwM2MClient.getSession(); } return null; } @@ -1302,15 +1302,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @return - sessionInfo after access connect client */ public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) { - return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration)); - } - - /** - * @param registrationId - - * @return - - */ - private SessionInfoProto getSessionInfoOrCloseSession(String registrationId) { - return getSessionInfoOrCloseSession(clientContext.getClientByRegistrationId(registrationId)); + return getSessionInfo(clientContext.getClientByEndpoint(registration.getEndpoint())); } /** @@ -1340,7 +1332,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param lwM2MClient - LwM2M Client */ public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); if (sessionInfo != null) { //#1.1 ConcurrentMap keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); @@ -1359,7 +1351,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) { if (lwM2MClient.getRegistration().getSupportedVersion(FW_ID) != null) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); if (sessionInfo != null) { DefaultLwM2MTransportMsgHandler handler = this; this.transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.FIRMWARE.name()), @@ -1368,16 +1360,15 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) { if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus()) && response.getType().equals(OtaPackageType.FIRMWARE.name())) { - log.warn ("7) firmware start with ver: [{}]", response.getVersion()); + log.warn("7) firmware start with ver: [{}]", response.getVersion()); lwM2MClient.getFwUpdate().setRpcRequest(rpcRequest); lwM2MClient.getFwUpdate().setCurrentVersion(response.getVersion()); lwM2MClient.getFwUpdate().setCurrentTitle(response.getTitle()); lwM2MClient.getFwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId()); if (rpcRequest == null) { lwM2MClient.getFwUpdate().sendReadObserveInfo(lwM2mTransportRequest); - } - else { - lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); + } else { + lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); } } else { log.trace("OtaPackage [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); @@ -1395,7 +1386,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) { if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); if (sessionInfo != null) { DefaultLwM2MTransportMsgHandler handler = this; transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.SOFTWARE.name()), @@ -1411,9 +1402,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest); if (rpcRequest == null) { lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest); - } - else { - lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); + } else { + lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); } } else { log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index f0e11aceb4..f1839e718a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -87,7 +87,7 @@ public class LwM2mServerListener { @Override public void cancelled(Observation observation) { String msg = String.format("%s: Canceled Observation %s.", LOG_LW2M_INFO, observation.getPath()); - service.sendLogsToThingsboard(msg, observation.getRegistrationId()); + service.sendLogsToThingsboard2(observation.getRegistrationId(), msg); log.warn(msg); } @@ -109,7 +109,7 @@ public class LwM2mServerListener { String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO, observation.getPath()); log.warn(msg); - service.sendLogsToThingsboard(msg, registration.getId()); + service.sendLogsToThingsboard2(registration.getId(), msg); } }; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java index 794df65db5..36f1209ff3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; import java.util.Collection; @@ -63,7 +64,9 @@ public interface LwM2mTransportMsgHandler { void onAwakeDev(Registration registration); - void sendLogsToThingsboard(String msg, String registrationId); + void sendLogsToThingsboard(LwM2mClient client, String msg); + + void sendLogsToThingsboard2(String registrationId, String msg); LwM2MTransportServerConfig getConfig(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index d1adde5515..d382b0b734 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java @@ -127,10 +127,10 @@ public class LwM2mTransportRequest { public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) { + LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()); try { String target = convertPathFromIdVerToObjectId(targetIdVer); ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; - LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration); LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null; if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { if (lwM2MClient.isValidObjectVersion(targetIdVer)) { @@ -185,7 +185,7 @@ public class LwM2mTransportRequest { } String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO, typeOper.name(), paths); - this.handler.sendLogsToThingsboard(msg, registration.getId()); + this.handler.sendLogsToThingsboard(lwM2MClient, msg); if (lwm2mClientRpcRequest != null) { String valueMsg = String.format("Paths - %s", paths); this.handler.sentRpcResponse(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); @@ -204,7 +204,7 @@ public class LwM2mTransportRequest { observeCancelMsg = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO, OBSERVE_CANCEL.name(), observeCancelCnt); } - this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest); + this.afterObserveCancel(lwM2MClient, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest); break; // lwm2mClientRpcRequest != null case FW_UPDATE: @@ -215,7 +215,7 @@ public class LwM2mTransportRequest { } catch (Exception e) { String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, typeOper.name(), e.getMessage()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); if (lwm2mClientRpcRequest != null) { String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage()); handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); @@ -273,7 +273,7 @@ public class LwM2mTransportRequest { contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat); request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type, - registration, rpcRequest); + lwM2MClient, rpcRequest); } break; case WRITE_UPDATE: @@ -337,11 +337,11 @@ public class LwM2mTransportRequest { lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); } if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { - this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest); + this.handleResponse(lwM2MClient, request.getPath().toString(), response, request, rpcRequest); } else { String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(), ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); if (!lwM2MClient.isInit()) { @@ -388,7 +388,7 @@ public class LwM2mTransportRequest { } String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString()); if (rpcRequest != null) { handler.sentRpcResponse(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR); @@ -398,7 +398,7 @@ public class LwM2mTransportRequest { private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type, - Registration registration, Lwm2mClientRpcRequest rpcRequest) { + LwM2mClient client, Lwm2mClientRpcRequest rpcRequest) { try { if (type != null) { switch (type) { @@ -433,7 +433,7 @@ public class LwM2mTransportRequest { String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", patn, type, value, e.toString()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(client, msg); log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); if (rpcRequest != null) { String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value); @@ -443,13 +443,13 @@ public class LwM2mTransportRequest { } } - private void handleResponse(Registration registration, final String path, LwM2mResponse response, + private void handleResponse(LwM2mClient lwM2mClient, final String path, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { responseRequestExecutor.submit(() -> { try { - this.sendResponse(registration, path, response, request, rpcRequest); + this.sendResponse(lwM2mClient, path, response, request, rpcRequest); } catch (Exception e) { - log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", registration.getEndpoint(), path, e); + log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", lwM2mClient.getRegistration().getEndpoint(), path, e); } }); } @@ -461,8 +461,9 @@ public class LwM2mTransportRequest { * @param path - * @param response - */ - private void sendResponse(Registration registration, String path, LwM2mResponse response, + private void sendResponse(LwM2mClient lwM2mClient, String path, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + Registration registration = lwM2mClient.getRegistration(); String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); String msgLog = ""; if (response instanceof ReadResponse) { @@ -477,7 +478,7 @@ public class LwM2mTransportRequest { String discoverValue = Link.serialize(((DiscoverResponse) response).getObjectLinks()); msgLog = String.format("%s: type operation: %s path: %s value: %s", LOG_LW2M_INFO, DISCOVER.name(), request.getPath().toString(), discoverValue); - handler.sendLogsToThingsboard(msgLog, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msgLog); log.warn("DiscoverResponse: [{}]", (DiscoverResponse) response); if (rpcRequest != null) { handler.sentRpcResponse(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE); @@ -486,7 +487,7 @@ public class LwM2mTransportRequest { msgLog = String.format("%s: type operation: %s path: %s", LOG_LW2M_INFO, EXECUTE.name(), request.getPath().toString()); log.warn("9) [{}] ", msgLog); - handler.sendLogsToThingsboard(msgLog, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msgLog); if (rpcRequest != null) { msgLog = String.format("Start %s path: %S. Preparation finished: %s", EXECUTE.name(), path, rpcRequest.getInfoMsg()); rpcRequest.setInfoMsg(msgLog); @@ -496,7 +497,7 @@ public class LwM2mTransportRequest { } else if (response instanceof WriteAttributesResponse) { msgLog = String.format("%s: type operation: %s path: %s value: %s", LOG_LW2M_INFO, WRITE_ATTRIBUTES.name(), request.getPath().toString(), ((WriteAttributesRequest) request).getAttributes().toString()); - handler.sendLogsToThingsboard(msgLog, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msgLog); log.warn("12) [{}] Path [{}] WriteAttributesResponse", pathIdVer, response); if (rpcRequest != null) { handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE); @@ -504,13 +505,14 @@ public class LwM2mTransportRequest { } else if (response instanceof WriteResponse) { msgLog = String.format("Type operation: Write path: %s", pathIdVer); log.warn("10) [{}] response: [{}]", msgLog, response); - this.infoWriteResponse(registration, response, request, rpcRequest); + this.infoWriteResponse(lwM2mClient, response, request, rpcRequest); handler.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request); } } - private void infoWriteResponse(Registration registration, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + private void infoWriteResponse(LwM2mClient lwM2mClient, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { try { + Registration registration = lwM2mClient.getRegistration(); LwM2mNode node = ((WriteRequest) request).getNode(); String msg = null; Object value; @@ -545,7 +547,7 @@ public class LwM2mTransportRequest { } } if (msg != null) { - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msg); if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) { this.afterWriteSuccessFwSwUpdate(registration, request); if (rpcRequest != null) { @@ -603,8 +605,8 @@ public class LwM2mTransportRequest { } } - private void afterObserveCancel(Registration registration, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) { - handler.sendLogsToThingsboard(observeCancelMsg, registration.getId()); + private void afterObserveCancel(LwM2mClient lwM2mClient, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) { + handler.sendLogsToThingsboard(lwM2mClient, observeCancelMsg); log.warn("[{}]", observeCancelMsg); if (rpcRequest != null) { rpcRequest.setInfoMsg(String.format("Count: %d", observeCancelCnt)); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java new file mode 100644 index 0000000000..b5ff57afc4 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java @@ -0,0 +1,22 @@ +/** + * 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.server.client; + +public enum LwM2MClientState { + + CREATED, REGISTERED, UNREGISTERED + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java new file mode 100644 index 0000000000..68e3c68742 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java @@ -0,0 +1,31 @@ +/** + * 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.server.client; + +import lombok.Getter; + +public class LwM2MClientStateException extends Exception { + + private static final long serialVersionUID = 3307690997951364046L; + + @Getter + private final LwM2MClientState state; + + public LwM2MClientStateException(LwM2MClientState state, String message) { + super(message); + this.state = state; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 05cc0f72c8..65c0dbcb0f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -49,6 +49,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; @@ -62,12 +64,28 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.g @Slf4j public class LwM2mClient implements Cloneable { + + private final String nodeId; + @Getter + private final String endpoint; + private final Lock lock; + @Getter @Setter + private LwM2MClientState state; + @Getter + private final Map resources; + @Getter + private final Map delayedRequests; + @Getter + @Setter + private final List pendingReadRequests; + @Getter + private final Queue queuedRequests; + @Getter private String deviceName; @Getter private String deviceProfileName; - @Getter - private String endpoint; + @Getter private String identity; @Getter @@ -92,15 +110,6 @@ public class LwM2mClient implements Cloneable { private ValidateDeviceCredentialsResponse credentials; - @Getter - private final Map resources; - @Getter - private final Map delayedRequests; - @Getter - @Setter - private final List pendingReadRequests; - @Getter - private final Queue queuedRequests; @Getter private boolean init; @@ -108,18 +117,23 @@ public class LwM2mClient implements Cloneable { return super.clone(); } - public LwM2mClient(String nodeId, String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) { + public LwM2mClient(String nodeId, String endpoint) { + this.nodeId = nodeId; this.endpoint = endpoint; - this.identity = identity; - this.securityInfo = securityInfo; - this.credentials = credentials; + this.lock = new ReentrantLock(); this.delayedRequests = new ConcurrentHashMap<>(); this.pendingReadRequests = new CopyOnWriteArrayList<>(); this.resources = new ConcurrentHashMap<>(); - this.profileId = profileId; - this.init = false; this.queuedRequests = new ConcurrentLinkedQueue<>(); + this.state = LwM2MClientState.CREATED; + } + public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) { + this.identity = identity; + this.securityInfo = securityInfo; + this.credentials = credentials; + this.profileId = profileId; + this.init = false; this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE); this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE); if (this.credentials != null && this.credentials.hasDeviceInfo()) { @@ -131,6 +145,14 @@ public class LwM2mClient implements Cloneable { } } + public void lock() { + lock.lock(); + } + + public void unlock() { + lock.unlock(); + } + public void onDeviceUpdate(Device device, Optional deviceProfileOpt) { SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session); this.deviceId = device.getUuidId(); 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 bb3e97b7e4..e9f292816c 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 @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; @@ -27,21 +28,27 @@ import java.util.UUID; public interface LwM2mClientContext { - void removeClientByRegistrationId(String registrationId); + LwM2mClient getClientByRegistrationId(String registrationId); LwM2mClient getClientByEndpoint(String endpoint); - LwM2mClient getClientByRegistrationId(String registrationId); + void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; + + void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; + + void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; + + SecurityInfo fetchSecurityInfoByCredentials(String credentialsId); LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo); - LwM2mClient getOrRegister(Registration registration); +// LwM2mClient getOrRegister(Registration registration); - LwM2mClient registerOrUpdate(Registration registration); +// LwM2mClient registerOrUpdate(Registration registration); - LwM2mClient fetchClientByEndpoint(String endpoint); +// LwM2mClient fetchClientByEndpoint(String endpoint); - Registration getRegistration(String registrationId); +// Registration getRegistration(String registrationId); Collection getLwM2mClients(); @@ -60,4 +67,6 @@ public interface LwM2mClientContext { LwM2mClient getClientByDeviceId(UUID deviceId); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); + + } 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 8674516e85..0225b78eaa 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 @@ -27,6 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; @@ -39,6 +40,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; @Slf4j @@ -58,36 +61,106 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public LwM2mClient getClientByEndpoint(String endpoint) { - return lwM2mClientsByEndpoint.get(endpoint); + return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> new LwM2mClient(context.getNodeId(), ep)); } @Override - public LwM2mClient getClientByRegistrationId(String registrationId) { - return lwM2mClientsByRegistrationId.get(registrationId); + public void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { + lwM2MClient.lock(); + try { + if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); + } + //TODO: Move this security info lookup to the TbLwM2mSecurityStore. + EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(lwM2MClient.getEndpoint(), LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + if (securityInfo.getSecurityMode() != null) { + if (securityInfo.getDeviceProfile() != null) { + UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null; + if (securityInfo.getSecurityInfo() != null) { + lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), profileUuid, UUID.randomUUID()); + } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { + lwM2MClient.init(null, null, securityInfo.getMsg(), profileUuid, UUID.randomUUID()); + } else { + throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); + } + } else { + throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); + } + } else { + throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", lwM2MClient.getEndpoint())); + } + lwM2MClient.setRegistration(registration); + this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient); + lwM2MClient.setState(LwM2MClientState.REGISTERED); + } finally { + lwM2MClient.unlock(); + } } @Override - public LwM2mClient getOrRegister(Registration registration) { - if (registration == null) { - return null; + public void updateRegistration(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { + lwM2MClient.lock(); + try { + if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); + } + Registration currentRegistration = lwM2MClient.getRegistration(); + if (currentRegistration.getId().equals(registration.getId())) { + lwM2MClient.setRegistration(registration); + } else { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration."); + } + } finally { + lwM2MClient.unlock(); } - LwM2mClient client = lwM2mClientsByRegistrationId.get(registration.getId()); - if (client == null) { - client = lwM2mClientsByEndpoint.get(registration.getEndpoint()); - if (client == null) { - client = registerOrUpdate(registration); + } + + @Override + public void unregister(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { + lwM2MClient.lock(); + try { + if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); + } + lwM2mClientsByRegistrationId.remove(registration.getId()); + Registration currentRegistration = lwM2MClient.getRegistration(); + if (currentRegistration.getId().equals(registration.getId())) { + lwM2MClient.setState(LwM2MClientState.UNREGISTERED); + lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); + this.securityStore.remove(lwM2MClient.getEndpoint(), false); + this.lwM2mClientsByRegistrationId.remove(registration.getId()); + UUID profileId = lwM2MClient.getProfileId(); + if (profileId != null) { + Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); + if (otherClients.isEmpty()) { + profiles.remove(profileId); + } + } + } else { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration."); } + } finally { + lwM2MClient.unlock(); } - return client; + } + + @Override + public LwM2mClient fetchSecurityInfoByCredentials(String credentialsId) { + return null; + } + + @Override + public LwM2mClient getClientByRegistrationId(String registrationId) { + return lwM2mClientsByRegistrationId.get(registrationId); } @Override public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c -> + LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c -> (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())) .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))) - ).findAny().get(); + ).findAny().orElse(null); if (lwM2mClient == null) { log.warn("Device TimeOut? lwM2mClient is null."); log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}]", sessionInfo, lwM2mClientsByEndpoint.values().size()); @@ -96,60 +169,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return lwM2mClient; } - @Override - public LwM2mClient registerOrUpdate(Registration registration) { - LwM2mClient lwM2MClient = lwM2mClientsByEndpoint.get(registration.getEndpoint()); - if (lwM2MClient == null) { - lwM2MClient = this.fetchClientByEndpoint(registration.getEndpoint()); - } - lwM2MClient.setRegistration(registration); -// TODO: this remove is probably redundant. We should remove it. -// this.lwM2mClientsByEndpoint.remove(registration.getEndpoint()); - this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient); - return lwM2MClient; - } - public Registration getRegistration(String registrationId) { return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration(); } - @Override - public LwM2mClient fetchClientByEndpoint(String endpoint) { - EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); - if (securityInfo.getSecurityMode() != null) { - if (securityInfo.getDeviceProfile() != null) { - UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile())!= null ? - securityInfo.getDeviceProfile().getUuidId() : null; - // TODO: for tests bug. - if (profileUuid== null) { - log.trace("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile()); - } - LwM2mClient client; - if (securityInfo.getSecurityInfo() != null) { - client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(), - securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), - securityInfo.getMsg(), profileUuid, UUID.randomUUID()); - } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { - client = new LwM2mClient(context.getNodeId(), endpoint, - null, null, - securityInfo.getMsg(), profileUuid, UUID.randomUUID()); - } else { - throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint)); - } - lwM2mClientsByEndpoint.put(client.getEndpoint(), client); - return client; - } else { - throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint)); - } - } else { - throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", endpoint)); - } - } - @Override public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) { - LwM2mClient client = new LwM2mClient(context.getNodeId(), registration.getEndpoint(), null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); - lwM2mClientsByEndpoint.put(registration.getEndpoint(), client); + LwM2mClient client = getClientByEndpoint(registration.getEndpoint()); + client.init(null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); lwM2mClientsByRegistrationId.put(registration.getId(), client); profileUpdate(credentials.getDeviceProfile()); } @@ -171,7 +198,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public LwM2mClientProfile getProfile(Registration registration) { - return this.getProfiles().get(getOrRegister(registration).getProfileId()); + return this.getProfiles().get(getClientByEndpoint(registration.getEndpoint()).getProfileId()); } @Override @@ -186,8 +213,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (lwM2MClientProfile != null) { profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile); return lwM2MClientProfile; - } - else { + } else { return null; } } @@ -215,20 +241,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); } - @Override - public void removeClientByRegistrationId(String registrationId) { - LwM2mClient lwM2MClient = this.lwM2mClientsByRegistrationId.get(registrationId); - if (lwM2MClient != null) { - this.securityStore.remove(lwM2MClient.getEndpoint(), false); - this.lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); - this.lwM2mClientsByRegistrationId.remove(registrationId); - UUID profileId = lwM2MClient.getProfileId(); - if (profileId != null) { - Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); - if (otherClients.isEmpty()) { - profiles.remove(profileId); - } - } - } - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java index e940061c66..7a93d15988 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java @@ -167,7 +167,7 @@ public class LwM2mFwSwUpdate { String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration()); String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LW2M_INFO, LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE.name(), FW_PACKAGE_ID); - handler.sendLogsToThingsboard(fwMsg, lwM2MClient.getRegistration().getId()); + handler.sendLogsToThingsboard(lwM2MClient, fwMsg); log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer); request.sendAllRequest(this.lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(), firmwareChunk, handler.config.getTimeout(), this.rpcRequest); @@ -190,7 +190,7 @@ public class LwM2mFwSwUpdate { if (LOG_LW2M_ERROR.equals(typeInfo)) { msg = String.format("%s Error: %s", msg, msgError); } - handler.sendLogsToThingsboard(msg, lwM2MClient.getRegistration().getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index 701d629154..c2d5d542f1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -68,7 +68,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()) { return null; } - securityInfo = clientContext.fetchClientByEndpoint(endpoint).getSecurityInfo(); + securityInfo = clientContext.fetchSecurityInfoByCredentials(endpoint); try { if (securityInfo != null) { add(securityInfo); @@ -84,7 +84,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { public SecurityInfo getByIdentity(String pskIdentity) { SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); if (securityInfo == null) { - securityInfo = clientContext.fetchClientByEndpoint(pskIdentity).getSecurityInfo(); + securityInfo = clientContext.fetchSecurityInfoByCredentials(pskIdentity); try { if (securityInfo != null) { add(securityInfo); From 74dc1c9df19075b3ba176e0a5a32c797f4811b08 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 7 Jun 2021 19:24:25 +0300 Subject: [PATCH 2/2] Fix initialization order --- .../secure/LwM2MBootstrapSecurityStore.java | 10 +- ...LwM2mCredentialsSecurityInfoValidator.java | 27 ++-- .../lwm2m/secure/TbLwM2MAuthorizer.java | 3 +- ...rityInfo.java => TbLwM2MSecurityInfo.java} | 2 +- .../DefaultLwM2MTransportMsgHandler.java | 14 +- .../server/DefaultLwM2mTransportService.java | 4 +- .../lwm2m/server/client/LwM2mClient.java | 1 - .../server/client/LwM2mClientContext.java | 5 +- .../server/client/LwM2mClientContextImpl.java | 25 +--- .../server/client/Lwm2mClientRpcRequest.java | 2 +- .../server/store/TbEditableSecurityStore.java | 27 ++++ .../server/store/TbInMemorySecurityStore.java | 130 ++++++++++++++++ .../store/TbLwM2mRedisSecurityStore.java | 141 ++++++++++-------- .../server/store/TbLwM2mSecurityStore.java | 81 +++++----- .../server/store/TbLwM2mStoreFactory.java | 11 +- .../lwm2m/server/store/TbSecurityStore.java | 25 ++++ 16 files changed, 344 insertions(+), 164 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{EndpointSecurityInfo.java => TbLwM2MSecurityInfo.java} (97%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 584b0542b6..197c3ba842 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -30,7 +30,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; @@ -72,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public Iterator getAllByEndpoint(String endPoint) { - EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); @@ -96,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public SecurityInfo getByIdentity(String identity) { - EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); @@ -113,7 +113,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { return null; } - private void setBootstrapConfigScurityInfo(EndpointSecurityInfo store) { + private void setBootstrapConfigScurityInfo(TbLwM2MSecurityInfo store) { /* BootstrapConfig */ LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { @@ -150,7 +150,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } } - private LwM2MBootstrapConfig getParametersBootstrap(EndpointSecurityInfo store) { + private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { try { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 8d90b2a86b..c57c2295c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -55,15 +55,15 @@ public class LwM2mCredentialsSecurityInfoValidator { private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; - public EndpointSecurityInfo getEndpointSecurityInfo(String endpoint, LwM2mTransportUtil.LwM2mTypeServer keyValue) { + public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTransportUtil.LwM2mTypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); - final EndpointSecurityInfo[] resultSecurityStore = new EndpointSecurityInfo[1]; - context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(), + final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1]; + context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(credentialsId).build(), new TransportServiceCallback<>() { @Override public void onSuccess(ValidateDeviceCredentialsResponse msg) { String credentialsBody = msg.getCredentials(); - resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue); + resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue); resultSecurityStore[0].setMsg(msg); resultSecurityStore[0].setDeviceProfile(msg.getDeviceProfile()); latch.countDown(); @@ -71,8 +71,8 @@ public class LwM2mCredentialsSecurityInfoValidator { @Override public void onError(Throwable e) { - log.trace("[{}] [{}] Failed to process credentials ", endpoint, e); - resultSecurityStore[0] = createSecurityInfo(endpoint, null, null); + log.trace("[{}] [{}] Failed to process credentials ", credentialsId, e); + resultSecurityStore[0] = createSecurityInfo(credentialsId, null, null); latch.countDown(); } }); @@ -91,8 +91,8 @@ public class LwM2mCredentialsSecurityInfoValidator { * @param keyValue - * @return SecurityInfo */ - private EndpointSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) { - EndpointSecurityInfo result = new EndpointSecurityInfo(); + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) { + TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); if (credentials != null) { if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { @@ -106,7 +106,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } else { switch (credentials.getClient().getSecurityConfigClientMode()) { case NO_SEC: - createClientSecurityInfoNoSec(result); + createClientSecurityInfoNoSec(result, endpoint); break; case PSK: createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); @@ -125,12 +125,13 @@ public class LwM2mCredentialsSecurityInfoValidator { return result; } - private void createClientSecurityInfoNoSec(EndpointSecurityInfo result) { + private void createClientSecurityInfoNoSec(TbLwM2MSecurityInfo result, String endpoint) { + result.setEndpoint(endpoint); result.setSecurityInfo(null); result.setSecurityMode(NO_SEC); } - private void createClientSecurityInfoPSK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoPSK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { PSKClientCredentials pskConfig = (PSKClientCredentials) clientCredentialsConfig; if (StringUtils.isNotEmpty(pskConfig.getIdentity())) { try { @@ -149,7 +150,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoRPK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoRPK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { RPKClientCredentials rpkConfig = (RPKClientCredentials) clientCredentialsConfig; try { if (rpkConfig.getKey() != null) { @@ -164,7 +165,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoX509(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoX509(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint)); result.setSecurityMode(X509); } 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 7269e78b5e..cd7f1f3072 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 @@ -27,6 +27,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 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.TbLwM2mSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; @Component @RequiredArgsConstructor @@ -34,7 +35,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore; public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; - private final TbLwM2mSecurityStore securityStore; + private final TbSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); private final LwM2mClientContext clientContext; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java index e8d3ae3c2b..9b9147c44f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @Data -public class EndpointSecurityInfo { +public class TbLwM2MSecurityInfo { private ValidateDeviceCredentialsResponse msg; private SecurityInfo securityInfo; private SecurityMode securityMode; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 41fcb1c9cb..6c5bbb5970 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -357,7 +357,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ @Override public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo); + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList()); msg.getSharedUpdatedList().forEach(tsKvProto -> { @@ -459,7 +459,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime()); Lwm2mClientRpcRequest lwm2mClientRpcRequest = null; try { - Registration registration = clientContext.getClient(sessionInfo).getRegistration(); + Registration registration = clientContext.getClientBySessionInfo(sessionInfo).getRegistration(); lwm2mClientRpcRequest = new Lwm2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this); if (lwm2mClientRpcRequest.getErrorMsg() != null) { lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name()); @@ -789,7 +789,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwM2MClient.getPendingReadRequests().addAll(pathSend); ConcurrentHashMap finalParams = params; pathSend.forEach(target -> { - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(), + lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TEXT.getName(), finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null); }); if (OBSERVE.equals(typeOper)) { @@ -1159,7 +1159,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler .collect(Collectors.toUnmodifiableSet()); if (!pathSend.isEmpty()) { ConcurrentHashMap finalParams = lwm2mAttributesNew; - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(), + pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TEXT.getName(), finalParams.get(target), this.config.getTimeout(), null)); } }); @@ -1176,7 +1176,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler Map params = (Map) lwm2mAttributesOld.get(target); params.clear(); params.put(OBJECT_VERSION, ""); - lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(), + lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TEXT.getName(), params, this.config.getTimeout(), null); }); } @@ -1227,7 +1227,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo); + LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo); return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey) .orElse(null); @@ -1262,7 +1262,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param sessionInfo */ public void updateAttributeFromThingsboard(List tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo); + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); if (lwM2MClient != null) { log.warn("1) UpdateAttributeFromThingsboard, tsKvProtos [{}]", tsKvProtos); tsKvProtos.forEach(tsKvProto -> { 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 90e3e13033..865168aed6 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 @@ -36,6 +36,8 @@ import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; 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.TbEditableSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -83,7 +85,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { private final LwM2mTransportServerHelper helper; private final LwM2mTransportMsgHandler handler; private final CaliforniumRegistrationStore registrationStore; - private final EditableSecurityStore securityStore; + private final TbSecurityStore securityStore; private final LwM2mClientContext lwM2mClientContext; private final TbLwM2MDtlsCertificateVerifier certificateVerifier; private final TbLwM2MAuthorizer authorizer; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 65c0dbcb0f..1fc876cc45 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -76,7 +76,6 @@ public class LwM2mClient implements Cloneable { @Getter private final Map delayedRequests; @Getter - @Setter private final List pendingReadRequests; @Getter private final Queue queuedRequests; 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 e9f292816c..e2e24ad1ff 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 @@ -32,15 +32,14 @@ public interface LwM2mClientContext { LwM2mClient getClientByEndpoint(String endpoint); + LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); + void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; - SecurityInfo fetchSecurityInfoByCredentials(String credentialsId); - - LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo); // LwM2mClient getOrRegister(Registration registration); 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 0225b78eaa..ac57040d7b 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 @@ -25,11 +25,11 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; -import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import java.util.Arrays; import java.util.Collection; @@ -40,8 +40,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; @Slf4j @@ -51,14 +49,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c public class LwM2mClientContextImpl implements LwM2mClientContext { private final LwM2mTransportContext context; + private final TbEditableSecurityStore securityStore; private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private Map profiles = new ConcurrentHashMap<>(); - private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; - - private final EditableSecurityStore securityStore; - @Override public LwM2mClient getClientByEndpoint(String endpoint) { return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> new LwM2mClient(context.getNodeId(), ep)); @@ -71,8 +66,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) { throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); } - //TODO: Move this security info lookup to the TbLwM2mSecurityStore. - EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(lwM2MClient.getEndpoint(), LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); if (securityInfo.getSecurityMode() != null) { if (securityInfo.getDeviceProfile() != null) { UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null; @@ -127,7 +121,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (currentRegistration.getId().equals(registration.getId())) { lwM2MClient.setState(LwM2MClientState.UNREGISTERED); lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); - this.securityStore.remove(lwM2MClient.getEndpoint(), false); + this.securityStore.remove(lwM2MClient.getEndpoint()); this.lwM2mClientsByRegistrationId.remove(registration.getId()); UUID profileId = lwM2MClient.getProfileId(); if (profileId != null) { @@ -144,18 +138,13 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } } - @Override - public LwM2mClient fetchSecurityInfoByCredentials(String credentialsId) { - return null; - } - @Override public LwM2mClient getClientByRegistrationId(String registrationId) { return lwM2mClientsByRegistrationId.get(registrationId); } @Override - public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) { + public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c -> (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())) .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java index d71c6b27f6..40dace0b5e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java @@ -273,7 +273,7 @@ public class Lwm2mClientRpcRequest { } private String getRezIdByResourceNameAndObjectInstanceId(String resourceName, DefaultLwM2MTransportMsgHandler handler) { - LwM2mClient lwM2mClient = handler.clientContext.getClient(this.sessionInfo); + LwM2mClient lwM2mClient = handler.clientContext.getClientBySessionInfo(this.sessionInfo); return lwM2mClient != null ? lwM2mClient.getRezIdByResourceNameAndObjectInstanceId(resourceName, this.targetIdVer, handler.config.getModelProvider()) : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java new file mode 100644 index 0000000000..9efd07dde0 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java @@ -0,0 +1,27 @@ +/** + * 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.server.store; + +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; + +public interface TbEditableSecurityStore extends TbSecurityStore { + + void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException; + + void remove(String endpoint); + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java new file mode 100644 index 0000000000..9c0b109082 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java @@ -0,0 +1,130 @@ +/** + * 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.server.store; + +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class TbInMemorySecurityStore implements TbEditableSecurityStore { + // lock for the two maps + protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + protected final Lock readLock = readWriteLock.readLock(); + protected final Lock writeLock = readWriteLock.writeLock(); + + // by client end-point + protected Map securityByEp = new HashMap<>(); + + // by PSK identity + protected Map securityByIdentity = new HashMap<>(); + + public TbInMemorySecurityStore() { + } + + /** + * {@inheritDoc} + */ + @Override + public SecurityInfo getByEndpoint(String endpoint) { + readLock.lock(); + try { + TbLwM2MSecurityInfo securityInfo = securityByEp.get(endpoint); + if (securityInfo != null) { + return securityInfo.getSecurityInfo(); + } else { + return null; + } + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public SecurityInfo getByIdentity(String identity) { + readLock.lock(); + try { + TbLwM2MSecurityInfo securityInfo = securityByIdentity.get(identity); + if (securityInfo != null) { + return securityInfo.getSecurityInfo(); + } else { + return null; + } + } finally { + readLock.unlock(); + } + } + + @Override + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { + writeLock.lock(); + try { + String identity = null; + if (tbSecurityInfo.getSecurityInfo() != null) { + identity = tbSecurityInfo.getSecurityInfo().getIdentity(); + if (identity != null) { + TbLwM2MSecurityInfo infoByIdentity = securityByIdentity.get(identity); + if (infoByIdentity != null && !tbSecurityInfo.getSecurityInfo().getEndpoint().equals(infoByIdentity.getEndpoint())) { + throw new NonUniqueSecurityInfoException("PSK Identity " + identity + " is already used"); + } + securityByIdentity.put(tbSecurityInfo.getSecurityInfo().getIdentity(), tbSecurityInfo); + } + } + + TbLwM2MSecurityInfo previous = securityByEp.put(tbSecurityInfo.getEndpoint(), tbSecurityInfo); + if (previous != null && previous.getSecurityInfo() != null) { + String previousIdentity = previous.getSecurityInfo().getIdentity(); + if (previousIdentity != null && !previousIdentity.equals(identity)) { + securityByIdentity.remove(previousIdentity); + } + } + } finally { + writeLock.unlock(); + } + } + + @Override + public void remove(String endpoint) { + writeLock.lock(); + try { + TbLwM2MSecurityInfo securityInfo = securityByEp.remove(endpoint); + if (securityInfo != null && securityInfo.getSecurityInfo() != null && securityInfo.getSecurityInfo().getIdentity() != null) { + securityByIdentity.remove(securityInfo.getSecurityInfo().getIdentity()); + } + } finally { + writeLock.unlock(); + } + } + + @Override + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) { + readLock.lock(); + try { + return securityByEp.get(endpoint); + } finally { + readLock.unlock(); + } + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java index 4cfe2a6829..9e3fe5625d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java @@ -24,13 +24,14 @@ import org.springframework.data.redis.connection.RedisClusterConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; -public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { +public class TbLwM2mRedisSecurityStore implements TbEditableSecurityStore { private static final String SEC_EP = "SEC#EP#"; private static final String PSKID_SEC = "PSKID#SEC"; @@ -72,73 +73,89 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { } @Override - public Collection getAll() { - try (var connection = connectionFactory.getConnection()) { - Collection list = new LinkedList<>(); - ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build(); - List> scans = new ArrayList<>(); - if (connection instanceof RedisClusterConnection) { - ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> { - scans.add(((RedisClusterConnection) connection).scan(node, scanOptions)); - }); - } else { - scans.add(connection.scan(scanOptions)); - } - - scans.forEach(scan -> { - scan.forEachRemaining(key -> { - byte[] element = connection.get(key); - list.add(deserialize(element)); - }); - }); - return list; - } + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { + //TODO: implement } @Override - public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { - byte[] data = serialize(info); - try (var connection = connectionFactory.getConnection()) { - if (info.getIdentity() != null) { - // populate the secondary index (security info by PSK id) - String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes())); - if (!oldEndpoint.equals(info.getEndpoint())) { - throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used"); - } - connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes()); - } - - byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data); - SecurityInfo previous = previousData == null ? null : deserialize(previousData); - String previousIdentity = previous == null ? null : previous.getIdentity(); - if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) { - connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes()); - } - - return previous; - } + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) { + //TODO: implement + return null; } @Override - public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { - try (var connection = connectionFactory.getConnection()) { - byte[] data = connection.get((SEC_EP + endpoint).getBytes()); - - if (data != null) { - SecurityInfo info = deserialize(data); - if (info.getIdentity() != null) { - connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes()); - } - connection.del((SEC_EP + endpoint).getBytes()); - if (listener != null) { - listener.securityInfoRemoved(infosAreCompromised, info); - } - return info; - } - } - return null; + public void remove(String endpoint) { + //TODO: implement } + // @Override +// public Collection getAll() { +// try (var connection = connectionFactory.getConnection()) { +// Collection list = new LinkedList<>(); +// ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build(); +// List> scans = new ArrayList<>(); +// if (connection instanceof RedisClusterConnection) { +// ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> { +// scans.add(((RedisClusterConnection) connection).scan(node, scanOptions)); +// }); +// } else { +// scans.add(connection.scan(scanOptions)); +// } +// +// scans.forEach(scan -> { +// scan.forEachRemaining(key -> { +// byte[] element = connection.get(key); +// list.add(deserialize(element)); +// }); +// }); +// return list; +// } +// } +// +// @Override +// public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { +// byte[] data = serialize(info); +// try (var connection = connectionFactory.getConnection()) { +// if (info.getIdentity() != null) { +// // populate the secondary index (security info by PSK id) +// String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes())); +// if (!oldEndpoint.equals(info.getEndpoint())) { +// throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used"); +// } +// connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes()); +// } +// +// byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data); +// SecurityInfo previous = previousData == null ? null : deserialize(previousData); +// String previousIdentity = previous == null ? null : previous.getIdentity(); +// if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) { +// connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes()); +// } +// +// return previous; +// } +// } +// +// @Override +// public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { +// try (var connection = connectionFactory.getConnection()) { +// byte[] data = connection.get((SEC_EP + endpoint).getBytes()); +// +// if (data != null) { +// SecurityInfo info = deserialize(data); +// if (info.getIdentity() != null) { +// connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes()); +// } +// connection.del((SEC_EP + endpoint).getBytes()); +// if (listener != null) { +// listener.securityInfoRemoved(infosAreCompromised, info); +// } +// return info; +// } +// } +// return null; +// } + private byte[] serialize(SecurityInfo secInfo) { return SecurityInfoSerDes.serialize(secInfo); } @@ -147,8 +164,4 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { return SecurityInfoSerDes.deserialize(data); } - @Override - public void setListener(SecurityStoreListener listener) { - this.listener = listener; - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index c2d5d542f1..8302af64fa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -19,63 +19,40 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; +import org.eclipse.leshan.server.security.SecurityStore; import org.eclipse.leshan.server.security.SecurityStoreListener; +import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Component; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.Collection; @Slf4j -@Component @TbLwM2mTransportComponent -public class TbLwM2mSecurityStore implements EditableSecurityStore { +public class TbLwM2mSecurityStore implements TbEditableSecurityStore { - private final LwM2mClientContext clientContext; - private final EditableSecurityStore securityStore; + private final TbEditableSecurityStore securityStore; + private final LwM2mCredentialsSecurityInfoValidator validator; - public TbLwM2mSecurityStore(LwM2mClientContext clientContext, EditableSecurityStore securityStore) { - this.clientContext = clientContext; + public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) { this.securityStore = securityStore; + this.validator = validator; } @Override - public Collection getAll() { - return securityStore.getAll(); - } - - @Override - public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { - return securityStore.add(info); - } - - @Override - public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { - return securityStore.remove(endpoint, infosAreCompromised); - } - - @Override - public void setListener(SecurityStoreListener listener) { - securityStore.setListener(listener); + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) { + return securityStore.getTbLwM2MSecurityInfoByEndpoint(endpoint); } @Override public SecurityInfo getByEndpoint(String endpoint) { SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint); if (securityInfo == null) { - LwM2mClient lwM2mClient = clientContext.getClientByEndpoint(endpoint); - if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()) { - return null; - } - securityInfo = clientContext.fetchSecurityInfoByCredentials(endpoint); - try { - if (securityInfo != null) { - add(securityInfo); - } - } catch (NonUniqueSecurityInfoException e) { - log.trace("Failed to add security info: {}", securityInfo, e); - } + securityInfo = fetchAndPutSecurityInfo(endpoint); } return securityInfo; } @@ -84,15 +61,31 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { public SecurityInfo getByIdentity(String pskIdentity) { SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); if (securityInfo == null) { - securityInfo = clientContext.fetchSecurityInfoByCredentials(pskIdentity); - try { - if (securityInfo != null) { - add(securityInfo); - } - } catch (NonUniqueSecurityInfoException e) { - log.trace("Failed to add security info: {}", securityInfo, e); - } + securityInfo = fetchAndPutSecurityInfo(pskIdentity); } return securityInfo; } + + @Nullable + public SecurityInfo fetchAndPutSecurityInfo(String credentialsId) { + TbLwM2MSecurityInfo securityInfo = validator.getEndpointSecurityInfoByCredentialsId(credentialsId, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + try { + if (securityInfo != null) { + securityStore.put(securityInfo); + } + } catch (NonUniqueSecurityInfoException e) { + log.trace("Failed to add security info: {}", securityInfo, e); + } + return securityInfo != null ? securityInfo.getSecurityInfo() : null; + } + + @Override + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { + securityStore.put(tbSecurityInfo); + } + + @Override + public void remove(String endpoint) { + securityStore.remove(endpoint); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java index 2c0c96212f..3dd9ebd3ed 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java @@ -19,6 +19,7 @@ import org.eclipse.leshan.server.californium.registration.CaliforniumRegistratio import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore; import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.InMemorySecurityStore; +import org.eclipse.leshan.server.security.SecurityStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -27,6 +28,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.Optional; @@ -42,8 +44,7 @@ public class TbLwM2mStoreFactory { private LwM2MTransportServerConfig config; @Autowired - @Lazy - private LwM2mClientContext clientContext; + private LwM2mCredentialsSecurityInfoValidator validator; @Value("${transport.lwm2m.redis.enabled:false}") private boolean useRedis; @@ -55,9 +56,9 @@ public class TbLwM2mStoreFactory { } @Bean - private EditableSecurityStore securityStore() { - return new TbLwM2mSecurityStore(clientContext, redisConfiguration.isPresent() && useRedis ? - new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new InMemorySecurityStore()); + private TbSecurityStore securityStore() { + return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ? + new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator); } @Bean diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java new file mode 100644 index 0000000000..a1aa394fb5 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java @@ -0,0 +1,25 @@ +/** + * 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.server.store; + +import org.eclipse.leshan.server.security.SecurityStore; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; + +public interface TbSecurityStore extends SecurityStore { + + TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint); + +}