diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index ab0857f863..8450a24aea 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.EdgeId; @@ -48,6 +49,7 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.Collections; import java.util.Map; import java.util.UUID; @@ -103,9 +105,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i .addService(this); if (sslEnabled) { try { - File certFile = new File(Resources.getResource(certFileResource).toURI()); - File privateKeyFile = new File(Resources.getResource(privateKeyResource).toURI()); - builder.useTransportSecurity(certFile, privateKeyFile); + InputStream certFileIs = ResourceUtils.getInputStream(this, certFileResource); + InputStream privateKeyFileIs = ResourceUtils.getInputStream(this, privateKeyResource); + builder.useTransportSecurity(certFileIs, privateKeyFileIs); } catch (Exception e) { log.error("Unable to set up SSL context. Reason: " + e.getMessage(), e); throw new RuntimeException("Unable to set up SSL context!", e); diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java index d5605ee29b..c25f57d41d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; @@ -87,7 +88,7 @@ public class TbCoapDtlsSettings { } else { DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); configBuilder.setAddress(getInetSocketAddress()); - String keyStoreFilePath = Resources.getResource(keyStoreFile).getPath(); + String keyStoreFilePath = ResourceUtils.getUri(this, keyStoreFile); SslContextUtil.Credentials serverCredentials = loadServerCredentials(keyStoreFilePath); SecurityMode securityMode = securityModeOpt.get(); if (securityMode.equals(SecurityMode.NO_AUTH)) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java new file mode 100644 index 0000000000..754476bc26 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java @@ -0,0 +1,86 @@ +/** + * 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.common.data; + +import com.google.common.io.Resources; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + +@Slf4j +public class ResourceUtils { + + public static InputStream getInputStream(Object classLoaderSource, String filePath) { + return getInputStream(classLoaderSource.getClass().getClassLoader(), filePath); + } + + public static InputStream getInputStream(ClassLoader classLoader, String filePath) { + try { + InputStream keyStoreInputStream; + File keyStoreFile = new File(filePath); + if (keyStoreFile.exists()) { + log.info("Reading key store from file {}", filePath); + keyStoreInputStream = new FileInputStream(keyStoreFile); + } else { + InputStream classPathStream = classLoader.getResourceAsStream(filePath); + if (classPathStream != null) { + log.info("Reading key store from class path {}", filePath); + keyStoreInputStream = classPathStream; + } else { + URI uri = Resources.getResource(filePath).toURI(); + log.info("Reading key store from URI {}", filePath); + keyStoreInputStream = new FileInputStream(new File(uri)); + } + } + return keyStoreInputStream; + } catch (Exception e) { + if (e instanceof NullPointerException) { + log.warn("Unable to find resource: " + filePath); + } else { + log.warn("Unable to find resource: " + filePath, e); + } + throw new RuntimeException("Unable to find resource: " + filePath); + } + } + + public static String getUri(Object classLoaderSource, String filePath) { + return getUri(classLoaderSource.getClass().getClassLoader(), filePath); + } + + public static String getUri(ClassLoader classLoader, String filePath) { + try { + File keyStoreFile = new File(filePath); + if (keyStoreFile.exists()) { + log.info("Reading key store from file {}", filePath); + return keyStoreFile.getAbsolutePath(); + } else { + URL url = classLoader.getResource(filePath); + return url.toURI().toString(); + } + } catch (Exception e) { + if (e instanceof NullPointerException) { + log.warn("Unable to find resource: " + filePath); + } else { + log.warn("Unable to find resource: " + filePath, e); + } + throw new RuntimeException("Unable to find resource: " + filePath); + } + } +} diff --git a/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java b/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java index c5099069ee..f54c9b5a10 100644 --- a/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java +++ b/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.edge.exception.EdgeConnectionException; +import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.gen.edge.ConnectRequestMsg; import org.thingsboard.server.gen.edge.ConnectResponseCode; import org.thingsboard.server.gen.edge.ConnectResponseMsg; @@ -79,8 +80,8 @@ public class EdgeGrpcClient implements EdgeRpcClient { .keepAliveTime(keepAliveTimeSec, TimeUnit.SECONDS); if (sslEnabled) { try { - builder.sslContext(GrpcSslContexts.forClient().trustManager(new File(Resources.getResource(certResource).toURI())).build()); - } catch (URISyntaxException | SSLException e) { + builder.sslContext(GrpcSslContexts.forClient().trustManager(ResourceUtils.getInputStream(this, certResource)).build()); + } catch (SSLException e) { log.error("Failed to initialize channel!", e); throw new RuntimeException(e); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index 54a9312eda..295b1eb9ba 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -20,15 +20,19 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.model.LwM2mModelProvider; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.ResourceUtils; import javax.annotation.PostConstruct; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.InputStream; import java.net.URI; +import java.net.URISyntaxException; import java.security.KeyStore; @Slf4j @@ -139,29 +143,15 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @PostConstruct public void init() { - URI uri = null; try { - InputStream keyStoreInputStream; - File keyStoreFile = new File(keyStoreFilePath); - if (keyStoreFile.exists()) { - log.info("Reading key store from file {}", keyStoreFilePath); - keyStoreInputStream = new FileInputStream(keyStoreFile); - } else { - InputStream classPathStream = this.getClass().getClassLoader().getResourceAsStream(keyStoreFilePath); - if (classPathStream != null) { - log.info("Reading key store from class path {}", keyStoreFilePath); - keyStoreInputStream = classPathStream; - } else { - uri = Resources.getResource(keyStoreFilePath).toURI(); - log.info("Reading key store from URI {}", keyStoreFilePath); - keyStoreInputStream = new FileInputStream(new File(uri)); - } - } + InputStream keyStoreInputStream = ResourceUtils.getInputStream(this, keyStoreFilePath); keyStoreValue = KeyStore.getInstance(keyStoreType); keyStoreValue.load(keyStoreInputStream, keyStorePassword == null ? null : keyStorePassword.toCharArray()); } catch (Exception e) { - log.info("Unable to lookup LwM2M keystore. Reason: {}, {}", uri, e.getMessage()); + log.info("Unable to lookup LwM2M keystore. Reason: {}, {}", keyStoreFilePath, e.getMessage()); } } + + } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java index 2a0419b43d..7771509c37 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java @@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; @@ -74,20 +75,15 @@ public class MqttSslHandlerProvider { public SslHandler getSslHandler() { try { - URL ksUrl = Resources.getResource(keyStoreFile); - File ksFile = new File(ksUrl.toURI()); - URL tsUrl = Resources.getResource(keyStoreFile); - File tsFile = new File(tsUrl.toURI()); - TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore trustStore = KeyStore.getInstance(keyStoreType); - try (InputStream tsFileInputStream = new FileInputStream(tsFile)) { + try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) { trustStore.load(tsFileInputStream, keyStorePassword.toCharArray()); } tmFactory.init(trustStore); KeyStore ks = KeyStore.getInstance(keyStoreType); - try (InputStream ksFileInputStream = new FileInputStream(ksFile)) { + try (InputStream ksFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) { ks.load(ksFileInputStream, keyStorePassword.toCharArray()); } KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttSslClient.java b/tools/src/main/java/org/thingsboard/client/tools/MqttSslClient.java index 1abe47acd4..72de97e83b 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttSslClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/MqttSslClient.java @@ -26,6 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.thingsboard.server.common.data.ResourceUtils; import javax.net.ssl.*; import java.io.File; @@ -47,20 +48,15 @@ public class MqttSslClient { public static void main(String[] args) { try { - URL ksUrl = Resources.getResource(KEY_STORE_FILE); - File ksFile = new File(ksUrl.toURI()); - URL tsUrl = Resources.getResource(KEY_STORE_FILE); - File tsFile = new File(tsUrl.toURI()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore trustStore = KeyStore.getInstance(JKS); char[] ksPwd = new char[]{0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x5F, 0x6B, 0x73, 0x5F, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64}; - trustStore.load(new FileInputStream(tsFile), ksPwd); + trustStore.load(ResourceUtils.getInputStream(MqttSslClient.class.getClassLoader(), KEY_STORE_FILE), ksPwd); tmf.init(trustStore); KeyStore ks = KeyStore.getInstance(JKS); - ks.load(new FileInputStream(ksFile), ksPwd); + ks.load(ResourceUtils.getInputStream(MqttSslClient.class.getClassLoader(), KEY_STORE_FILE), ksPwd); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); char[] clientPwd = new char[]{0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x5F, 0x6B, 0x65, 0x79, 0x5F, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64}; kmf.init(ks, clientPwd);