You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/06/09 15:53:17 UTC
[2/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
new file mode 100644
index 0000000..dc7d958
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.agent;
+
+import static org.apache.sshd.util.Utils.createTestKeyPairProvider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.local.LocalAgentFactory;
+import org.apache.sshd.agent.local.ProxyAgentFactory;
+import org.apache.sshd.agent.unix.AgentClient;
+import org.apache.sshd.agent.unix.AgentServer;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.PublickeyAuthenticator.AcceptAllPublickeyAuthenticator;
+import org.apache.sshd.server.forward.ForwardingFilter;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.Utils;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AgentTest extends BaseTestSupport {
+ public AgentTest() {
+ super();
+ }
+
+ @Test
+ public void testAgentServer() throws Exception {
+ // TODO: revisit this test to work without BC
+ Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+
+ try(AgentServer agent = new AgentServer()) {
+ String authSocket;
+ try {
+ authSocket = agent.start();
+ } catch (UnsatisfiedLinkError e) {
+ // the native library is not available, so these tests should be skipped
+ authSocket = null;
+ }
+ Assume.assumeTrue("Native library N/A", authSocket != null);
+
+ try(SshAgent client = new AgentClient(authSocket)) {
+ List<SshAgent.Pair<PublicKey, String>> keys = client.getIdentities();
+ assertNotNull("No initial identities", keys);
+ assertEquals("Unexpected initial identities size", 0, keys.size());
+
+ KeyPair k = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+ client.addIdentity(k, "");
+ keys = client.getIdentities();
+ assertNotNull("No registered identities after add", keys);
+ assertEquals("Mismatched registered keys size", 1, keys.size());
+
+ client.removeIdentity(k.getPublic());
+ keys = client.getIdentities();
+ assertNotNull("No registered identities after remove", keys);
+ assertEquals("Registered keys size not empty", 0, keys.size());
+
+ client.removeAllIdentities();
+ }
+ }
+ }
+
+ @Test
+ public void testAgentForwarding() throws Exception {
+ // TODO: revisit this test to work without BC
+ Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+
+ TestEchoShellFactory shellFactory = new TestEchoShellFactory();
+ ProxyAgentFactory agentFactory = new ProxyAgentFactory();
+ LocalAgentFactory localAgentFactory = new LocalAgentFactory();
+ String username = getCurrentTestName();
+ KeyPair pair = createTestKeyPairProvider("dsaprivkey.pem").loadKey(KeyPairProvider.SSH_DSS);
+ localAgentFactory.getAgent().addIdentity(pair, username);
+
+ try(SshServer sshd1 = SshServer.setUpDefaultServer()) {
+ sshd1.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd1.setShellFactory(shellFactory);
+ sshd1.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd1.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+ sshd1.setAgentFactory(agentFactory);
+ sshd1.setTcpipForwardingFilter(ForwardingFilter.AcceptAllForwardingFilter.INSTANCE);
+ sshd1.start();
+
+ final int port1 = sshd1.getPort();
+ try(SshServer sshd2 = SshServer.setUpDefaultServer()) {
+ sshd2.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd2.setShellFactory(new TestEchoShellFactory());
+ sshd2.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd2.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+ sshd1.setTcpipForwardingFilter(ForwardingFilter.AcceptAllForwardingFilter.INSTANCE);
+ sshd2.setAgentFactory(new ProxyAgentFactory());
+ sshd2.start();
+
+ final int port2 = sshd2.getPort();
+ try(SshClient client1 = SshClient.setUpDefaultClient()) {
+ client1.setAgentFactory(localAgentFactory);
+ client1.start();
+
+ try(ClientSession session1 = client1.connect(username, "localhost", port1).await().getSession()) {
+ session1.auth().verify(15L, TimeUnit.SECONDS);
+
+ try(ChannelShell channel1 = session1.createShellChannel();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel1.setOut(out);
+ channel1.setErr(err);
+ channel1.setAgentForwarding(true);
+ channel1.open().await();
+
+ try(OutputStream pipedIn = channel1.getInvertedIn()) {
+ synchronized (shellFactory.shell) {
+ System.out.println("Possibly waiting for remote shell to start");
+ if (!shellFactory.shell.started) {
+ shellFactory.shell.wait();
+ }
+ }
+
+ try(SshClient client2 = SshClient.setUpDefaultClient()) {
+ client2.setAgentFactory(agentFactory);
+ client2.getProperties().putAll(shellFactory.shell.getEnvironment().getEnv());
+ client2.start();
+
+ try(ClientSession session2 = client2.connect(username, "localhost", port2).await().getSession()) {
+ session2.auth().verify(15L, TimeUnit.SECONDS);
+
+ try(ChannelShell channel2 = session2.createShellChannel()) {
+ channel2.setIn(shellFactory.shell.getIn());
+ channel2.setOut(shellFactory.shell.getOut());
+ channel2.setErr(shellFactory.shell.getErr());
+ channel2.setAgentForwarding(true);
+ channel2.open().await();
+
+ pipedIn.write("foo\n".getBytes());
+ pipedIn.flush();
+ }
+
+ Thread.sleep(1000);
+
+ System.out.println(out.toString());
+ System.err.println(err.toString());
+
+ sshd1.stop(true);
+ sshd2.stop(true);
+ client1.stop();
+ client2.stop();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static class TestEchoShellFactory extends EchoShellFactory {
+
+ TestEchoShell shell = new TestEchoShell();
+
+ @Override
+ public Command create() {
+ return shell;
+ }
+
+ public class TestEchoShell extends EchoShell {
+
+ boolean started;
+
+ @Override
+ public synchronized void start(Environment env) throws IOException {
+ super.start(env);
+ started = true;
+ notifyAll();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
new file mode 100644
index 0000000..8285002
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
@@ -0,0 +1,958 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.SocketAddress;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.UserAuthPassword;
+import org.apache.sshd.client.auth.UserAuthPublicKey;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.channel.ClientChannel;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.RuntimeSshException;
+import org.apache.sshd.common.Service;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoReadFuture;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.IoWriteFuture;
+import org.apache.sshd.common.io.mina.MinaSession;
+import org.apache.sshd.common.io.nio2.Nio2Session;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.NoCloseOutputStream;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.PublickeyAuthenticator;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.PublickeyAuthenticator.AcceptAllPublickeyAuthenticator;
+import org.apache.sshd.server.channel.ChannelSession;
+import org.apache.sshd.server.command.UnknownCommand;
+import org.apache.sshd.server.forward.TcpipServerChannel;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.server.session.ServerConnectionService;
+import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.session.ServerUserAuthService;
+import org.apache.sshd.util.AsyncEchoShellFactory;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.TeeOutputStream;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ClientTest extends BaseTestSupport {
+
+ private SshServer sshd;
+ private SshClient client;
+ private int port;
+ private CountDownLatch authLatch;
+ private CountDownLatch channelLatch;
+
+ public ClientTest() {
+ super();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ authLatch = new CountDownLatch(0);
+ channelLatch = new CountDownLatch(0);
+
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setShellFactory(new TestEchoShellFactory());
+ sshd.setCommandFactory(new CommandFactory() {
+ @Override
+ public Command createCommand(String command) {
+ return new UnknownCommand(command);
+ }
+ });
+ sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+ sshd.setServiceFactories(Arrays.asList(
+ new ServerUserAuthService.Factory() {
+ @Override
+ public Service create(Session session) throws IOException {
+ return new ServerUserAuthService(session) {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void process(byte cmd, Buffer buffer) throws Exception {
+ authLatch.await();
+ super.process(cmd, buffer);
+ }
+ };
+ }
+ },
+ new ServerConnectionService.Factory()
+ ));
+ sshd.setChannelFactories(Arrays.<NamedFactory<Channel>>asList(
+ new ChannelSession.ChannelSessionFactory() {
+ @Override
+ public Channel create() {
+ return new ChannelSession() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public OpenFuture open(int recipient, int rwsize, int rmpsize, Buffer buffer) {
+ try {
+ channelLatch.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeSshException(e);
+ }
+ return super.open(recipient, rwsize, rmpsize, buffer);
+ }
+
+ @Override
+ public String toString() {
+ return "ChannelSession" + "[id=" + id + ", recipient=" + recipient + "]";
+ }
+ };
+ }
+ },
+ TcpipServerChannel.DirectTcpipFactory.INSTANCE));
+ sshd.start();
+ port = sshd.getPort();
+
+ client = SshClient.setUpDefaultClient();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ if (client != null) {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testAsyncClient() throws Exception {
+ FactoryManagerUtils.updateProperty(sshd, FactoryManager.WINDOW_SIZE, 1024);
+ sshd.setShellFactory(new AsyncEchoShellFactory());
+
+ FactoryManagerUtils.updateProperty(client, FactoryManager.WINDOW_SIZE, 1024);
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(final ChannelShell channel = session.createShellChannel()) {
+ channel.setStreaming(ClientChannel.Streaming.Async);
+ channel.open().verify(5L, TimeUnit.SECONDS);
+
+ final byte[] message = "0123456789\n".getBytes();
+ final int nbMessages = 1000;
+
+ try(final ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+ final ByteArrayOutputStream baosErr = new ByteArrayOutputStream()) {
+ final AtomicInteger writes = new AtomicInteger(nbMessages);
+
+ channel.getAsyncIn().write(new ByteArrayBuffer(message))
+ .addListener(new SshFutureListener<IoWriteFuture>() {
+ @Override
+ public void operationComplete(IoWriteFuture future) {
+ try {
+ if (future.isWritten()) {
+ if (writes.decrementAndGet() > 0) {
+ channel.getAsyncIn().write(new ByteArrayBuffer(message)).addListener(this);
+ } else {
+ channel.getAsyncIn().close(false);
+ }
+ } else {
+ throw new SshException("Error writing", future.getException());
+ }
+ } catch (IOException e) {
+ if (!channel.isClosing()) {
+ e.printStackTrace();
+ channel.close(true);
+ }
+ }
+ }
+ });
+ channel.getAsyncOut().read(new ByteArrayBuffer())
+ .addListener(new SshFutureListener<IoReadFuture>() {
+ @Override
+ public void operationComplete(IoReadFuture future) {
+ try {
+ future.verify(5L, TimeUnit.SECONDS);
+ Buffer buffer = future.getBuffer();
+ baosOut.write(buffer.array(), buffer.rpos(), buffer.available());
+ buffer.rpos(buffer.rpos() + buffer.available());
+ buffer.compact();
+ channel.getAsyncOut().read(buffer).addListener(this);
+ } catch (IOException e) {
+ if (!channel.isClosing()) {
+ e.printStackTrace();
+ channel.close(true);
+ }
+ }
+ }
+ });
+ channel.getAsyncErr().read(new ByteArrayBuffer())
+ .addListener(new SshFutureListener<IoReadFuture>() {
+ @Override
+ public void operationComplete(IoReadFuture future) {
+ try {
+ future.verify(5L, TimeUnit.SECONDS);
+ Buffer buffer = future.getBuffer();
+ baosErr.write(buffer.array(), buffer.rpos(), buffer.available());
+ buffer.rpos(buffer.rpos() + buffer.available());
+ buffer.compact();
+ channel.getAsyncErr().read(buffer).addListener(this);
+ } catch (IOException e) {
+ if (!channel.isClosing()) {
+ e.printStackTrace();
+ channel.close(true);
+ }
+ }
+ }
+ });
+
+ channel.waitFor(ClientChannel.CLOSED, 0);
+
+ assertEquals(nbMessages * message.length, baosOut.size());
+ }
+ }
+
+ client.close(true);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testCommandDeadlock() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ChannelExec channel = session.createExecChannel("test");
+ OutputStream stdout = new NoCloseOutputStream(System.out);
+ OutputStream stderr = new NoCloseOutputStream(System.err)) {
+
+ channel.setOut(stdout);
+ channel.setErr(stderr);
+ channel.open().await();
+ Thread.sleep(100);
+ try {
+ for (int i = 0; i < 100; i++) {
+ channel.getInvertedIn().write("a".getBytes());
+ channel.getInvertedIn().flush();
+ }
+ } catch (SshException e) {
+ // That's ok, the channel is being closed by the other side
+ }
+ assertEquals(ClientChannel.CLOSED, channel.waitFor(ClientChannel.CLOSED, 0) & ClientChannel.CLOSED);
+ session.close(false).await();
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testClient() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ ByteArrayOutputStream sent = new ByteArrayOutputStream();
+ PipedOutputStream pipedIn = new PipedOutputStream();
+ PipedInputStream pipedOut = new PipedInputStream(pipedIn)) {
+
+ channel.setIn(pipedOut);
+
+ try(OutputStream teeOut = new TeeOutputStream(sent, pipedIn);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open();
+
+ teeOut.write("this is my command\n".getBytes());
+ teeOut.flush();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ sb.append("0123456789");
+ }
+ sb.append("\n");
+ teeOut.write(sb.toString().getBytes());
+
+ teeOut.write("exit\n".getBytes());
+ teeOut.flush();
+
+ channel.waitFor(ClientChannel.CLOSED, 0);
+
+ channel.close(false);
+ client.stop();
+
+ assertArrayEquals(sent.toByteArray(), out.toByteArray());
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testClientInverted() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ ByteArrayOutputStream sent = new ByteArrayOutputStream();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open().await();
+
+ try(OutputStream pipedIn = new TeeOutputStream(sent, channel.getInvertedIn())) {
+ pipedIn.write("this is my command\n".getBytes());
+ pipedIn.flush();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ sb.append("0123456789");
+ }
+ sb.append("\n");
+ pipedIn.write(sb.toString().getBytes());
+
+ pipedIn.write("exit\n".getBytes());
+ pipedIn.flush();
+ }
+
+ channel.waitFor(ClientChannel.CLOSED, 0);
+
+ channel.close(false);
+ client.stop();
+
+ assertArrayEquals(sent.toByteArray(), out.toByteArray());
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testClientWithCustomChannel() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ChannelShell channel = new ChannelShell();
+ ByteArrayOutputStream sent = new ByteArrayOutputStream();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ session.getService(ConnectionService.class).registerChannel(channel);
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open().verify(5L, TimeUnit.SECONDS);
+ channel.close(false).await();
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testClientClosingStream() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ ByteArrayOutputStream sent = new ByteArrayOutputStream();
+ PipedOutputStream pipedIn = new PipedOutputStream();
+ InputStream inPipe = new PipedInputStream(pipedIn);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setIn(inPipe);
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open();
+
+ try(OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
+ teeOut.write("this is my command\n".getBytes());
+ teeOut.flush();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ sb.append("0123456789");
+ }
+ sb.append("\n");
+ teeOut.write(sb.toString().getBytes());
+ }
+
+ channel.waitFor(ClientChannel.CLOSED, 0);
+
+ channel.close(false);
+ client.stop();
+
+ assertArrayEquals(sent.toByteArray(), out.toByteArray());
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testClientWithLengthyDialog() throws Exception {
+ // Reduce window size and packet size
+// FactoryManagerUtils.updateProperty(client, SshClient.WINDOW_SIZE, 0x20000);
+// FactoryManagerUtils.updateProperty(client, SshClient.MAX_PACKET_SIZE, 0x1000);
+// FactoryManagerUtils.updateProperty(sshd, SshServer.WINDOW_SIZE, 0x20000);
+// FactoryManagerUtils.updateProperty(sshd, SshServer.MAX_PACKET_SIZE, 0x1000);
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ ByteArrayOutputStream sent = new ByteArrayOutputStream();
+ PipedOutputStream pipedIn = new PipedOutputStream();
+ InputStream inPipe = new PipedInputStream(pipedIn);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setIn(inPipe);
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open().await();
+
+
+ int bytes = 0;
+ byte[] data = "01234567890123456789012345678901234567890123456789\n".getBytes();
+ long t0 = System.currentTimeMillis();
+ try(OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
+ for (int i = 0; i < 10000; i++) {
+ teeOut.write(data);
+ teeOut.flush();
+ bytes += data.length;
+ if ((bytes & 0xFFF00000) != ((bytes - data.length) & 0xFFF00000)) {
+ System.out.println("Bytes written: " + bytes);
+ }
+ }
+ teeOut.write("exit\n".getBytes());
+ teeOut.flush();
+ }
+ long t1 = System.currentTimeMillis();
+
+ System.out.println("Sent " + (bytes / 1024) + " Kb in " + (t1 - t0) + " ms");
+
+ System.out.println("Waiting for channel to be closed");
+
+ channel.waitFor(ClientChannel.CLOSED, 0);
+
+ channel.close(false);
+ client.stop();
+
+ assertArrayEquals(sent.toByteArray(), out.toByteArray());
+ //assertArrayEquals(sent.toByteArray(), out.toByteArray());
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test(expected = SshException.class)
+ public void testOpenChannelOnClosedSession() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
+ session.close(false);
+
+ try(PipedOutputStream pipedIn = new PipedOutputStream();
+ InputStream inPipe = new PipedInputStream(pipedIn);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setIn(inPipe);
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testCloseBeforeAuthSucceed() throws Exception {
+ authLatch = new CountDownLatch(1);
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+
+ AuthFuture authFuture = session.auth();
+ CloseFuture closeFuture = session.close(false);
+ authLatch.countDown();
+ authFuture.await();
+ closeFuture.await();
+ assertNotNull("No authentication exception", authFuture.getException());
+ assertTrue("Future not closed", closeFuture.isClosed());
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testCloseCleanBeforeChannelOpened() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ InputStream inp = new ByteArrayInputStream(GenericUtils.EMPTY_BYTE_ARRAY);
+ OutputStream out = new ByteArrayOutputStream();
+ OutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setIn(inp);
+ channel.setOut(out);
+ channel.setErr(err);
+
+ OpenFuture openFuture = channel.open();
+ CloseFuture closeFuture = session.close(false);
+ openFuture.await();
+ closeFuture.await();
+ assertTrue("Not open", openFuture.isOpened());
+ assertTrue("Not closed", closeFuture.isClosed());
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testCloseImmediateBeforeChannelOpened() throws Exception {
+ channelLatch = new CountDownLatch(1);
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ InputStream inp = new ByteArrayInputStream(GenericUtils.EMPTY_BYTE_ARRAY);
+ OutputStream out = new ByteArrayOutputStream();
+ OutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setIn(inp);
+ channel.setOut(out);
+ channel.setErr(err);
+
+ OpenFuture openFuture = channel.open();
+ CloseFuture closeFuture = session.close(true);
+ channelLatch.countDown();
+ openFuture.await();
+ closeFuture.await();
+ assertNotNull("No open exception", openFuture.getException());
+ assertTrue("Not closed", closeFuture.isClosed());
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testPublicKeyAuth() throws Exception {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+ session.addPublicKeyIdentity(pair);
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testPublicKeyAuthNew() throws Exception {
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPublicKeyIdentity(Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA));
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testPublicKeyAuthNewWithFailureOnFirstIdentity() throws Exception {
+ final KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+ sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
+ @Override
+ public boolean authenticate(String username, PublicKey key, ServerSession session) {
+ return key.equals(pair.getPublic());
+ }
+ });
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPublicKeyIdentity(new SimpleGeneratorHostKeyProvider(null, "RSA").loadKey(KeyPairProvider.SSH_RSA));
+ session.addPublicKeyIdentity(pair);
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testPasswordAuthNew() throws Exception {
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPassword.UserAuthPasswordFactory()));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testPasswordAuthNewWithFailureOnFirstIdentity() throws Exception {
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPassword.UserAuthPasswordFactory()));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getClass().getSimpleName());
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testKeyboardInteractiveAuthNew() throws Exception {
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testKeyboardInteractiveAuthNewWithFailureOnFirstIdentity() throws Exception {
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getClass().getSimpleName());
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testKeyboardInteractiveWithFailures() throws Exception {
+ final AtomicInteger count = new AtomicInteger();
+ final int MAX_PROMPTS = 3;
+ FactoryManagerUtils.updateProperty(client, ClientFactoryManager.PASSWORD_PROMPTS, MAX_PROMPTS);
+
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory()));
+ client.setUserInteraction(new UserInteraction() {
+ @Override
+ public void welcome(String banner) {
+ // ignored
+ }
+ @Override
+ public String[] interactive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
+ count.incrementAndGet();
+ return new String[] { "bad" };
+ }
+ });
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ AuthFuture future = session.auth();
+ future.await();
+ assertTrue("Unexpected authentication success", future.isFailure());
+ assertEquals("Mismatched authentication retry count", MAX_PROMPTS, count.get());
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testKeyboardInteractiveInSessionUserInteractive() throws Exception {
+ final AtomicInteger count = new AtomicInteger();
+ final int MAX_PROMPTS = 3;
+ FactoryManagerUtils.updateProperty(client, ClientFactoryManager.PASSWORD_PROMPTS, MAX_PROMPTS);
+
+ client.setUserAuthFactories(Arrays
+ .<NamedFactory<UserAuth>> asList(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.setUserInteraction(new UserInteraction() {
+ @Override
+ public void welcome(String banner) {
+ // ignored
+ }
+
+ @Override
+ public String[] interactive(String destination, String name, String instruction,
+ String[] prompt, boolean[] echo) {
+ count.incrementAndGet();
+ return new String[] { getCurrentTestName() };
+ }
+ });
+ AuthFuture future = session.auth();
+ future.await();
+ assertTrue("Authentication not marked as success", future.isSuccess());
+ assertFalse("Authentication marked as failure", future.isFailure());
+ assertEquals("Mismatched authentication attempts count", 1, count.get());
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testKeyboardInteractiveInSessionUserInteractiveFailure() throws Exception {
+ final AtomicInteger count = new AtomicInteger();
+ final int MAX_PROMPTS = 3;
+ FactoryManagerUtils.updateProperty(client, ClientFactoryManager.PASSWORD_PROMPTS, MAX_PROMPTS);
+ client.setUserAuthFactories(Arrays
+ .<NamedFactory<UserAuth>> asList(new UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory()));
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.setUserInteraction(new UserInteraction() {
+ @Override
+ public void welcome(String banner) {
+ // ignored
+ }
+
+ @Override
+ public String[] interactive(String destination, String name, String instruction,
+ String[] prompt, boolean[] echo) {
+ count.incrementAndGet();
+ return new String[] { "bad" };
+ }
+ });
+ AuthFuture future = session.auth();
+ future.await();
+ assertTrue("Authentication not, marked as failure", future.isFailure());
+ assertEquals("Mismatched authentication retry count", MAX_PROMPTS, count.get());
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testClientDisconnect() throws Exception {
+ TestEchoShellFactory.TestEchoShell.latch = new CountDownLatch(1);
+ try {
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ PipedOutputStream pipedIn = new PipedOutputStream();
+ InputStream inPipe = new PipedInputStream(pipedIn);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+ channel.setIn(inPipe);
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open().await();
+
+ // ((AbstractSession) session).disconnect(SshConstants.SSH2_DISCONNECT_BY_APPLICATION, "Cancel");
+ AbstractSession cs = (AbstractSession) session;
+ Buffer buffer = cs.createBuffer(SshConstants.SSH_MSG_DISCONNECT);
+ buffer.putInt(SshConstants.SSH2_DISCONNECT_BY_APPLICATION);
+ buffer.putString("Cancel");
+ buffer.putString("");
+ IoWriteFuture f = cs.writePacket(buffer);
+ f.await();
+ suspend(cs.getIoSession());
+
+ TestEchoShellFactory.TestEchoShell.latch.await();
+ }
+ } finally {
+ client.stop();
+ }
+ } finally {
+ TestEchoShellFactory.TestEchoShell.latch = null;
+ }
+ }
+
+ @Test
+ public void testWaitAuth() throws Exception {
+ final AtomicBoolean ok = new AtomicBoolean();
+ client.setServerKeyVerifier(
+ new ServerKeyVerifier() {
+ @Override
+ public boolean verifyServerKey(
+ ClientSession sshClientSession,
+ SocketAddress remoteAddress,
+ PublicKey serverKey
+ ) {
+ System.out.println(serverKey);
+ ok.set(true);
+ return true;
+ }
+ }
+ );
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.waitFor(ClientSession.WAIT_AUTH, TimeUnit.SECONDS.toMillis(10L));
+ assertTrue(ok.get());
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testSwitchToNoneCipher() throws Exception {
+ sshd.getCipherFactories().add(BuiltinCiphers.none);
+ client.getCipherFactories().add(BuiltinCiphers.none);
+ client.start();
+
+ try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ session.switchToNoneCipher().await();
+
+ try(ClientChannel channel = session.createSubsystemChannel(SftpConstants.SFTP_SUBSYSTEM_NAME)) {
+ channel.open().verify(5L, TimeUnit.SECONDS);
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ private void suspend(IoSession ioSession) {
+ if (ioSession instanceof MinaSession) {
+ ((MinaSession) ioSession).suspend();
+ } else {
+ ((Nio2Session) ioSession).suspend();
+ }
+ }
+
+ public static class TestEchoShellFactory extends EchoShellFactory {
+ @Override
+ public Command create() {
+ return new TestEchoShell();
+ }
+ public static class TestEchoShell extends EchoShell {
+
+ public static CountDownLatch latch = new CountDownLatch(1);
+
+ @Override
+ public void destroy() {
+ if (latch != null) {
+ latch.countDown();
+ }
+ super.destroy();
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ SshClient.main(args);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
new file mode 100644
index 0000000..c17e711
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.client.session;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.ServiceFactory;
+import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.random.JceRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.random.SingletonRandomFactory;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mockito;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ClientSessionImplTest extends BaseTestSupport {
+ public ClientSessionImplTest() {
+ super();
+ }
+
+ @Test
+ public void testAddRemoveIdentities() throws Exception {
+ ClientFactoryManager client = Mockito.mock(ClientFactoryManager.class);
+ Mockito.when(client.getTcpipForwarderFactory()).thenReturn(DefaultTcpipForwarderFactory.INSTANCE);
+
+ Factory<Random> randomFactory = new SingletonRandomFactory(JceRandom.JceRandomFactory.INSTANCE);
+ Mockito.when(client.getRandomFactory()).thenReturn(randomFactory);
+
+ List<ServiceFactory> serviceFactories = Arrays.asList(
+ new ClientUserAuthService.Factory(),
+ new ClientConnectionService.Factory()
+ );
+ Mockito.when(client.getServiceFactories()).thenReturn(serviceFactories);
+
+ try(ClientSession session = new ClientSessionImpl(client, Mockito.mock(IoSession.class)) {
+ @Override
+ protected void sendClientIdentification() {
+ // ignored
+ }
+
+ @Override
+ protected void sendKexInit() throws IOException {
+ // ignored
+ }
+
+ @Override
+ public void close() throws IOException {
+ // ignored
+ }
+ }) {
+ {
+ String expected = getCurrentTestName();
+ assertNull("Unexpected initial password identity", session.removePasswordIdentity(expected));
+ session.addPasswordIdentity(expected);
+
+ String actual = session.removePasswordIdentity(expected);
+ assertSame("Mismatched removed password identity", expected, actual);
+ assertNull("Password identity not removed", session.removePasswordIdentity(expected));
+ }
+
+ {
+ KeyPair expected = new KeyPair(Mockito.mock(PublicKey.class), Mockito.mock(PrivateKey.class));
+ assertNull("Unexpected initial pubket identity", session.removePublicKeyIdentity(expected));
+ session.addPublicKeyIdentity(expected);
+
+ KeyPair actual = session.removePublicKeyIdentity(expected);
+ assertSame("Mismatched removed pubkey identity", expected, actual);
+ assertNull("Pubkey identity not removed", session.removePublicKeyIdentity(expected));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
index 1d79f0f..71cd5b0 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
@@ -47,8 +47,8 @@ import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.file.root.RootedFileSystemProvider;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.sftp.SftpConstants;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.command.ScpCommandFactory;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
index 7aadf8c..7dc2694 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
@@ -47,9 +47,9 @@ import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.file.root.RootedFileSystemProvider;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.sftp.SftpConstants;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.command.ScpCommandFactory;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java b/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
new file mode 100644
index 0000000..f801f44
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.sshd.common.BaseBuilder;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.Cipher;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.mac.BuiltinMacs;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SshBuilderTest extends BaseTestSupport {
+ public SshBuilderTest() {
+ super();
+ }
+
+ /**
+ * Make sure that all values in {@link BuiltinCiphers} are
+ * listed in {@link BaseBuilder#DEFAULT_CIPHERS_PREFERENCE}
+ */
+ @Test
+ public void testAllBuiltinCiphersListed() {
+ Set<BuiltinCiphers> all=EnumSet.allOf(BuiltinCiphers.class);
+ // The 'none' cipher is not listed as preferred - it is implied
+ assertTrue("Missing " + BuiltinCiphers.Constants.NONE + " cipher in all values", all.remove(BuiltinCiphers.none));
+ testAllInstancesListed(all, BaseBuilder.DEFAULT_CIPHERS_PREFERENCE);
+ }
+
+ /**
+ * Make sure that all values in {@link BuiltinMacs} are
+ * listed in {@link BaseBuilder#DEFAULT_MAC_PREFERENCE}
+ */
+ @Test
+ public void testAllBuiltinMacsListed() {
+ testAllInstancesListed(BuiltinMacs.VALUES, BaseBuilder.DEFAULT_MAC_PREFERENCE);
+ }
+
+ /**
+ * Make sure that all values in {@link BuiltinSignatures} are
+ * listed in {@link BaseBuilder#DEFAULT_SIGNATURE_PREFERENCE}
+ */
+ @Test
+ public void testAllBuiltinSignaturesListed() {
+ testAllInstancesListed(BuiltinSignatures.VALUES, BaseBuilder.DEFAULT_SIGNATURE_PREFERENCE);
+ }
+
+ /**
+ * Make sure that all values in {@link BuiltinDHFactories} are
+ * listed in {@link BaseBuilder#DEFAULT_KEX_PREFERENCE}
+ */
+ @Test
+ public void testAllBuiltinDHFactoriesListed() {
+ testAllInstancesListed(BuiltinDHFactories.VALUES, BaseBuilder.DEFAULT_KEX_PREFERENCE);
+ }
+
+ private static <E extends Enum<E>> void testAllInstancesListed(Set<? extends E> expValues, Collection<? extends E> actValues) {
+ assertEquals("Mismatched actual values size", expValues.size(), actValues.size());
+ for (E expected : expValues) {
+ assertTrue(expected.name() + " not found in actual values", actValues.contains(expected));
+ }
+ }
+
+ /**
+ * Make sure that {@link BaseBuilder#setUpDefaultCiphers(boolean)} returns
+ * the correct result - i.e., according to the {@code ingoreUnsupported}
+ * parameter and in the defined preference order
+ */
+ @Test
+ public void testSetUpDefaultCiphers() {
+ for (boolean ignoreUnsupported : new boolean[] { true, false }) {
+ List<NamedFactory<Cipher>> ciphers=BaseBuilder.setUpDefaultCiphers(ignoreUnsupported);
+ int numCiphers=GenericUtils.size(ciphers);
+ // make sure returned list size matches expected count
+ if (ignoreUnsupported) {
+ assertEquals("Incomplete full ciphers size", BaseBuilder.DEFAULT_CIPHERS_PREFERENCE.size(), numCiphers);
+ } else {
+ int expectedCount=0;
+ for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
+ if (c.isSupported()) {
+ expectedCount++;
+ }
+ }
+ assertEquals("Incomplete supported ciphers size", expectedCount, numCiphers);
+ }
+
+ // make sure order is according to the default preference list
+ List<String> cipherNames=NamedResource.Utils.getNameList(ciphers);
+ int nameIndex=0;
+ for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
+ if ((!c.isSupported()) && (!ignoreUnsupported)) {
+ continue;
+ }
+
+ String expectedName=c.getName();
+ assertTrue("Out of actual ciphers for expected=" + expectedName, nameIndex < numCiphers);
+
+ String actualName=cipherNames.get(nameIndex);
+ assertEquals("Mismatched cipher at position " + nameIndex + " for ignoreUnsupported=" + ignoreUnsupported, expectedName, actualName);
+ nameIndex++;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java b/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
new file mode 100644
index 0000000..bc2d2ff
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.cipher;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.Cipher;
+import org.apache.sshd.common.random.BouncyCastleRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.JSchLogger;
+import org.apache.sshd.util.SimpleUserInfo;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jcraft.jsch.JSch;
+
+/**
+ * Test Cipher algorithms.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CipherTest extends BaseTestSupport {
+
+ private SshServer sshd;
+ private int port;
+
+ @Test
+ public void testAES128CBC() throws Exception {
+ if (BuiltinCiphers.aes128cbc.isSupported()
+ && checkCipher(com.jcraft.jsch.jce.AES128CBC.class.getName())) {
+ setUp(BuiltinCiphers.aes128cbc);
+ runTest();
+ }
+ }
+
+ @Test
+ public void testAES192CBC() throws Exception {
+ if (BuiltinCiphers.aes192cbc.isSupported()
+ && checkCipher(com.jcraft.jsch.jce.AES192CBC.class.getName())) {
+ setUp(BuiltinCiphers.aes192cbc);
+ runTest();
+ }
+ }
+
+ @Test
+ public void testAES256CBC() throws Exception {
+ if (BuiltinCiphers.aes256cbc.isSupported()
+ && checkCipher(com.jcraft.jsch.jce.AES256CBC.class.getName())) {
+ setUp(BuiltinCiphers.aes256cbc);
+ runTest();
+ }
+ }
+
+ @Test
+ public void testBlowfishCBC() throws Exception {
+ if (BuiltinCiphers.blowfishcbc.isSupported()
+ && checkCipher(com.jcraft.jsch.jce.BlowfishCBC.class.getName())) {
+ setUp(BuiltinCiphers.blowfishcbc);
+ runTest();
+ }
+ }
+
+ @Test
+ public void testTripleDESCBC() throws Exception {
+ if (BuiltinCiphers.tripledescbc.isSupported()
+ && checkCipher(com.jcraft.jsch.jce.TripleDESCBC.class.getName())) {
+ setUp(BuiltinCiphers.tripledescbc);
+ runTest();
+ }
+ }
+
+ @Test
+ public void loadTest() throws Exception {
+ Random random = new BouncyCastleRandom();
+ loadTest(BuiltinCiphers.aes128cbc, random);
+ loadTest(BuiltinCiphers.blowfishcbc, random);
+ loadTest(BuiltinCiphers.tripledescbc, random);
+ }
+
+ protected void loadTest(NamedFactory<Cipher> factory, Random random) throws Exception {
+ Cipher cipher = factory.create();
+ byte[] key = new byte[cipher.getBlockSize()];
+ byte[] iv = new byte[cipher.getIVSize()];
+ random.fill(key, 0, key.length);
+ random.fill(iv, 0, iv.length);
+ cipher.init(Cipher.Mode.Encrypt, key, iv);
+
+ byte[] input = new byte[cipher.getBlockSize()];
+ random.fill(input, 0, input.length);
+ long t0 = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ cipher.update(input, 0, input.length);
+ }
+ long t1 = System.currentTimeMillis();
+ System.err.println(factory.getName() + ": " + (t1 - t0) + " ms");
+ }
+
+
+ protected void setUp(NamedFactory<org.apache.sshd.common.cipher.Cipher> cipher) throws Exception {
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setCipherFactories(Arrays.<NamedFactory<org.apache.sshd.common.cipher.Cipher>>asList(cipher));
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd.start();
+ port = sshd.getPort();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ }
+
+ protected void runTest() throws Exception {
+ JSchLogger.init();
+ JSch sch = new JSch();
+ JSch.setConfig("cipher.s2c", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+ JSch.setConfig("cipher.c2s", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+ com.jcraft.jsch.Session s = sch.getSession(getCurrentTestName(), "localhost", port);
+ s.setUserInfo(new SimpleUserInfo(getCurrentTestName()));
+ s.connect();
+ com.jcraft.jsch.Channel c = s.openChannel("shell");
+ c.connect();
+ OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream();
+ for (int i = 0; i < 10; i++) {
+ os.write("this is my command\n".getBytes());
+ os.flush();
+ byte[] data = new byte[512];
+ int len = is.read(data);
+ String str = new String(data, 0, len);
+ assertEquals("this is my command\n", str);
+ }
+ c.disconnect();
+ s.disconnect();
+ }
+
+ static boolean checkCipher(String cipher){
+ try{
+ Class<?> c=Class.forName(cipher);
+ com.jcraft.jsch.Cipher _c = (com.jcraft.jsch.Cipher)(c.newInstance());
+ _c.init(com.jcraft.jsch.Cipher.ENCRYPT_MODE,
+ new byte[_c.getBlockSize()],
+ new byte[_c.getIVSize()]);
+ return true;
+ }
+ catch(Exception e){
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java b/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
index 5a9aa61..41b4296 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
@@ -32,7 +32,6 @@ import org.apache.sshd.common.Closeable;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.cipher.BuiltinCiphers;
import org.apache.sshd.common.cipher.Cipher;
import org.apache.sshd.common.compression.BuiltinCompressions;
@@ -44,6 +43,7 @@ import org.apache.sshd.common.mac.Mac;
import org.apache.sshd.common.signature.BuiltinSignatures;
import org.apache.sshd.common.signature.Signature;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.util.BaseTestSupport;
import org.junit.FixMethodOrder;
import org.junit.Test;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
new file mode 100644
index 0000000..680eec8
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.config.keys;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class KeyUtilsTest extends BaseTestSupport {
+ private static int[] DSS_SIZES = { 512, 768, 1024 };
+ private static int[] RSA_SIZES = { 1024, 2048, 3072, 4096 };
+
+ public KeyUtilsTest() {
+ super();
+ }
+
+ @Test
+ public void testGenerateRSAKeyPairs() throws GeneralSecurityException {
+ GeneralSecurityException err = null;
+ for (int keySize : RSA_SIZES) {
+ try {
+ KeyPair kp = generateKeyPair(KeyPairProvider.SSH_RSA, keySize);
+ testKeyPairCloning(KeyPairProvider.SSH_RSA, keySize, kp);
+ } catch(GeneralSecurityException e) {
+ err = GenericUtils.accumulateException(err, e);
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ @Test
+ public void testGenerateDSSKeyPairs() throws GeneralSecurityException {
+ GeneralSecurityException err = null;
+ for (int keySize : DSS_SIZES) {
+ try {
+ KeyPair kp = generateKeyPair(KeyPairProvider.SSH_DSS, keySize);
+ testKeyPairCloning(KeyPairProvider.SSH_DSS, keySize, kp);
+ } catch(GeneralSecurityException e) {
+ err = GenericUtils.accumulateException(err, e);
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ @Test
+ public void testGenerateECDSAKeyPairs() throws GeneralSecurityException {
+ Assume.assumeTrue("No ECC support", SecurityUtils.hasEcc());
+
+ GeneralSecurityException err = null;
+ for (String curveName : ECCurves.NAMES) {
+ Integer keySize = ECCurves.getCurveSize(curveName);
+ try {
+ String keyType = ECCurves.ECDSA_SHA2_PREFIX + curveName;
+ KeyPair kp = generateKeyPair(keyType, keySize.intValue());
+ testKeyPairCloning(keyType, keySize.intValue(), kp);
+ } catch(GeneralSecurityException e) {
+ err = GenericUtils.accumulateException(err, e);
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ private static KeyPair generateKeyPair(String keyType, int keySize) throws GeneralSecurityException {
+ try {
+ System.out.println("generateKeyPair(" + keyType + ")[" + keySize + "]");
+ return KeyUtils.generateKeyPair(keyType, keySize);
+ } catch(GeneralSecurityException e) {
+ System.err.println("Failed (" + e.getClass().getSimpleName() + ") to generate key-pair for " + keyType + "/" + keySize + ": " + e.getMessage());
+ throw e;
+ }
+ }
+
+ private static void testKeyPairCloning(String keyType, int keySize, KeyPair kp) throws GeneralSecurityException {
+ String prefix = keyType + "[" + keySize + "]";
+ System.out.println("testKeyPairCloning(" + prefix + ")");
+
+ KeyPair cloned = KeyUtils.cloneKeyPair(keyType, kp);
+ assertNotSame(prefix + ": Key pair not cloned", kp, cloned);
+ assertTrue(prefix + ": Cloned pair not equals", KeyUtils.compareKeyPairs(kp, cloned));
+
+ {
+ PublicKey k1 = kp.getPublic(), k2 = cloned.getPublic();
+ assertNotSame(prefix + ": Public key not cloned", k1, k2);
+ assertTrue(prefix + ": Cloned public key not equals", KeyUtils.compareKeys(k1, k2));
+
+ String f1 = KeyUtils.getFingerPrint(k1), f2 = KeyUtils.getFingerPrint(k2);
+ assertEquals(prefix + ": Mismatched fingerprints", f1, f2);
+ }
+
+ {
+ PrivateKey k1 = kp.getPrivate(), k2 = cloned.getPrivate();
+ assertNotSame(prefix + ": Private key not cloned", k1, k2);
+ assertTrue(prefix + ": Cloned private key not equals", KeyUtils.compareKeys(k1, k2));
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
new file mode 100644
index 0000000..ea9c555
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.mac;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.Cipher;
+import org.apache.sshd.common.mac.BuiltinMacs;
+import org.apache.sshd.common.mac.Mac;
+import org.apache.sshd.common.random.BouncyCastleRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.JSchLogger;
+import org.apache.sshd.util.SimpleUserInfo;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.FixMethodOrder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jcraft.jsch.JSch;
+
+/**
+ * Test Cipher algorithms.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MacTest extends BaseTestSupport {
+
+ private SshServer sshd;
+ private int port;
+
+ @Test
+ public void testHMACMD5() throws Exception {
+ setUp(BuiltinMacs.hmacmd5);
+ runTest();
+ }
+
+ @Test
+ public void testHMACMD596() throws Exception {
+ setUp(BuiltinMacs.hmacmd596);
+ runTest();
+ }
+
+ @Test
+ public void testHMACSHA1() throws Exception {
+ setUp(BuiltinMacs.hmacsha1);
+ runTest();
+ }
+
+ @Test
+ public void testHMACSHA196() throws Exception {
+ setUp(BuiltinMacs.hmacsha196);
+ runTest();
+ }
+
+ @Test
+ public void testHMACSHA256() throws Exception {
+ setUp(BuiltinMacs.hmacsha256);
+ runTest();
+ }
+
+ @Test
+ @Ignore("Lead to ArrayIndexOutOfBoundsException in JSch")
+ public void testHMACSHA512() throws Exception {
+ setUp(BuiltinMacs.hmacsha512);
+ runTest();
+ }
+
+ @Test
+ public void loadTest() throws Exception {
+ Random random = new BouncyCastleRandom();
+ loadTest(BuiltinCiphers.aes128cbc, random);
+ loadTest(BuiltinCiphers.blowfishcbc, random);
+ loadTest(BuiltinCiphers.tripledescbc, random);
+ }
+
+ protected void loadTest(NamedFactory<Cipher> factory, Random random) throws Exception {
+ Cipher cipher = factory.create();
+ byte[] key = new byte[cipher.getBlockSize()];
+ byte[] iv = new byte[cipher.getIVSize()];
+ random.fill(key, 0, key.length);
+ random.fill(iv, 0, iv.length);
+ cipher.init(Cipher.Mode.Encrypt, key, iv);
+
+ byte[] input = new byte[cipher.getBlockSize()];
+ random.fill(input, 0, input.length);
+ long t0 = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ cipher.update(input, 0, input.length);
+ }
+ long t1 = System.currentTimeMillis();
+ System.err.println(factory.getName() + ": " + (t1 - t0) + " ms");
+ }
+
+
+ protected void setUp(NamedFactory<Mac> mac) throws Exception {
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setMacFactories(Arrays.<NamedFactory<Mac>>asList(mac));
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd.start();
+ port = sshd.getPort();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ }
+
+ protected void runTest() throws Exception {
+ JSchLogger.init();
+ JSch sch = new JSch();
+ JSch.setConfig("cipher.s2c", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+ JSch.setConfig("cipher.c2s", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+ JSch.setConfig("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96,hmac-sha2-512");
+ JSch.setConfig("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96,hmac-sha2-512");
+ JSch.setConfig("hmac-sha2-512", "com.jcraft.jsch.jce.HMACSHA512");
+ com.jcraft.jsch.Session s = sch.getSession(getCurrentTestName(), "localhost", port);
+ try {
+ s.setUserInfo(new SimpleUserInfo(getCurrentTestName()));
+ s.connect();
+ com.jcraft.jsch.Channel c = s.openChannel("shell");
+ c.connect();
+
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+
+ String expected = "this is my command\n";
+ byte[] bytes = expected.getBytes();
+ byte[] data = new byte[bytes.length + Long.SIZE];
+ for (int i = 0; i < 10; i++) {
+ os.write(bytes);
+ os.flush();
+ int len = is.read(data);
+ String str = new String(data, 0, len);
+ assertEquals("Mismatched data at iteration " + i, expected, str);
+ }
+ } finally {
+ c.disconnect();
+ }
+ } finally {
+ s.disconnect();
+ }
+ }
+
+ static boolean checkCipher(String cipher){
+ try{
+ Class<?> c=Class.forName(cipher);
+ com.jcraft.jsch.Cipher _c = (com.jcraft.jsch.Cipher)(c.newInstance());
+ _c.init(com.jcraft.jsch.Cipher.ENCRYPT_MODE,
+ new byte[_c.getBlockSize()],
+ new byte[_c.getIVSize()]);
+ return true;
+ }
+ catch(Exception e){
+ return false;
+ }
+ }
+}