From: Ruslan Kashapov Date: Wed, 18 Oct 2023 14:21:51 +0000 (+0300) Subject: Ext service integration support for Netconf SSH client X-Git-Tag: v7.0.0~314 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=deaf5ad75ce5c33d883e1ffb76402fdb33cf44ae;p=netconf.git Ext service integration support for Netconf SSH client Netconf topology and call-home components are using own services for authorization, configuration only approach for ssh client is not sufficient. JIRA: NETCONF-1108 Change-Id: Iac63445067b235437ebf6d2c06df7f9f22acbf89 Signed-off-by: Ruslan Kashapov --- diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java index 36ddec0345..6c9424db2d 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java @@ -77,7 +77,7 @@ public class NetconfClientFactoryImpl implements NetconfClientFactory { } else if (SSH.equals(protocol)) { factory.connectClient(TransportConstants.SSH_SUBSYSTEM, new ClientTransportChannelListener(future, channelInitializer), configuration.getTcpParameters(), - configuration.getSshParameters()); + configuration.getSshParameters(), configuration.getSshConfigurator()); } return future; } diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java index 9653a6b976..24b7a75cfd 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java @@ -21,6 +21,7 @@ import org.opendaylight.netconf.client.NetconfClientSessionListener; import org.opendaylight.netconf.client.SslHandlerFactory; import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient; +import org.opendaylight.netconf.transport.ssh.ClientFactoryManagerConfigurator; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.SshClientGrouping; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.client.rev230417.TcpClientGrouping; @@ -50,6 +51,7 @@ public class NetconfClientConfiguration { private final TlsClientGrouping tlsParameters; private final org.opendaylight.netconf.transport.tls.SslHandlerFactory transportSslHandlerFactory; private final SshClientGrouping sshParameters; + private final ClientFactoryManagerConfigurator sshConfigurator; NetconfClientConfiguration(final NetconfClientProtocol protocol, final InetSocketAddress address, final Long connectionTimeoutMillis, @@ -74,6 +76,7 @@ public class NetconfClientConfiguration { this.tlsParameters = null; this.transportSslHandlerFactory = null; this.sshParameters = null; + this.sshConfigurator = null; validateConfiguration(); } @@ -82,6 +85,7 @@ public class NetconfClientConfiguration { final TlsClientGrouping tlsParameters, final org.opendaylight.netconf.transport.tls.SslHandlerFactory transportSslHandlerFactory, final SshClientGrouping sshParameters, + final ClientFactoryManagerConfigurator sshConfigurator, final NetconfClientSessionListener sessionListener, final List odlHelloCapabilities, final Long connectionTimeoutMillis, @@ -93,6 +97,7 @@ public class NetconfClientConfiguration { this.tlsParameters = tlsParameters; this.transportSslHandlerFactory = transportSslHandlerFactory; this.sshParameters = sshParameters; + this.sshConfigurator = sshConfigurator; this.sessionListener = requireNonNull(sessionListener); this.odlHelloCapabilities = odlHelloCapabilities; this.connectionTimeoutMillis = connectionTimeoutMillis; @@ -172,6 +177,10 @@ public class NetconfClientConfiguration { return sshParameters; } + public ClientFactoryManagerConfigurator getSshConfigurator() { + return sshConfigurator; + } + private void validateConfiguration() { switch (requireNonNull(clientProtocol)) { case TLS: diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java index ce368e7cdf..01fb02c1da 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java @@ -18,6 +18,7 @@ import org.opendaylight.netconf.client.SslHandlerFactory; import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator; import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient; +import org.opendaylight.netconf.transport.ssh.ClientFactoryManagerConfigurator; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.SshClientGrouping; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.client.rev230417.TcpClientGrouping; @@ -48,6 +49,7 @@ public class NetconfClientConfigurationBuilder { private TlsClientGrouping tlsParameters; private org.opendaylight.netconf.transport.tls.SslHandlerFactory transportSslHandlerFactory; private SshClientGrouping sshParameters; + private ClientFactoryManagerConfigurator sshConfigurator; protected NetconfClientConfigurationBuilder() { } @@ -258,6 +260,19 @@ public class NetconfClientConfigurationBuilder { return this; } + /** + * Set SSH Client Factory Manager configurator. + * + * @param sshConfigurator configurator + * @return current builder instance + */ + @SuppressWarnings("checkstyle:hiddenField") + public NetconfClientConfigurationBuilder withSshConfigurator( + final ClientFactoryManagerConfigurator sshConfigurator) { + this.sshConfigurator = sshConfigurator; + return this; + } + final InetSocketAddress getAddress() { return address; } @@ -315,7 +330,7 @@ public class NetconfClientConfigurationBuilder { maximumIncomingChunkSize, name) // new configuration : new NetconfClientConfiguration(clientProtocol, tcpParameters, tlsParameters, transportSslHandlerFactory, - sshParameters, sessionListener, odlHelloCapabilities, connectionTimeoutMillis, + sshParameters, sshConfigurator, sessionListener, odlHelloCapabilities, connectionTimeoutMillis, maximumIncomingChunkSize, additionalHeader, name); } } diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java index ea8436b68d..f049750486 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java @@ -46,9 +46,14 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder; +import org.opendaylight.netconf.shaded.sshd.client.auth.password.PasswordIdentityProvider; +import org.opendaylight.netconf.shaded.sshd.server.auth.password.UserAuthPasswordFactory; +import org.opendaylight.netconf.shaded.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; import org.opendaylight.netconf.transport.api.TransportChannel; import org.opendaylight.netconf.transport.api.TransportChannelListener; +import org.opendaylight.netconf.transport.ssh.ClientFactoryManagerConfigurator; import org.opendaylight.netconf.transport.ssh.SSHTransportStackFactory; +import org.opendaylight.netconf.transport.ssh.ServerFactoryManagerConfigurator; import org.opendaylight.netconf.transport.tcp.TCPServer; import org.opendaylight.netconf.transport.tls.TLSServer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana.crypt.hash.rev140806.CryptHash; @@ -258,4 +263,38 @@ class NetconfClientFactoryImplTest { new UsersBuilder().setUser(Map.of(user.key(), user)).build() ).build(); } + + @Test + void sshClientWithConfigurator() throws Exception { + final ServerFactoryManagerConfigurator serverConfigurator = factoryManager -> { + factoryManager.setUserAuthFactories(List.of(new UserAuthPasswordFactory())); + factoryManager.setPasswordAuthenticator( + (usr, psw, session) -> USERNAME.equals(usr) && PASSWORD.equals(psw)); + factoryManager.setKeyPairProvider(new SimpleGeneratorHostKeyProvider()); + }; + final ClientFactoryManagerConfigurator clientConfigurator = factoryManager -> { + factoryManager.setPasswordIdentityProvider(PasswordIdentityProvider.wrapPasswords(PASSWORD)); + factoryManager.setUserAuthFactories(List.of( + new org.opendaylight.netconf.shaded.sshd.client.auth.password.UserAuthPasswordFactory())); + }; + + final var server = serverTransportFactory.listenServer("netconf", serverTransportListener, tcpServerParams, + null, serverConfigurator).get(10, TimeUnit.SECONDS); + try { + final var clientConfig = NetconfClientConfigurationBuilder.create() + .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH) + .withTcpParameters(tcpClientParams) + .withSshParameters(new SshClientParametersBuilder() + .setClientIdentity(new ClientIdentityBuilder().setUsername(USERNAME).build()).build()) + .withSshConfigurator(clientConfigurator) + .withSessionListener(sessionListener) + .withConnectionTimeoutMillis(10_000) + .build(); + assertNotNull(factory.createClient(clientConfig)); + verify(serverTransportListener, timeout(10_000L)) + .onTransportChannelEstablished(any(TransportChannel.class)); + } finally { + server.shutdown().get(1, TimeUnit.SECONDS); + } + } }