Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@
<version>2.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>


</dependencies>
</project>
50 changes: 50 additions & 0 deletions src/main/java/net/juniper/netconf/Device.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
import com.jcraft.jsch.ChannelSubsystem;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
Expand All @@ -22,13 +25,16 @@
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.net.ssl.SSLSocketFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -228,6 +234,50 @@ private Session loginWithUserPass(int timeoutMilliSeconds) throws NetconfExcepti
session.setConfig("userauth", "password");
session.setConfig("StrictHostKeyChecking", isStrictHostKeyChecking() ? "yes" : "no");
session.setPassword(password);

final String socksProxyHost = System.getenv("SOCKS_PROXY_HOST");
final String socksProxyPort = System.getenv("SOCKS_PROXY_PORT");
final String socksProxyUser = System.getenv("SOCKS_PROXY_USER");
final String socksProxyPass = System.getenv("SOCKS_PROXY_PASS");
if (socksProxyHost != null && socksProxyPort != null && socksProxyUser != null && socksProxyPass != null) {
log.info("Using socks5 proxy");
final ProxySOCKS5 proxy = new ProxySOCKS5(socksProxyHost, Integer.parseInt(socksProxyPort));
proxy.setUserPasswd(socksProxyUser, socksProxyPass);
session.setProxy(proxy);
}
else {
final String httpProxyHost = System.getenv("HTTP_PROXY_HOST");
final String httpProxyPort = System.getenv("HTTP_PROXY_PORT");
final String httpProxyUser = System.getenv("HTTP_PROXY_USER");
final String httpProxyPass = System.getenv("HTTP_PROXY_PASS");
if(httpProxyHost != null && httpProxyPort != null && httpProxyUser != null && httpProxyPass != null) {
log.info("Using http proxy");
final ProxyHTTP proxy = new ProxyHTTP(httpProxyHost, Integer.parseInt(httpProxyPort));
proxy.setUserPasswd(httpProxyUser, httpProxyPass);
session.setProxy(proxy);
// ProxyHTTP class doesn't know anything about TLS. We are supplying a socket
// factory which takes care of the low level TLS tunnel between the client
// and the proxy server
session.setSocketFactory((new SocketFactory() {
final javax.net.SocketFactory fact = SSLSocketFactory.getDefault();
@Override
public Socket createSocket(String host, int port) throws IOException {
return fact.createSocket(host, port);
}

@Override
public InputStream getInputStream(Socket socket) throws IOException {
return socket.getInputStream();
}

@Override
public OutputStream getOutputStream(Socket socket) throws IOException {
return socket.getOutputStream();
}
}));
}
}

session.connect(timeoutMilliSeconds);
return session;
} catch (JSchException e) {
Expand Down
89 changes: 89 additions & 0 deletions src/test/java/net/juniper/netconf/DeviceTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package net.juniper.netconf;

import com.github.stefanbirkner.systemlambda.SystemLambda;
import com.jcraft.jsch.ChannelSubsystem;
import com.jcraft.jsch.HostKeyRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.ArgumentCaptor;
import org.xmlunit.assertj.XmlAssert;

import java.io.ByteArrayInputStream;
Expand Down Expand Up @@ -136,6 +140,90 @@ public void GIVEN_sshAvailableNetconfNot_THEN_closeDevice() throws Exception {
verifyNoMoreInteractions(sshClient);
}

@Test
public void GIVEN_netConfWithHttpProxy_THEN_setHttpProxy() throws Exception {

String httpProxyHost = "testHttpProxyHost";
String httpProxyPort = "8080";
String httpProxyUser = "username";
String httpProxyPass = "password";
SystemLambda.withEnvironmentVariable("HTTP_PROXY_HOST", httpProxyHost)
.and("HTTP_PROXY_PORT", httpProxyPort)
.and("HTTP_PROXY_USER", httpProxyUser)
.and("HTTP_PROXY_PASS", httpProxyPass)
.execute(() -> {
JSch sshClient = mock(JSch.class);
Session session = mock(Session.class);
HostKeyRepository hostKeyRepository = mock(HostKeyRepository.class);

when(sshClient.getSession(eq(TEST_USERNAME), eq(TEST_HOSTNAME),
eq(DEFAULT_NETCONF_PORT))).thenReturn(session);
when(sshClient.getHostKeyRepository()).thenReturn(hostKeyRepository);

try (Device device = Device.builder()
.sshClient(sshClient)
.hostName(TEST_HOSTNAME)
.userName(TEST_USERNAME)
.password(TEST_PASSWORD)
.strictHostKeyChecking(false)
.build()) {
device.connect();
}
catch (NetconfException e) {
// Do nothing
}

ProxyHTTP httpProxy = new ProxyHTTP(httpProxyHost, Integer.parseInt(httpProxyPort));
httpProxy.setUserPasswd(httpProxyUser, httpProxyPass);
ArgumentCaptor<ProxyHTTP> actualProxyCaptor = ArgumentCaptor.forClass(ProxyHTTP.class);
verify(session).setProxy(actualProxyCaptor.capture());
ProxyHTTP actualHttpProxy = actualProxyCaptor.getValue();
assertThat(actualHttpProxy).usingRecursiveComparison().isEqualTo(httpProxy);
});
}

@Test
public void GIVEN_netConfWithSocksProxy_THEN_setHttpProxy() throws Exception {

String socksProxyHost = "testSocksProxyHost";
String socksProxyPort = "8080";
String socksProxyUser = "username";
String socksProxyPass = "password";
SystemLambda.withEnvironmentVariable("SOCKS_PROXY_HOST", socksProxyHost)
.and("SOCKS_PROXY_PORT", socksProxyPort)
.and("SOCKS_PROXY_USER", socksProxyUser)
.and("SOCKS_PROXY_PASS", socksProxyPass)
.execute(() -> {
JSch sshClient = mock(JSch.class);
Session session = mock(Session.class);
HostKeyRepository hostKeyRepository = mock(HostKeyRepository.class);

when(sshClient.getSession(eq(TEST_USERNAME), eq(TEST_HOSTNAME),
eq(DEFAULT_NETCONF_PORT))).thenReturn(session);
when(sshClient.getHostKeyRepository()).thenReturn(hostKeyRepository);

try (Device device = Device.builder()
.sshClient(sshClient)
.hostName(TEST_HOSTNAME)
.userName(TEST_USERNAME)
.password(TEST_PASSWORD)
.strictHostKeyChecking(false)
.build()) {
device.connect();
}
catch (NetconfException e) {
// Do nothing
}

ProxySOCKS5 socksProxy = new ProxySOCKS5(socksProxyHost, Integer.parseInt(socksProxyPort));
socksProxy.setUserPasswd(socksProxyUser, socksProxyPass);
ArgumentCaptor<ProxySOCKS5> actualProxyCaptor = ArgumentCaptor.forClass(ProxySOCKS5.class);
verify(session).setProxy(actualProxyCaptor.capture());
ProxySOCKS5 actualSocksProxy = actualProxyCaptor.getValue();
assertThat(actualSocksProxy).usingRecursiveComparison().isEqualTo(socksProxy);
});
}

@Test
public void GIVEN_newDevice_WHEN_withNullUserName_THEN_throwsException() {
assertThatThrownBy(() -> Device.builder().hostName("foo").build())
Expand Down Expand Up @@ -222,4 +310,5 @@ private JSch givenConnectingSshClient() throws IOException, JSchException {
.thenReturn(sshSession);
return sshClient;
}

}