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.callhome.server.tls;
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.callhome.server.AbstractCallHomeSessionContextManager;
18 import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder;
19 import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
23 public class CallHomeTlsSessionContextManager extends AbstractCallHomeSessionContextManager<CallHomeTlsSessionContext> {
24 private static final Logger LOG = LoggerFactory.getLogger(CallHomeTlsSessionContextManager.class);
26 private final CallHomeTlsAuthProvider authProvider;
27 private final CallHomeStatusRecorder statusRecorder;
29 public CallHomeTlsSessionContextManager(final CallHomeTlsAuthProvider authProvider,
30 final CallHomeStatusRecorder statusRecorder) {
32 this.authProvider = requireNonNull(authProvider);
33 this.statusRecorder = requireNonNull(statusRecorder);
37 public CallHomeTlsSessionContext findByChannel(final Channel channel) {
38 requireNonNull(channel);
39 return channel.isOpen() ? createValidContext(channel) : null;
42 private CallHomeTlsSessionContext createValidContext(final Channel channel) {
43 // extract peer public key from SSL session
44 final PublicKey publicKey;
46 final var cert = channel.pipeline().get(SslHandler.class).engine().getSession()
47 .getPeerCertificates()[0];
48 publicKey = cert.getPublicKey();
49 } catch (SSLPeerUnverifiedException e) {
50 LOG.error("Exception retrieving certificate", e);
53 // identify connection
54 final String id = authProvider.idFor(publicKey);
56 statusRecorder.reportUnknown(channel.remoteAddress(), publicKey);
60 final var context = createContext(id, channel);
61 if (context == null) {
62 // if there is an issue creating context then the cause expected to be
63 // logged within overridden createContext() method
68 channel.closeFuture().addListener(ignored -> {
70 if (context.settableFuture().isDone()) {
71 // disconnect after netconf session established
72 statusRecorder.reportDisconnected(id);
76 LOG.debug("Session context is created for TLS session: {}", context);
81 * Builds {@link CallHomeTlsSessionContext} based on {@link Channel} object.
83 * <p> The method expected to be overridden in order to inject
84 * {@link org.opendaylight.netconf.client.NetconfClientSessionListener NetconfClientSessionListener} and/or
85 * {@link SettableFuture} of a {@link org.opendaylight.netconf.client.NetconfClientSession NetconfClientSession}
86 * to be established on current connection.
88 * @param id unique client (device) identifier
89 * @param channel netty channel instance
90 * @return created object or {@code null} if it cannot be created for some reason
92 public CallHomeTlsSessionContext createContext(final String id, final Channel channel) {
93 return new CallHomeTlsSessionContext(id, channel, new SimpleNetconfClientSessionListener(),
94 SettableFuture.create());