2 * Copyright (c) 2020 Pantheon Technologies, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.callhome.mount.tls;
10 import static com.google.common.base.Preconditions.checkState;
12 import com.google.common.collect.ImmutableSet;
13 import io.netty.handler.ssl.SslHandler;
14 import java.util.Collection;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.DataObjectModification;
20 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.mdsal.binding.api.DataTreeModification;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.netconf.client.SslHandlerFactory;
25 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter;
26 import org.opendaylight.netconf.sal.connect.util.SslHandlerFactoryImpl;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.NetconfCallhomeServer;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.AllowedDevices;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.Device;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.device.transport.Tls;
31 import org.opendaylight.yangtools.concepts.AbstractRegistration;
32 import org.opendaylight.yangtools.concepts.Registration;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 public class SslHandlerFactoryAdapter extends AbstractRegistration implements SslHandlerFactory {
38 private static final DataTreeIdentifier<Device> ALLOWED_DEVICES =
39 DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
40 InstanceIdentifier.builder(NetconfCallhomeServer.class).child(AllowedDevices.class).child(Device.class)
43 private static final Logger LOG = LoggerFactory.getLogger(SslHandlerFactoryAdapter.class);
45 private final DeviceListener deviceListener = new DeviceListener();
46 private final NetconfKeystoreAdapter keystoreAdapter;
47 private final SslHandlerFactory sslHandlerFactory;
48 private final Registration deviceListenerReg;
50 public SslHandlerFactoryAdapter(final DataBroker dataBroker) {
51 this.keystoreAdapter = new NetconfKeystoreAdapter(dataBroker);
52 this.sslHandlerFactory = new SslHandlerFactoryImpl(keystoreAdapter);
53 this.deviceListenerReg = dataBroker.registerDataTreeChangeListener(ALLOWED_DEVICES, deviceListener);
57 public SslHandler createSslHandler() {
58 return createSslHandlerFilteredByKeys();
62 public SslHandler createSslHandler(final Set<String> allowedKeys) {
63 return createSslHandlerFilteredByKeys();
67 protected void removeRegistration() {
68 deviceListenerReg.close();
71 private SslHandler createSslHandlerFilteredByKeys() {
72 return sslHandlerFactory.createSslHandler(deviceListener.getAllowedKeys());
75 private static final class DeviceListener implements DataTreeChangeListener<Device> {
76 private final ConcurrentMap<String, String> allowedKeys = new ConcurrentHashMap<>();
79 public void onDataTreeChanged(final Collection<DataTreeModification<Device>> mods) {
80 for (final DataTreeModification<Device> dataTreeModification : mods) {
81 final DataObjectModification<Device> deviceMod = dataTreeModification.getRootNode();
82 final DataObjectModification.ModificationType modType = deviceMod.getModificationType();
85 deleteDevice(deviceMod.getDataBefore());
87 case SUBTREE_MODIFIED:
89 deleteDevice(deviceMod.getDataBefore());
90 writeDevice(deviceMod.getDataAfter());
93 throw new IllegalStateException("Unhandled modification type " + modType);
98 Set<String> getAllowedKeys() {
99 final Set<String> ret = ImmutableSet.copyOf(allowedKeys.values());
100 checkState(!ret.isEmpty(), "No associated keys for TLS authentication were found");
104 private void deleteDevice(final Device dataBefore) {
105 if (dataBefore != null && dataBefore.getTransport() instanceof Tls) {
106 LOG.debug("Removing device {}", dataBefore.getUniqueId());
107 allowedKeys.remove(dataBefore.getUniqueId());
111 private void writeDevice(final Device dataAfter) {
112 if (dataAfter != null && dataAfter.getTransport() instanceof Tls) {
113 LOG.debug("Adding device {}", dataAfter.getUniqueId());
114 final String tlsKeyId = ((Tls) dataAfter.getTransport()).getTlsClientParams().getKeyId();
115 allowedKeys.putIfAbsent(dataAfter.getUniqueId(), tlsKeyId);