Adding netcfg listener to disconnect switches when certificate is
updated or removed.
Change-Id: I04b170aec328b4c91a6d699ff128347d9a148736
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
index 92358c4..70de681 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
@@ -50,19 +50,23 @@
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.security.DigestInputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
@@ -272,13 +276,25 @@
return oldValue != this.workerThreads; // restart if number of threads has changed
}
- private static class TlsParams {
- TlsMode mode;
- String ksLocation;
- String tsLocation;
- String ksPwd;
- String tsPwd;
- //TODO add the hash of the keystore file contents, so that we restart if the keystore has changed
+ static class TlsParams {
+ final TlsMode mode;
+ final String ksLocation;
+ final String tsLocation;
+ final String ksPwd;
+ final String tsPwd;
+ final byte[] ksSignature;
+ final byte[] tsSignature;
+
+ TlsParams(TlsMode mode, String ksLocation, String tsLocation,
+ String ksPwd, String tsPwd) {
+ this.mode = mode;
+ this.ksLocation = ksLocation;
+ this.tsLocation = tsLocation;
+ this.ksPwd = ksPwd;
+ this.tsPwd = tsPwd;
+ this.ksSignature = getSha1Checksum(ksLocation);
+ this.tsSignature = getSha1Checksum(tsLocation);
+ }
public char[] ksPwd() {
return ksPwd.toCharArray();
@@ -292,9 +308,34 @@
return TLS_ENABLED.contains(mode);
}
+ public byte[] getSha1Checksum(String filepath) {
+ if (filepath == null) {
+ return new byte[0];
+ }
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA1");
+ File f = new File(filepath);
+ FileInputStream is = new FileInputStream(f);
+ DigestInputStream dis = new DigestInputStream(is, digest);
+ byte[] buffer = new byte[1024];
+ while (dis.read(buffer) > 0) {
+ // nothing to do :)
+ }
+ dis.getMessageDigest().digest();
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (IOException e) {
+ log.info("Error reading file file: {}", filepath);
+ }
+ return new byte[0];
+ }
+
@Override
public int hashCode() {
- return 1; //TODO
+ if (mode == TlsMode.DISABLED) {
+ return Objects.hash(mode);
+ }
+ return Objects.hash(mode, ksLocation, tsLocation,
+ ksPwd, tsPwd, ksSignature, tsSignature);
}
@Override
@@ -314,7 +355,9 @@
Objects.equals(this.ksLocation, that.ksLocation) &&
Objects.equals(this.tsLocation, that.tsLocation) &&
Objects.equals(this.ksPwd, that.ksPwd) &&
- Objects.equals(this.tsPwd, that.tsPwd);
+ Objects.equals(this.tsPwd, that.tsPwd) &&
+ Arrays.equals(this.ksSignature, that.ksSignature) &&
+ Arrays.equals(this.tsSignature, that.tsSignature);
}
return false;
}
@@ -339,67 +382,68 @@
private boolean setTlsParameters(Dictionary<?, ?> properties) {
TlsParams oldParams = this.tlsParams;
- TlsParams newParams = new TlsParams();
+ TlsMode mode = null;
String tlsString = get(properties, "tlsMode");
if (!Strings.isNullOrEmpty(tlsString)) {
try {
- newParams.mode = TlsMode.valueOf(tlsString.toUpperCase());
+ mode = TlsMode.valueOf(tlsString.toUpperCase());
} catch (IllegalArgumentException e) {
log.info("Invalid TLS mode {}. TLS is disabled.", tlsString);
- newParams.mode = TlsMode.DISABLED;
+ mode = TlsMode.DISABLED;
}
} else {
// Fallback to system properties
// TODO this method of configuring TLS is deprecated and should be removed eventually
tlsString = System.getProperty("enableOFTLS");
- newParams.mode = !Strings.isNullOrEmpty(tlsString) && Boolean.parseBoolean(tlsString) ?
+ mode = !Strings.isNullOrEmpty(tlsString) && Boolean.parseBoolean(tlsString) ?
TlsMode.ENABLED : TlsMode.DISABLED;
}
- if (newParams.isTlsEnabled()) {
- newParams.ksLocation = get(properties, "keyStore");
- if (Strings.isNullOrEmpty(newParams.ksLocation)) {
+ String ksLocation = null, tsLocation = null, ksPwd = null, tsPwd = null;
+ if (TLS_ENABLED.contains(mode)) {
+ ksLocation = get(properties, "keyStore");
+ if (Strings.isNullOrEmpty(ksLocation)) {
// Fallback to system properties
// TODO remove this eventually
- newParams.ksLocation = System.getProperty("javax.net.ssl.keyStore");
+ ksLocation = System.getProperty("javax.net.ssl.keyStore");
}
- if (Strings.isNullOrEmpty(newParams.ksLocation)) {
- newParams.mode = TlsMode.DISABLED;
+ if (Strings.isNullOrEmpty(ksLocation)) {
+ mode = TlsMode.DISABLED;
}
- newParams.tsLocation = get(properties, "trustStore");
- if (Strings.isNullOrEmpty(newParams.tsLocation)) {
+ tsLocation = get(properties, "trustStore");
+ if (Strings.isNullOrEmpty(tsLocation)) {
// Fallback to system properties
// TODO remove this eventually
- newParams.tsLocation = System.getProperty("javax.net.ssl.trustStore");
+ tsLocation = System.getProperty("javax.net.ssl.trustStore");
}
- if (Strings.isNullOrEmpty(newParams.tsLocation)) {
- newParams.mode = TlsMode.DISABLED;
+ if (Strings.isNullOrEmpty(tsLocation)) {
+ mode = TlsMode.DISABLED;
}
- newParams.ksPwd = get(properties, "keyStorePassword");
- if (Strings.isNullOrEmpty(newParams.ksPwd)) {
+ ksPwd = get(properties, "keyStorePassword");
+ if (Strings.isNullOrEmpty(ksPwd)) {
// Fallback to system properties
// TODO remove this eventually
- newParams.ksPwd = System.getProperty("javax.net.ssl.keyStorePassword");
+ ksPwd = System.getProperty("javax.net.ssl.keyStorePassword");
}
- if (Strings.isNullOrEmpty(newParams.ksPwd) || MIN_KS_LENGTH > newParams.ksPwd.length()) {
- newParams.mode = TlsMode.DISABLED;
+ if (Strings.isNullOrEmpty(ksPwd) || MIN_KS_LENGTH > ksPwd.length()) {
+ mode = TlsMode.DISABLED;
}
- newParams.tsPwd = get(properties, "trustStorePassword");
- if (Strings.isNullOrEmpty(newParams.tsPwd)) {
+ tsPwd = get(properties, "trustStorePassword");
+ if (Strings.isNullOrEmpty(tsPwd)) {
// Fallback to system properties
// TODO remove this eventually
- newParams.tsPwd = System.getProperty("javax.net.ssl.trustStorePassword");
+ tsPwd = System.getProperty("javax.net.ssl.trustStorePassword");
}
- if (Strings.isNullOrEmpty(newParams.tsPwd) || MIN_KS_LENGTH > newParams.tsPwd.length()) {
- newParams.mode = TlsMode.DISABLED;
+ if (Strings.isNullOrEmpty(tsPwd) || MIN_KS_LENGTH > tsPwd.length()) {
+ mode = TlsMode.DISABLED;
}
}
- this.tlsParams = newParams;
+ this.tlsParams = new TlsParams(mode, ksLocation, tsLocation, ksPwd, tsPwd);
log.info("OpenFlow TLS Params: {}", tlsParams);
- return !Objects.equals(newParams, oldParams); // restart if TLS params change
+ return !Objects.equals(this.tlsParams, oldParams); // restart if TLS params change
}
/**
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
index 6224842..bcf9edf 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -30,6 +30,8 @@
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.driver.DriverService;
@@ -79,6 +81,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@@ -213,14 +216,56 @@
private final Controller ctrl = new Controller();
+ private final NetworkConfigListener netCfgListener = new NetworkConfigListener() {
+ @Override
+ public boolean isRelevant(NetworkConfigEvent event) {
+ return OpenFlowDeviceConfig.class.equals(event.configClass());
+ }
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ // We only receive NetworkConfigEvents
+ OpenFlowDeviceConfig prevConfig = null;
+ if (event.prevConfig().isPresent()) {
+ prevConfig = (OpenFlowDeviceConfig) event.prevConfig().get();
+ }
+
+ OpenFlowDeviceConfig newConfig = null;
+ if (event.config().isPresent()) {
+ newConfig = (OpenFlowDeviceConfig) event.config().get();
+ }
+
+ boolean closeConnection = false;
+ if (prevConfig != null && newConfig != null) {
+ if (!Objects.equals(prevConfig.keyAlias(), newConfig.keyAlias())) {
+ closeConnection = true;
+ }
+ } else if (prevConfig != null) {
+ // config was removed
+ closeConnection = true;
+ }
+ if (closeConnection) {
+ if (event.subject() instanceof DeviceId) {
+ DeviceId deviceId = (DeviceId) event.subject();
+ Dpid dpid = Dpid.dpid(deviceId.uri());
+ OpenFlowSwitch sw = getSwitch(dpid);
+ if (sw != null && ctrl.tlsParams.mode == Controller.TlsMode.STRICT) {
+ sw.disconnectSwitch();
+ log.info("Disconnecting switch {} because key has been updated or removed", dpid);
+ }
+ }
+ }
+ }
+ };
+
@Activate
public void activate(ComponentContext context) {
coreService.registerApplication(APP_ID, this::cleanup);
cfgService.registerProperties(getClass());
netCfgService.registerConfigFactory(factory);
+ netCfgService.addListener(netCfgListener);
ctrl.setConfigParams(context.getProperties());
ctrl.start(agent, driverService, netCfgService);
- // TODO register a netcfg listener that disconnects switches when the keyAlias changes
}
private void cleanup() {
@@ -237,14 +282,13 @@
public void deactivate() {
cleanup();
cfgService.unregisterProperties(getClass(), false);
+ netCfgService.removeListener(netCfgListener);
netCfgService.unregisterConfigFactory(factory);
}
@Modified
public void modified(ComponentContext context) {
- //ctrl.stop();
ctrl.setConfigParams(context.getProperties());
- //ctrl.start(agent, driverService, netCfgService);
}
@Override