Skip to content

Commit

Permalink
Add reload credentials to demo-server.
Browse files Browse the repository at this point in the history
Signed-off-by: Achim Kraus <achim.kraus@cloudcoap.net>
  • Loading branch information
boaks committed Jan 13, 2023
1 parent 11b77ce commit 82ce5e5
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
import org.eclipse.californium.elements.util.NetworkInterfacesUtil.SimpleInetAddressFilter;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.elements.util.StringUtil;
import org.eclipse.californium.elements.util.SystemResourceMonitors;
import org.eclipse.californium.elements.util.SystemResourceMonitors.SystemResourceMonitor;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.DtlsHealthLogger;
import org.eclipse.californium.scandium.MdcConnectionListener;
Expand Down Expand Up @@ -133,7 +135,9 @@ public enum InterfaceType {
*/
public static final TimeDefinition UDP_DROPS_READ_INTERVAL = new TimeDefinition("UDP_DROPS_READ_INTERVAL",
"Interval to read upd drops from OS (currently only Linux).", 2000, TimeUnit.MILLISECONDS);

/**
* Maximum device in cache.
*/
public static final IntegerDefinition CACHE_MAX_DEVICES = new IntegerDefinition("CACHE_MAX_DEVICES",
"Cache maximum devices.", 5000, 100);
/**
Expand All @@ -144,10 +148,17 @@ public enum InterfaceType {
+ "if at least for that threshold no messages are exchanged using that device.",
24, TimeUnit.HOURS);
/**
* Interval to reload credentials.
* Interval to reload https credentials.
*/
public static final TimeDefinition HTTPS_CREDENTIALS_RELOAD_INTERVAL = new TimeDefinition(
"HTTPS_CREDENTIALS_RELOAD_INTERVAL",
"Reload https credentials interval. 0 to load credentials only on startup.", 30, TimeUnit.MINUTES);
/**
* Interval to reload device credentials.
*/
public static final TimeDefinition CREDENTIALS_RELOAD_INTERVAL = new TimeDefinition("CREDENTIALS_RELOAD_INTERVAL",
"Reload credentials interval. 0 to load credentials only on startup.", 10, TimeUnit.MINUTES);
public static final TimeDefinition DEVICE_CREDENTIALS_RELOAD_INTERVAL = new TimeDefinition(
"DEVICE_CREDENTIALS_RELOAD_INTERVAL",
"Reload device credentials interval. 0 to load credentials only on startup.", 30, TimeUnit.SECONDS);

public static DefinitionsProvider DEFAULTS = new DefinitionsProvider() {

Expand Down Expand Up @@ -182,6 +193,8 @@ public void applyDefinitions(Configuration config) {
config.set(UDP_DROPS_READ_INTERVAL, 2000, TimeUnit.MILLISECONDS);
config.set(CACHE_MAX_DEVICES, 5000);
config.set(CACHE_STALE_DEVICE_THRESHOLD, 24, TimeUnit.HOURS);
config.set(HTTPS_CREDENTIALS_RELOAD_INTERVAL, 30, TimeUnit.MINUTES);
config.set(DEVICE_CREDENTIALS_RELOAD_INTERVAL, 30, TimeUnit.SECONDS);
}
};

Expand Down Expand Up @@ -381,6 +394,11 @@ public static void start(String[] args, String name, ServerConfig config, BaseSe
if (http) {
if (HttpService.startHttpService()) {
LOGGER.info("HTTPS service at port {} started", config.httpsPort);
long interval = server.getConfig().get(HTTPS_CREDENTIALS_RELOAD_INTERVAL, TimeUnit.MINUTES);
if (interval > 0) {
SystemResourceMonitor httpsCredentialsMonitor = HttpService.getHttpService().getFileMonitor();
server.monitor.addMonitor("https", interval, TimeUnit.MINUTES, httpsCredentialsMonitor);
}
}
}
long interval = server.getConfig().get(SystemConfig.HEALTH_STATUS_INTERVAL, TimeUnit.MILLISECONDS);
Expand Down Expand Up @@ -489,12 +507,26 @@ public static void exportPsk(ServerConfig.PskStore config) {
}
}

protected SystemResourceMonitors monitor;

public BaseServer(Configuration config) {
super(config);
setVersion(CALIFORNIUM_BUILD_VERSION);
setTag("CLOUD-DEMO");
}

@Override
public void start() {
super.start();
monitor.start();
}

@Override
public void stop() {
super.stop();
monitor.stop();
}

public void initialize(ServerConfig cliConfig) throws SocketException {
Configuration config = getConfig();
// executors
Expand All @@ -504,6 +536,8 @@ public void initialize(ServerConfig cliConfig) throws SocketException {
ScheduledExecutorService secondaryExecutor = ExecutorsUtil
.newDefaultSecondaryScheduler("CoapServer(secondary)#");

monitor = new SystemResourceMonitors(secondaryExecutor);

addEndpoints(cliConfig);

addResource(cliConfig, executor);
Expand Down Expand Up @@ -538,7 +572,6 @@ public void addEndpoints(ServerConfig cliConfig) {
boolean healthLogger = config.get(SystemConfig.HEALTH_STATUS_INTERVAL, TimeUnit.MILLISECONDS) > 0;
KeyManager[] serverCredentials = null;
Certificate[] trustedCertificates = null;
AdvancedPskStore pskStore = null;

// load certificate credentials
try {
Expand All @@ -552,18 +585,7 @@ public void addEndpoints(ServerConfig cliConfig) {
e.printStackTrace();
}

// load PSK credentials
if (cliConfig.pskStore != null) {
if (cliConfig.pskStore.password64 != null) {
byte[] secret = StringUtil.base64ToByteArray(cliConfig.pskStore.password64);
SecretKey key = SecretUtil.create(secret, "PW");
Bytes.clear(secret);
pskStore = new MultiPskFileStore().loadPskCredentials(cliConfig.pskStore.file, key);
SecretUtil.destroy(key);
} else {
pskStore = new MultiPskFileStore().loadPskCredentials(cliConfig.pskStore.file);
}
}
AdvancedPskStore pskStore = setupPskStore(cliConfig);

// Context matcher load PSK credentials
EndpointContextMatcher customContextMatcher = null;
Expand Down Expand Up @@ -640,6 +662,36 @@ public void addEndpoints(ServerConfig cliConfig) {
}
}

public AdvancedPskStore setupPskStore(ServerConfig cliConfig) {
AdvancedPskStore pskStore = null;
// load PSK credentials
if (cliConfig.pskStore != null) {
MultiPskFileStore pskFileStore = new MultiPskFileStore();
long interval = getConfig().get(DEVICE_CREDENTIALS_RELOAD_INTERVAL, TimeUnit.SECONDS);
if (cliConfig.pskStore.password64 != null) {
byte[] secret = StringUtil.base64ToByteArray(cliConfig.pskStore.password64);
SecretKey key = SecretUtil.create(secret, "PW");
Bytes.clear(secret);
pskFileStore.loadPskCredentials(cliConfig.pskStore.file, key);
if (interval > 0) {
SystemResourceMonitor fileMonitor = pskFileStore.getMonitor(cliConfig.pskStore.file, key);
monitor.addMonitor("encrypted PSK-store", interval, TimeUnit.SECONDS, fileMonitor);
}
SecretUtil.destroy(key);
LOGGER.info("Load encrypted PSK-store from file {}", cliConfig.pskStore.file);
} else {
pskFileStore.loadPskCredentials(cliConfig.pskStore.file);
if (interval > 0) {
SystemResourceMonitor fileMonitor = pskFileStore.getMonitor(cliConfig.pskStore.file, null);
monitor.addMonitor("PSK-store", interval, TimeUnit.SECONDS, fileMonitor);
}
LOGGER.info("Load PSK-store from file {}", cliConfig.pskStore.file);
}
pskStore = pskFileStore;
}
return pskStore;
}

public void setupHttpService(ServerConfig config) {
if (config.httpsCredentials != null) {
HttpService httpService = HttpService.getHttpService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ public class DemoServer extends CoapServer {
" DemoServer --psk-file device.psk --store-file dtls.bin --store-max-age 168 \\",
" --store-password64 ZVhiRW5pdkx1RUs2dmVoZg==",
" (DemoServer with PSK credentials from file and dtls-graceful restart.",
" Devices/sessions with no exchange for more then a week (168 hours)", " are skipped when saving.)",
" Devices/sessions with no exchange for more then a week (168 hours)",
" are skipped when saving.)",
"", " DemoServer --psk-file device.psk \\",
" --psk-file-export-password64 V3plQUdkTnFLQjRnZWtSeg==",
" (DemoServer encrypts plain PSK credentials file (in place).", " Exits afterwards.)", "", })
" (DemoServer encrypts plain PSK credentials file (in place).",
" Exits afterwards.)", "", })
public static class Config extends ServerConfig {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
import org.eclipse.californium.elements.util.Bytes;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.elements.util.StandardCharsets;
import org.eclipse.californium.elements.util.SystemResourceMonitors.FileMonitor;
import org.eclipse.californium.elements.util.SystemResourceMonitors.SystemResourceMonitor;
import org.eclipse.californium.scandium.dtls.x509.CertificateConfigurationHelper;
import org.eclipse.californium.elements.util.SystemResourceMonitors.SystemResourceCheckReady;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -275,20 +279,51 @@ public void stop() {
}

public boolean reloadCredentials() {
boolean reloaded = false;
try {
if (loadCredentials(credentials)) {
LOGGER.info("restart - certificates reloaded.");
stop();
start();
reloaded = true;
for (int loop = 0; loop < 3; ++loop) {
try {
if (loadCredentials(credentials)) {
LOGGER.info("restart - certificates reloaded.");
stop();
start();
return true;
}
} catch (IllegalArgumentException ex) {
LOGGER.info("Error", ex);
// key pair mismatch
// race condition reading new file pair?
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
} catch (IOException e) {
LOGGER.error("I/O error", e);
break;
} catch (GeneralSecurityException e) {
LOGGER.error("Crypto error", e);
break;
}
} catch (IOException e) {
LOGGER.error("I/O error", e);
} catch (GeneralSecurityException e) {
LOGGER.error("Crypto error", e);
}
return reloaded;
return false;
}

/**
* Get resource monitor for automatic credentials reloading.
*
* @return resource monitor
*/
public SystemResourceMonitor getFileMonitor() {
return new FileMonitor(credentials.fullChainUrl) {

@Override
protected void update(MonitoredValues values, SystemResourceCheckReady ready) {
if (httpService.reloadCredentials()) {
ready(values);
} else {
ready(null);
}
ready.ready(false);
}
};
}

/**
Expand Down Expand Up @@ -545,6 +580,8 @@ public static boolean loadCredentials(Credentials credentials) throws IOExceptio
if (certificateChain.length > 0) {
if (credentials.node == null || !credentials.node.equals(certificateChain[0])) {
PrivateKey privateKey = SslContextUtil.loadPrivateKey(credentials.privateKeyUrl, null, null, null);
CertificateConfigurationHelper helper = new CertificateConfigurationHelper();
helper.verifyKeyPair(privateKey, certificateChain[0].getPublicKey());
KeyManager[] keyManager = SslContextUtil.createKeyManager("server", privateKey, certificateChain);
TrustManager[] trustManager = SslContextUtil.createTrustAllManager();
SSLContext sslContext = SSLContext.getInstance(credentials.tls12Only ? TLS_1_2 : TLS);
Expand Down
3 changes: 3 additions & 0 deletions demo-apps/cf-cloud-demo-server/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
<logger name="org.eclipse.californium.elements.util.NetworkInterfacesUtil" level="INFO" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.eclipse.californium.elements.util.SystemResourceMonitors" level="INFO" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.eclipse.californium.cloud" level="INFO" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
Expand Down

0 comments on commit 82ce5e5

Please # to comment.