diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 0855e4ee1f..9e6d393b30 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -46,9 +47,11 @@ public class Lwm2mController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{securityMode}/{bootstrapServerIs}", method = RequestMethod.GET) @ResponseBody - public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String securityMode, + public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String strSecurityMode, @PathVariable("bootstrapServerIs") boolean bootstrapServer) throws ThingsboardException { + checkNotNull(strSecurityMode); try { + SecurityMode securityMode = SecurityMode.valueOf(strSecurityMode); return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(securityMode, bootstrapServer); } catch (Exception e) { throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java index 012cd3e359..06190cdf70 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.lwm2m; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.util.Hex; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; @@ -25,7 +26,6 @@ import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import java.math.BigInteger; import java.security.AlgorithmParameters; @@ -55,17 +55,16 @@ public class LwM2MServerSecurityInfoRepository { * @param bootstrapServer * @return ServerSecurityConfig more value is default: Important - port, host, publicKey */ - public ServerSecurityConfig getServerSecurityInfo(String securityMode, boolean bootstrapServer) { - LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase()); - ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig, lwM2MSecurityMode); + public ServerSecurityConfig getServerSecurityInfo(SecurityMode securityMode, boolean bootstrapServer) { + ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig, securityMode); result.setBootstrapServerIs(bootstrapServer); return result; } - private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig, LwM2MSecurityMode mode) { + private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig, SecurityMode securityMode) { ServerSecurityConfig bsServ = new ServerSecurityConfig(); bsServ.setServerId(serverConfig.getId()); - switch (mode) { + switch (securityMode) { case NO_SEC: bsServ.setHost(serverConfig.getHost()); bsServ.setPort(serverConfig.getPort()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 937257b189..2f175a6bce 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -73,17 +73,17 @@ public class LwM2MBootstrapConfig { configBs.servers.put(0, server0); /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ this.bootstrapServer.setBootstrapServerIs(true); - configBs.security.put(0, setServerSecuruty(this.bootstrapServer.getHost(), this.bootstrapServer.getPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); + configBs.security.put(0, setServerSecurity(this.bootstrapServer.getHost(), this.bootstrapServer.getPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ - configBs.security.put(1, setServerSecuruty(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); + configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); return configBs; } - private BootstrapConfig.ServerSecurity setServerSecuruty(String host, Integer port, boolean bootstrapServer, String securityMode, String clientPublicKey, String serverPublicKey, String secretKey, int serverId) { + private BootstrapConfig.ServerSecurity setServerSecurity(String host, Integer port, boolean bootstrapServer, SecurityMode securityMode, String clientPublicKey, String serverPublicKey, String secretKey, int serverId) { BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity(); serverSecurity.uri = "coaps://" + host + ":" + Integer.toString(port); serverSecurity.bootstrapServer = bootstrapServer; - serverSecurity.securityMode = SecurityMode.valueOf(securityMode); + serverSecurity.securityMode = securityMode; serverSecurity.publicKeyOrId = setPublicKeyOrId(clientPublicKey, securityMode); serverSecurity.serverPublicKey = (serverPublicKey != null && !serverPublicKey.isEmpty()) ? Hex.decodeHex(serverPublicKey.toCharArray()) : new byte[]{}; serverSecurity.secretKey = (secretKey != null && !secretKey.isEmpty()) ? Hex.decodeHex(secretKey.toCharArray()) : new byte[]{}; @@ -91,9 +91,9 @@ public class LwM2MBootstrapConfig { return serverSecurity; } - private byte[] setPublicKeyOrId(String publicKeyOrIdStr, String securityMode) { + private byte[] setPublicKeyOrId(String publicKeyOrIdStr, SecurityMode securityMode) { return (publicKeyOrIdStr == null || publicKeyOrIdStr.isEmpty()) ? new byte[]{} : - SecurityMode.valueOf(securityMode).equals(SecurityMode.PSK) ? publicKeyOrIdStr.getBytes(StandardCharsets.UTF_8) : + SecurityMode.PSK.equals(securityMode) ? publicKeyOrIdStr.getBytes(StandardCharsets.UTF_8) : Hex.decodeHex(publicKeyOrIdStr.toCharArray()); } } 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 22e0540c09..b1edd0a1a5 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 @@ -31,7 +31,6 @@ 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.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; @@ -73,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public List getAllByEndpoint(String endPoint) { EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); - if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); @@ -97,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public SecurityInfo getByIdentity(String identity) { EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); - if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); BootstrapConfig bsConfig = store.getBootstrapConfig(); @@ -118,29 +117,29 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { /* Security info */ - switch (SecurityMode.valueOf(lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode())) { + switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { /* Use RPK only */ case PSK: store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); - store.setSecurityMode(SecurityMode.PSK.code); + store.setSecurityMode(SecurityMode.PSK); break; case RPK: try { store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); - store.setSecurityMode(SecurityMode.RPK.code); + store.setSecurityMode(SecurityMode.RPK); break; } catch (IOException | GeneralSecurityException e) { log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); } case X509: store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); - store.setSecurityMode(SecurityMode.X509.code); + store.setSecurityMode(SecurityMode.X509); break; case NO_SEC: - store.setSecurityMode(SecurityMode.NO_SEC.code); + store.setSecurityMode(SecurityMode.NO_SEC); store.setSecurityInfo(null); break; default: @@ -152,10 +151,9 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(EndpointSecurityInfo store) { try { - JsonObject bootstrapJsonCredential = store.getBootstrapJsonCredential(); - if (bootstrapJsonCredential != null) { + LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); + if (lwM2MBootstrapConfig != null) { ObjectMapper mapper = new ObjectMapper(); - LwM2MBootstrapConfig lwM2MBootstrapConfig = mapper.readValue(bootstrapJsonCredential.toString(), LwM2MBootstrapConfig.class); JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class); LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java index 9dca6057da..27d2e8c865 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java @@ -32,7 +32,7 @@ public class LwM2MServerBootstrap { String host = "0.0.0.0"; Integer port = 0; - String securityMode = SecurityMode.NO_SEC.name(); + SecurityMode securityMode = SecurityMode.NO_SEC; Integer serverId = 123; boolean bootstrapServerIs = false; 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/EndpointSecurityInfo.java index f65acf04bd..e8d3ae3c2b 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/EndpointSecurityInfo.java @@ -15,25 +15,23 @@ */ package org.thingsboard.server.transport.lwm2m.secure; -import com.google.gson.JsonObject; import lombok.Data; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; 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.ValidateDeviceCredentialsResponseMsg; - -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @Data public class EndpointSecurityInfo { private ValidateDeviceCredentialsResponse msg; private SecurityInfo securityInfo; - private int securityMode = DEFAULT_MODE.code; + private SecurityMode securityMode; /** bootstrap */ private DeviceProfile deviceProfile; - private JsonObject bootstrapJsonCredential; + private LwM2MBootstrapConfig bootstrapCredentialConfig; private String endpoint; private BootstrapConfig bootstrapConfig; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java index b99192ece3..22c5878a58 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java @@ -33,16 +33,6 @@ import java.util.Arrays; @Slf4j public class LWM2MGenerationPSkRPkECC { - public LWM2MGenerationPSkRPkECC(Integer dtlsMode) { - switch (LwM2MSecurityMode.fromSecurityMode(dtlsMode)) { - case PSK: - generationPSkKey(); - break; - case RPK: - generationRPKECCKey(); - } - } - public LWM2MGenerationPSkRPkECC() { generationPSkKey(); generationRPKECCKey(); @@ -102,12 +92,12 @@ public class LWM2MGenerationPSkRPkECC { /* Get Curves params */ String privHex = Hex.encodeHexString(privKey.getEncoded()); log.info("\nCreating new RPK for the next start... \n" + - " Public Key (Hex): [{}]\n" + - " Private Key (Hex): [{}]" + - " public_x : [{}] \n" + - " public_y : [{}] \n" + - " private_encode : [{}] \n" + - " Elliptic Curve parameters : [{}] \n", + " Public Key (Hex): [{}]\n" + + " Private Key (Hex): [{}]" + + " public_x : [{}] \n" + + " public_y : [{}] \n" + + " private_encode : [{}] \n" + + " Elliptic Curve parameters : [{}] \n", Hex.encodeHexString(pubKey.getEncoded()), privHex, Hex.encodeHexString(x), diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java deleted file mode 100644 index faf776b76c..0000000000 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * 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.secure; - -public enum LwM2MSecurityMode { - - PSK(0, "psk"), - RPK(1, "rpk"), - X509(2, "x509"), - NO_SEC(3, "no_sec"), - X509_EST(4, "x509_est"), - REDIS(7, "redis"), - DEFAULT_MODE(255, "default_mode"); - - public int code; - public String subEndpoint; - - LwM2MSecurityMode(int code, String subEndpoint) { - this.code = code; - this.subEndpoint = subEndpoint; - } - - public static LwM2MSecurityMode fromSecurityMode(long code) { - return fromSecurityMode((int) code); - } - - public static LwM2MSecurityMode fromSecurityMode(int code) { - for (LwM2MSecurityMode sm : LwM2MSecurityMode.values()) { - if (sm.code == code) { - return sm; - } - } - throw new IllegalArgumentException(String.format("Unsupported security code : %d", code)); - } - - - public static LwM2MSecurityMode fromSecurityMode(String subEndpoint) { - for (LwM2MSecurityMode sm : LwM2MSecurityMode.values()) { - if (sm.subEndpoint.equals(subEndpoint)) { - return sm; - } - } - throw new IllegalArgumentException(String.format("Unsupported security subEndpoint : %d", subEndpoint)); - } -} 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 ec5200602c..cd78cd4c1e 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 @@ -15,34 +15,36 @@ */ package org.thingsboard.server.transport.lwm2m.secure; -import com.google.gson.JsonObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentialsConfig; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; +import org.thingsboard.server.transport.lwm2m.secure.credentials.PSKClientCredentialsConfig; +import org.thingsboard.server.transport.lwm2m.secure.credentials.RPKClientCredentialsConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PublicKey; -import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PSK; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; +import static org.eclipse.leshan.core.SecurityMode.NO_SEC; +import static org.eclipse.leshan.core.SecurityMode.PSK; +import static org.eclipse.leshan.core.SecurityMode.RPK; +import static org.eclipse.leshan.core.SecurityMode.X509; @Slf4j @Component @@ -53,7 +55,6 @@ public class LwM2mCredentialsSecurityInfoValidator { private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; - public EndpointSecurityInfo getEndpointSecurityInfo(String endpoint, LwM2mTransportUtil.LwM2mTypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); final EndpointSecurityInfo[] resultSecurityStore = new EndpointSecurityInfo[1]; @@ -92,39 +93,32 @@ public class LwM2mCredentialsSecurityInfoValidator { */ private EndpointSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) { EndpointSecurityInfo result = new EndpointSecurityInfo(); - JsonObject objectMsg = LwM2mTransportUtil.validateJson(jsonStr); - if (objectMsg != null && !objectMsg.isJsonNull()) { - JsonObject object = (objectMsg.has(keyValue.type) && !objectMsg.get(keyValue.type).isJsonNull()) ? objectMsg.get(keyValue.type).getAsJsonObject() : null; - /** - * Only PSK - */ - String endpointPsk = (objectMsg.has("client") - && objectMsg.get("client").getAsJsonObject().has("endpoint") - && objectMsg.get("client").getAsJsonObject().get("endpoint").isJsonPrimitive()) ? objectMsg.get("client").getAsJsonObject().get("endpoint").getAsString() : null; - endpoint = (endpointPsk == null || endpointPsk.isEmpty()) ? endpoint : endpointPsk; - if (object != null && !object.isJsonNull()) { - if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { - result.setBootstrapJsonCredential(object); - result.setEndpoint(endpoint); - result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code); - } else { - LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase()); - switch (lwM2MSecurityMode) { - case NO_SEC: - createClientSecurityInfoNoSec(result); - break; - case PSK: - createClientSecurityInfoPSK(result, endpoint, object); - break; - case RPK: - createClientSecurityInfoRPK(result, endpoint, object); - break; - case X509: - createClientSecurityInfoX509(result, endpoint); - break; - default: - break; - } + LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); + if (credentials != null) { + if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { + result.setBootstrapCredentialConfig(credentials.getBootstrap()); + if (SecurityMode.PSK.equals(credentials.getClient().getSecurityConfigClientMode())) { + PSKClientCredentialsConfig pskClientConfig = (PSKClientCredentialsConfig) credentials.getClient(); + endpoint = StringUtils.isNotEmpty(pskClientConfig.getEndpoint()) ? pskClientConfig.getEndpoint() : endpoint; + } + result.setEndpoint(endpoint); + result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); + } else { + switch (credentials.getClient().getSecurityConfigClientMode()) { + case NO_SEC: + createClientSecurityInfoNoSec(result); + break; + case PSK: + createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); + break; + case RPK: + createClientSecurityInfoRPK(result, endpoint, credentials.getClient()); + break; + case X509: + createClientSecurityInfoX509(result, endpoint, credentials.getClient()); + break; + default: + break; } } } @@ -133,19 +127,18 @@ public class LwM2mCredentialsSecurityInfoValidator { private void createClientSecurityInfoNoSec(EndpointSecurityInfo result) { result.setSecurityInfo(null); - result.setSecurityMode(NO_SEC.code); + result.setSecurityMode(NO_SEC); } - private void createClientSecurityInfoPSK(EndpointSecurityInfo result, String endpoint, JsonObject object) { - /** PSK Deserialization */ - String identity = (object.has("identity") && object.get("identity").isJsonPrimitive()) ? object.get("identity").getAsString() : null; - if (identity != null && !identity.isEmpty()) { + private void createClientSecurityInfoPSK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentialsConfig clientCredentialsConfig) { + PSKClientCredentialsConfig pskConfig = (PSKClientCredentialsConfig) clientCredentialsConfig; + if (StringUtils.isNotEmpty(pskConfig.getIdentity())) { try { - byte[] key = (object.has("key") && object.get("key").isJsonPrimitive()) ? Hex.decodeHex(object.get("key").getAsString().toCharArray()) : null; - if (key != null && key.length > 0) { + if (pskConfig.getKey() != null && pskConfig.getKey().length > 0) { + endpoint = StringUtils.isNotEmpty(pskConfig.getEndpoint()) ? pskConfig.getEndpoint() : endpoint; if (endpoint != null && !endpoint.isEmpty()) { - result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endpoint, identity, key)); - result.setSecurityMode(PSK.code); + result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endpoint, pskConfig.getIdentity(), pskConfig.getKey())); + result.setSecurityMode(PSK); } } } catch (IllegalArgumentException e) { @@ -156,13 +149,13 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoRPK(EndpointSecurityInfo result, String endpoint, JsonObject object) { + private void createClientSecurityInfoRPK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentialsConfig clientCredentialsConfig) { + RPKClientCredentialsConfig rpkConfig = (RPKClientCredentialsConfig) clientCredentialsConfig; try { - if (object.has("key") && object.get("key").isJsonPrimitive()) { - byte[] rpkkey = Hex.decodeHex(object.get("key").getAsString().toLowerCase().toCharArray()); - PublicKey key = SecurityUtil.publicKey.decode(rpkkey); + if (rpkConfig.getKey() != null) { + PublicKey key = SecurityUtil.publicKey.decode(rpkConfig.getKey()); result.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(endpoint, key)); - result.setSecurityMode(RPK.code); + result.setSecurityMode(RPK); } else { log.error("Missing RPK key"); } @@ -171,8 +164,8 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoX509(EndpointSecurityInfo result, String endpoint) { + private void createClientSecurityInfoX509(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentialsConfig clientCredentialsConfig) { result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint)); - result.setSecurityMode(X509.code); + result.setSecurityMode(X509); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/HasKey.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/HasKey.java new file mode 100644 index 0000000000..7c75589c4c --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/HasKey.java @@ -0,0 +1,17 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import org.eclipse.leshan.core.util.Hex; + +public class HasKey { + private byte[] key; + + public void setKey(String key) { + if (key != null) { + this.key = Hex.decodeHex(key.toLowerCase().toCharArray()); + } + } + + public byte[] getKey() { + return key; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentialsConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentialsConfig.java new file mode 100644 index 0000000000..33a297c91a --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentialsConfig.java @@ -0,0 +1,22 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.eclipse.leshan.core.SecurityMode; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + property = "securityConfigClientMode") +@JsonSubTypes({ + @JsonSubTypes.Type(value = NoSecClientCredentialsConfig.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKClientCredentialsConfig.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKClientCredentialsConfig.class, name = "RPK"), + @JsonSubTypes.Type(value = X509ClientCredentialsConfig.class, name = "X509")}) +public interface LwM2MClientCredentialsConfig { + + @JsonIgnore + SecurityMode getSecurityConfigClientMode(); +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java new file mode 100644 index 0000000000..ebb1fc138b --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java @@ -0,0 +1,10 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import lombok.Data; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; + +@Data +public class LwM2MCredentials { + private LwM2MClientCredentialsConfig client; + private LwM2MBootstrapConfig bootstrap; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/NoSecClientCredentialsConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/NoSecClientCredentialsConfig.java new file mode 100644 index 0000000000..bcac7174aa --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/NoSecClientCredentialsConfig.java @@ -0,0 +1,13 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import org.eclipse.leshan.core.SecurityMode; + +import static org.eclipse.leshan.core.SecurityMode.NO_SEC; + +public class NoSecClientCredentialsConfig implements LwM2MClientCredentialsConfig { + + @Override + public SecurityMode getSecurityConfigClientMode() { + return NO_SEC; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/PSKClientCredentialsConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/PSKClientCredentialsConfig.java new file mode 100644 index 0000000000..d79083647f --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/PSKClientCredentialsConfig.java @@ -0,0 +1,17 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import lombok.Data; +import org.eclipse.leshan.core.SecurityMode; + +import static org.eclipse.leshan.core.SecurityMode.PSK; + +@Data +public class PSKClientCredentialsConfig extends HasKey implements LwM2MClientCredentialsConfig { + private String identity; + private String endpoint; + + @Override + public SecurityMode getSecurityConfigClientMode() { + return PSK; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/RPKClientCredentialsConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/RPKClientCredentialsConfig.java new file mode 100644 index 0000000000..280e8492f8 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/RPKClientCredentialsConfig.java @@ -0,0 +1,13 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import org.eclipse.leshan.core.SecurityMode; + +import static org.eclipse.leshan.core.SecurityMode.RPK; + +public class RPKClientCredentialsConfig extends HasKey implements LwM2MClientCredentialsConfig { + + @Override + public SecurityMode getSecurityConfigClientMode() { + return RPK; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/X509ClientCredentialsConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/X509ClientCredentialsConfig.java new file mode 100644 index 0000000000..35fe63c376 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/X509ClientCredentialsConfig.java @@ -0,0 +1,17 @@ +package org.thingsboard.server.transport.lwm2m.secure.credentials; + +import lombok.Data; +import org.eclipse.leshan.core.SecurityMode; + +import static org.eclipse.leshan.core.SecurityMode.X509; + +@Data +public class X509ClientCredentialsConfig implements LwM2MClientCredentialsConfig { + private boolean allowTrustedOnly; + private String cert; + + @Override + public SecurityMode getSecurityConfigClientMode() { + return X509; + } +} 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 b8583523d5..02ef1ccfb2 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,7 +25,6 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes 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.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; @@ -38,7 +37,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; +import static org.eclipse.leshan.core.SecurityMode.NO_SEC; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; @Service @@ -111,7 +110,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public LwM2mClient fetchClientByEndpoint(String endpoint) { EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); - if (securityInfo.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + if (securityInfo.getSecurityMode() != null) { if (securityInfo.getDeviceProfile() != null) { toClientProfile(securityInfo.getDeviceProfile()); UUID profileUuid = securityInfo.getDeviceProfile().getUuidId(); @@ -120,7 +119,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(), securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), profileUuid, UUID.randomUUID()); - } else if (securityInfo.getSecurityMode() == NO_SEC.code) { + } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { client = new LwM2mClient(context.getNodeId(), endpoint, null, null, securityInfo.getMsg(), profileUuid, UUID.randomUUID());