Ssh proxy served as a bridge to local tcp netconf server.
New ssh transport implementation does not require a proxy.
JIRA: NETCONF-1106
Change-Id: I1b5aee1f6128b4e98918176e35f6e80f1b2c7527
Signed-off-by: Ruslan Kashapov <ruslan.kashapov@pantheon.tech>
+++ /dev/null
-/*
- * Copyright (c) 2022 PANTHEON.tech, 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.northbound.ssh;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.util.concurrent.ForwardingExecutorService;
-import java.util.concurrent.ExecutorService;
-
-/**
- * Facade for guarding against {@link #shutdown()} invocations. This is necessary as SSHD wants to shutdown the executor
- * when the server shuts down.
- */
-@Deprecated(since = "7.0.0", forRemoval = true)
-final class ExecutorServiceFacade extends ForwardingExecutorService {
- private final ExecutorService delegate;
-
- ExecutorServiceFacade(final ExecutorService delegate) {
- this.delegate = requireNonNull(delegate);
- }
-
- @Override
- protected ExecutorService delegate() {
- return delegate;
- }
-
- @Override
- public void shutdown() {
- // NO-OP
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import static java.util.Objects.requireNonNull;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.local.LocalChannel;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoInputStream;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoOutputStream;
-import org.opendaylight.netconf.shaded.sshd.server.Environment;
-import org.opendaylight.netconf.shaded.sshd.server.ExitCallback;
-import org.opendaylight.netconf.shaded.sshd.server.channel.ChannelSession;
-import org.opendaylight.netconf.shaded.sshd.server.command.AsyncCommand;
-import org.opendaylight.netconf.shaded.sshd.server.command.Command;
-import org.opendaylight.netconf.shaded.sshd.server.session.ServerSession;
-import org.opendaylight.netconf.shaded.sshd.server.subsystem.SubsystemFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This command handles all netconf related rpc and forwards to delegate server.
- * Uses netty to make a local connection to delegate server.
- *
- * <p>
- * Command is Apache Mina SSH terminology for objects handling ssh data.
- */
-@Deprecated(since = "7.0.0", forRemoval = true)
-final class RemoteNetconfCommand implements AsyncCommand {
- private static final Logger LOG = LoggerFactory.getLogger(RemoteNetconfCommand.class);
-
- private final EventLoopGroup clientEventGroup;
- private final LocalAddress localAddress;
-
- private IoInputStream in;
- private IoOutputStream out;
- private ExitCallback callback;
- private NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader;
-
- private Channel clientChannel;
- private ChannelFuture clientChannelFuture;
-
- RemoteNetconfCommand(final EventLoopGroup clientEventGroup, final LocalAddress localAddress) {
- this.clientEventGroup = clientEventGroup;
- this.localAddress = localAddress;
- }
-
- @Override
- @SuppressWarnings("checkstyle:hiddenField")
- public void setIoInputStream(final IoInputStream in) {
- this.in = in;
- }
-
- @Override
- @SuppressWarnings("checkstyle:hiddenField")
- public void setIoOutputStream(final IoOutputStream out) {
- this.out = out;
- }
-
- @Override
- public void setIoErrorStream(final IoOutputStream err) {
- // TODO do we want to use error stream in some way ?
- }
-
- @Override
- @SuppressWarnings("checkstyle:hiddenField")
- public void setInputStream(final InputStream in) {
- throw new UnsupportedOperationException("Synchronous IO is unsupported");
- }
-
- @Override
- @SuppressWarnings("checkstyle:hiddenField")
- public void setOutputStream(final OutputStream out) {
- throw new UnsupportedOperationException("Synchronous IO is unsupported");
-
- }
-
- @Override
- public void setErrorStream(final OutputStream err) {
- throw new UnsupportedOperationException("Synchronous IO is unsupported");
-
- }
-
- @Override
- @SuppressWarnings("checkstyle:hiddenField")
- public void setExitCallback(final ExitCallback callback) {
- this.callback = callback;
- }
-
- @Override
- public void start(final ChannelSession channel, final Environment env) {
- final ServerSession session = channel.getServerSession();
- final SocketAddress remoteAddress = session.getIoSession().getRemoteAddress();
- final String hostName;
- final String port;
- if (remoteAddress instanceof InetSocketAddress remoteInetAddress) {
- hostName = remoteInetAddress.getAddress().getHostAddress();
- port = Integer.toString(remoteInetAddress.getPort());
- } else {
- hostName = "";
- port = "";
- }
- netconfHelloMessageAdditionalHeader = new NetconfHelloMessageAdditionalHeader(session.getUsername(), hostName,
- port, "ssh", "client");
-
- LOG.trace("Establishing internal connection to netconf server for client: {}", getClientAddress());
-
- final Bootstrap clientBootstrap = new Bootstrap();
- clientBootstrap.group(clientEventGroup).channel(LocalChannel.class);
-
- clientBootstrap.handler(new ChannelInitializer<LocalChannel>() {
- @Override
- public void initChannel(final LocalChannel ch) {
- ch.pipeline()
- .addLast(new SshProxyClientHandler(in, out, netconfHelloMessageAdditionalHeader, callback));
- }
- });
- clientChannelFuture = clientBootstrap.connect(localAddress);
- clientChannelFuture.addListener(future -> {
- if (future.isSuccess()) {
- clientChannel = clientChannelFuture.channel();
- } else {
- LOG.warn("Unable to establish internal connection to netconf server for client: {}",
- getClientAddress());
- requireNonNull(callback, "Exit callback must be set").onExit(1,
- "Unable to establish internal connection to netconf server for client: " + getClientAddress());
- }
- });
- }
-
- @Override
- public void destroy(final ChannelSession channel) {
- LOG.trace("Releasing internal connection to netconf server for client: {} on channel: {}",
- getClientAddress(), clientChannel);
-
- clientChannelFuture.cancel(true);
- if (clientChannel != null) {
- clientChannel.close().addListener(future -> {
- if (!future.isSuccess()) {
- LOG.warn("Unable to release internal connection to netconf server on channel: {}",
- clientChannel);
- }
- });
- }
- }
-
- private String getClientAddress() {
- return netconfHelloMessageAdditionalHeader.getAddress();
- }
-
- static class NetconfCommandFactory implements SubsystemFactory {
- public static final String NETCONF = "netconf";
-
- private final EventLoopGroup clientBootstrap;
- private final LocalAddress localAddress;
-
- NetconfCommandFactory(final EventLoopGroup clientBootstrap, final LocalAddress localAddress) {
- this.clientBootstrap = clientBootstrap;
- this.localAddress = localAddress;
- }
-
- @Override
- public String getName() {
- return NETCONF;
- }
-
- @Override
- public Command createSubsystem(final ChannelSession channel) {
- return new RemoteNetconfCommand(clientBootstrap, localAddress);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import java.nio.charset.StandardCharsets;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader;
-import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerWriter;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoInputStream;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoOutputStream;
-import org.opendaylight.netconf.shaded.sshd.server.ExitCallback;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Netty handler that reads SSH from remote client and writes to delegate server
- * and reads from delegate server and writes to remote client.
- */
-@Deprecated(since = "7.0.0", forRemoval = true)
-final class SshProxyClientHandler extends ChannelInboundHandlerAdapter {
- private static final Logger LOG = LoggerFactory.getLogger(SshProxyClientHandler.class);
-
- private final IoInputStream in;
- private final IoOutputStream out;
-
- private AsyncSshHandlerReader asyncSshHandlerReader;
- private AsyncSshHandlerWriter asyncSshHandlerWriter;
-
- private final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader;
- private final ExitCallback callback;
-
- SshProxyClientHandler(final IoInputStream in, final IoOutputStream out,
- final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader,
- final ExitCallback callback) {
- this.in = in;
- this.out = out;
- this.netconfHelloMessageAdditionalHeader = netconfHelloMessageAdditionalHeader;
- this.callback = callback;
- }
-
- @Override
- public void channelActive(final ChannelHandlerContext ctx) throws Exception {
- writeAdditionalHeader(ctx);
-
- asyncSshHandlerWriter = new AsyncSshHandlerWriter(out);
- asyncSshHandlerReader = new AsyncSshHandlerReader(() -> {
- // Close both sessions (delegate server and remote client)
- ctx.fireChannelInactive();
- ctx.disconnect();
- ctx.close();
- asyncSshHandlerReader.close();
- asyncSshHandlerWriter.close();
- }, msg -> {
- if (LOG.isTraceEnabled()) {
- LOG.trace("Forwarding message for client: {} on channel: {}, message: {}",
- netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel(),
- AsyncSshHandlerWriter.byteBufToString(msg));
- }
- // Just forward to delegate
- ctx.writeAndFlush(msg);
- }, "ssh" + netconfHelloMessageAdditionalHeader.getAddress(), in);
-
-
- super.channelActive(ctx);
- }
-
- private void writeAdditionalHeader(final ChannelHandlerContext ctx) {
- ctx.writeAndFlush(Unpooled.copiedBuffer(netconfHelloMessageAdditionalHeader.toFormattedString()
- .getBytes(StandardCharsets.UTF_8)));
- }
-
- @Override
- public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
- asyncSshHandlerWriter.write(ctx, msg, ctx.newPromise());
- }
-
- @Override
- public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
- LOG.debug("Internal connection to netconf server was dropped for client: {} on channel: {}",
- netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel());
- callback.onExit(1, "Internal connection to netconf server was dropped for client: "
- + netconfHelloMessageAdditionalHeader.getAddress() + " on channel: " + ctx.channel());
- super.channelInactive(ctx);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import io.netty.channel.EventLoopGroup;
-import java.io.IOException;
-import java.nio.channels.AsynchronousChannelGroup;
-import java.time.Duration;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-import org.opendaylight.netconf.shaded.sshd.common.FactoryManager;
-import org.opendaylight.netconf.shaded.sshd.common.NamedFactory;
-import org.opendaylight.netconf.shaded.sshd.common.RuntimeSshException;
-import org.opendaylight.netconf.shaded.sshd.common.cipher.BuiltinCiphers;
-import org.opendaylight.netconf.shaded.sshd.common.cipher.Cipher;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoAcceptor;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoConnector;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoHandler;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoServiceEventListener;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoServiceFactory;
-import org.opendaylight.netconf.shaded.sshd.common.io.IoServiceFactoryFactory;
-import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2Acceptor;
-import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2Connector;
-import org.opendaylight.netconf.shaded.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
-import org.opendaylight.netconf.shaded.sshd.common.session.SessionHeartbeatController.HeartbeatType;
-import org.opendaylight.netconf.shaded.sshd.common.util.closeable.AbstractCloseable;
-import org.opendaylight.netconf.shaded.sshd.core.CoreModuleProperties;
-import org.opendaylight.netconf.shaded.sshd.server.SshServer;
-
-/**
- * Proxy SSH server that just delegates decrypted content to a delegate server within same VM.
- * Implemented using Apache Mina SSH lib.
- */
-@Deprecated(since = "7.0.0", forRemoval = true)
-public class SshProxyServer implements AutoCloseable {
- private final SshServer sshServer;
- private final ScheduledExecutorService minaTimerExecutor;
- private final EventLoopGroup clientGroup;
- private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory;
-
- private SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup,
- final IoServiceFactoryFactory serviceFactory) {
- this.minaTimerExecutor = minaTimerExecutor;
- this.clientGroup = clientGroup;
- nioServiceWithPoolFactoryFactory = serviceFactory;
- sshServer = SshServer.setUpDefaultServer();
- }
-
- public SshProxyServer(final ScheduledExecutorService minaTimerExecutor,
- final EventLoopGroup clientGroup, final ExecutorService nioExecutor) {
- this(minaTimerExecutor, clientGroup, new NioServiceWithPoolFactoryFactory(nioExecutor));
- }
-
- /**
- * Create a server with a shared {@link AsynchronousChannelGroup}. Unlike the other constructor, this does
- * not create a dedicated thread group, which is useful when you need to start a large number of servers and do
- * not want to have a thread group (and hence an anonyous thread) for each of them.
- */
- @VisibleForTesting
- public SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup,
- final AsynchronousChannelGroup group) {
- this(minaTimerExecutor, clientGroup, new SharedNioServiceFactoryFactory(group));
- }
-
- public void bind(final SshProxyServerConfiguration sshProxyServerConfiguration) throws IOException {
- sshServer.setHost(sshProxyServerConfiguration.getBindingAddress().getHostString());
- sshServer.setPort(sshProxyServerConfiguration.getBindingAddress().getPort());
-
- //remove rc4 ciphers
- final List<NamedFactory<Cipher>> cipherFactories = sshServer.getCipherFactories();
- cipherFactories.removeIf(factory -> factory.getName().contains(BuiltinCiphers.arcfour128.getName())
- || factory.getName().contains(BuiltinCiphers.arcfour256.getName()));
- sshServer.setPasswordAuthenticator(
- (username, password, session)
- -> sshProxyServerConfiguration.getAuthenticator().authenticated(username, password));
-
- sshProxyServerConfiguration.getPublickeyAuthenticator().ifPresent(sshServer::setPublickeyAuthenticator);
-
- sshServer.setKeyPairProvider(sshProxyServerConfiguration.getKeyPairProvider());
-
- sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory);
- sshServer.setScheduledExecutorService(minaTimerExecutor);
-
- final int idleTimeoutMillis = sshProxyServerConfiguration.getIdleTimeout();
- final Duration idleTimeout = Duration.ofMillis(idleTimeoutMillis);
- CoreModuleProperties.IDLE_TIMEOUT.set(sshServer, idleTimeout);
-
- final Duration nioReadTimeout;
- if (idleTimeoutMillis > 0) {
- final long heartBeat = idleTimeoutMillis * 333333L;
- sshServer.setSessionHeartbeat(HeartbeatType.IGNORE, TimeUnit.NANOSECONDS, heartBeat);
- nioReadTimeout = Duration.ofMillis(idleTimeoutMillis + TimeUnit.SECONDS.toMillis(15L));
- } else {
- nioReadTimeout = Duration.ZERO;
- }
- CoreModuleProperties.NIO2_READ_TIMEOUT.set(sshServer, nioReadTimeout);
- CoreModuleProperties.AUTH_TIMEOUT.set(sshServer, idleTimeout);
- CoreModuleProperties.TCP_NODELAY.set(sshServer, Boolean.TRUE);
-
- final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory =
- new RemoteNetconfCommand.NetconfCommandFactory(clientGroup,
- sshProxyServerConfiguration.getLocalAddress());
- sshServer.setSubsystemFactories(ImmutableList.of(netconfCommandFactory));
- sshServer.start();
- }
-
- @Override
- public void close() throws IOException {
- try {
- sshServer.stop(true);
- } finally {
- sshServer.close(true);
- }
- }
-
- private abstract static class AbstractNioServiceFactory extends AbstractCloseable implements IoServiceFactory {
- private final FactoryManager manager;
- private final AsynchronousChannelGroup group;
- private final ExecutorService resumeTasks;
- private IoServiceEventListener eventListener;
-
- AbstractNioServiceFactory(final FactoryManager manager, final AsynchronousChannelGroup group,
- final ExecutorService resumeTasks) {
- this.manager = requireNonNull(manager);
- this.group = requireNonNull(group);
- this.resumeTasks = requireNonNull(resumeTasks);
- }
-
- final AsynchronousChannelGroup group() {
- return group;
- }
-
- final ExecutorService resumeTasks() {
- return resumeTasks;
- }
-
- @Override
- public final IoConnector createConnector(final IoHandler handler) {
- return new Nio2Connector(manager, handler, group, resumeTasks);
- }
-
- @Override
- public final IoAcceptor createAcceptor(final IoHandler handler) {
- return new Nio2Acceptor(manager, handler, group, resumeTasks);
- }
-
- @Override
- public final IoServiceEventListener getIoServiceEventListener() {
- return eventListener;
- }
-
- @Override
- public final void setIoServiceEventListener(final IoServiceEventListener listener) {
- eventListener = listener;
- }
- }
-
- /**
- * Based on Nio2ServiceFactory with one addition: injectable executor.
- */
- private static final class NioServiceWithPoolFactory extends AbstractNioServiceFactory {
- NioServiceWithPoolFactory(final FactoryManager manager, final AsynchronousChannelGroup group,
- final ExecutorService resumeTasks) {
- super(manager, group, resumeTasks);
- }
-
- @Override
- protected void doCloseImmediately() {
- try {
- resumeTasks().shutdownNow();
- group().shutdownNow();
- resumeTasks().awaitTermination(5, TimeUnit.SECONDS);
- group().awaitTermination(5, TimeUnit.SECONDS);
- } catch (final IOException | InterruptedException e) {
- log.debug("Exception caught while closing channel group", e);
- } finally {
- super.doCloseImmediately();
- }
- }
- }
-
- private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory {
- private static final AtomicLong COUNTER = new AtomicLong();
-
- private final ExecutorServiceFacade nioExecutor;
-
- NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) {
- this.nioExecutor = new ExecutorServiceFacade(nioExecutor);
- }
-
- @Override
- public IoServiceFactory create(final FactoryManager manager) {
- try {
- return new NioServiceWithPoolFactory(manager, AsynchronousChannelGroup.withThreadPool(nioExecutor),
- Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
- .setNameFormat("sshd-resume-read-" + COUNTER.getAndIncrement() + "-%d")
- .build()));
- } catch (final IOException e) {
- throw new RuntimeSshException("Failed to create channel group", e);
- }
- }
- }
-
- private static final class SharedNioServiceFactory extends AbstractNioServiceFactory {
- SharedNioServiceFactory(final FactoryManager manager, final AsynchronousChannelGroup group,
- final ExecutorService resumeTasks) {
- super(manager, group, resumeTasks);
- }
- }
-
- private static final class SharedNioServiceFactoryFactory extends Nio2ServiceFactoryFactory {
- private final AsynchronousChannelGroup group;
-
- SharedNioServiceFactoryFactory(final AsynchronousChannelGroup group) {
- this.group = requireNonNull(group);
- }
-
- @Override
- public IoServiceFactory create(final FactoryManager manager) {
- return new SharedNioServiceFactory(manager, group, Executors.newSingleThreadExecutor());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-import io.netty.channel.local.LocalAddress;
-import java.net.InetSocketAddress;
-import java.util.Optional;
-import org.opendaylight.netconf.auth.AuthProvider;
-import org.opendaylight.netconf.shaded.sshd.common.keyprovider.KeyPairProvider;
-import org.opendaylight.netconf.shaded.sshd.server.auth.pubkey.PublickeyAuthenticator;
-
-@Deprecated(since = "7.0.0", forRemoval = true)
-public final class SshProxyServerConfiguration {
- private final InetSocketAddress bindingAddress;
- private final LocalAddress localAddress;
- private final AuthProvider authenticator;
- private final KeyPairProvider keyPairProvider;
- private final int idleTimeout;
- private final Optional<PublickeyAuthenticator> publickeyAuthenticator;
-
- SshProxyServerConfiguration(final InetSocketAddress bindingAddress, final LocalAddress localAddress,
- final AuthProvider authenticator, final PublickeyAuthenticator publickeyAuthenticator,
- final KeyPairProvider keyPairProvider, final int idleTimeout) {
- this.bindingAddress = requireNonNull(bindingAddress);
- this.localAddress = requireNonNull(localAddress);
- this.authenticator = requireNonNull(authenticator);
- this.keyPairProvider = requireNonNull(keyPairProvider);
- // Idle timeout cannot be disabled in the sshd by using =< 0 value
- checkArgument(idleTimeout > 0, "Idle timeout has to be > 0");
- this.idleTimeout = idleTimeout;
- this.publickeyAuthenticator = Optional.ofNullable(publickeyAuthenticator);
- }
-
- public InetSocketAddress getBindingAddress() {
- return bindingAddress;
- }
-
- public LocalAddress getLocalAddress() {
- return localAddress;
- }
-
- public AuthProvider getAuthenticator() {
- return authenticator;
- }
-
- public KeyPairProvider getKeyPairProvider() {
- return keyPairProvider;
- }
-
- public int getIdleTimeout() {
- return idleTimeout;
- }
-
- public Optional<PublickeyAuthenticator> getPublickeyAuthenticator() {
- return publickeyAuthenticator;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.channel.local.LocalAddress;
-import java.net.InetSocketAddress;
-import org.opendaylight.netconf.auth.AuthProvider;
-import org.opendaylight.netconf.shaded.sshd.common.keyprovider.KeyPairProvider;
-import org.opendaylight.netconf.shaded.sshd.server.auth.pubkey.PublickeyAuthenticator;
-
-@Deprecated(since = "7.0.0", forRemoval = true)
-public final class SshProxyServerConfigurationBuilder {
- private InetSocketAddress bindingAddress;
- private LocalAddress localAddress;
- private AuthProvider authenticator;
- private KeyPairProvider keyPairProvider;
- private int idleTimeout;
- private PublickeyAuthenticator publickeyAuthenticator = null;
-
- public SshProxyServerConfigurationBuilder setBindingAddress(final InetSocketAddress bindingAddress) {
- this.bindingAddress = bindingAddress;
- return this;
- }
-
- public SshProxyServerConfigurationBuilder setLocalAddress(final LocalAddress localAddress) {
- this.localAddress = localAddress;
- return this;
- }
-
- public SshProxyServerConfigurationBuilder setAuthenticator(final AuthProvider authenticator) {
- this.authenticator = authenticator;
- return this;
- }
-
- public SshProxyServerConfigurationBuilder setPublickeyAuthenticator(
- final PublickeyAuthenticator publickeyAuthenticator) {
- this.publickeyAuthenticator = publickeyAuthenticator;
- return this;
- }
-
- public SshProxyServerConfigurationBuilder setKeyPairProvider(final KeyPairProvider keyPairProvider) {
- this.keyPairProvider = keyPairProvider;
- return this;
- }
-
- public SshProxyServerConfigurationBuilder setIdleTimeout(final int idleTimeout) {
- this.idleTimeout = idleTimeout;
- return this;
- }
-
- public SshProxyServerConfiguration createSshProxyServerConfiguration() {
- return new SshProxyServerConfiguration(bindingAddress, localAddress, authenticator, publickeyAuthenticator,
- keyPairProvider, idleTimeout);
- }
-
- public static SshProxyServerConfigurationBuilder create() {
- return new SshProxyServerConfigurationBuilder();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.local.LocalChannel;
-import io.netty.channel.nio.NioEventLoopGroup;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Sends one message when a connection is open and echoes back any received
- * data to the server. Simply put, the echo client initiates the ping-pong
- * traffic between the echo client and server by sending the first message to
- * the server.
- */
-public class EchoClient extends Thread {
- private static final Logger LOG = LoggerFactory.getLogger(EchoClient.class);
-
- private final ChannelInitializer<LocalChannel> channelInitializer;
-
- public EchoClient(final ChannelHandler clientHandler) {
- channelInitializer = new ChannelInitializer<>() {
- @Override
- public void initChannel(final LocalChannel ch) {
- ch.pipeline().addLast(clientHandler);
- }
- };
- }
-
- public EchoClient(final ChannelInitializer<LocalChannel> channelInitializer) {
- this.channelInitializer = channelInitializer;
- }
-
- @Override
- public void run() {
- // Configure the client.
- EventLoopGroup group = new NioEventLoopGroup();
- try {
- Bootstrap bootstrap = new Bootstrap();
-
- bootstrap.group(group)
- .channel(LocalChannel.class)
- .handler(channelInitializer);
-
- // Start the client.
- LocalAddress localAddress = new LocalAddress("foo");
- ChannelFuture future = bootstrap.connect(localAddress).sync();
-
- // Wait until the connection is closed.
- future.channel().closeFuture().sync();
- } catch (InterruptedException e) {
- LOG.error("Error in client", e);
- throw new RuntimeException("Error in client", e);
- } finally {
- // Shut down the event loop to terminate all threads.
- LOG.info("Client is shutting down");
- group.shutdownGracefully();
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import static com.google.common.base.Preconditions.checkState;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Handler implementation for the echo client. It initiates the ping-pong
- * traffic between the echo client and server by sending the first message to
- * the server.
- */
-public class EchoClientHandler extends ChannelInboundHandlerAdapter implements ChannelFutureListener {
- public enum State {
- CONNECTING, CONNECTED, FAILED_TO_CONNECT, CONNECTION_CLOSED
- }
-
- private static final Logger LOG = LoggerFactory.getLogger(EchoClientHandler.class);
-
- private final StringBuilder fromServer = new StringBuilder();
- private ChannelHandlerContext context;
- private State state = State.CONNECTING;
-
- @Override
- public synchronized void channelActive(final ChannelHandlerContext ctx) {
- checkState(context == null);
- LOG.info("channelActive");
- context = ctx;
- state = State.CONNECTED;
- }
-
- @Override
- public synchronized void channelInactive(final ChannelHandlerContext ctx) throws Exception {
- state = State.CONNECTION_CLOSED;
- }
-
- @Override
- public synchronized void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
- ByteBuf bb = (ByteBuf) msg;
- String string = bb.toString(UTF_8);
- fromServer.append(string);
- LOG.info(">{}", string);
- bb.release();
- }
-
- @Override
- public synchronized void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
- // Close the connection when an exception is raised.
- LOG.warn("Unexpected exception from downstream.", cause);
- checkState(context.equals(ctx));
- ctx.close();
- context = null;
- }
-
- public synchronized void write(final String message) {
- ByteBuf byteBuf = Unpooled.copiedBuffer(message.getBytes());
- context.writeAndFlush(byteBuf);
- }
-
- public synchronized boolean isConnected() {
- return state == State.CONNECTED;
- }
-
- public synchronized String read() {
- return fromServer.toString();
- }
-
- @Override
- public synchronized void operationComplete(final ChannelFuture future) throws Exception {
- checkState(state == State.CONNECTING);
- if (future.isSuccess()) {
- LOG.trace("Successfully connected, state will be switched in channelActive");
- } else {
- state = State.FAILED_TO_CONNECT;
- }
- }
-
- public State getState() {
- return state;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.local.LocalChannel;
-import io.netty.channel.local.LocalServerChannel;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.handler.logging.LogLevel;
-import io.netty.handler.logging.LoggingHandler;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Echoes back any received data from a client.
- */
-public class EchoServer implements Runnable {
- private static final Logger LOG = LoggerFactory.getLogger(EchoServer.class);
-
- @Override
- public void run() {
- // Configure the server.
- EventLoopGroup bossGroup = new NioEventLoopGroup(1);
- EventLoopGroup workerGroup = new NioEventLoopGroup();
- try {
- ServerBootstrap bootstrap = new ServerBootstrap();
- bootstrap.group(bossGroup, workerGroup)
- .channel(LocalServerChannel.class)
- .option(ChannelOption.SO_BACKLOG, 100)
- .handler(new LoggingHandler(LogLevel.INFO))
- .childHandler(new ChannelInitializer<LocalChannel>() {
- @Override
- public void initChannel(final LocalChannel ch) {
- ch.pipeline().addLast(new EchoServerHandler());
- }
- });
-
- // Start the server.
- LocalAddress localAddress = new LocalAddress("netconf");
- ChannelFuture future = bootstrap.bind(localAddress).sync();
-
- // Wait until the server socket is closed.
- future.channel().closeFuture().sync();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } finally {
- // Shut down all event loops to terminate all threads.
- bossGroup.shutdownGracefully();
- workerGroup.shutdownGracefully();
- }
- }
-
- public static void main(final String[] args) throws InterruptedException, IOException {
- new Thread(new EchoServer()).start();
- Thread.sleep(1000);
- EchoClientHandler clientHandler = new EchoClientHandler();
- EchoClient echoClient = new EchoClient(clientHandler);
- new Thread(echoClient).start();
-
- BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
- do {
- String message = reader.readLine();
- if (message == null || "exit".equalsIgnoreCase(message)) {
- break;
- }
- LOG.debug("Got '{}'", message);
- clientHandler.write(message);
- } while (true);
- System.exit(0);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import com.google.common.base.Splitter;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandler.Sharable;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import java.nio.charset.StandardCharsets;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Handler implementation for the echo server.
- */
-@Sharable
-public class EchoServerHandler extends ChannelInboundHandlerAdapter {
-
- private static final Logger LOG = LoggerFactory.getLogger(EchoServerHandler.class);
- private String fromLastNewLine = "";
- private final Splitter splitter = Splitter.onPattern("\r?\n");
-
- @Override
- public void channelActive(final ChannelHandlerContext ctx) throws Exception {
- LOG.debug("sleep start");
- Thread.sleep(1000);
- LOG.debug("sleep done");
- }
-
- @Override
- public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
- ByteBuf byteBuf = (ByteBuf) msg;
- String message = byteBuf.toString(StandardCharsets.UTF_8);
- LOG.info("writing back '{}'", message);
- ctx.write(msg);
- fromLastNewLine += message;
- for (String line : splitter.split(fromLastNewLine)) {
- if ("quit".equals(line)) {
- LOG.info("closing server ctx");
- ctx.flush();
- ctx.close();
- break;
- }
- fromLastNewLine = line; // last line should be preserved
- }
-
- // do not release byteBuf as it is handled back
- }
-
- @Override
- public void channelReadComplete(final ChannelHandlerContext ctx) {
- LOG.debug("flushing");
- ctx.flush();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 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.northbound.ssh;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import java.nio.charset.StandardCharsets;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class ProxyClientHandler extends ChannelInboundHandlerAdapter {
- private static final Logger LOG = LoggerFactory.getLogger(ProxyClientHandler.class);
-
- private final ChannelHandlerContext remoteCtx;
-
-
- ProxyClientHandler(final ChannelHandlerContext remoteCtx) {
- this.remoteCtx = remoteCtx;
- }
-
- @Override
- public void channelActive(final ChannelHandlerContext ctx) {
- LOG.info("client active");
- }
-
- @Override
- public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
- ByteBuf bb = (ByteBuf) msg;
- LOG.info(">{}", bb.toString(StandardCharsets.UTF_8));
- remoteCtx.write(msg);
- }
-
- @Override
- public void channelReadComplete(final ChannelHandlerContext ctx) {
- LOG.debug("Flushing server ctx");
- remoteCtx.flush();
- }
-
- @Override
- public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
- // Close the connection when an exception is raised.
- LOG.warn("Unexpected exception from downstream", cause);
- ctx.close();
- }
-
- // called both when local or remote connection dies
- @Override
- public void channelInactive(final ChannelHandlerContext ctx) {
- LOG.debug("channelInactive() called, closing remote client ctx");
- remoteCtx.close();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
-import io.netty.handler.logging.LogLevel;
-import io.netty.handler.logging.LoggingHandler;
-import java.net.InetSocketAddress;
-
-public class ProxyServer implements Runnable {
- private final ProxyHandlerFactory proxyHandlerFactory;
-
- public ProxyServer(final ProxyHandlerFactory proxyHandlerFactory) {
- this.proxyHandlerFactory = proxyHandlerFactory;
- }
-
- @Override
- public void run() {
- // Configure the server.
- final EventLoopGroup bossGroup = new NioEventLoopGroup();
- EventLoopGroup workerGroup = new NioEventLoopGroup();
- try {
- final LocalAddress localAddress = new LocalAddress("netconf");
- ServerBootstrap serverBootstrap = new ServerBootstrap();
- serverBootstrap.group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class)
- .option(ChannelOption.SO_BACKLOG, 100)
- .handler(new LoggingHandler(LogLevel.INFO))
- .childHandler(new ChannelInitializer<SocketChannel>() {
- @Override
- public void initChannel(final SocketChannel ch) throws Exception {
- ch.pipeline().addLast(proxyHandlerFactory.create(bossGroup, localAddress));
- }
- });
-
- // Start the server.
- InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8080);
- ChannelFuture future = serverBootstrap.bind(address).sync();
-
- // Wait until the server socket is closed.
- future.channel().closeFuture().sync();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } finally {
- // Shut down all event loops to terminate all threads.
- bossGroup.shutdownGracefully();
- workerGroup.shutdownGracefully();
- }
- }
-
- public interface ProxyHandlerFactory {
- ChannelHandler create(EventLoopGroup bossGroup, LocalAddress localAddress);
- }
-
- public static void main(final String[] args) {
- ProxyHandlerFactory proxyHandlerFactory = ProxyServerHandler::new;
- start(proxyHandlerFactory);
- }
-
- public static void start(final ProxyHandlerFactory proxyHandlerFactory) {
- new Thread(new EchoServer()).start();
- new Thread(new ProxyServer(proxyHandlerFactory)).start();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.local.LocalChannel;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ProxyServerHandler extends ChannelInboundHandlerAdapter {
- private static final Logger LOG = LoggerFactory.getLogger(ProxyServerHandler.class);
-
- private final Bootstrap clientBootstrap;
- private final LocalAddress localAddress;
-
- private Channel clientChannel;
-
- public ProxyServerHandler(final EventLoopGroup bossGroup, final LocalAddress localAddress) {
- clientBootstrap = new Bootstrap();
- clientBootstrap.group(bossGroup).channel(LocalChannel.class);
- this.localAddress = localAddress;
- }
-
- @Override
- public void channelActive(final ChannelHandlerContext remoteCtx) {
- final ProxyClientHandler clientHandler = new ProxyClientHandler(remoteCtx);
- clientBootstrap.handler(new ChannelInitializer<LocalChannel>() {
- @Override
- public void initChannel(final LocalChannel ch) {
- ch.pipeline().addLast(clientHandler);
- }
- });
- ChannelFuture clientChannelFuture = clientBootstrap.connect(localAddress).awaitUninterruptibly();
- clientChannel = clientChannelFuture.channel();
- clientChannel.writeAndFlush(Unpooled.copiedBuffer("connected\n".getBytes()));
- }
-
- @Override
- public void channelInactive(final ChannelHandlerContext ctx) {
- LOG.info("channelInactive - closing client connection");
- clientChannel.close();
- }
-
- @Override
- public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
- LOG.debug("Writing to client {}", msg);
- clientChannel.write(msg);
- }
-
- @Override
- public void channelReadComplete(final ChannelHandlerContext ctx) {
- LOG.debug("flushing");
- clientChannel.flush();
- }
-
- @Override
- public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
- // Close the connection when an exception is raised.
- LOG.warn("Unexpected exception from downstream.", cause);
- ctx.close();
- }
-}
-
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.northbound.ssh;
-
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.nio.NioEventLoopGroup;
-import java.io.File;
-import java.net.InetSocketAddress;
-import java.nio.file.Files;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.netconf.shaded.sshd.client.SshClient;
-import org.opendaylight.netconf.shaded.sshd.client.future.AuthFuture;
-import org.opendaylight.netconf.shaded.sshd.client.future.ConnectFuture;
-import org.opendaylight.netconf.shaded.sshd.client.session.ClientSession;
-import org.opendaylight.netconf.shaded.sshd.common.util.security.SecurityUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SSHServerTest {
- private static final String USER = "netconf";
- private static final String PASSWORD = "netconf";
- private static final String HOST = "127.0.0.1";
- private static final int PORT = 1830;
- private static final Logger LOG = LoggerFactory.getLogger(SSHServerTest.class);
-
- private File sshKeyPair;
- private SshProxyServer server;
-
- private final ExecutorService nioExec = Executors.newFixedThreadPool(1);
- private final EventLoopGroup clientGroup = new NioEventLoopGroup();
- private final ScheduledExecutorService minaTimerEx = Executors.newScheduledThreadPool(1);
-
- @Before
- public void setUp() throws Exception {
- sshKeyPair = Files.createTempFile("sshKeyPair", ".pem").toFile();
- sshKeyPair.deleteOnExit();
-
- LOG.info("Creating SSH server");
-
- final InetSocketAddress addr = InetSocketAddress.createUnresolved(HOST, PORT);
- server = new SshProxyServer(minaTimerEx, clientGroup, nioExec);
- server.bind(new SshProxyServerConfigurationBuilder()
- .setBindingAddress(addr).setLocalAddress(new LocalAddress("netconf"))
- .setAuthenticator((username, password) -> true)
- .setKeyPairProvider(SecurityUtils.createGeneratorHostKeyProvider(sshKeyPair.toPath()))
- .setIdleTimeout(Integer.MAX_VALUE).createSshProxyServerConfiguration());
- LOG.info("SSH server started on {}", PORT);
- }
-
- @Test
- public void connect() throws Exception {
- final SshClient sshClient = SshClient.setUpDefaultClient();
- sshClient.start();
- try {
- final ConnectFuture connect = sshClient.connect(USER, HOST, PORT);
- connect.await(30, TimeUnit.SECONDS);
- org.junit.Assert.assertTrue(connect.isConnected());
- final ClientSession session = connect.getSession();
- session.addPasswordIdentity(PASSWORD);
- final AuthFuture auth = session.auth();
- auth.await(30, TimeUnit.SECONDS);
- org.junit.Assert.assertTrue(auth.isSuccess());
- } finally {
- sshClient.close(true);
- server.close();
- clientGroup.shutdownGracefully().await();
- minaTimerEx.shutdownNow();
- nioExec.shutdownNow();
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.northbound.ssh;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.google.common.base.Stopwatch;
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.util.HashedWheelTimer;
-import java.io.File;
-import java.net.InetSocketAddress;
-import java.nio.file.Files;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
-import org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandler;
-import org.opendaylight.netconf.northbound.ssh.EchoClientHandler.State;
-import org.opendaylight.netconf.shaded.sshd.common.util.security.SecurityUtils;
-
-public class SSHTest {
- public static final String AHOJ = "ahoj\n";
-
- private static EventLoopGroup nettyGroup;
- private static HashedWheelTimer hashedWheelTimer;
- private static ExecutorService nioExec;
- private static ScheduledExecutorService minaTimerEx;
-
- @BeforeClass
- public static void setUp() throws Exception {
- hashedWheelTimer = new HashedWheelTimer();
- nettyGroup = new NioEventLoopGroup();
- nioExec = Executors.newFixedThreadPool(1);
- minaTimerEx = Executors.newScheduledThreadPool(1);
- }
-
- @AfterClass
- public static void tearDown() throws Exception {
- hashedWheelTimer.stop();
- nettyGroup.shutdownGracefully().await(5, TimeUnit.SECONDS);
- minaTimerEx.shutdownNow();
- nioExec.shutdownNow();
- }
-
- @Test
- public void test() throws Exception {
- File sshKeyPair = Files.createTempFile("sshKeyPair", ".pem").toFile();
- sshKeyPair.deleteOnExit();
- new Thread(new EchoServer(), "EchoServer").start();
-
- final InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 10831);
- try (var sshProxyServer = new SshProxyServer(minaTimerEx, nettyGroup, nioExec)) {
- sshProxyServer.bind(new SshProxyServerConfigurationBuilder()
- .setBindingAddress(addr).setLocalAddress(new LocalAddress("netconf"))
- .setAuthenticator((username, password) -> true)
- .setKeyPairProvider(SecurityUtils.createGeneratorHostKeyProvider(sshKeyPair.toPath()))
- .setIdleTimeout(Integer.MAX_VALUE).createSshProxyServerConfiguration());
-
- final EchoClientHandler echoClientHandler = connectClient(addr);
-
- Stopwatch stopwatch = Stopwatch.createStarted();
- while (echoClientHandler.isConnected() == false && stopwatch.elapsed(TimeUnit.SECONDS) < 30) {
- Thread.sleep(500);
- }
- assertTrue(echoClientHandler.isConnected());
- echoClientHandler.write(AHOJ);
-
- // check that server sent back the same string
- stopwatch = stopwatch.reset().start();
- while (echoClientHandler.read().endsWith(AHOJ) == false && stopwatch.elapsed(TimeUnit.SECONDS) < 30) {
- Thread.sleep(500);
- }
-
- final String read = echoClientHandler.read();
- assertTrue(read + " should end with " + AHOJ, read.endsWith(AHOJ));
- }
- }
-
- public EchoClientHandler connectClient(final InetSocketAddress address) {
- final EchoClientHandler echoClientHandler = new EchoClientHandler();
- final ChannelInitializer<NioSocketChannel> channelInitializer = new ChannelInitializer<>() {
- @Override
- public void initChannel(final NioSocketChannel ch) throws Exception {
- ch.pipeline().addFirst(AsyncSshHandler.createForNetconfSubsystem(new LoginPasswordHandler("a", "a")));
- ch.pipeline().addLast(echoClientHandler);
- }
- };
- final Bootstrap b = new Bootstrap();
-
- b.group(nettyGroup)
- .channel(NioSocketChannel.class)
- .handler(channelInitializer);
-
- // Start the client.
- b.connect(address).addListener(echoClientHandler);
- return echoClientHandler;
- }
-
- @Test
- public void testClientWithoutServer() throws Exception {
- final InetSocketAddress address = new InetSocketAddress(12345);
- final EchoClientHandler echoClientHandler = connectClient(address);
- final Stopwatch stopwatch = Stopwatch.createStarted();
- while (echoClientHandler.getState() == State.CONNECTING && stopwatch.elapsed(TimeUnit.SECONDS) < 5) {
- Thread.sleep(100);
- }
- assertFalse(echoClientHandler.isConnected());
- assertEquals(State.FAILED_TO_CONNECT, echoClientHandler.getState());
- }
-
-}