--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.protocol.tls;
+
+import static java.util.Objects.requireNonNull;
+
+import io.netty.channel.Channel;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import io.netty.util.concurrent.Promise;
+import java.net.SocketAddress;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import org.opendaylight.netconf.callhome.protocol.CallHomeNetconfSubsystemListener;
+import org.opendaylight.netconf.callhome.protocol.CallHomeProtocolSessionContext;
+import org.opendaylight.netconf.callhome.protocol.TransportType;
+import org.opendaylight.netconf.client.NetconfClientSession;
+import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
+import org.opendaylight.netconf.client.SslHandlerFactory;
+import org.opendaylight.netconf.client.TlsClientChannelInitializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class CallHomeTlsSessionContext implements CallHomeProtocolSessionContext {
+ private static final Logger LOG = LoggerFactory.getLogger(CallHomeTlsSessionContext.class);
+
+ private final AtomicBoolean activated = new AtomicBoolean();
+ private final SslHandlerFactory sslHandlerFactory;
+ private final CallHomeNetconfSubsystemListener subsystemListener;
+ private final String channelId;
+ private final Channel channel;
+ private final PublicKey publicKey;
+ private final SocketAddress socketAddress;
+
+ CallHomeTlsSessionContext(final Channel channel, final SslHandlerFactory sslHandlerFactory,
+ final CallHomeNetconfSubsystemListener subsystemListener) {
+ this.channel = requireNonNull(channel, "channel");
+ this.channelId = channel.id().asLongText();
+ this.socketAddress = channel.remoteAddress();
+ this.publicKey = createPublicKey(channel);
+ this.sslHandlerFactory = requireNonNull(sslHandlerFactory, "sslHandlerFactory");
+ this.subsystemListener = subsystemListener;
+ }
+
+ private static Promise<NetconfClientSession> newSessionPromise() {
+ return GlobalEventExecutor.INSTANCE.newPromise();
+ }
+
+ void openNetconfChannel(final Channel ch) {
+ LOG.debug("Opening NETCONF Subsystem on TLS connection {}", channelId);
+ subsystemListener.onNetconfSubsystemOpened(this, listener -> doActivate(ch, listener));
+ }
+
+ @Override
+ public void terminate() {
+ channel.close();
+ }
+
+ private Promise<NetconfClientSession> doActivate(final Channel ch, final NetconfClientSessionListener listener) {
+ final Promise<NetconfClientSession> activationPromise = newSessionPromise();
+ if (!activated.compareAndExchange(false, true)) {
+ return activationPromise.setFailure(new IllegalStateException("Session (channel) already activated."));
+ }
+
+ LOG.info("Activating Netconf channel for {} with {}", getRemoteAddress(), listener);
+ final NetconfClientSessionNegotiatorFactory negotiatorFactory = new NetconfClientSessionNegotiatorFactory(
+ new HashedWheelTimer(), Optional.empty(), TimeUnit.SECONDS.toMillis(5));
+ final TlsClientChannelInitializer tlsClientChannelInitializer = new TlsClientChannelInitializer(
+ sslHandlerFactory, negotiatorFactory, listener);
+ tlsClientChannelInitializer.initialize(ch, activationPromise);
+ return activationPromise;
+ }
+
+ @Override
+ public PublicKey getRemoteServerKey() {
+ return publicKey;
+ }
+
+ @Override
+ public SocketAddress getRemoteAddress() {
+ return socketAddress;
+ }
+
+ @Override
+ public String getSessionId() {
+ return channelId;
+ }
+
+ @Override
+ public TransportType getTransportType() {
+ return TransportType.TLS;
+ }
+
+ private static PublicKey createPublicKey(final Channel ch) {
+ final SslHandler sslHandler = ch.pipeline().get(SslHandler.class);
+ final Certificate[] certificates;
+ try {
+ certificates = sslHandler.engine().getSession().getPeerCertificates();
+ } catch (SSLPeerUnverifiedException e) {
+ LOG.error("Peer certificate was not established during the handshake", e);
+ throw new IllegalStateException("No peer certificate present", e);
+ }
+ return certificates[0].getPublicKey();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.protocol.tls;
+
+import static java.util.Objects.requireNonNull;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import java.net.InetSocketAddress;
+import org.opendaylight.netconf.callhome.protocol.CallHomeNetconfSubsystemListener;
+import org.opendaylight.netconf.client.SslHandlerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfCallHomeTlsServer {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfCallHomeTlsServer.class);
+
+ private final String host;
+ private final Integer port;
+ private final Integer timeout;
+ private final Integer maxConnections;
+ private final SslHandlerFactory sslHandlerFactory;
+ private final CallHomeNetconfSubsystemListener subsystemListener;
+ private final EventLoopGroup bossGroup;
+ private final EventLoopGroup workerGroup;
+
+ private ChannelFuture cf;
+
+ NetconfCallHomeTlsServer(final String host, final Integer port, final Integer timeout, final Integer maxConnections,
+ final SslHandlerFactory sslHandlerFactory,
+ final CallHomeNetconfSubsystemListener subsystemListener,
+ final EventLoopGroup bossGroup, final EventLoopGroup workerGroup) {
+ this.host = requireNonNull(host);
+ this.port = requireNonNull(port);
+ this.timeout = requireNonNull(timeout);
+ this.maxConnections = requireNonNull(maxConnections);
+ this.sslHandlerFactory = requireNonNull(sslHandlerFactory);
+ this.subsystemListener = requireNonNull(subsystemListener);
+ this.bossGroup = requireNonNull(bossGroup);
+ this.workerGroup = requireNonNull(workerGroup);
+ }
+
+ public void start() {
+ final ChannelFuture bindFuture = new ServerBootstrap()
+ .group(bossGroup, workerGroup)
+ // FIXME: a case against using globals: we really would like to use epoll() here
+ .channel(NioServerSocketChannel.class)
+ .localAddress(new InetSocketAddress(host, port))
+ .childOption(ChannelOption.SO_KEEPALIVE, true)
+ .childOption(ChannelOption.SO_BACKLOG, maxConnections)
+ .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)
+ .childHandler(new TlsAuthChannelInitializer(sslHandlerFactory, handshakeListener))
+ .bind();
+ bindFuture.addListener(bindListener);
+ }
+
+ GenericFutureListener<Future<Channel>> handshakeListener = new GenericFutureListener<>() {
+ @Override
+ public void operationComplete(final Future<Channel> future) throws Exception {
+ if (future.isSuccess()) {
+ LOG.debug("SSL handshake completed successfully, accepting connection...");
+ final Channel channel = future.get();
+ final CallHomeTlsSessionContext tlsSessionContext = new CallHomeTlsSessionContext(channel,
+ sslHandlerFactory, subsystemListener);
+ tlsSessionContext.openNetconfChannel(channel);
+ } else {
+ LOG.debug("SSL handshake failed, rejecting connection...");
+ future.get().close();
+ }
+ }
+ };
+
+ GenericFutureListener<ChannelFuture> bindListener = future -> {
+ if (future.isSuccess()) {
+ LOG.debug("Call-Home TLS server bind completed");
+ } else {
+ LOG.error("Call-Home TLS server bind failed", future.cause());
+ }
+ cf = future.channel().closeFuture().addListener(f -> stop());
+ };
+
+ public void stop() {
+ LOG.debug("Stopping the Call-Home TLS server...");
+ try {
+ if (cf != null && cf.channel().isOpen()) {
+ cf.channel().close().sync();
+ }
+ } catch (final InterruptedException e) {
+ LOG.error("Error during shutdown of the Call-Home TLS server", e);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.protocol.tls;
+
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.netconf.callhome.protocol.CallHomeNetconfSubsystemListener;
+import org.opendaylight.netconf.client.SslHandlerFactory;
+
+public class NetconfCallHomeTlsServerBuilder {
+ private String host = "0.0.0.0";
+ private Integer port = 4335;
+ private Integer timeout = 10;
+ private Integer maxConnections = 64;
+ private SslHandlerFactory sslHandlerFactory;
+ private CallHomeNetconfSubsystemListener subsystemListener;
+ private EventLoopGroup bossGroup;
+ private EventLoopGroup workerGroup;
+
+ public NetconfCallHomeTlsServerBuilder setHost(final String host) {
+ this.host = host;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setPort(final Integer port) {
+ this.port = port;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setTimeout(final Integer timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setMaxConnections(final Integer maxConnections) {
+ this.maxConnections = maxConnections;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setSslHandlerFactory(final SslHandlerFactory sslHandlerFactory) {
+ this.sslHandlerFactory = sslHandlerFactory;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setSubsystemListener(final CallHomeNetconfSubsystemListener listener) {
+ this.subsystemListener = listener;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setBossGroup(final EventLoopGroup bossGroup) {
+ this.bossGroup = bossGroup;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServerBuilder setWorkerGroup(final EventLoopGroup workerGroup) {
+ this.workerGroup = workerGroup;
+ return this;
+ }
+
+ public NetconfCallHomeTlsServer build() {
+ return new NetconfCallHomeTlsServer(host, port, timeout, maxConnections, sslHandlerFactory, subsystemListener,
+ bossGroup, workerGroup);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.protocol.tls;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.concurrent.GenericFutureListener;
+import org.opendaylight.netconf.client.SslHandlerFactory;
+
+@SuppressWarnings("rawtypes")
+final class TlsAuthChannelInitializer extends ChannelInitializer {
+
+ private static final String SSL_HANDLER_CHANNEL_NAME = "sslHandler";
+
+ private final SslHandlerFactory sslHandlerFactory;
+ private final GenericFutureListener listener;
+
+ TlsAuthChannelInitializer(final SslHandlerFactory sslHandlerFactory, final GenericFutureListener listener) {
+ this.sslHandlerFactory = sslHandlerFactory;
+ this.listener = listener;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void initChannel(final Channel ch) {
+ final SslHandler sslHandler = sslHandlerFactory.createSslHandler();
+ sslHandler.handshakeFuture().addListener(listener);
+ ch.pipeline().addFirst(SSL_HANDLER_CHANNEL_NAME, sslHandler).fireChannelActive();
+ }
+}
\ No newline at end of file
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.Transport;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.Ssh;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.SshBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.Tls;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.ssh.SshClientParams;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.ssh.SshClientParamsBuilder;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
final SshClientParams params = new SshClientParamsBuilder().setHostKey(hostKey).build();
final Transport sshTransport = new SshBuilder().setSshClientParams(params).build();
deviceBuilder.setTransport(sshTransport);
+ } else if (cfgDevice.getTransport() instanceof Tls) {
+ deviceBuilder.setTransport(cfgDevice.getTransport());
} else if (cfgDevice.getSshHostKey() != null) {
deviceBuilder.setSshHostKey(cfgDevice.getSshHostKey());
}
--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.mount.tls;
+
+public class Configuration {
+ private String host;
+ private Integer port;
+ private Integer timeout;
+ private Integer maxConnections;
+
+ public Configuration() {
+ // empty constructor
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(final String host) {
+ this.host = host;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(final Integer port) {
+ this.port = port;
+ }
+
+ public Integer getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(final Integer timeout) {
+ this.timeout = timeout;
+ }
+
+ public Integer getMaxConnections() {
+ return maxConnections;
+ }
+
+ public void setMaxConnections(final Integer maxConnections) {
+ this.maxConnections = maxConnections;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.mount.tls;
+
+import static java.util.Objects.requireNonNull;
+
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.netconf.callhome.protocol.CallHomeNetconfSubsystemListener;
+import org.opendaylight.netconf.callhome.protocol.tls.NetconfCallHomeTlsServer;
+import org.opendaylight.netconf.callhome.protocol.tls.NetconfCallHomeTlsServerBuilder;
+import org.opendaylight.netconf.client.SslHandlerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfCallHomeTlsService implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfCallHomeTlsService.class);
+
+ private final Configuration config;
+ private final SslHandlerFactory sslHandlerFactory;
+ private final CallHomeNetconfSubsystemListener subsystemListener;
+ private final EventLoopGroup bossGroup;
+ private final EventLoopGroup workerGroup;
+
+ private NetconfCallHomeTlsServer server;
+
+ public NetconfCallHomeTlsService(final Configuration config,
+ final DataBroker dataBroker,
+ final CallHomeNetconfSubsystemListener subsystemListener,
+ final EventLoopGroup bossGroup,
+ final EventLoopGroup workerGroup) {
+ this.config = requireNonNull(config);
+ this.subsystemListener = requireNonNull(subsystemListener);
+ this.bossGroup = requireNonNull(bossGroup);
+ this.workerGroup = requireNonNull(workerGroup);
+ this.sslHandlerFactory = new SslHandlerFactoryAdapter(dataBroker);
+ }
+
+ public void init() {
+ LOG.info("Initializing Call Home TLS server instance");
+
+ final NetconfCallHomeTlsServerBuilder builder = new NetconfCallHomeTlsServerBuilder();
+ server = builder.setHost(config.getHost())
+ .setPort(config.getPort())
+ .setTimeout(config.getTimeout())
+ .setMaxConnections(config.getMaxConnections())
+ .setSslHandlerFactory(sslHandlerFactory)
+ .setSubsystemListener(subsystemListener)
+ .setBossGroup(bossGroup)
+ .setWorkerGroup(workerGroup)
+ .build();
+ server.start();
+
+ LOG.info("Initializing Call Home TLS server instance completed successfuly");
+ }
+
+ @Override
+ public void close() {
+ server.stop();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.callhome.mount.tls;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.collect.ImmutableSet;
+import io.netty.handler.ssl.SslHandler;
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netconf.client.SslHandlerFactory;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter;
+import org.opendaylight.netconf.sal.connect.util.SslHandlerFactoryImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.NetconfCallhomeServer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.AllowedDevices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.Device;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.Tls;
+import org.opendaylight.yangtools.concepts.AbstractRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SslHandlerFactoryAdapter extends AbstractRegistration implements SslHandlerFactory {
+ private static final DataTreeIdentifier<Device> ALLOWED_DEVICES =
+ DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(NetconfCallhomeServer.class).child(AllowedDevices.class).child(Device.class)
+ .build());
+
+ private static final Logger LOG = LoggerFactory.getLogger(SslHandlerFactoryAdapter.class);
+
+ private final DeviceListener deviceListener = new DeviceListener();
+ private final NetconfKeystoreAdapter keystoreAdapter;
+ private final SslHandlerFactory sslHandlerFactory;
+ private final Registration deviceListenerReg;
+
+ public SslHandlerFactoryAdapter(final DataBroker dataBroker) {
+ this.keystoreAdapter = new NetconfKeystoreAdapter(dataBroker);
+ this.sslHandlerFactory = new SslHandlerFactoryImpl(keystoreAdapter);
+ this.deviceListenerReg = dataBroker.registerDataTreeChangeListener(ALLOWED_DEVICES, deviceListener);
+ }
+
+ @Override
+ public SslHandler createSslHandler() {
+ return createSslHandlerFilteredByKeys();
+ }
+
+ @Override
+ public SslHandler createSslHandler(final Set<String> allowedKeys) {
+ return createSslHandlerFilteredByKeys();
+ }
+
+ @Override
+ protected void removeRegistration() {
+ deviceListenerReg.close();
+ }
+
+ private SslHandler createSslHandlerFilteredByKeys() {
+ return sslHandlerFactory.createSslHandler(deviceListener.getAllowedKeys());
+ }
+
+ private static final class DeviceListener implements DataTreeChangeListener<Device> {
+ private final ConcurrentMap<String, String> allowedKeys = new ConcurrentHashMap<>();
+
+ @Override
+ public void onDataTreeChanged(final Collection<DataTreeModification<Device>> mods) {
+ for (final DataTreeModification<Device> dataTreeModification : mods) {
+ final DataObjectModification<Device> deviceMod = dataTreeModification.getRootNode();
+ final DataObjectModification.ModificationType modType = deviceMod.getModificationType();
+ switch (modType) {
+ case DELETE:
+ deleteDevice(deviceMod.getDataBefore());
+ break;
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ deleteDevice(deviceMod.getDataBefore());
+ writeDevice(deviceMod.getDataAfter());
+ break;
+ default:
+ throw new IllegalStateException("Unhandled modification type " + modType);
+ }
+ }
+ }
+
+ Set<String> getAllowedKeys() {
+ final Set<String> ret = ImmutableSet.copyOf(allowedKeys.values());
+ checkState(!ret.isEmpty(), "No associated keys for TLS authentication were found");
+ return ret;
+ }
+
+ private void deleteDevice(final Device dataBefore) {
+ if (dataBefore != null && dataBefore.getTransport() instanceof Tls) {
+ LOG.debug("Removing device {}", dataBefore.getUniqueId());
+ allowedKeys.remove(dataBefore.getUniqueId());
+ }
+ }
+
+ private void writeDevice(final Device dataAfter) {
+ if (dataAfter != null && dataAfter.getTransport() instanceof Tls) {
+ LOG.debug("Adding device {}", dataAfter.getUniqueId());
+ final String tlsKeyId = ((Tls) dataAfter.getTransport()).getTlsClientParams().getKeyId();
+ allowedKeys.putIfAbsent(dataAfter.getUniqueId(), tlsKeyId);
+ }
+ }
+ }
+}
\ No newline at end of file
interface="org.opendaylight.netconf.sal.connect.api.SchemaResourceManager"/>
<reference id="baseSchemas"
interface="org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas"/>
+ <reference id="globalBossGroup"
+ interface="io.netty.channel.EventLoopGroup"
+ odl:type="global-boss-group"/>
+ <reference id="globalWorkerGroup"
+ interface="io.netty.channel.EventLoopGroup"
+ odl:type="global-worker-group"/>
<bean id="callhomeProvider" class="org.opendaylight.netconf.callhome.mount.IetfZeroTouchCallHomeServerProvider"
init-method="init"
<argument ref="encryptionService"/>
<argument ref="deviceActionFactory"/>
</bean>
+
+ <!-- Configuration for NetConf Call-Home TLS -->
+ <bean id="netconfCallHomeTlsConfiguration" class="org.opendaylight.netconf.callhome.mount.tls.Configuration">
+ <property name="host" value="0.0.0.0" />
+ <property name="port" value="4335" />
+ <property name="timeout" value="10000" />
+ <property name="maxConnections" value="64" />
+ </bean>
+
+ <bean id="netconfCallHomeService" class="org.opendaylight.netconf.callhome.mount.tls.NetconfCallHomeTlsService"
+ init-method="init"
+ destroy-method="close">
+ <argument ref="netconfCallHomeTlsConfiguration" />
+ <argument ref="dataBroker" />
+ <argument ref="callhomeDispatcher" />
+ <argument ref="globalBossGroup"/>
+ <argument ref="globalWorkerGroup"/>
+ </bean>
+
</blueprint>
import io.netty.util.concurrent.Promise;
import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer;
-final class TlsClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
+public final class TlsClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
public static final String CHANNEL_ACTIVE_SENTRY = "channelActiveSentry";
private final SslHandlerFactory sslHandlerFactory;
private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
private final NetconfClientSessionListener sessionListener;
- TlsClientChannelInitializer(final SslHandlerFactory sslHandlerFactory,
- final NetconfClientSessionNegotiatorFactory negotiatorFactory,
- final NetconfClientSessionListener sessionListener) {
+ public TlsClientChannelInitializer(final SslHandlerFactory sslHandlerFactory,
+ final NetconfClientSessionNegotiatorFactory negotiatorFactory,
+ final NetconfClientSessionListener sessionListener) {
this.sslHandlerFactory = sslHandlerFactory;
this.negotiatorFactory = negotiatorFactory;
this.sessionListener = sessionListener;