2 * Copyright (c) 2023 PANTHEON.tech 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.topology.callhome;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.util.concurrent.SettableFuture;
13 import io.netty.channel.Channel;
14 import io.netty.handler.ssl.SslHandler;
15 import java.security.PublicKey;
16 import javax.net.ssl.SSLPeerUnverifiedException;
17 import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
21 public class CallHomeTlsSessionContextManager extends AbstractCallHomeSessionContextManager<CallHomeTlsSessionContext> {
22 private static final Logger LOG = LoggerFactory.getLogger(CallHomeTlsSessionContextManager.class);
24 private final CallHomeTlsAuthProvider authProvider;
25 private final CallHomeStatusRecorder statusRecorder;
27 public CallHomeTlsSessionContextManager(final CallHomeTlsAuthProvider authProvider,
28 final CallHomeStatusRecorder statusRecorder) {
30 this.authProvider = requireNonNull(authProvider);
31 this.statusRecorder = requireNonNull(statusRecorder);
35 public CallHomeTlsSessionContext findByChannel(final Channel channel) {
36 requireNonNull(channel);
37 return channel.isOpen() ? createValidContext(channel) : null;
40 private CallHomeTlsSessionContext createValidContext(final Channel channel) {
41 // extract peer public key from SSL session
42 final PublicKey publicKey;
44 final var cert = channel.pipeline().get(SslHandler.class).engine().getSession()
45 .getPeerCertificates()[0];
46 publicKey = cert.getPublicKey();
47 } catch (SSLPeerUnverifiedException e) {
48 LOG.error("Exception retrieving certificate", e);
51 // identify connection
52 final String id = authProvider.idFor(publicKey);
54 statusRecorder.reportUnknown(channel.remoteAddress(), publicKey);
58 final var context = createContext(id, channel);
59 if (context == null) {
60 // if there is an issue creating context then the cause expected to be
61 // logged within overridden createContext() method
66 channel.closeFuture().addListener(ignored -> {
68 if (context.settableFuture().isDone()) {
69 // disconnect after netconf session established
70 statusRecorder.reportDisconnected(id);
74 LOG.debug("Session context is created for TLS session: {}", context);
79 * Builds {@link CallHomeTlsSessionContext} based on {@link Channel} object.
81 * <p> The method expected to be overridden in order to inject
82 * {@link org.opendaylight.netconf.client.NetconfClientSessionListener NetconfClientSessionListener} and/or
83 * {@link SettableFuture} of a {@link org.opendaylight.netconf.client.NetconfClientSession NetconfClientSession}
84 * to be established on current connection.
86 * @param id unique client (device) identifier
87 * @param channel netty channel instance
88 * @return created object or {@code null} if it cannot be created for some reason
90 public CallHomeTlsSessionContext createContext(final String id, final Channel channel) {
91 return new CallHomeTlsSessionContext(id, channel, new SimpleNetconfClientSessionListener(),
92 SettableFuture.create());