Browse Source

Improve SSL reload clarity: document trade-offs, use Path API, deduplicate PEM path logic

pull/15301/head
Andrii Landiak 6 months ago
parent
commit
635920534d
  1. 5
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java
  2. 8
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java
  3. 24
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java
  4. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/CertificateReloadManager.java

5
common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java

@ -154,6 +154,7 @@ public class DefaultCoapServerService implements CoapServerService, SmartInitial
return networkConfig; return networkConfig;
} }
// Note: this method has a side effect — it sets COAP_SECURE_PORT on the provided networkConfig.
private DtlsConnectorConfig buildDtlsConnectorConfig(Configuration networkConfig) throws UnknownHostException { private DtlsConnectorConfig buildDtlsConnectorConfig(Configuration networkConfig) throws UnknownHostException {
TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings(); TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings();
DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(networkConfig); DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(networkConfig);
@ -195,7 +196,9 @@ public class DefaultCoapServerService implements CoapServerService, SmartInitial
DTLSConnector newConnector = createDtlsConnector(dtlsConnectorConfig); DTLSConnector newConnector = createDtlsConnector(dtlsConnectorConfig);
CoapEndpoint newEndpoint = buildDtlsEndpoint(networkConfig, newConnector); CoapEndpoint newEndpoint = buildDtlsEndpoint(networkConfig, newConnector);
// Stop the old endpoint first to release the port before starting the new one // Californium binds the DTLS port at connector construction time, so we must stop the old
// endpoint first to release the port. This creates a brief window where the port is unbound;
// if the new endpoint fails to start, we attempt to restore the old one (see rollback below).
if (oldDtlsEndpoint != null) { if (oldDtlsEndpoint != null) {
log.info("Stopping old DTLS endpoint to release the port..."); log.info("Stopping old DTLS endpoint to release the port...");
server.getEndpoints().remove(oldDtlsEndpoint); server.getEndpoints().remove(oldDtlsEndpoint);

8
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java

@ -20,9 +20,9 @@ import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.data.ResourceUtils;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyStore; import java.security.KeyStore;
@ -62,9 +62,9 @@ public class KeystoreSslCredentials extends AbstractSslCredentials {
@Override @Override
public List<Path> getCertificateFilePaths() { public List<Path> getCertificateFilePaths() {
if (!StringUtils.isEmpty(storeFile) && !storeFile.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) { if (!StringUtils.isEmpty(storeFile) && !storeFile.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
File storeFileObj = new File(storeFile); Path resolved = Path.of(storeFile).toAbsolutePath();
if (storeFileObj.exists()) { if (Files.exists(resolved)) {
return Collections.singletonList(storeFileObj.toPath().toAbsolutePath()); return Collections.singletonList(resolved);
} }
} }
return Collections.emptyList(); return Collections.emptyList();

24
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java

@ -30,10 +30,10 @@ import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.data.ResourceUtils;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyStore; import java.security.KeyStore;
@ -145,22 +145,18 @@ public class PemSslCredentials extends AbstractSslCredentials {
@Override @Override
public List<Path> getCertificateFilePaths() { public List<Path> getCertificateFilePaths() {
List<Path> paths = new ArrayList<>(); List<Path> paths = new ArrayList<>();
addIfFileSystemPath(paths, certFile);
addIfFileSystemPath(paths, keyFile);
return paths;
}
if (!StringUtils.isEmpty(certFile) && !certFile.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) { private static void addIfFileSystemPath(List<Path> paths, String filePath) {
File certFileObj = new File(certFile); if (!StringUtils.isEmpty(filePath) && !filePath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
if (certFileObj.exists()) { Path resolved = Path.of(filePath).toAbsolutePath();
paths.add(certFileObj.toPath().toAbsolutePath()); if (Files.exists(resolved)) {
} paths.add(resolved);
}
if (!StringUtils.isEmpty(keyFile) && !keyFile.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
File keyFileObj = new File(keyFile);
if (keyFileObj.exists()) {
paths.add(keyFileObj.toPath().toAbsolutePath());
} }
} }
return paths;
} }
} }

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/CertificateReloadManager.java

@ -247,6 +247,8 @@ public class CertificateReloadManager implements SmartInitializingSingleton, Dis
} catch (Exception e) { } catch (Exception e) {
consecutiveFailures++; consecutiveFailures++;
failedCombinedChecksum = combinedChecksum; failedCombinedChecksum = combinedChecksum;
// Deliberately NOT updating the lastModifiedMap here, so the next poll cycle retries
// (mtime mismatch passes the early gate, checksum matches failedCombinedChecksum).
log.error("Failed to reload certificate for {} (attempt {}/{}): {}", log.error("Failed to reload certificate for {} (attempt {}/{}): {}",
name, consecutiveFailures, MAX_CONSECUTIVE_FAILURES, e.getMessage(), e); name, consecutiveFailures, MAX_CONSECUTIVE_FAILURES, e.getMessage(), e);
} }

Loading…
Cancel
Save