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:16 UTC
[1/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
Repository: mina-sshd
Updated Branches:
refs/heads/master ff6a4b04f -> 6432a7af3
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java b/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
new file mode 100644
index 0000000..bd293f6
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.random;
+
+import org.apache.sshd.common.random.BouncyCastleRandom;
+import org.apache.sshd.common.random.JceRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.util.BaseTestSupport;
+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 RandomTest extends BaseTestSupport {
+
+ @Test
+ public void testJce() {
+ long t = test(new JceRandom());
+ System.out.println("JCE: " + t + " micro");
+ }
+
+ @Test
+ public void testBc() {
+ long t = test(new BouncyCastleRandom());
+ System.out.println("BC: " + t + " micro");
+ }
+
+ protected long test(Random random) {
+ byte[] bytes = new byte[32];
+ long l0 = System.nanoTime();
+ for (int i = 0; i < 1000; i++) {
+ random.fill(bytes, 8, 16);
+ }
+ long l1 = System.nanoTime();
+ return (l1 - l0) / 1000;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/session/AbstractSessionTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/session/AbstractSessionTest.java b/sshd-core/src/test/java/org/apache/sshd/common/session/AbstractSessionTest.java
new file mode 100644
index 0000000..7ee8e11
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/session/AbstractSessionTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.session;
+
+import java.io.IOException;
+
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Test basic stuff on AbstractSession.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AbstractSessionTest extends BaseTestSupport {
+
+ private MySession session;
+
+ @Before
+ public void setUp() throws Exception {
+ session = new MySession();
+ }
+
+ @Test
+ public void testReadIdentSimple() {
+ Buffer buf = new ByteArrayBuffer("SSH-2.0-software\r\n".getBytes());
+ String ident = session.doReadIdentification(buf);
+ assertEquals("SSH-2.0-software", ident);
+ }
+
+ @Test
+ public void testReadIdentWithoutCR() {
+ Buffer buf = new ByteArrayBuffer("SSH-2.0-software\n".getBytes());
+ String ident = session.doReadIdentification(buf);
+ assertEquals("SSH-2.0-software", ident);
+ }
+
+ @Test
+ public void testReadIdentWithHeaders() {
+ Buffer buf = new ByteArrayBuffer(("a header line\r\nSSH-2.0-software\r\n").getBytes());
+ String ident = session.doReadIdentification(buf);
+ assertEquals("SSH-2.0-software", ident);
+ }
+
+ @Test
+ public void testReadIdentWithSplitPackets() {
+ Buffer buf = new ByteArrayBuffer("header line\r\nSSH".getBytes());
+ String ident = session.doReadIdentification(buf);
+ assertNull(ident);
+ buf.putRawBytes("-2.0-software\r\n".getBytes());
+ ident = session.doReadIdentification(buf);
+ assertEquals("SSH-2.0-software", ident);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testReadIdentBadLineEnding() {
+ Buffer buf = new ByteArrayBuffer(("SSH-2.0-software\ra").getBytes());
+ String ident = session.doReadIdentification(buf);
+ fail("Unexpected success: " + ident);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testReadIdentLongLine() {
+ Buffer buf = new ByteArrayBuffer(("SSH-2.0-software" +
+ "01234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789").getBytes());
+ String ident = session.doReadIdentification(buf);
+ fail("Unexpected success: " + ident);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testReadIdentLongHeader() {
+ StringBuilder sb = new StringBuilder(32768);
+ for (int i = 0; i < 500; i++) {
+ sb.append("01234567890123456789012345678901234567890123456789\r\n");
+ }
+ sb.append("SSH-2.0-software\r\n");
+ Buffer buf = new ByteArrayBuffer(sb.toString().getBytes());
+ String ident = session.doReadIdentification(buf);
+ fail("Unexpected success: " + ident);
+ }
+
+ public static class MySession extends AbstractSession {
+ public MySession() {
+ super(true, SshServer.setUpDefaultServer(), null);
+ }
+ @Override
+ protected void handleMessage(Buffer buffer) throws Exception {
+ // ignored
+ }
+ @Override
+ protected boolean readIdentification(Buffer buffer) {
+ return false;
+ }
+ public String doReadIdentification(Buffer buffer) {
+ return super.doReadIdentification(buffer, false);
+ }
+ @Override
+ protected void sendKexInit() throws IOException {
+ // ignored
+ }
+ @Override
+ protected void checkKeys() {
+ // ignored
+ }
+ @Override
+ protected void receiveKexInit(Buffer buffer) throws IOException {
+ // ignored
+ }
+ @Override
+ public void startService(String name) throws Exception {
+ // ignored
+ }
+ @Override
+ public void resetIdleTimeout() {
+ // ignored
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
index 7d3628a..5504365 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
@@ -22,6 +22,7 @@ package org.apache.sshd.common.util;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.NoSuchElementException;
import org.apache.sshd.util.BaseTestSupport;
import org.junit.FixMethodOrder;
@@ -116,4 +117,30 @@ public class GenericUtilsTest extends BaseTestSupport {
assertSame("Mismatched result for delim at index=" + index, expected, GenericUtils.stripDelimiters(expected, delim));
}
}
+
+ @Test
+ public void testAccumulateExceptionOnNullValues() {
+ assertNull("Unexpected null/null result", GenericUtils.accumulateException(null, null));
+
+ Throwable expected=new NoSuchMethodException(getClass().getName() + "#" + getCurrentTestName());
+ assertSame("Mismatched null/extra result", expected, GenericUtils.accumulateException(null, expected));
+ assertSame("Mismatched current/null result", expected, GenericUtils.accumulateException(expected, null));
+ }
+
+ @Test
+ public void testAccumulateExceptionOnExistingCurrent() {
+ RuntimeException[] expected=new RuntimeException[] {
+ new IllegalArgumentException(getCurrentTestName()),
+ new ClassCastException(getClass().getName()),
+ new NoSuchElementException(getClass().getPackage().getName())
+ };
+ RuntimeException current=new UnsupportedOperationException("top");
+ for (RuntimeException extra : expected) {
+ RuntimeException actual=GenericUtils.accumulateException(current, extra);
+ assertSame("Mismatched returned actual exception", current, actual);
+ }
+
+ Throwable[] actual=current.getSuppressed();
+ assertArrayEquals("Suppressed", expected, actual);
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java
new file mode 100644
index 0000000..f7c1e56
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sshd.common.util.buffer.BufferUtils;
+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 EmptyInputStreamTest extends BaseTestSupport {
+ public EmptyInputStreamTest() {
+ super();
+ }
+
+ @Test
+ public void testEmptyInputStream() throws IOException {
+ try(EmptyInputStream in = new EmptyInputStream()) {
+ testEmptyInputStream(in, false);
+ }
+ }
+
+ @Test
+ public void testCloseableEmptyInputStream() throws IOException {
+ try(EmptyInputStream in = new CloseableEmptyInputStream()) {
+ testEmptyInputStream(in, true);
+ }
+ }
+
+ private void testEmptyInputStream(InputStream in, boolean failAfterClose) throws IOException {
+ testEmptyInputStream("open", in, false);
+ in.close();
+ testEmptyInputStream("closed", in, failAfterClose);
+ }
+
+ private void testEmptyInputStream(String message, InputStream in, boolean errorExpected) {
+ assertFalse(message + ": unexpected markSupported()", in.markSupported());
+ try {
+ in.mark(Long.SIZE);
+ fail(message + ": unexpected mark success");
+ } catch(UnsupportedOperationException e) {
+ // expected
+ }
+
+ try {
+ int len = in.available();
+ assertFalse(message + ": Unexpected success in available(): " + len, errorExpected);
+ assertEquals(message + ": Mismatched available() result", 0, len);
+ } catch(IOException e) {
+ assertTrue(message + ": Unexpected error on available(): " + e.getMessage(), errorExpected);
+ }
+
+ try {
+ int data = in.read();
+ assertFalse(message + ": Unexpected success in read(): " + data, errorExpected);
+ assertEquals(message + ": Mismatched read() result", (-1), data);
+ } catch(IOException e) {
+ assertTrue(message + ": Unexpected error on read(): " + e.getMessage(), errorExpected);
+ }
+
+ byte[] bytes = new byte[Byte.SIZE];
+ try {
+ int len = in.read(bytes);
+ assertFalse(message + ": Unexpected success in read([]): " + BufferUtils.printHex(':', bytes), errorExpected);
+ assertEquals(message + ": Mismatched read([]) result", (-1), len);
+ } catch(IOException e) {
+ assertTrue(message + ": Unexpected error on read([]): " + e.getMessage(), errorExpected);
+ }
+
+ try {
+ int len = in.read(bytes, 0, bytes.length);
+ assertFalse(message + ": Unexpected success in read([],int,int): " + BufferUtils.printHex(':', bytes), errorExpected);
+ assertEquals(message + ": Mismatched read([],int,int) result", (-1), len);
+ } catch(IOException e) {
+ assertTrue(message + ": Unexpected error on read([],int,int): " + e.getMessage(), errorExpected);
+ }
+
+ try {
+ long len = in.skip(Byte.MAX_VALUE);
+ assertFalse(message + ": Unexpected success in skip(): " + len, errorExpected);
+ assertEquals(message + ": Mismatched skip() result", 0L, len);
+ } catch(IOException e) {
+ assertTrue(message + ": Unexpected error on skip(): " + e.getMessage(), errorExpected);
+ }
+
+ try {
+ in.reset();
+ assertFalse(message + ": Unexpected success in reset()", errorExpected);
+ } catch(IOException e) {
+ assertTrue(message + ": Unexpected error on reset(): " + e.getMessage(), errorExpected);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/deprecated/AbstractUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/AbstractUserAuth.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/AbstractUserAuth.java
index e7ab084..3cbd5a4 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/AbstractUserAuth.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/AbstractUserAuth.java
@@ -19,7 +19,7 @@
package org.apache.sshd.deprecated;
import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
*/
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/server/ServerMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerMain.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerMain.java
new file mode 100644
index 0000000..6c9fb10
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerMain.java
@@ -0,0 +1,34 @@
+/*
+ * 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.server;
+
+import org.apache.sshd.server.SshServer;
+
+
+/**
+ * An activator for the {@link SshServer#main(String[])} - the reason it is
+ * here is because the logging configuration is available only for test scope
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ServerMain {
+ public static void main(String[] args) throws Throwable {
+ SshServer.main(args);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
new file mode 100644
index 0000000..8cc32ea
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
@@ -0,0 +1,561 @@
+/*
+ * 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.server;
+
+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.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.client.SessionFactory;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.session.ClientConnectionService;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.channel.WindowClosedException;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.session.AbstractConnectionService;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.deprecated.ClientUserAuthServiceOld;
+import org.apache.sshd.deprecated.UserAuthPassword;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.server.sftp.SftpSubsystemFactory;
+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.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ServerTest extends BaseTestSupport {
+
+ private SshServer sshd;
+ private SshClient client;
+ private int port;
+
+ @Before
+ public void setUp() throws Exception {
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setShellFactory(new TestEchoShellFactory());
+ sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd.setSessionFactory(new org.apache.sshd.server.session.SessionFactory());
+ sshd.start();
+ port = sshd.getPort();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ if (client != null) {
+ client.stop();
+ }
+ }
+
+ /**
+ * Send bad password. The server should disconnect after a few attempts
+ * @throws Exception
+ */
+ @Test
+ public void testFailAuthenticationWithWaitFor() throws Exception {
+ final int MAX_AUTH_REQUESTS=10;
+ FactoryManagerUtils.updateProperty(sshd, ServerFactoryManager.MAX_AUTH_REQUESTS, MAX_AUTH_REQUESTS);
+
+ client = SshClient.setUpDefaultClient();
+ client.setServiceFactories(Arrays.asList(
+ new ClientUserAuthServiceOld.Factory(),
+ new ClientConnectionService.Factory()
+ ));
+ client.start();
+
+ try(ClientSession s = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ int nbTrials = 0;
+ int res = 0;
+ while ((res & ClientSession.CLOSED) == 0) {
+ nbTrials ++;
+ s.getService(ClientUserAuthServiceOld.class)
+ .auth(new UserAuthPassword((ClientSessionImpl) s, "ssh-connection", "buggy"));
+ res = s.waitFor(ClientSession.CLOSED | ClientSession.WAIT_AUTH, 5000);
+ if (res == ClientSession.TIMEOUT) {
+ throw new TimeoutException();
+ }
+ }
+ assertTrue("Number trials (" + nbTrials + ") below min.=" + MAX_AUTH_REQUESTS, nbTrials > MAX_AUTH_REQUESTS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testFailAuthenticationWithFuture() throws Exception {
+ final int MAX_AUTH_REQUESTS=10;
+ FactoryManagerUtils.updateProperty(sshd, ServerFactoryManager.MAX_AUTH_REQUESTS, MAX_AUTH_REQUESTS);
+
+ client = SshClient.setUpDefaultClient();
+ client.setServiceFactories(Arrays.asList(
+ new ClientUserAuthServiceOld.Factory(),
+ new ClientConnectionService.Factory()
+ ));
+ client.start();
+ try(ClientSession s = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ int nbTrials = 0;
+ AuthFuture authFuture;
+ do {
+ nbTrials++;
+ assertTrue(nbTrials < 100);
+ authFuture = s.getService(ClientUserAuthServiceOld.class)
+ .auth(new UserAuthPassword((ClientSessionImpl) s, "ssh-connection", "buggy"));
+ assertTrue("Authentication wait failed", authFuture.await(5000));
+ assertTrue("Authentication not done", authFuture.isDone());
+ assertFalse("Authentication unexpectedly successful", authFuture.isSuccess());
+ }
+ while (authFuture.isFailure());
+ assertNotNull("Missing auth future exception", authFuture.getException());
+ assertTrue("Number trials (" + nbTrials + ") below min.=" + MAX_AUTH_REQUESTS, nbTrials > MAX_AUTH_REQUESTS);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testAuthenticationTimeout() throws Exception {
+ final int AUTH_TIMEOUT=5000;
+ FactoryManagerUtils.updateProperty(sshd, FactoryManager.AUTH_TIMEOUT, AUTH_TIMEOUT);
+
+ client = SshClient.setUpDefaultClient();
+ client.start();
+ try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
+ int res = s.waitFor(ClientSession.CLOSED, 2 * AUTH_TIMEOUT);
+ assertEquals("Session should be closed", ClientSession.CLOSED | ClientSession.WAIT_AUTH, res);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testIdleTimeout() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ TestEchoShellFactory.TestEchoShell.latch = new CountDownLatch(1);
+ final int IDLE_TIMEOUT=2500;
+ FactoryManagerUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, IDLE_TIMEOUT);
+
+ sshd.getSessionFactory().addListener(new SessionListener() {
+ @Override
+ public void sessionCreated(Session session) {
+ System.out.println("Session created");
+ }
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ System.out.println("Session event: " + event);
+ }
+ @Override
+ public void sessionClosed(Session session) {
+ System.out.println("Session closed");
+ latch.countDown();
+ }
+ });
+
+ client = SshClient.setUpDefaultClient();
+ client.start();
+ try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
+ s.addPasswordIdentity("test");
+ s.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ChannelShell shell = s.createShellChannel();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+ shell.setOut(out);
+ shell.setErr(err);
+ shell.open().await();
+ int res = s.waitFor(ClientSession.CLOSED, 2 * IDLE_TIMEOUT);
+ assertEquals("Session should be closed", ClientSession.CLOSED | ClientSession.AUTHED, res);
+ }
+ } finally {
+ client.stop();
+ }
+
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+ assertTrue(TestEchoShellFactory.TestEchoShell.latch.await(1, TimeUnit.SECONDS));
+ }
+
+ /**
+ * The scenario is the following:
+ * - create a command that sends continuous data to the client
+ * - the client does not read the data, filling the ssh window and the tcp socket
+ * - the server session becomes idle, but the ssh disconnect message can't be written
+ * - the server session is forcibly closed
+ */
+ @Test
+ public void testServerIdleTimeoutWithForce() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ sshd.setCommandFactory(new StreamCommand.Factory());
+
+ FactoryManagerUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, 5000);
+ FactoryManagerUtils.updateProperty(sshd, FactoryManager.DISCONNECT_TIMEOUT, 2000);
+ sshd.getSessionFactory().addListener(new SessionListener() {
+ @Override
+ public void sessionCreated(Session session) {
+ System.out.println("Session created");
+ }
+
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ System.out.println("Session event: " + event);
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ System.out.println("Session closed");
+ latch.countDown();
+ }
+ });
+
+ client = SshClient.setUpDefaultClient();
+ client.start();
+
+ try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
+ s.addPasswordIdentity("test");
+ s.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(ChannelExec shell = s.createExecChannel("normal");
+ // Create a pipe that will block reading when the buffer is full
+ PipedInputStream pis = new PipedInputStream();
+ PipedOutputStream pos = new PipedOutputStream(pis)) {
+
+ shell.setOut(pos);
+ shell.open().verify(5L, TimeUnit.SECONDS);
+
+ try(AbstractSession serverSession = sshd.getActiveSessions().iterator().next();
+ Channel channel = serverSession.getService(AbstractConnectionService.class).getChannels().iterator().next()) {
+
+ while (channel.getRemoteWindow().getSize() > 0) {
+ Thread.sleep(1);
+ }
+
+ LoggerFactory.getLogger(getClass()).info("Waiting for session idle timeouts");
+
+ long t0 = System.currentTimeMillis();
+ latch.await(1, TimeUnit.MINUTES);
+ long t1 = System.currentTimeMillis(), diff = t1 - t0;
+ assertTrue("Wait time too low: " + diff, diff > 7000);
+ assertTrue("Wait time too high: " + diff, diff < 10000);
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testLanguage() throws Exception {
+ client = SshClient.setUpDefaultClient();
+ client.setSessionFactory(new SessionFactory() {
+ @Override
+ protected AbstractSession createSession(IoSession ioSession) throws Exception {
+ return new ClientSessionImpl(client, ioSession) {
+ @Override
+ protected String[] createProposal(String hostKeyTypes) {
+ String[] proposal = super.createProposal(hostKeyTypes);
+ proposal[SshConstants.PROPOSAL_LANG_CTOS] = "en-US";
+ proposal[SshConstants.PROPOSAL_LANG_STOC] = "en-US";
+ return proposal;
+ }
+ };
+ }
+ });
+ client.start();
+ try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
+ s.close(false);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testKexCompletedEvent() throws Exception {
+ final AtomicInteger serverEventCount=new AtomicInteger(0);
+ sshd.getSessionFactory().addListener(new SessionListener() {
+ @Override
+ public void sessionCreated(Session session) {
+ // ignored
+ }
+
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ if (event == Event.KexCompleted) {
+ serverEventCount.incrementAndGet();
+ }
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ // ignored
+ }
+ });
+
+ client = SshClient.setUpDefaultClient();
+ client.start();
+ final AtomicInteger clientEventCount=new AtomicInteger(0);
+ client.getSessionFactory().addListener(new SessionListener() {
+ @Override
+ public void sessionCreated(Session session) {
+ // ignored
+ }
+
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ if (event == Event.KexCompleted) {
+ clientEventCount.incrementAndGet();
+ }
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ // ignored
+ }
+ });
+
+ try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
+ s.addPasswordIdentity("test");
+ s.auth().verify(5L, TimeUnit.SECONDS);
+ assertEquals("Mismatched client events count", 1, clientEventCount.get());
+ assertEquals("Mismatched server events count", 1, serverEventCount.get());
+ s.close(false);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test // see https://issues.apache.org/jira/browse/SSHD-456
+ public void testServerStillListensIfSessionListenerThrowsException() throws InterruptedException {
+ final Map<String,SocketAddress> eventsMap = new TreeMap<String, SocketAddress>(String.CASE_INSENSITIVE_ORDER);
+ sshd.getSessionFactory().addListener(new SessionListener() {
+ private final Logger log=LoggerFactory.getLogger(getClass());
+ @Override
+ public void sessionCreated(Session session) {
+ throwException("SessionCreated", session);
+ }
+
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ throwException("SessionEvent", session);
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ throwException("SessionClosed", session);
+ }
+
+ private void throwException(String phase, Session session) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress addr = ioSession.getRemoteAddress();
+ synchronized (eventsMap) {
+ if (eventsMap.put(phase, addr) != null) {
+ return; // already generated an event for this phase
+ }
+ }
+
+ RuntimeException e = new RuntimeException("Synthetic exception at phase=" + phase + ": " + addr);
+ log.info(e.getMessage());
+ throw e;
+ }
+ });
+
+ client = SshClient.setUpDefaultClient();
+ client.start();
+
+ int curCount=0;
+ for (int retryCount=0; retryCount < Byte.SIZE; retryCount++){
+ synchronized(eventsMap) {
+ if ((curCount=eventsMap.size()) >= 3) {
+ return;
+ }
+ }
+
+ try {
+ try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
+ s.addPasswordIdentity("test");
+ s.auth().verify(5L, TimeUnit.SECONDS);
+ }
+
+ synchronized(eventsMap) {
+ assertTrue("Unexpected premature success: " + eventsMap, eventsMap.size() >= 3);
+ }
+ } catch(IOException e) {
+ // expected - ignored
+ synchronized(eventsMap) {
+ int nextCount=eventsMap.size();
+ assertTrue("No session event generated", nextCount > curCount);
+ }
+ }
+ }
+
+ fail("No success to authenticate");
+ }
+
+ 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 class StreamCommand implements Command, Runnable {
+
+ public static class Factory implements CommandFactory {
+ @Override
+ public Command createCommand(String name) {
+ return new StreamCommand(name);
+ }
+ }
+
+ public static CountDownLatch latch;
+
+ private final String name;
+ private OutputStream out;
+
+ public StreamCommand(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void setInputStream(InputStream in) {
+ // ignored
+ }
+
+ @Override
+ public void setOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ @Override
+ public void setErrorStream(OutputStream err) {
+ // ignored
+ }
+
+ @Override
+ public void setExitCallback(ExitCallback callback) {
+ // ignored
+ }
+
+ @Override
+ public void start(Environment env) throws IOException {
+ new Thread(this).start();
+ }
+
+ @Override
+ public void destroy() {
+ synchronized (name) {
+ if ("block".equals(name)) {
+ try {
+ name.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(5000);
+ while (true) {
+ for (int i = 0; i < 100; i++) {
+ out.write("0123456789\n".getBytes());
+ }
+ out.flush();
+ }
+ } catch (WindowClosedException e) {
+ // ok, do nothing
+ } catch (Throwable e) {
+ e.printStackTrace();
+ } finally {
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ SshServer sshd = SshServer.setUpDefaultServer();
+ FactoryManagerUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, TimeUnit.SECONDS.toMillis(10L));
+ sshd.setPort(8001);
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory()));
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setCommandFactory(new ScpCommandFactory());
+ sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+ sshd.start();
+ Thread.sleep(100000);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/server/SshServerMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/SshServerMain.java b/sshd-core/src/test/java/org/apache/sshd/server/SshServerMain.java
new file mode 100644
index 0000000..5422c51
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/server/SshServerMain.java
@@ -0,0 +1,35 @@
+/*
+ * 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.server;
+
+import org.apache.sshd.server.SshServer;
+
+/**
+ * Just a test class used to invoke {@link SshServer#main(String[])} in
+ * order to have logging - which is in {@code test} scope
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SshServerMain {
+
+ public static void main(String[] args) throws Exception {
+ SshServer.main(args);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/server/SshServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/SshServerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/SshServerTest.java
new file mode 100644
index 0000000..5c8e08e
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/server/SshServerTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.server;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+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.Utils;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author Kohsuke Kawaguchi
+ * @author Michael Heemskerk
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SshServerTest extends BaseTestSupport {
+
+ @Test
+ public void stopMethodShouldBeIdempotent() throws Exception {
+ try(SshServer sshd = new SshServer()) {
+ sshd.stop();
+ sshd.stop();
+ sshd.stop();
+ }
+ }
+
+ @Test
+ public void testExecutorShutdownFalse() throws Exception {
+ ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+
+ try(SshServer sshd = createTestServer()) {
+ sshd.setScheduledExecutorService(executorService);
+
+ sshd.start();
+ sshd.stop();
+
+ assertFalse(executorService.isShutdown());
+ executorService.shutdownNow();
+ }
+ }
+
+ @Test
+ public void testExecutorShutdownTrue() throws Exception {
+ ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+
+ try(SshServer sshd = createTestServer()) {
+ sshd.setScheduledExecutorService(executorService, true);
+
+ sshd.start();
+ sshd.stop();
+
+ assertTrue(executorService.isShutdown());
+ }
+ }
+
+ @Test
+ public void testDynamicPort() throws Exception {
+ try(SshServer sshd = createTestServer()) {
+ sshd.setHost("localhost");
+ sshd.start();
+
+ assertNotEquals(0, sshd.getPort());
+
+ sshd.stop();
+ }
+ }
+
+
+ private SshServer createTestServer() {
+ SshServer sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+
+ return sshd;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntryTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntryTest.java b/sshd-core/src/test/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntryTest.java
index 328a257..0740d4c 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntryTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntryTest.java
@@ -33,8 +33,8 @@ import java.util.Collection;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.util.BaseTestSupport;
import org.junit.FixMethodOrder;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticatorTest.java b/sshd-core/src/test/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticatorTest.java
index a1101f7..9fb9de3 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticatorTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticatorTest.java
@@ -28,7 +28,7 @@ import java.nio.file.Path;
import java.security.PublicKey;
import java.util.Collection;
-import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.util.BaseTestSupport;
import org.junit.FixMethodOrder;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/util/BogusInvertedShell.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/BogusInvertedShell.java b/sshd-core/src/test/java/org/apache/sshd/util/BogusInvertedShell.java
index 4d38f6a..28e1abf 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/BogusInvertedShell.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/BogusInvertedShell.java
@@ -24,7 +24,7 @@ import java.io.OutputStream;
import java.util.Collections;
import java.util.Map;
-import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.shell.InvertedShell;
public class BogusInvertedShell implements InvertedShell {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/util/BogusPasswordAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/BogusPasswordAuthenticator.java b/sshd-core/src/test/java/org/apache/sshd/util/BogusPasswordAuthenticator.java
index 40a3162..cff5a72 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/BogusPasswordAuthenticator.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/BogusPasswordAuthenticator.java
@@ -18,7 +18,7 @@
*/
package org.apache.sshd.util;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;
[4/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
Posted by lg...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
new file mode 100644
index 0000000..9bae57e
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
@@ -0,0 +1,293 @@
+/*
+ * 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.util.io;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.sshd.common.util.OsUtils;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class IoUtils {
+
+ public static final LinkOption[] EMPTY_OPTIONS = new LinkOption[0];
+ private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+
+ public static LinkOption[] getLinkOptions(boolean followLinks) {
+ if (followLinks) {
+ return EMPTY_OPTIONS;
+ } else { // return a clone that modifications to the array will not affect others
+ return NO_FOLLOW_OPTIONS.clone();
+ }
+ }
+
+ public static final int DEFAULT_COPY_SIZE=8192;
+
+ public static long copy(InputStream source, OutputStream sink) throws IOException {
+ return copy(source, sink, DEFAULT_COPY_SIZE);
+ }
+
+ public static long copy(InputStream source, OutputStream sink, int bufferSize) throws IOException {
+ long nread = 0L;
+ byte[] buf = new byte[bufferSize];
+ int n;
+ while ((n = source.read(buf)) > 0) {
+ sink.write(buf, 0, n);
+ nread += n;
+ }
+ return nread;
+ }
+
+ public static void closeQuietly(Closeable... closeables) {
+ for (Closeable c : closeables) {
+ try {
+ if (c != null) {
+ c.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ public static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS = Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
+
+ /**
+ * @param fileName The file name to be evaluated - ignored if {@code null}/empty
+ * @return {@code true} if the file ends in one of the {@link #WINDOWS_EXECUTABLE_EXTENSIONS}
+ */
+ public static boolean isWindowsExecutable(String fileName) {
+ if ((fileName == null) || (fileName.length() <= 0)) {
+ return false;
+ }
+ for (String suffix : WINDOWS_EXECUTABLE_EXTENSIONS) {
+ if (fileName.endsWith(suffix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If the "posix" view is supported, then it returns
+ * {@link Files#getPosixFilePermissions(Path, LinkOption...)}, otherwise
+ * uses the {@link #getPermissionsFromFile(File)} method
+ * @param path The {@link Path}
+ * @return A {@link Set} of {@link PosixFilePermission}
+ * @throws IOException If failed to access the file system in order to
+ * retrieve the permissions
+ */
+ public static Set<PosixFilePermission> getPermissions(Path path) throws IOException {
+ FileSystem fs = path.getFileSystem();
+ Collection<String> views = fs.supportedFileAttributeViews();
+ if (views.contains("posix")) {
+ return Files.getPosixFilePermissions(path, getLinkOptions(false));
+ } else {
+ return getPermissionsFromFile(path.toFile());
+ }
+ }
+
+ /**
+ * @param f The {@link File} to be checked
+ * @return A {@link Set} of {@link PosixFilePermission}s based on whether
+ * the file is readable/writable/executable. If so, then <U>all</U> the
+ * relevant permissions are set (i.e., owner, group and others)
+ */
+ public static Set<PosixFilePermission> getPermissionsFromFile(File f) {
+ Set<PosixFilePermission> perms = EnumSet.noneOf(PosixFilePermission.class);
+ if (f.canRead()) {
+ perms.add(PosixFilePermission.OWNER_READ);
+ perms.add(PosixFilePermission.GROUP_READ);
+ perms.add(PosixFilePermission.OTHERS_READ);
+ }
+
+ if (f.canWrite()) {
+ perms.add(PosixFilePermission.OWNER_WRITE);
+ perms.add(PosixFilePermission.GROUP_WRITE);
+ perms.add(PosixFilePermission.OTHERS_WRITE);
+ }
+
+ if (f.canExecute() || (OsUtils.isWin32() && isWindowsExecutable(f.getName()))) {
+ perms.add(PosixFilePermission.OWNER_EXECUTE);
+ perms.add(PosixFilePermission.GROUP_EXECUTE);
+ perms.add(PosixFilePermission.OTHERS_EXECUTE);
+ }
+
+ return perms;
+ }
+
+ /**
+ * If the "posix" view is supported, then it invokes
+ * {@link Files#setPosixFilePermissions(Path, Set)}, otherwise
+ * uses the {@link #setPermissionsToFile(File, Collection)} method
+ * @param path The {@link Path}
+ * @param perms The {@link Set} of {@link PosixFilePermission}s
+ * @throws IOException If failed to access the file system
+ */
+ public static void setPermissions(Path path, Set<PosixFilePermission> perms) throws IOException {
+ FileSystem fs = path.getFileSystem();
+ Collection<String> views = fs.supportedFileAttributeViews();
+ if (views.contains("posix")) {
+ Files.setPosixFilePermissions(path, perms);
+ } else {
+ setPermissionsToFile(path.toFile(), perms);
+ }
+ }
+
+ /**
+ * @param f The {@link File}
+ * @param perms A {@link Collection} of {@link PosixFilePermission}s to set on it.
+ * <B>Note:</B> the file is set to readable/writable/executable not only by the
+ * owner if <U>any</U> of relevant the owner/group/others permission is set
+ */
+ public static void setPermissionsToFile(File f, Collection<PosixFilePermission> perms) {
+ boolean readable = perms != null &&
+ (perms.contains(PosixFilePermission.OWNER_READ)
+ || perms.contains(PosixFilePermission.GROUP_READ)
+ || perms.contains(PosixFilePermission.OTHERS_READ));
+ f.setReadable(readable, false);
+
+ boolean writable = perms != null &&
+ (perms.contains(PosixFilePermission.OWNER_WRITE)
+ || perms.contains(PosixFilePermission.GROUP_WRITE)
+ || perms.contains(PosixFilePermission.OTHERS_WRITE));
+ f.setWritable(writable, false);
+
+ boolean executable = perms != null &&
+ (perms.contains(PosixFilePermission.OWNER_EXECUTE)
+ || perms.contains(PosixFilePermission.GROUP_EXECUTE)
+ || perms.contains(PosixFilePermission.OTHERS_EXECUTE));
+ f.setExecutable(executable, false);
+ }
+
+ /**
+ * <P>Checks if a file exists - <B>Note:</B> according to the
+ * <A HREF="http://docs.oracle.com/javase/tutorial/essential/io/check.html">Java tutorial - Checking a File or Directory</A>:
+ * </P></BR>
+ * <PRE>
+ * The methods in the Path class are syntactic, meaning that they operate
+ * on the Path instance. But eventually you must access the file system
+ * to verify that a particular Path exists, or does not exist. You can do
+ * so with the exists(Path, LinkOption...) and the notExists(Path, LinkOption...)
+ * methods. Note that !Files.exists(path) is not equivalent to Files.notExists(path).
+ * When you are testing a file's existence, three results are possible:
+ *
+ * - The file is verified to exist.
+ * - The file is verified to not exist.
+ * - The file's status is unknown.
+ *
+ * This result can occur when the program does not have access to the file.
+ * If both exists and notExists return false, the existence of the file cannot
+ * be verified.
+ * </PRE>
+ * @param path The {@link Path} to be tested
+ * @param options The {@link LinkOption}s to use
+ * @return {@link Boolean#TRUE}/{@link Boolean#FALSE} or {@code null}
+ * according to the file status as explained above
+ */
+ public static Boolean checkFileExists(Path path, LinkOption ... options) {
+ if (Files.exists(path, options)) {
+ return Boolean.TRUE;
+ } else if (Files.notExists(path, options)) {
+ return Boolean.FALSE;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Read the requested number of bytes or fail if there are not enough left.
+ * @param input where to read input from
+ * @param buffer destination
+ * @throws IOException if there is a problem reading the file
+ * @throws EOFException if the number of bytes read was incorrect
+ */
+ public static void readFully(InputStream input, byte[] buffer) throws IOException {
+ readFully(input, buffer, 0, buffer.length);
+ }
+
+ /**
+ * Read the requested number of bytes or fail if there are not enough left.
+ * @param input where to read input from
+ * @param buffer destination
+ * @param offset initial offset into buffer
+ * @param length length to read, must be >= 0
+ * @throws IOException if there is a problem reading the file
+ * @throws EOFException if the number of bytes read was incorrect
+ */
+ public static void readFully(InputStream input, byte[] buffer, int offset, int length) throws IOException {
+ int actual = read(input, buffer, offset, length);
+ if (actual != length) {
+ throw new EOFException("Premature EOF - expected=" + length + ", actual=" + actual);
+ }
+ }
+
+ /**
+ * Read as many bytes as possible until EOF or achieved required length
+ * @param input where to read input from
+ * @param buffer destination
+ * @return actual length read; may be less than requested if EOF was reached
+ * @throws IOException if a read error occurs
+ */
+ public static int read(InputStream input, byte[] buffer) throws IOException {
+ return read(input, buffer, 0, buffer.length);
+ }
+
+ /**
+ * Read as many bytes as possible until EOF or achieved required length
+ * @param input where to read input from
+ * @param buffer destination
+ * @param offset initial offset into buffer
+ * @param length length to read - ignored if non-positive
+ * @return actual length read; may be less than requested if EOF was reached
+ * @throws IOException if a read error occurs
+ */
+ public static int read(InputStream input, byte[] buffer, int offset, int length) throws IOException {
+ for (int remaining = length, curOffset = offset; remaining > 0; ) {
+ int count = input.read(buffer, curOffset, remaining);
+ if (count == (-1)) { // EOF before achieved required length
+ return curOffset - offset;
+ }
+
+ remaining -= count;
+ curOffset += count;
+ }
+
+ return length;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
index 83c1656..ddf0efb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
@@ -29,10 +29,9 @@ import java.nio.file.attribute.FileTime;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Watches over changes for a file and re-loads them if file has changed - including
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java
new file mode 100644
index 0000000..c041750
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util.logging;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Serves as a common base class for the vast majority of classes that require
+ * some kind of logging. Facilitates quick and easy replacement of the actual used
+ * logger from one framework to another
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractLoggingBean {
+ protected final Logger log;
+
+ /**
+ * Default constructor - creates a logger using the full class name
+ */
+ protected AbstractLoggingBean() {
+ log = LoggerFactory.getLogger(getClass());
+ }
+
+ /**
+ * Create a logger for instances of the same class for which we might
+ * want to have a "discriminator" for them
+ * @param discriminator The discriminator value
+ */
+ protected AbstractLoggingBean(String discriminator) {
+ log = LoggerFactory.getLogger(getClass().getName() + "[" + discriminator + "]");
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractSimplifiedLog.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractSimplifiedLog.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractSimplifiedLog.java
new file mode 100644
index 0000000..8492cfe
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractSimplifiedLog.java
@@ -0,0 +1,36 @@
+/*
+ * 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.util.logging;
+
+import java.util.logging.Level;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSimplifiedLog implements SimplifiedLog {
+ protected AbstractSimplifiedLog() {
+ super();
+ }
+
+ @Override
+ public void log(Level level, Object message) {
+ log(level, message, null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java
new file mode 100644
index 0000000..9467ee5
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java
@@ -0,0 +1,144 @@
+/*
+ * 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.util.logging;
+
+import java.util.Objects;
+import java.util.logging.Level;
+
+import org.slf4j.Logger;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class LoggingUtils {
+ private LoggingUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
+ /**
+ * Verifies if the given level is above the required threshold for logging.
+ * @param level The {@link Level} to evaluate
+ * @param threshold The threshold {@link Level}
+ * @return {@code true} if the evaluated level is above the required
+ * threshold.</BR>
+ * <P><B>Note(s):</B></BR></P>
+ * <P><UL>
+ * <LI>
+ * If either argument is {@code null} then result is {@code false}.
+ * </LI>
+ *
+ * <LI>
+ * If the evaluated level is {@link Level#OFF} then result is {@code false}
+ * regardless of the threshold.
+ * </LI>
+ *
+ * <LI>
+ * If the threshold is {@link Level#ALL} and the evaluated level is
+ * <U>not</U> {@link Level#OFF} the result is {@code true}.
+ * </LI>
+ *
+ * <LI>
+ * Otherwise, the evaluated level {@link Level#intValue()} must be
+ * greater or equal to the threshold.
+ * </LI>
+ * </UL></P>
+ */
+ public static final boolean isLoggable(Level level, Level threshold) {
+ if ((level == null) || (threshold == null)) {
+ return false;
+ } else if (Level.OFF.equals(level) || Level.OFF.equals(threshold)) {
+ return false;
+ } else if (Level.ALL.equals(threshold)) {
+ return true;
+ } else if (level.intValue() < threshold.intValue()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public static final SimplifiedLog wrap(final Logger logger) {
+ if (logger == null) {
+ return SimplifiedLog.EMPTY;
+ } else {
+ return new AbstractSimplifiedLog() {
+ @Override
+ public void log(Level level, Object message, Throwable t) {
+ if (isEnabled(level)) {
+ logMessage(logger, level, message, t);
+ }
+
+ }
+
+ @Override
+ public boolean isEnabled(Level level) {
+ return isLoggable(logger, level);
+ }
+ };
+ }
+ }
+
+ // NOTE: assume that level enabled has been checked !!!
+ public static final void logMessage(Logger logger, Level level, Object message, Throwable t) {
+ if ((logger == null) || (level == null) || Level.OFF.equals(level)) {
+ return;
+ } else if (Level.SEVERE.equals(level)) {
+ logger.error(Objects.toString(message), t);
+ } else if (Level.WARNING.equals(level)) {
+ logger.warn(Objects.toString(message), t);
+ } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) {
+ logger.info(Objects.toString(message), t);
+ } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) {
+ logger.debug(Objects.toString(message), t);
+ } else {
+ logger.trace(Objects.toString(message), t);
+ }
+ }
+
+ /**
+ * @param logger The {@link Logger} instance - ignored if {@code null}
+ * @param level The validate log {@link Level} - ignored if {@code null}
+ * @return <P>{@code true} if the level is enabled for the logger. The
+ * mapping of the level to the logger is as follows:</P></BR>
+ * <UL>
+ * <LI>{@link Level#OFF} always returns {@code false}</LI>
+ * <LI>{@link Level#SEVERE} returns {@link Logger#isErrorEnabled()}</LI>
+ * <LI>{@link Level#WARNING} returns {@link Logger#isWarnEnabled()}</LI>
+ * <LI>{@link Level#INFO} and {@link Level#ALL} returns {@link Logger#isInfoEnabled()}</LI>
+ * <LI>{@link Level#CONFIG} and {@link Level#FINE} returns {@link Logger#isDebugEnabled()}</LI>
+ * <LI>All other levels return {@link Logger#isTraceEnabled()}</LI>
+ * </UL>
+ */
+ public static final boolean isLoggable(Logger logger, Level level) {
+ if ((logger == null) || (level == null) || Level.OFF.equals(level)) {
+ return false;
+ } else if (Level.SEVERE.equals(level)) {
+ return logger.isErrorEnabled();
+ } else if (Level.WARNING.equals(level)) {
+ return logger.isWarnEnabled();
+ } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) {
+ return logger.isInfoEnabled();
+ } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) {
+ return logger.isDebugEnabled();
+ } else {
+ return logger.isTraceEnabled();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java
new file mode 100644
index 0000000..0599d37
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.logging;
+
+import java.util.logging.Level;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface SimplifiedLog {
+ boolean isEnabled(Level level);
+
+ void log(Level level, Object message);
+
+ void log(Level level, Object message, Throwable t);
+
+ /**
+ * An "empty" {@link SimplifiedLog} that does nothing
+ */
+ SimplifiedLog EMPTY=new AbstractSimplifiedLog() {
+ @Override
+ public boolean isEnabled(Level level) {
+ return false;
+ }
+
+ @Override
+ public void log(Level level, Object message, Throwable t) {
+ return;
+ }
+
+ @Override
+ public String toString() {
+ return "EMPTY";
+ }
+ };
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/PasswordAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/PasswordAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/PasswordAuthenticator.java
index 9f44851..9164e07 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/PasswordAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/PasswordAuthenticator.java
@@ -18,7 +18,7 @@
*/
package org.apache.sshd.server;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.session.ServerSession;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/PublickeyAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/PublickeyAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/PublickeyAuthenticator.java
index d6224fb..b924bb2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/PublickeyAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/PublickeyAuthenticator.java
@@ -23,8 +23,8 @@ import java.util.Collection;
import java.util.Collections;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.session.ServerSession;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
index 93a9b37..d8ea7b0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
@@ -24,10 +24,10 @@ import java.util.List;
import org.apache.sshd.common.BaseBuilder;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.DHFactory;
import org.apache.sshd.common.kex.KeyExchange;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.config.keys.DefaultAuthorizedKeysAuthenticator;
import org.apache.sshd.server.forward.TcpipServerChannel;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
index 9293ff2..d334edb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
@@ -18,8 +18,8 @@
*/
package org.apache.sshd.server.auth;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.session.ServerSession;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
index 74329db..44069cb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
@@ -50,9 +50,9 @@ import org.apache.sshd.common.future.DefaultCloseFuture;
import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.util.CloseableUtils;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.LoggingFilterOutputStream;
import org.apache.sshd.server.AsyncCommand;
import org.apache.sshd.server.ChannelSessionAware;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
index 677ae72..05a4e7e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
@@ -25,8 +25,8 @@ import java.io.OutputStream;
import org.apache.sshd.common.channel.ChannelPipedInputStream;
import org.apache.sshd.common.channel.ChannelPipedOutputStream;
import org.apache.sshd.common.channel.Window;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.io.LoggingFilterOutputStream;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* {@link ChannelDataReceiver} that buffers the received data into byte buffer
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/channel/PuttyRequestHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/PuttyRequestHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/PuttyRequestHandler.java
index c8b4ae3..ea2d2d6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/PuttyRequestHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/PuttyRequestHandler.java
@@ -20,8 +20,8 @@ package org.apache.sshd.server.channel;
import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.channel.RequestHandler;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Handles Putty specific channel requests as indicated by
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java b/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
index baf6ca2..acf9c7f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
@@ -30,7 +30,7 @@ import java.util.concurrent.Future;
import org.apache.sshd.common.file.FileSystemAware;
import org.apache.sshd.common.scp.ScpHelper;
import org.apache.sshd.common.scp.ScpTransferEventListener;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntry.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntry.java b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntry.java
index e817405..b5e37e0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntry.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeyEntry.java
@@ -317,7 +317,7 @@ public class AuthorizedKeyEntry extends PublicKeyEntry {
}
String keyType = line.substring(0, startPos);
- PublicKeyEntryDecoder<? extends PublicKey> decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
+ PublicKeyEntryDecoder<?,?> decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
final AuthorizedKeyEntry entry;
if (decoder == null) { // assume this is due to the fact that it starts with login options
if ((entry=parseAuthorizedKeyEntry(line.substring(startPos + 1).trim())) == null) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeysAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeysAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeysAuthenticator.java
index 177686e..69d7107 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeysAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/AuthorizedKeysAuthenticator.java
@@ -29,8 +29,8 @@ import java.util.Collection;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.ModifiableFileWatcher;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.session.ServerSession;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticator.java
index 6bad436..ddecc16 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/DefaultAuthorizedKeysAuthenticator.java
@@ -31,9 +31,9 @@ import java.util.EnumSet;
import java.util.Set;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.session.ServerSession;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
index 4d20ee1..0e0fcc3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
@@ -26,8 +26,8 @@ import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Determines if a forwarding request will be permitted.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
index 383991e..2edd32c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
@@ -23,8 +23,8 @@ import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Handler for cancel-tcpip-forward global request.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
index f51f1d3..dc6adcb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
@@ -23,8 +23,8 @@ import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Handler for tcpip-forward global request.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/jaas/JaasPasswordAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/jaas/JaasPasswordAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/jaas/JaasPasswordAuthenticator.java
index 7200083..0f4ea2a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/jaas/JaasPasswordAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/jaas/JaasPasswordAuthenticator.java
@@ -28,7 +28,7 @@ import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
index ecc8d29..e3f4152 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
@@ -80,13 +80,13 @@ import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.FactoryManagerUtils;
import org.apache.sshd.common.file.FileSystemAware;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.SelectorUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
index 0555186..9e5161a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
@@ -27,9 +27,9 @@ import java.util.EnumSet;
import java.util.Map;
import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.Command;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/AbstractSessionTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/AbstractSessionTest.java b/sshd-core/src/test/java/org/apache/sshd/AbstractSessionTest.java
deleted file mode 100644
index 099c002..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/AbstractSessionTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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;
-
-import java.io.IOException;
-
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.server.SshServer;
-import org.apache.sshd.util.BaseTestSupport;
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test basic stuff on AbstractSession.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class AbstractSessionTest extends BaseTestSupport {
-
- private MySession session;
-
- @Before
- public void setUp() throws Exception {
- session = new MySession();
- }
-
- @Test
- public void testReadIdentSimple() {
- Buffer buf = new ByteArrayBuffer("SSH-2.0-software\r\n".getBytes());
- String ident = session.doReadIdentification(buf);
- assertEquals("SSH-2.0-software", ident);
- }
-
- @Test
- public void testReadIdentWithoutCR() {
- Buffer buf = new ByteArrayBuffer("SSH-2.0-software\n".getBytes());
- String ident = session.doReadIdentification(buf);
- assertEquals("SSH-2.0-software", ident);
- }
-
- @Test
- public void testReadIdentWithHeaders() {
- Buffer buf = new ByteArrayBuffer(("a header line\r\nSSH-2.0-software\r\n").getBytes());
- String ident = session.doReadIdentification(buf);
- assertEquals("SSH-2.0-software", ident);
- }
-
- @Test
- public void testReadIdentWithSplitPackets() {
- Buffer buf = new ByteArrayBuffer("header line\r\nSSH".getBytes());
- String ident = session.doReadIdentification(buf);
- assertNull(ident);
- buf.putRawBytes("-2.0-software\r\n".getBytes());
- ident = session.doReadIdentification(buf);
- assertEquals("SSH-2.0-software", ident);
- }
-
- @Test(expected = IllegalStateException.class)
- public void testReadIdentBadLineEnding() {
- Buffer buf = new ByteArrayBuffer(("SSH-2.0-software\ra").getBytes());
- String ident = session.doReadIdentification(buf);
- fail("Unexpected success: " + ident);
- }
-
- @Test(expected = IllegalStateException.class)
- public void testReadIdentLongLine() {
- Buffer buf = new ByteArrayBuffer(("SSH-2.0-software" +
- "01234567890123456789012345678901234567890123456789" +
- "01234567890123456789012345678901234567890123456789" +
- "01234567890123456789012345678901234567890123456789" +
- "01234567890123456789012345678901234567890123456789" +
- "01234567890123456789012345678901234567890123456789" +
- "01234567890123456789012345678901234567890123456789").getBytes());
- String ident = session.doReadIdentification(buf);
- fail("Unexpected success: " + ident);
- }
-
- @Test(expected = IllegalStateException.class)
- public void testReadIdentLongHeader() {
- StringBuilder sb = new StringBuilder(32768);
- for (int i = 0; i < 500; i++) {
- sb.append("01234567890123456789012345678901234567890123456789\r\n");
- }
- sb.append("SSH-2.0-software\r\n");
- Buffer buf = new ByteArrayBuffer(sb.toString().getBytes());
- String ident = session.doReadIdentification(buf);
- fail("Unexpected success: " + ident);
- }
-
- public static class MySession extends AbstractSession {
- public MySession() {
- super(true, SshServer.setUpDefaultServer(), null);
- }
- @Override
- protected void handleMessage(Buffer buffer) throws Exception {
- // ignored
- }
- @Override
- protected boolean readIdentification(Buffer buffer) {
- return false;
- }
- public String doReadIdentification(Buffer buffer) {
- return super.doReadIdentification(buffer, false);
- }
- @Override
- protected void sendKexInit() throws IOException {
- // ignored
- }
- @Override
- protected void checkKeys() {
- // ignored
- }
- @Override
- protected void receiveKexInit(Buffer buffer) throws IOException {
- // ignored
- }
- @Override
- public void startService(String name) throws Exception {
- // ignored
- }
- @Override
- public void resetIdleTimeout() {
- // ignored
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/AgentTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/AgentTest.java b/sshd-core/src/test/java/org/apache/sshd/AgentTest.java
deleted file mode 100644
index abdd37e..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/AgentTest.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * 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;
-
-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/CipherTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/CipherTest.java b/sshd-core/src/test/java/org/apache/sshd/CipherTest.java
deleted file mode 100644
index c8e3ef2..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/CipherTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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;
-
-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;
- }
- }
-}
[2/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
Posted by lg...@apache.org.
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;
+ }
+ }
+}
[3/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
Posted by lg...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
deleted file mode 100644
index 5f956b6..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
+++ /dev/null
@@ -1,958 +0,0 @@
-/*
- * 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;
-
-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/MacTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/MacTest.java b/sshd-core/src/test/java/org/apache/sshd/MacTest.java
deleted file mode 100644
index 6f3ea60..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/MacTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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;
-
-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;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/RandomTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/RandomTest.java b/sshd-core/src/test/java/org/apache/sshd/RandomTest.java
deleted file mode 100644
index f35a265..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/RandomTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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;
-
-import org.apache.sshd.common.random.BouncyCastleRandom;
-import org.apache.sshd.common.random.JceRandom;
-import org.apache.sshd.common.random.Random;
-import org.apache.sshd.util.BaseTestSupport;
-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 RandomTest extends BaseTestSupport {
-
- @Test
- public void testJce() {
- long t = test(new JceRandom());
- System.out.println("JCE: " + t + " micro");
- }
-
- @Test
- public void testBc() {
- long t = test(new BouncyCastleRandom());
- System.out.println("BC: " + t + " micro");
- }
-
- protected long test(Random random) {
- byte[] bytes = new byte[32];
- long l0 = System.nanoTime();
- for (int i = 0; i < 1000; i++) {
- random.fill(bytes, 8, 16);
- }
- long l1 = System.nanoTime();
- return (l1 - l0) / 1000;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/ServerMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ServerMain.java b/sshd-core/src/test/java/org/apache/sshd/ServerMain.java
deleted file mode 100644
index 2d9195f..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/ServerMain.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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;
-
-import org.apache.sshd.server.SshServer;
-
-
-/**
- * An activator for the {@link SshServer#main(String[])} - the reason it is
- * here is because the logging configuration is available only for test scope
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class ServerMain {
- public static void main(String[] args) throws Throwable {
- SshServer.main(args);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/ServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ServerTest.java b/sshd-core/src/test/java/org/apache/sshd/ServerTest.java
deleted file mode 100644
index 160b033..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/ServerTest.java
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * 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;
-
-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.util.Arrays;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.sshd.client.SessionFactory;
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.channel.ChannelExec;
-import org.apache.sshd.client.channel.ChannelShell;
-import org.apache.sshd.client.future.AuthFuture;
-import org.apache.sshd.client.session.ClientConnectionService;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.channel.Channel;
-import org.apache.sshd.common.channel.WindowClosedException;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.session.AbstractConnectionService;
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.session.SessionListener;
-import org.apache.sshd.deprecated.ClientUserAuthServiceOld;
-import org.apache.sshd.deprecated.UserAuthPassword;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.Environment;
-import org.apache.sshd.server.ExitCallback;
-import org.apache.sshd.server.ServerFactoryManager;
-import org.apache.sshd.server.SshServer;
-import org.apache.sshd.server.command.ScpCommandFactory;
-import org.apache.sshd.server.sftp.SftpSubsystemFactory;
-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.After;
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runners.MethodSorters;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class ServerTest extends BaseTestSupport {
-
- private SshServer sshd;
- private SshClient client;
- private int port;
-
- @Before
- public void setUp() throws Exception {
- sshd = SshServer.setUpDefaultServer();
- sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
- sshd.setShellFactory(new TestEchoShellFactory());
- sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
- sshd.setSessionFactory(new org.apache.sshd.server.session.SessionFactory());
- sshd.start();
- port = sshd.getPort();
- }
-
- @After
- public void tearDown() throws Exception {
- if (sshd != null) {
- sshd.stop(true);
- }
- if (client != null) {
- client.stop();
- }
- }
-
- /**
- * Send bad password. The server should disconnect after a few attempts
- * @throws Exception
- */
- @Test
- public void testFailAuthenticationWithWaitFor() throws Exception {
- final int MAX_AUTH_REQUESTS=10;
- FactoryManagerUtils.updateProperty(sshd, ServerFactoryManager.MAX_AUTH_REQUESTS, MAX_AUTH_REQUESTS);
-
- client = SshClient.setUpDefaultClient();
- client.setServiceFactories(Arrays.asList(
- new ClientUserAuthServiceOld.Factory(),
- new ClientConnectionService.Factory()
- ));
- client.start();
-
- try(ClientSession s = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
- int nbTrials = 0;
- int res = 0;
- while ((res & ClientSession.CLOSED) == 0) {
- nbTrials ++;
- s.getService(ClientUserAuthServiceOld.class)
- .auth(new UserAuthPassword((ClientSessionImpl) s, "ssh-connection", "buggy"));
- res = s.waitFor(ClientSession.CLOSED | ClientSession.WAIT_AUTH, 5000);
- if (res == ClientSession.TIMEOUT) {
- throw new TimeoutException();
- }
- }
- assertTrue("Number trials (" + nbTrials + ") below min.=" + MAX_AUTH_REQUESTS, nbTrials > MAX_AUTH_REQUESTS);
- } finally {
- client.stop();
- }
- }
-
- @Test
- public void testFailAuthenticationWithFuture() throws Exception {
- final int MAX_AUTH_REQUESTS=10;
- FactoryManagerUtils.updateProperty(sshd, ServerFactoryManager.MAX_AUTH_REQUESTS, MAX_AUTH_REQUESTS);
-
- client = SshClient.setUpDefaultClient();
- client.setServiceFactories(Arrays.asList(
- new ClientUserAuthServiceOld.Factory(),
- new ClientConnectionService.Factory()
- ));
- client.start();
- try(ClientSession s = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
- int nbTrials = 0;
- AuthFuture authFuture;
- do {
- nbTrials++;
- assertTrue(nbTrials < 100);
- authFuture = s.getService(ClientUserAuthServiceOld.class)
- .auth(new UserAuthPassword((ClientSessionImpl) s, "ssh-connection", "buggy"));
- assertTrue("Authentication wait failed", authFuture.await(5000));
- assertTrue("Authentication not done", authFuture.isDone());
- assertFalse("Authentication unexpectedly successful", authFuture.isSuccess());
- }
- while (authFuture.isFailure());
- assertNotNull("Missing auth future exception", authFuture.getException());
- assertTrue("Number trials (" + nbTrials + ") below min.=" + MAX_AUTH_REQUESTS, nbTrials > MAX_AUTH_REQUESTS);
- } finally {
- client.stop();
- }
- }
-
- @Test
- public void testAuthenticationTimeout() throws Exception {
- final int AUTH_TIMEOUT=5000;
- FactoryManagerUtils.updateProperty(sshd, FactoryManager.AUTH_TIMEOUT, AUTH_TIMEOUT);
-
- client = SshClient.setUpDefaultClient();
- client.start();
- try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
- int res = s.waitFor(ClientSession.CLOSED, 2 * AUTH_TIMEOUT);
- assertEquals("Session should be closed", ClientSession.CLOSED | ClientSession.WAIT_AUTH, res);
- } finally {
- client.stop();
- }
- }
-
- @Test
- public void testIdleTimeout() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- TestEchoShellFactory.TestEchoShell.latch = new CountDownLatch(1);
- final int IDLE_TIMEOUT=2500;
- FactoryManagerUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, IDLE_TIMEOUT);
-
- sshd.getSessionFactory().addListener(new SessionListener() {
- @Override
- public void sessionCreated(Session session) {
- System.out.println("Session created");
- }
- @Override
- public void sessionEvent(Session session, Event event) {
- System.out.println("Session event: " + event);
- }
- @Override
- public void sessionClosed(Session session) {
- System.out.println("Session closed");
- latch.countDown();
- }
- });
-
- client = SshClient.setUpDefaultClient();
- client.start();
- try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
- s.addPasswordIdentity("test");
- s.auth().verify(5L, TimeUnit.SECONDS);
-
- try(ChannelShell shell = s.createShellChannel();
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ByteArrayOutputStream err = new ByteArrayOutputStream()) {
- shell.setOut(out);
- shell.setErr(err);
- shell.open().await();
- int res = s.waitFor(ClientSession.CLOSED, 2 * IDLE_TIMEOUT);
- assertEquals("Session should be closed", ClientSession.CLOSED | ClientSession.AUTHED, res);
- }
- } finally {
- client.stop();
- }
-
- assertTrue(latch.await(1, TimeUnit.SECONDS));
- assertTrue(TestEchoShellFactory.TestEchoShell.latch.await(1, TimeUnit.SECONDS));
- }
-
- /**
- * The scenario is the following:
- * - create a command that sends continuous data to the client
- * - the client does not read the data, filling the ssh window and the tcp socket
- * - the server session becomes idle, but the ssh disconnect message can't be written
- * - the server session is forcibly closed
- */
- @Test
- public void testServerIdleTimeoutWithForce() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
-
- sshd.setCommandFactory(new StreamCommand.Factory());
-
- FactoryManagerUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, 5000);
- FactoryManagerUtils.updateProperty(sshd, FactoryManager.DISCONNECT_TIMEOUT, 2000);
- sshd.getSessionFactory().addListener(new SessionListener() {
- @Override
- public void sessionCreated(Session session) {
- System.out.println("Session created");
- }
-
- @Override
- public void sessionEvent(Session session, Event event) {
- System.out.println("Session event: " + event);
- }
-
- @Override
- public void sessionClosed(Session session) {
- System.out.println("Session closed");
- latch.countDown();
- }
- });
-
- client = SshClient.setUpDefaultClient();
- client.start();
-
- try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
- s.addPasswordIdentity("test");
- s.auth().verify(5L, TimeUnit.SECONDS);
-
- try(ChannelExec shell = s.createExecChannel("normal");
- // Create a pipe that will block reading when the buffer is full
- PipedInputStream pis = new PipedInputStream();
- PipedOutputStream pos = new PipedOutputStream(pis)) {
-
- shell.setOut(pos);
- shell.open().verify(5L, TimeUnit.SECONDS);
-
- try(AbstractSession serverSession = sshd.getActiveSessions().iterator().next();
- Channel channel = serverSession.getService(AbstractConnectionService.class).getChannels().iterator().next()) {
-
- while (channel.getRemoteWindow().getSize() > 0) {
- Thread.sleep(1);
- }
-
- LoggerFactory.getLogger(getClass()).info("Waiting for session idle timeouts");
-
- long t0 = System.currentTimeMillis();
- latch.await(1, TimeUnit.MINUTES);
- long t1 = System.currentTimeMillis(), diff = t1 - t0;
- assertTrue("Wait time too low: " + diff, diff > 7000);
- assertTrue("Wait time too high: " + diff, diff < 10000);
- }
- }
- } finally {
- client.stop();
- }
- }
-
- @Test
- public void testLanguage() throws Exception {
- client = SshClient.setUpDefaultClient();
- client.setSessionFactory(new SessionFactory() {
- @Override
- protected AbstractSession createSession(IoSession ioSession) throws Exception {
- return new ClientSessionImpl(client, ioSession) {
- @Override
- protected String[] createProposal(String hostKeyTypes) {
- String[] proposal = super.createProposal(hostKeyTypes);
- proposal[SshConstants.PROPOSAL_LANG_CTOS] = "en-US";
- proposal[SshConstants.PROPOSAL_LANG_STOC] = "en-US";
- return proposal;
- }
- };
- }
- });
- client.start();
- try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
- s.close(false);
- } finally {
- client.stop();
- }
- }
-
- @Test
- public void testKexCompletedEvent() throws Exception {
- final AtomicInteger serverEventCount=new AtomicInteger(0);
- sshd.getSessionFactory().addListener(new SessionListener() {
- @Override
- public void sessionCreated(Session session) {
- // ignored
- }
-
- @Override
- public void sessionEvent(Session session, Event event) {
- if (event == Event.KexCompleted) {
- serverEventCount.incrementAndGet();
- }
- }
-
- @Override
- public void sessionClosed(Session session) {
- // ignored
- }
- });
-
- client = SshClient.setUpDefaultClient();
- client.start();
- final AtomicInteger clientEventCount=new AtomicInteger(0);
- client.getSessionFactory().addListener(new SessionListener() {
- @Override
- public void sessionCreated(Session session) {
- // ignored
- }
-
- @Override
- public void sessionEvent(Session session, Event event) {
- if (event == Event.KexCompleted) {
- clientEventCount.incrementAndGet();
- }
- }
-
- @Override
- public void sessionClosed(Session session) {
- // ignored
- }
- });
-
- try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
- s.addPasswordIdentity("test");
- s.auth().verify(5L, TimeUnit.SECONDS);
- assertEquals("Mismatched client events count", 1, clientEventCount.get());
- assertEquals("Mismatched server events count", 1, serverEventCount.get());
- s.close(false);
- } finally {
- client.stop();
- }
- }
-
- @Test // see https://issues.apache.org/jira/browse/SSHD-456
- public void testServerStillListensIfSessionListenerThrowsException() throws InterruptedException {
- final Map<String,SocketAddress> eventsMap = new TreeMap<String, SocketAddress>(String.CASE_INSENSITIVE_ORDER);
- sshd.getSessionFactory().addListener(new SessionListener() {
- private final Logger log=LoggerFactory.getLogger(getClass());
- @Override
- public void sessionCreated(Session session) {
- throwException("SessionCreated", session);
- }
-
- @Override
- public void sessionEvent(Session session, Event event) {
- throwException("SessionEvent", session);
- }
-
- @Override
- public void sessionClosed(Session session) {
- throwException("SessionClosed", session);
- }
-
- private void throwException(String phase, Session session) {
- IoSession ioSession = session.getIoSession();
- SocketAddress addr = ioSession.getRemoteAddress();
- synchronized (eventsMap) {
- if (eventsMap.put(phase, addr) != null) {
- return; // already generated an event for this phase
- }
- }
-
- RuntimeException e = new RuntimeException("Synthetic exception at phase=" + phase + ": " + addr);
- log.info(e.getMessage());
- throw e;
- }
- });
-
- client = SshClient.setUpDefaultClient();
- client.start();
-
- int curCount=0;
- for (int retryCount=0; retryCount < Byte.SIZE; retryCount++){
- synchronized(eventsMap) {
- if ((curCount=eventsMap.size()) >= 3) {
- return;
- }
- }
-
- try {
- try(ClientSession s = client.connect("test", "localhost", port).await().getSession()) {
- s.addPasswordIdentity("test");
- s.auth().verify(5L, TimeUnit.SECONDS);
- }
-
- synchronized(eventsMap) {
- assertTrue("Unexpected premature success: " + eventsMap, eventsMap.size() >= 3);
- }
- } catch(IOException e) {
- // expected - ignored
- synchronized(eventsMap) {
- int nextCount=eventsMap.size();
- assertTrue("No session event generated", nextCount > curCount);
- }
- }
- }
-
- fail("No success to authenticate");
- }
-
- 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 class StreamCommand implements Command, Runnable {
-
- public static class Factory implements CommandFactory {
- @Override
- public Command createCommand(String name) {
- return new StreamCommand(name);
- }
- }
-
- public static CountDownLatch latch;
-
- private final String name;
- private OutputStream out;
-
- public StreamCommand(String name) {
- this.name = name;
- }
-
- @Override
- public void setInputStream(InputStream in) {
- // ignored
- }
-
- @Override
- public void setOutputStream(OutputStream out) {
- this.out = out;
- }
-
- @Override
- public void setErrorStream(OutputStream err) {
- // ignored
- }
-
- @Override
- public void setExitCallback(ExitCallback callback) {
- // ignored
- }
-
- @Override
- public void start(Environment env) throws IOException {
- new Thread(this).start();
- }
-
- @Override
- public void destroy() {
- synchronized (name) {
- if ("block".equals(name)) {
- try {
- name.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- @Override
- public void run() {
- try {
- Thread.sleep(5000);
- while (true) {
- for (int i = 0; i < 100; i++) {
- out.write("0123456789\n".getBytes());
- }
- out.flush();
- }
- } catch (WindowClosedException e) {
- // ok, do nothing
- } catch (Throwable e) {
- e.printStackTrace();
- } finally {
- if (latch != null) {
- latch.countDown();
- }
- }
- }
- }
-
- public static void main(String[] args) throws Exception {
- SshServer sshd = SshServer.setUpDefaultServer();
- FactoryManagerUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, TimeUnit.SECONDS.toMillis(10L));
- sshd.setPort(8001);
- sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
- sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory()));
- sshd.setShellFactory(new EchoShellFactory());
- sshd.setCommandFactory(new ScpCommandFactory());
- sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
- sshd.start();
- Thread.sleep(100000);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java b/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
deleted file mode 100644
index 7f06812..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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;
-
-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/SshServerMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SshServerMain.java b/sshd-core/src/test/java/org/apache/sshd/SshServerMain.java
deleted file mode 100644
index 72d662f..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/SshServerMain.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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;
-
-import org.apache.sshd.server.SshServer;
-
-/**
- * Just a test class used to invoke {@link SshServer#main(String[])} in
- * order to have logging - which is in {@code test} scope
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class SshServerMain {
-
- public static void main(String[] args) throws Exception {
- SshServer.main(args);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/SshServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SshServerTest.java b/sshd-core/src/test/java/org/apache/sshd/SshServerTest.java
deleted file mode 100644
index 674aba1..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/SshServerTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
-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.Utils;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runners.MethodSorters;
-
-/**
- * @author Kohsuke Kawaguchi
- * @author Michael Heemskerk
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class SshServerTest extends BaseTestSupport {
-
- @Test
- public void stopMethodShouldBeIdempotent() throws Exception {
- try(SshServer sshd = new SshServer()) {
- sshd.stop();
- sshd.stop();
- sshd.stop();
- }
- }
-
- @Test
- public void testExecutorShutdownFalse() throws Exception {
- ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
-
- try(SshServer sshd = createTestServer()) {
- sshd.setScheduledExecutorService(executorService);
-
- sshd.start();
- sshd.stop();
-
- assertFalse(executorService.isShutdown());
- executorService.shutdownNow();
- }
- }
-
- @Test
- public void testExecutorShutdownTrue() throws Exception {
- ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
-
- try(SshServer sshd = createTestServer()) {
- sshd.setScheduledExecutorService(executorService, true);
-
- sshd.start();
- sshd.stop();
-
- assertTrue(executorService.isShutdown());
- }
- }
-
- @Test
- public void testDynamicPort() throws Exception {
- try(SshServer sshd = createTestServer()) {
- sshd.setHost("localhost");
- sshd.start();
-
- assertNotEquals(0, sshd.getPort());
-
- sshd.stop();
- }
- }
-
-
- private SshServer createTestServer() {
- SshServer sshd = SshServer.setUpDefaultServer();
- sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
- sshd.setShellFactory(new EchoShellFactory());
- sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
-
- return sshd;
- }
-}
[6/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
Posted by lg...@apache.org.
[SSHD-488] Implement (a naive) ssh-keyscan
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/6432a7af
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/6432a7af
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/6432a7af
Branch: refs/heads/master
Commit: 6432a7af36c3053af17cdd51a6dda4ff14af318d
Parents: ff6a4b0
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue Jun 9 16:53:02 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue Jun 9 16:53:02 2015 +0300
----------------------------------------------------------------------
.../sshd/agent/common/AbstractAgentClient.java | 2 +-
.../sshd/agent/common/AbstractAgentProxy.java | 2 +-
.../sshd/agent/local/AgentServerProxy.java | 2 +-
.../org/apache/sshd/agent/unix/AgentServer.java | 2 +-
.../sshd/agent/unix/AgentServerProxy.java | 2 +-
.../org/apache/sshd/client/ClientBuilder.java | 2 +-
.../java/org/apache/sshd/client/SshKeyScan.java | 508 ++++++++++
.../auth/UserAuthKeyboardInteractive.java | 2 +-
.../sshd/client/auth/UserAuthPassword.java | 2 +-
.../sshd/client/auth/UserAuthPublicKey.java | 2 +-
.../client/channel/AbstractClientChannel.java | 2 +-
.../DelegatingServerKeyVerifier.java | 2 +-
.../keyverifier/RequiredServerKeyVerifier.java | 2 +-
.../keyverifier/StaticServerKeyVerifier.java | 2 +-
.../sshd/client/scp/AbstractScpClient.java | 4 +-
.../sshd/client/session/ClientSession.java | 23 +
.../sshd/client/session/ClientSessionImpl.java | 99 +-
.../client/session/ClientUserAuthService.java | 2 +-
.../sshd/client/sftp/AbstractSftpClient.java | 2 +-
.../client/sftp/SftpFileSystemProvider.java | 2 +-
.../org/apache/sshd/common/NamedFactory.java | 1 +
.../org/apache/sshd/common/NamedResource.java | 1 +
.../org/apache/sshd/common/SshConstants.java | 29 +-
.../org/apache/sshd/common/Transformer.java | 58 --
.../org/apache/sshd/common/channel/Window.java | 2 +-
.../sshd/common/cipher/CipherFactory.java | 2 +-
.../org/apache/sshd/common/cipher/ECCurves.java | 83 +-
.../common/compression/CompressionFactory.java | 2 +-
.../sshd/common/config/SshConfigFileReader.java | 2 +-
.../keys/AbstractPublicKeyEntryDecoder.java | 90 +-
.../config/keys/DSSPublicKeyEntryDecoder.java | 41 +-
.../config/keys/ECDSAPublicKeyEntryDecoder.java | 75 +-
.../sshd/common/config/keys/KeyUtils.java | 194 +++-
.../sshd/common/config/keys/PublicKeyEntry.java | 4 +-
.../config/keys/PublicKeyEntryDecoder.java | 67 +-
.../common/config/keys/RSAPublicKeyDecoder.java | 46 +-
.../file/nativefs/NativeFileSystemFactory.java | 2 +-
.../file/root/RootedFileSystemProvider.java | 2 +-
.../sshd/common/future/DefaultSshFuture.java | 2 +-
.../io/AbstractIoServiceFactoryFactory.java | 2 +-
.../common/kex/dh/AbstractDHKeyExchange.java | 2 +-
.../keyprovider/AbstractKeyPairProvider.java | 2 +-
.../keyprovider/MappedKeyPairProvider.java | 2 +-
.../org/apache/sshd/common/mac/MacFactory.java | 2 +-
.../scp/LocalFileScpSourceStreamResolver.java | 4 +-
.../scp/LocalFileScpTargetStreamResolver.java | 4 +-
.../org/apache/sshd/common/scp/ScpHelper.java | 4 +-
.../sshd/common/session/AbstractSession.java | 6 +-
.../common/session/SessionTimeoutListener.java | 2 +-
.../sshd/common/signature/SignatureFactory.java | 2 +-
.../sshd/common/util/AbstractLoggingBean.java | 49 -
.../apache/sshd/common/util/CloseableUtils.java | 11 +-
.../sshd/common/util/EventListenerUtils.java | 6 +-
.../apache/sshd/common/util/GenericUtils.java | 29 +-
.../org/apache/sshd/common/util/IoUtils.java | 291 ------
.../org/apache/sshd/common/util/OsUtils.java | 2 +-
.../apache/sshd/common/util/SecurityUtils.java | 5 +-
.../apache/sshd/common/util/Transformer.java | 58 ++
.../apache/sshd/common/util/ValidateUtils.java | 6 +-
.../apache/sshd/common/util/buffer/Buffer.java | 61 +-
.../util/io/CloseableEmptyInputStream.java | 94 ++
.../sshd/common/util/io/EmptyInputStream.java | 65 ++
.../org/apache/sshd/common/util/io/IoUtils.java | 293 ++++++
.../common/util/io/ModifiableFileWatcher.java | 3 +-
.../util/logging/AbstractLoggingBean.java | 49 +
.../util/logging/AbstractSimplifiedLog.java | 36 +
.../sshd/common/util/logging/LoggingUtils.java | 144 +++
.../sshd/common/util/logging/SimplifiedLog.java | 53 +
.../sshd/server/PasswordAuthenticator.java | 2 +-
.../sshd/server/PublickeyAuthenticator.java | 2 +-
.../org/apache/sshd/server/ServerBuilder.java | 2 +-
.../sshd/server/auth/AbstractUserAuth.java | 2 +-
.../sshd/server/channel/ChannelSession.java | 2 +-
.../sshd/server/channel/PipeDataReceiver.java | 2 +-
.../server/channel/PuttyRequestHandler.java | 2 +-
.../apache/sshd/server/command/ScpCommand.java | 2 +-
.../server/config/keys/AuthorizedKeyEntry.java | 2 +-
.../keys/AuthorizedKeysAuthenticator.java | 2 +-
.../DefaultAuthorizedKeysAuthenticator.java | 2 +-
.../sshd/server/forward/ForwardingFilter.java | 2 +-
.../global/CancelTcpipForwardHandler.java | 2 +-
.../sshd/server/global/TcpipForwardHandler.java | 2 +-
.../server/jaas/JaasPasswordAuthenticator.java | 2 +-
.../apache/sshd/server/sftp/SftpSubsystem.java | 4 +-
.../sshd/server/shell/ProcessShellFactory.java | 2 +-
.../org/apache/sshd/AbstractSessionTest.java | 147 ---
.../test/java/org/apache/sshd/AgentTest.java | 212 ----
.../test/java/org/apache/sshd/CipherTest.java | 181 ----
.../test/java/org/apache/sshd/ClientTest.java | 958 -------------------
.../src/test/java/org/apache/sshd/MacTest.java | 188 ----
.../test/java/org/apache/sshd/RandomTest.java | 58 --
.../test/java/org/apache/sshd/ServerMain.java | 34 -
.../test/java/org/apache/sshd/ServerTest.java | 561 -----------
.../java/org/apache/sshd/SshBuilderTest.java | 136 ---
.../java/org/apache/sshd/SshServerMain.java | 35 -
.../java/org/apache/sshd/SshServerTest.java | 99 --
.../java/org/apache/sshd/agent/AgentTest.java | 212 ++++
.../java/org/apache/sshd/client/ClientTest.java | 958 +++++++++++++++++++
.../client/session/ClientSessionImplTest.java | 103 ++
.../sshd/client/sftp/SftpFileSystemTest.java | 2 +-
.../org/apache/sshd/client/sftp/SftpTest.java | 2 +-
.../org/apache/sshd/common/SshBuilderTest.java | 136 +++
.../apache/sshd/common/cipher/CipherTest.java | 181 ++++
.../common/config/SshConfigFileReaderTest.java | 2 +-
.../sshd/common/config/keys/KeyUtilsTest.java | 138 +++
.../org/apache/sshd/common/mac/MacTest.java | 188 ++++
.../apache/sshd/common/random/RandomTest.java | 58 ++
.../common/session/AbstractSessionTest.java | 147 +++
.../sshd/common/util/GenericUtilsTest.java | 27 +
.../common/util/io/EmptyInputStreamTest.java | 117 +++
.../sshd/deprecated/AbstractUserAuth.java | 2 +-
.../java/org/apache/sshd/server/ServerMain.java | 34 +
.../java/org/apache/sshd/server/ServerTest.java | 561 +++++++++++
.../org/apache/sshd/server/SshServerMain.java | 35 +
.../org/apache/sshd/server/SshServerTest.java | 99 ++
.../config/keys/AuthorizedKeyEntryTest.java | 2 +-
.../DefaultAuthorizedKeysAuthenticatorTest.java | 2 +-
.../apache/sshd/util/BogusInvertedShell.java | 2 +-
.../sshd/util/BogusPasswordAuthenticator.java | 2 +-
119 files changed, 5113 insertions(+), 3198 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
index 20510ec..c99977b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
@@ -34,10 +34,10 @@ import java.util.List;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
public abstract class AbstractAgentClient extends AbstractLoggingBean {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
index 61df6ae..9ec0adf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
@@ -37,11 +37,11 @@ import java.util.concurrent.ExecutorService;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer;
public abstract class AbstractAgentProxy extends AbstractLoggingBean implements SshAgent, ExecutorServiceConfigurer {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
index 7df3f2b..7a6d5a6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
@@ -26,9 +26,9 @@ import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentServer;
import org.apache.sshd.client.future.OpenFuture;
import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* The server side fake agent, acting as an agent, but actually forwarding the requests to the auth channel on the client side.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
index f176790..ca9ecdc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
@@ -27,10 +27,10 @@ import java.util.concurrent.Future;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.common.AbstractAgentClient;
import org.apache.sshd.agent.local.AgentImpl;
-import org.apache.sshd.common.util.AbstractLoggingBean;
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.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.tomcat.jni.Local;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
index 0907b63..1b02795 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
@@ -29,9 +29,9 @@ import org.apache.sshd.agent.SshAgentServer;
import org.apache.sshd.client.future.OpenFuture;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.tomcat.jni.Local;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
index ccea2d6..1ab0d28 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
@@ -27,11 +27,11 @@ import org.apache.sshd.client.kex.DHGEXClient;
import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier;
import org.apache.sshd.common.BaseBuilder;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.DHFactory;
import org.apache.sshd.common.kex.KeyExchange;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.server.forward.TcpipServerChannel;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java b/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
new file mode 100644
index 0000000..e6b7cfa
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
@@ -0,0 +1,508 @@
+/*
+ * 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.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Writer;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.PublicKeyEntry;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.apache.sshd.common.util.logging.AbstractSimplifiedLog;
+import org.apache.sshd.common.util.logging.LoggingUtils;
+
+/**
+ * A naive implementation of <A HREF="https://www.freebsd.org/cgi/man.cgi?query=ssh-keyscan&sektion=1">ssh-keyscan(1)</A>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SshKeyScan extends AbstractSimplifiedLog
+ implements Closeable, Callable<Void>, ServerKeyVerifier, SessionListener {
+ /**
+ * Default key types if not overridden from the command line
+ */
+ public static final List<String> DEFAULT_KEY_TYPES =
+ Collections.unmodifiableList(Arrays.asList("rsa", "ecdsa"));
+ public static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
+ public static final Level DEFAULT_LEVEL = Level.INFO;
+
+ private int port;
+ private long timeout;
+ private List<String> keyTypes;
+ private InputStream input;
+ private Level level;
+ private final Map<String,String> currentHostFingerprints = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+
+ public SshKeyScan() {
+ super();
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public InputStream getInputStream() {
+ return input;
+ }
+
+ public void setInputStream(InputStream input) {
+ this.input = input;
+ }
+
+ public List<String> getKeyTypes() {
+ return keyTypes;
+ }
+
+ public void setKeyTypes(List<String> keyTypes) {
+ this.keyTypes = keyTypes;
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ public Level getLogLevel() {
+ return level;
+ }
+
+ public void setLogLevel(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public void log(Level level, Object message, Throwable t) {
+ if (isEnabled(level)) {
+ PrintStream ps = System.out;
+ if ((t != null) || Level.SEVERE.equals(level) || Level.WARNING.equals(level)) {
+ ps = System.err;
+ }
+
+ ps.append('\t').println(message);
+ if (t != null) {
+ ps.append("\t\t").append(t.getClass().getSimpleName()).append(": ").println(t.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public boolean isEnabled(Level level) {
+ return LoggingUtils.isLoggable(level, getLogLevel());
+ }
+
+ @Override
+ public Void call() throws Exception {
+ Exception err = null;
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ Collection<String> typeNames = getKeyTypes();
+ Map<String,KeyPair> pairsMap = createKeyPairs(typeNames);
+ client.setServerKeyVerifier(this);
+
+ try(BufferedReader rdr = new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8))) {
+ client.start();
+
+ for (String line = rdr.readLine(); line != null; line = rdr.readLine()) {
+ line = GenericUtils.trimToEmpty(line);
+ if (GenericUtils.isEmpty(line)) {
+ continue;
+ }
+
+ try {
+ resolveServerKeys(client, line, pairsMap);
+ } catch(Exception e) {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Failed to retrieve keys from " + line, e);
+ }
+ err = GenericUtils.accumulateException(err, e);
+ } finally {
+ currentHostFingerprints.clear();
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+
+ return null;
+ }
+
+ protected void resolveServerKeys(SshClient client, String host, Map<String,KeyPair> pairsMap) {
+ for (Map.Entry<String,KeyPair> pe : pairsMap.entrySet()) {
+ String kt = pe.getKey();
+ try {
+ resolveServerKeys(client, host, kt, pe.getValue());
+ } catch(Exception e) {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Failed to resolve key=" + kt + " for " + host);
+ }
+
+ if (e instanceof ConnectException) {
+ return; // makes no sense to try again with another key type...
+ }
+ }
+ }
+ }
+
+ protected void resolveServerKeys(SshClient client, String host, String kt, KeyPair kp) throws Exception {
+ int connectPort = getPort();
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Connecting to " + host + ":" + connectPort);
+ }
+
+ ConnectFuture future = client.connect(UUID.randomUUID().toString(), host, connectPort);
+ long waitTime = getTimeout();
+ if (!future.await(waitTime)) {
+ throw new ConnectException("Failed to connect to " + host + ":" + connectPort + " within " + waitTime + " msec.");
+ }
+
+ try(ClientSession session = future.getSession()) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress remoteAddress = ioSession.getRemoteAddress();
+ String remoteLocation = toString(remoteAddress);
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Connected to " + remoteLocation);
+ }
+
+ try {
+ session.addListener(this);
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "Authenticating with " + kt + " to " + remoteLocation);
+ }
+
+ // shouldn't really succeed, but do it since key exchange occurs only on auth attempt
+ session.addPublicKeyIdentity(kp);
+ try {
+ session.auth().verify(waitTime);
+ log(Level.WARNING, "Unexpected authentication success using key type=" + kt + " with " + remoteLocation);
+ } catch(Exception e) {
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "Failed to authenticate using key type=" + kt + " with " + remoteLocation);
+ }
+ }
+ } finally {
+ session.removeListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void sessionCreated(Session session) {
+ logSessionEvent(session, "Created");
+ }
+
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ logSessionEvent(session, event);
+ if (isEnabled(Level.FINEST) && Event.KexCompleted.equals(event)) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress remoteAddress = ioSession.getRemoteAddress();
+ String remoteLocation = toString(remoteAddress);
+ for (int paramType = 0; paramType < SshConstants.PROPOSAL_KEX_NAMES.size(); paramType++) {
+ String paramName = SshConstants.PROPOSAL_KEX_NAMES.get(paramType);
+ String paramValue = session.getNegotiatedKexParameter(paramType);
+ log(Level.FINEST, remoteLocation + "[" + paramName + "]: " + paramValue);
+ }
+ }
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ logSessionEvent(session, "Closed");
+ }
+
+ protected void logSessionEvent(Session session, Object event) {
+ if (isEnabled(Level.FINEST)) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress remoteAddress = ioSession.getRemoteAddress();
+ log(Level.FINEST, "Session " + toString(remoteAddress) + " event: " + event);
+ }
+ }
+
+ @Override
+ public boolean verifyServerKey(ClientSession sshClientSession, SocketAddress remoteAddress, PublicKey serverKey) {
+ String remoteLocation = toString(remoteAddress);
+ try {
+ String extra = KeyUtils.getFingerPrint(serverKey);
+ String keyType = KeyUtils.getKeyType(serverKey);
+ String current = GenericUtils.isEmpty(keyType) ? null : currentHostFingerprints.get(keyType);
+ if (Objects.equals(current, extra)) {
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "verifyServerKey(" + remoteLocation + ")[" + keyType + "] skip existing key: " + extra);
+ }
+ } else {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "verifyServerKey(" + remoteLocation + ")[" + keyType + "] found new key: " + extra);
+ }
+
+ StringBuilder sb = new StringBuilder(256).append(remoteLocation).append(' ');
+ PublicKeyEntry.appendPublicKeyEntry(sb, serverKey);
+ log(Level.INFO, sb);
+
+ if (!GenericUtils.isEmpty(keyType)) {
+ currentHostFingerprints.put(keyType, extra);
+ }
+ }
+ } catch(Exception e) {
+ log(Level.SEVERE, "Failed to output the public key from " + remoteLocation, e);
+ }
+
+ return true;
+ }
+
+ private static final String toString(SocketAddress addr) {
+ if (addr == null) {
+ return null;
+ } else if (addr instanceof InetSocketAddress) {
+ return ((InetSocketAddress) addr).getHostString();
+ } else if (addr instanceof SshdSocketAddress) {
+ return ((SshdSocketAddress) addr).getHostName();
+ } else {
+ return addr.toString();
+ }
+ }
+
+ protected Map<String,KeyPair> createKeyPairs(Collection<String> typeNames) throws GeneralSecurityException {
+ if (GenericUtils.isEmpty(typeNames)) {
+ return Collections.emptyMap();
+ }
+
+ Map<String,KeyPair> pairsMap = new TreeMap<String, KeyPair>(String.CASE_INSENSITIVE_ORDER);
+ for (String kt : typeNames) {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Generate key pair for " + kt);
+ }
+
+ if ("rsa".equalsIgnoreCase(kt)) {
+ pairsMap.put(KeyPairProvider.SSH_RSA, KeyUtils.generateKeyPair(KeyPairProvider.SSH_RSA, 1024));
+ } else if ("dsa".equalsIgnoreCase(kt)) {
+ pairsMap.put(KeyPairProvider.SSH_DSS, KeyUtils.generateKeyPair(KeyPairProvider.SSH_DSS, 512));
+ } else if ("ecdsa".equalsIgnoreCase(kt)) {
+ if (!SecurityUtils.hasEcc()) {
+ throw new InvalidKeySpecException("ECC not supported");
+ }
+
+ for (String curveName : ECCurves.NAMES) {
+ Integer keySize = ECCurves.getCurveSize(curveName);
+ if (keySize == null) {
+ throw new InvalidKeySpecException("Unknown curve: " + curveName);
+ }
+
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "Generate key pair for curve=" + curveName);
+ }
+
+ String keyName = ECCurves.ECDSA_SHA2_PREFIX + curveName;
+ pairsMap.put(keyName, KeyUtils.generateKeyPair(keyName, keySize.intValue()));
+ }
+ }
+ }
+
+ return pairsMap;
+ }
+
+ @Override
+ public void close() throws IOException {
+ IOException err = null;
+ if (input != null) {
+ try {
+ input.close();
+ } catch(IOException e) {
+ err = GenericUtils.accumulateException(err, e);
+ } finally {
+ input = null;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+
+ // returns a List of the hosts to be contacted
+ public static final List<String> parseCommandLineArguments(SshKeyScan scanner, String ... args) throws IOException {
+ int numArgs = GenericUtils.length(args);
+ for (int index=0; index < numArgs; index++) {
+ String optName = args[index];
+ if ("-f".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(scanner.getInputStream() == null, "%s option re-specified", optName);
+
+ String filePath = args[index];
+ if ("-".equals(filePath)) {
+ scanner.setInputStream(new NoCloseInputStream(System.in));
+ } else {
+ scanner.setInputStream(new FileInputStream(filePath));
+ }
+ } else if ("-t".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(GenericUtils.isEmpty(scanner.getKeyTypes()), "%s option re-specified", optName);
+
+ String typeList = args[index];
+ String[] types = GenericUtils.split(typeList, ',');
+ ValidateUtils.checkTrue(GenericUtils.length(types) > 0, "No types specified for %s", optName);
+ } else if ("-p".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(scanner.getPort() <= 0, "%s option re-specified", optName);
+
+ String portValue = args[index];
+ int port = Integer.parseInt(portValue);
+ ValidateUtils.checkTrue((port > 0) && (port <= 0xFFFF), "Bad port: %s", portValue);
+ scanner.setPort(port);
+ } else if ("-T".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(scanner.getTimeout() <= 0, "%s option re-specified", optName);
+
+ String timeoutValue = args[index];
+ long timeout = Long.parseLong(timeoutValue);
+ ValidateUtils.checkTrue(timeout > 0L, "Bad timeout: %s", timeoutValue);
+ scanner.setTimeout(timeout);
+ } else if ("-v".equals(optName)) {
+ ValidateUtils.checkTrue(scanner.getLogLevel() == null, "%s option re-specified", optName);
+ scanner.setLogLevel(Level.FINEST);
+ } else { // stop at first non-option - assume the rest are host names/addresses
+ ValidateUtils.checkTrue((optName.charAt(0) != '-'), "Unknown option: %s", optName);
+
+ int remaining = numArgs - index;
+ if (remaining == 1) {
+ return Collections.singletonList(optName);
+ }
+
+ List<String> hosts = new ArrayList<String>(remaining);
+ for ( ; index < numArgs; index++) {
+ hosts.add(args[index]);
+ }
+
+ return hosts;
+ }
+ }
+
+ return Collections.emptyList();
+ }
+
+ /* -------------------------------------------------------------------- */
+
+ public static final <S extends SshKeyScan> S setInputStream(S scanner, Collection<String> hosts) throws IOException {
+ if (GenericUtils.isEmpty(hosts)) {
+ ValidateUtils.checkNotNull(scanner.getInputStream(), "No hosts or file specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+ } else {
+ ValidateUtils.checkTrue(scanner.getInputStream() == null, "Both hosts and file specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+ // convert the hosts from the arguments into a "file" - one host per line
+ try(ByteArrayOutputStream baos = new ByteArrayOutputStream(hosts.size() * 32)) {
+ try(Writer w = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {
+ String EOL = System.getProperty("line.separator");
+ for (String h : hosts) {
+ w.append(h).append(EOL);
+ }
+ }
+
+ byte[] data = baos.toByteArray();
+ scanner.setInputStream(new ByteArrayInputStream(data));
+ }
+ }
+
+ return scanner;
+ }
+
+ public static final <S extends SshKeyScan> S initializeScanner(S scanner, Collection<String> hosts) throws IOException {
+ setInputStream(scanner, hosts);
+ if (scanner.getPort() <= 0) {
+ scanner.setPort(SshConfigFileReader.DEFAULT_PORT);
+ }
+
+ if (scanner.getTimeout() <= 0L) {
+ scanner.setTimeout(DEFAULT_TIMEOUT);
+ }
+
+ if (GenericUtils.isEmpty(scanner.getKeyTypes())) {
+ scanner.setKeyTypes(DEFAULT_KEY_TYPES);
+ }
+
+ if (scanner.getLogLevel() == null) {
+ scanner.setLogLevel(DEFAULT_LEVEL);
+ }
+
+ return scanner;
+ }
+
+ /* -------------------------------------------------------------------- */
+
+ public static void main(String[] args) throws Exception {
+ try(SshKeyScan scanner = new SshKeyScan()) {
+ Collection<String> hosts = parseCommandLineArguments(scanner, args);
+ initializeScanner(scanner, hosts);
+ scanner.call();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
index af17b13..6adc678 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
@@ -33,9 +33,9 @@ import org.apache.sshd.client.UserInteraction;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
index ea3cb8a..b9e885b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
@@ -27,8 +27,8 @@ import org.apache.sshd.client.UserAuth;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
index 6bc90bf..2d2c95a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
@@ -38,9 +38,9 @@ import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
index ddb16e3..b444c16 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
@@ -35,9 +35,9 @@ import org.apache.sshd.common.channel.ChannelAsyncOutputStream;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.io.IoInputStream;
import org.apache.sshd.common.io.IoOutputStream;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
index 6c58647..73ba903 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
@@ -24,7 +24,7 @@ import java.util.Map;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/*
* A ServerKeyVerifier that delegates verification to the ServerKeyVerifier found in the ClientSession metadata
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
index 8342eb9..6cd5dbc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
@@ -23,8 +23,8 @@ import java.security.PublicKey;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* A ServerKeyVerifier that accepts one server key (specified in the constructor)
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
index f80e82b..18bb93a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
@@ -25,7 +25,7 @@ import java.security.PublicKey;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Returns the same constant answer {@code true/false} regardless
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
index d59000d..fcefa3e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
@@ -36,10 +36,10 @@ import java.util.EnumSet;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.scp.ScpHelper;
import org.apache.sshd.common.scp.ScpTimestamp;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
index d4bd108..6a885d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
@@ -68,9 +68,32 @@ public interface ClientSession extends Session {
int WAIT_AUTH = 0x0004;
int AUTHED = 0x0008;
+ /**
+ * @param password Password to be added - may not be {@code null}/empty
+ */
void addPasswordIdentity(String password);
+
+ /**
+ * @param password The password to remove - ignored if {@code null}/empty
+ * @return The removed password - same one that was added via
+ * {@link #addPasswordIdentity(String)} - or {@code null} if no
+ * match found
+ */
+ String removePasswordIdentity(String password);
+
+ /**
+ * @param key The {@link KeyPair} to add - may not be {@code null}
+ */
void addPublicKeyIdentity(KeyPair key);
+ /**
+ * @param kp The {@link KeyPair} to remove - ignored if {@code null}
+ * @return The removed {@link KeyPair} - same one that was added via
+ * {@link #addPublicKeyIdentity(KeyPair)} - or {@code null} if no
+ * match found
+ */
+ KeyPair removePublicKeyIdentity(KeyPair kp);
+
UserInteraction getUserInteraction();
void setUserInteraction(UserInteraction userInteraction);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index d29b350..eaf1901 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -23,6 +23,7 @@ import java.net.SocketAddress;
import java.nio.file.FileSystem;
import java.security.KeyPair;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -50,6 +51,7 @@ import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.cipher.CipherNone;
+import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.future.DefaultSshFuture;
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.io.IoSession;
@@ -58,6 +60,8 @@ import org.apache.sshd.common.session.AbstractConnectionService;
import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
/**
@@ -66,6 +70,37 @@ import org.apache.sshd.common.util.buffer.Buffer;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class ClientSessionImpl extends AbstractSession implements ClientSession {
+ /**
+ * Compares 2 password identities - returns zero ONLY if <U>both</U> compared
+ * objects are {@link String}s and equal to each other
+ */
+ public static final Comparator<Object> PASSWORD_IDENTITY_COMPARATOR = new Comparator<Object>() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ if ((!(o1 instanceof String)) || (!(o2 instanceof String))) {
+ return (-1);
+ } else {
+ return ((String) o1).compareTo((String) o2);
+ }
+ }
+ };
+
+ /**
+ * Compares 2 {@link KeyPair} identities - returns zero ONLY if <U>both</U> compared
+ * objects are {@link KeyPair}s and equal to each other
+ */
+ public static final Comparator<Object> KEYPAIR_IDENTITY_COMPARATOR = new Comparator<Object>() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ if ((!(o1 instanceof KeyPair)) || (!(o2 instanceof KeyPair))) {
+ return (-1);
+ } else if (KeyUtils.compareKeyPairs((KeyPair) o1, (KeyPair) o2)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ };
/**
* For clients to store their own metadata
@@ -85,12 +120,12 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
public ClientSessionImpl(ClientFactoryManager client, IoSession session) throws Exception {
super(false, client, session);
- log.info("Client session created: {}", session);
+ log.debug("Client session created: {}", session);
// Need to set the initial service early as calling code likes to start trying to
// manipulate it before the connection has even been established. For instance, to
// set the authPassword.
List<ServiceFactory> factories = client.getServiceFactories();
- if (factories == null || factories.isEmpty() || factories.size() > 2) {
+ if (GenericUtils.isEmpty(factories) || factories.size() > 2) {
throw new IllegalArgumentException("One or two services must be configured");
}
currentServiceFactory = factories.get(0);
@@ -128,12 +163,62 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
@Override
public void addPasswordIdentity(String password) {
- identities.add(password);
+ identities.add(ValidateUtils.checkNotNullAndNotEmpty(password, "No password provided", GenericUtils.EMPTY_OBJECT_ARRAY));
+ if (log.isDebugEnabled()) { // don't show the password in the log
+ log.debug("addPasswordIdentity(" + KeyUtils.getFingerPrint(password) + ")");
+ }
+ }
+
+ @Override
+ public String removePasswordIdentity(String password) {
+ if (GenericUtils.isEmpty(password)) {
+ return null;
+ }
+
+ int index = findIdentityIndex(PASSWORD_IDENTITY_COMPARATOR, password);
+ if (index >= 0) {
+ return (String) identities.remove(index);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addPublicKeyIdentity(KeyPair kp) {
+ ValidateUtils.checkNotNull(kp, "No key-pair to add", GenericUtils.EMPTY_OBJECT_ARRAY);
+ ValidateUtils.checkNotNull(kp.getPublic(), "No public key", GenericUtils.EMPTY_OBJECT_ARRAY);
+ ValidateUtils.checkNotNull(kp.getPrivate(), "No private key", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+ identities.add(kp);
+
+ if (log.isDebugEnabled()) {
+ log.debug("addPublicKeyIdentity(" + KeyUtils.getFingerPrint(kp.getPublic()) + ")");
+ }
}
@Override
- public void addPublicKeyIdentity(KeyPair key) {
- identities.add(key);
+ public KeyPair removePublicKeyIdentity(KeyPair kp) {
+ if (kp == null) {
+ return null;
+ }
+
+ int index = findIdentityIndex(KEYPAIR_IDENTITY_COMPARATOR, kp);
+ if (index >= 0) {
+ return (KeyPair) identities.remove(index);
+ } else {
+ return null;
+ }
+ }
+
+ protected int findIdentityIndex(Comparator<? super Object> comp, Object target) {
+ for (int index = 0; index < identities.size(); index++) {
+ Object value = identities.get(index);
+ if (comp.compare(value, target) == 0) {
+ return index;
+ }
+ }
+
+ return (-1);
}
@Override
@@ -382,7 +467,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
if (serverVersion == null) {
return false;
}
- log.info("Server version string: {}", serverVersion);
+ log.debug("Server version string: {}", serverVersion);
if (!(serverVersion.startsWith("SSH-2.0-") || serverVersion.startsWith("SSH-1.99-"))) {
throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
"Unsupported protocol version: " + serverVersion);
@@ -390,7 +475,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
return true;
}
- private void sendClientIdentification() {
+ protected void sendClientIdentification() {
clientVersion = "SSH-2.0-" + getFactoryManager().getVersion();
sendIdentification(clientVersion);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
index 1bb5b58..72d8601 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
@@ -169,7 +169,7 @@ public class ClientUserAuthService extends CloseableUtils.AbstractCloseable impl
return;
}
if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
- log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ log.debug("Received SSH_MSG_USERAUTH_FAILURE");
String mths = buffer.getString();
boolean partial = buffer.getBoolean();
if (partial || serverMethods == null) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
index b532b9d..2bcb9ef 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
@@ -26,8 +26,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
index d4c171a..4f7b693 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
@@ -82,8 +82,8 @@ import org.apache.sshd.common.SshException;
import org.apache.sshd.common.config.SshConfigFileReader;
import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
index 3337e46..76c1e0c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.List;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
/**
* A named factory is a factory identified by a name.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
index d57f433..b38670f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
@@ -26,6 +26,7 @@ import java.util.Comparator;
import java.util.List;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
index eebd1b1..d6a41be 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
@@ -18,6 +18,10 @@
*/
package org.apache.sshd.common;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* This interface defines constants for the SSH protocol.
*
@@ -100,18 +104,19 @@ public interface SshConstants {
* list index matches the {@code PROPOSAL_XXX} constant
* @see <A HREF="http://tools.ietf.org/html/rfc4253#section-7.1">RFC-4253 - section 7.1</A>
*/
- static final String[] PROPOSAL_KEX_NAMES = {
- "kex algorithms",
- "server host key algorithms",
- "encryption algorithms (client to server)",
- "encryption algorithms (server to client)",
- "mac algorithms (client to server)",
- "mac algorithms (server to client)",
- "compression algorithms (client to server)",
- "compression algorithms (server to client)",
- "languages (client to server)",
- "languages (server to client)"
- };
+ static final List<String> PROPOSAL_KEX_NAMES =
+ Collections.unmodifiableList(Arrays.asList(
+ "kex algorithms",
+ "server host key algorithms",
+ "encryption algorithms (client to server)",
+ "encryption algorithms (server to client)",
+ "mac algorithms (client to server)",
+ "mac algorithms (server to client)",
+ "compression algorithms (client to server)",
+ "compression algorithms (server to client)",
+ "languages (client to server)",
+ "languages (server to client)"
+ ));
//
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java b/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java
deleted file mode 100644
index 952b2c0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.Objects;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface Transformer<I, O> {
- // TODO in JDK-8 replace this with Function
- /**
- * @param input Input value
- * @return Transformed output value
- */
- O transform(I input);
-
- /**
- * Invokes {@link Objects#toString(Object)} on the argument
- */
- Transformer<Object,String> TOSTRING=new Transformer<Object,String>() {
- @Override
- public String transform(Object input) {
- return Objects.toString(input);
- }
- };
-
- /**
- * Returns {@link Enum#name()} or {@code null} if argument is {@code null}
- */
- Transformer<Enum<?>,String> ENUM_NAME_EXTRACTOR=new Transformer<Enum<?>,String>() {
- @Override
- public String transform(Enum<?> input) {
- if (input == null) {
- return null;
- } else {
- return input.name();
- }
- }
- };
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
index bf2a91a..d72395e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
@@ -25,9 +25,9 @@ import java.util.Map;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.FactoryManagerUtils;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* A Window for a given channel.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
index 6f4963f..94834b4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.cipher;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
index 0c0c66f..d3f0b34 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
@@ -24,7 +24,9 @@ import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -58,16 +60,89 @@ public class ECCurves {
}
/**
+ * Key=curve name, value=num. of bits
+ */
+ private static final Map<String,Integer> CURVENAME2SIZE =
+ Collections.unmodifiableMap(new TreeMap<String,Integer>(String.CASE_INSENSITIVE_ORDER) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ put(NISTP256, Integer.valueOf(256));
+ put(NISTP384, Integer.valueOf(384));
+ put(NISTP521, Integer.valueOf(521));
+ }
+
+ });
+
+ /**
+ * An un-modifiable {@link List} of all the known curve names
+ */
+ @SuppressWarnings("synthetic-access")
+ public static final List<String> NAMES =
+ Collections.unmodifiableList(new ArrayList<String>(CURVENAME2SIZE.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ addAll(CURVENAME2SIZE.keySet());
+ Collections.sort(this); // as a courtesy
+ }
+ });
+
+ /**
+ * An un-modifiable {@link List} of all the known curve types according to {@code OpenSSH}
+ */
+ public static final List<String> TYPES =
+ Collections.unmodifiableList(new ArrayList<String>(CURVENAME2SIZE.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ for (String n : NAMES) {
+ add(ECDSA_SHA2_PREFIX + n);
+ }
+
+ Collections.sort(this); // as a courtesy
+ }
+ });
+ /**
+ * An un-modifiable {@link List} of all the known curve sizes
+ */
+ @SuppressWarnings("synthetic-access")
+ public static final List<Integer> SIZES =
+ Collections.unmodifiableList(new ArrayList<Integer>(CURVENAME2SIZE.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ addAll(CURVENAME2SIZE.values());
+ Collections.sort(this); // as a courtesy
+ }
+ });
+
+ /**
+ * @param name The curve name - ignored if {@code null}/empty
+ * @return The curve size - {@code null} if unknown curve
+ */
+ public static Integer getCurveSize(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ } else {
+ return CURVENAME2SIZE.get(name);
+ }
+ }
+
+ /**
* Key=num. of bits, value=curve name
*/
+ @SuppressWarnings("synthetic-access")
private static final Map<Integer, String> SIZE2CURVENAME =
Collections.unmodifiableMap(new TreeMap<Integer, String>() {
private static final long serialVersionUID = 1L; // we're not serializing it
{
- put(Integer.valueOf(256), NISTP256);
- put(Integer.valueOf(384), NISTP384);
- put(Integer.valueOf(521), NISTP521);
+ for (Map.Entry<String,Integer> e : CURVENAME2SIZE.entrySet()) {
+ String name = e.getKey();
+ Integer size = e.getValue();
+ put(size, name);
+ }
}
});
@@ -234,7 +309,7 @@ public class ECCurves {
private static final class LazySpecsMapHolder {
private static final Map<String,ECParameterSpec> specsMap =
- Collections.unmodifiableMap(new TreeMap<String, ECParameterSpec>(String.CASE_INSENSITIVE_ORDER) {
+ Collections.unmodifiableMap(new TreeMap<String,ECParameterSpec>(String.CASE_INSENSITIVE_ORDER) {
private static final long serialVersionUID = 1L; // we're not serializing it
{
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
index 3af29d7..9895922 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.compression;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
index e15d16f..92587a3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
@@ -39,7 +39,6 @@ import org.apache.sshd.client.ClientBuilder;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.common.AbstractFactoryManager;
import org.apache.sshd.common.NamedFactory;
-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.cipher.CipherFactory;
@@ -57,6 +56,7 @@ import org.apache.sshd.common.signature.BuiltinSignatures;
import org.apache.sshd.common.signature.Signature;
import org.apache.sshd.common.signature.SignatureFactory;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.NoCloseInputStream;
import org.apache.sshd.common.util.io.NoCloseReader;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
index 763a8ce..8c701a7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
@@ -28,31 +28,80 @@ import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Collection;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> implements PublicKeyEntryDecoder<K> {
- private final Class<K> keyType;
+public abstract class AbstractPublicKeyEntryDecoder<PUB extends PublicKey,PRV extends PrivateKey>
+ implements PublicKeyEntryDecoder<PUB,PRV> {
+ private final Class<PUB> pubType;
+ private final Class<PRV> prvType;
private final Collection<String> names;
- protected AbstractPublicKeyEntryDecoder(Class<K> keyType, Collection<String> names) {
- this.keyType = ValidateUtils.checkNotNull(keyType, "No key type specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+ protected AbstractPublicKeyEntryDecoder(Class<PUB> pubType, Class<PRV> prvType, Collection<String> names) {
+ this.pubType = ValidateUtils.checkNotNull(pubType, "No public key type specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+ this.prvType = ValidateUtils.checkNotNull(prvType, "No private key type specified", GenericUtils.EMPTY_OBJECT_ARRAY);
this.names = ValidateUtils.checkNotNullAndNotEmpty(names, "No type names provided", GenericUtils.EMPTY_OBJECT_ARRAY);
}
@Override
- public final Class<K> getKeyType() {
- return keyType;
+ public final Class<PUB> getPublicKeyType() {
+ return pubType;
+ }
+
+ @Override
+ public final Class<PRV> getPrivateKeyType() {
+ return prvType;
+ }
+
+ @Override
+ public KeyPair cloneKeyPair(KeyPair kp) throws GeneralSecurityException {
+ if (kp == null) {
+ return null;
+ }
+
+ PUB pubCloned = null;
+ {
+ PublicKey pubOriginal = kp.getPublic();
+ Class<PUB> pubExpected = getPublicKeyType();
+ if (pubOriginal != null) {
+ Class<?> orgType = pubOriginal.getClass();
+ if (!pubExpected.isAssignableFrom(orgType)) {
+ throw new InvalidKeyException("Mismatched public key types: expected=" + pubExpected.getSimpleName() + ", actual=" + orgType.getSimpleName());
+ }
+
+ pubCloned = clonePublicKey(pubExpected.cast(pubOriginal));
+ }
+ }
+
+ PRV prvCloned = null;
+ {
+ PrivateKey prvOriginal = kp.getPrivate();
+ Class<PRV> prvExpected = getPrivateKeyType();
+ if (prvOriginal != null) {
+ Class<?> orgType = prvOriginal.getClass();
+ if (!prvExpected.isAssignableFrom(orgType)) {
+ throw new InvalidKeyException("Mismatched private key types: expected=" + prvExpected.getSimpleName() + ", actual=" + orgType.getSimpleName());
+ }
+
+ prvCloned = clonePrivateKey(prvExpected.cast(prvOriginal));
+ }
+ }
+
+ return new KeyPair(pubCloned, prvCloned);
}
@Override
@@ -61,12 +110,12 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
}
@Override
- public K decodePublicKey(byte... keyData) throws IOException, GeneralSecurityException {
+ public PUB decodePublicKey(byte... keyData) throws IOException, GeneralSecurityException {
return decodePublicKey(keyData, 0, GenericUtils.length(keyData));
}
@Override
- public K decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException {
+ public PUB decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException {
if (length <= 0) {
return null;
}
@@ -77,7 +126,7 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
}
@Override
- public K decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException {
+ public PUB decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException {
// the actual data is preceded by a string that repeats the key type
String type = decodeString(keyData);
if (GenericUtils.isEmpty(type)) {
@@ -92,13 +141,17 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
return decodePublicKey(type, keyData);
}
- public K generatePublicKey(KeySpec keySpec) throws GeneralSecurityException {
+ public PUB generatePublicKey(KeySpec keySpec) throws GeneralSecurityException {
KeyFactory factory = getKeyFactoryInstance();
- Class<K> keyType = getKeyType();
+ Class<PUB> keyType = getPublicKeyType();
return keyType.cast(factory.generatePublic(keySpec));
}
- public abstract KeyFactory getKeyFactoryInstance() throws GeneralSecurityException;
+ public PRV generatePrivateKey(KeySpec keySpec) throws GeneralSecurityException {
+ KeyFactory factory = getKeyFactoryInstance();
+ Class<PRV> keyType = getPrivateKeyType();
+ return keyType.cast(factory.generatePrivate(keySpec));
+ }
/**
* @param keyType The reported / encode key type
@@ -108,11 +161,18 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
* @throws IOException If failed to read from the data stream
* @throws GeneralSecurityException If failed to generate the key
*/
- public abstract K decodePublicKey(String keyType, InputStream keyData) throws IOException, GeneralSecurityException;
+ public abstract PUB decodePublicKey(String keyType, InputStream keyData) throws IOException, GeneralSecurityException;
+
+ @Override
+ public KeyPair generateKeyPair(int keySize) throws GeneralSecurityException {
+ KeyPairGenerator gen=getKeyPairGenerator();
+ gen.initialize(keySize);
+ return gen.generateKeyPair();
+ }
@Override
public String toString() {
- return getKeyType().getSimpleName() + ": " + getSupportedTypeNames();
+ return getPublicKeyType().getSimpleName() + ": " + getSupportedTypeNames();
}
public static final int encodeString(OutputStream s, String v) throws IOException {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
index 05af8ba..b48d3cf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
@@ -24,9 +24,13 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.util.Collections;
@@ -39,11 +43,11 @@ import org.apache.sshd.common.util.ValidateUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAPublicKey> {
+public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAPublicKey,DSAPrivateKey> {
public static final DSSPublicKeyEntryDecoder INSTANCE = new DSSPublicKeyEntryDecoder();
public DSSPublicKeyEntryDecoder() {
- super(DSAPublicKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
+ super(DSAPublicKey.class, DSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
}
@Override
@@ -75,6 +79,39 @@ public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAP
}
@Override
+ public DSAPublicKey clonePublicKey(DSAPublicKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ }
+
+ DSAParams params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePublicKey(new DSAPublicKeySpec(key.getY(), params.getP(), params.getQ(), params.getG()));
+ }
+
+ @Override
+ public DSAPrivateKey clonePrivateKey(DSAPrivateKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ }
+
+ DSAParams params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePrivateKey(new DSAPrivateKeySpec(key.getX(), params.getP(), params.getQ(), params.getG()));
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException {
+ return SecurityUtils.getKeyPairGenerator("DSA");
+ }
+
+ @Override
public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException {
return SecurityUtils.getKeyFactory("DSA");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
index 3325a26..feba09c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
@@ -26,20 +26,23 @@ import java.io.OutputStream;
import java.io.StreamCorruptedException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.NoSuchProviderException;
+import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
-import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
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.common.util.ValidateUtils;
@@ -48,13 +51,11 @@ import org.apache.sshd.common.util.buffer.BufferUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<ECPublicKey> {
+public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<ECPublicKey,ECPrivateKey> {
public static final ECDSAPublicKeyEntryDecoder INSTANCE = new ECDSAPublicKeyEntryDecoder();
public ECDSAPublicKeyEntryDecoder() {
- super(ECPublicKey.class,
- Collections.unmodifiableList(
- Arrays.asList(KeyPairProvider.ECDSA_SHA2_NISTP256, KeyPairProvider.ECDSA_SHA2_NISTP384, KeyPairProvider.ECDSA_SHA2_NISTP521)));
+ super(ECPublicKey.class, ECPrivateKey.class, ECCurves.TYPES);
}
@Override
@@ -96,6 +97,42 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
}
@Override
+ public ECPublicKey clonePublicKey(ECPublicKey key) throws GeneralSecurityException {
+ if (!SecurityUtils.hasEcc()) {
+ throw new NoSuchProviderException("ECC not supported");
+ }
+
+ if (key == null) {
+ return null;
+ }
+
+ ECParameterSpec params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePublicKey(new ECPublicKeySpec(key.getW(), params));
+ }
+
+ @Override
+ public ECPrivateKey clonePrivateKey(ECPrivateKey key) throws GeneralSecurityException {
+ if (!SecurityUtils.hasEcc()) {
+ throw new NoSuchProviderException("ECC not supported");
+ }
+
+ if (key == null) {
+ return null;
+ }
+
+ ECParameterSpec params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePrivateKey(new ECPrivateKeySpec(key.getS(), params));
+ }
+
+ @Override
public String encodePublicKey(OutputStream s, ECPublicKey key) throws IOException {
ValidateUtils.checkNotNull(key, "No public key provided", GenericUtils.EMPTY_OBJECT_ARRAY);
@@ -118,6 +155,32 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
}
}
+ @Override
+ public KeyPair generateKeyPair(int keySize) throws GeneralSecurityException {
+ String curveName = ECCurves.getCurveName(keySize);
+ if (GenericUtils.isEmpty(curveName)) {
+ throw new InvalidKeySpecException("Unknown curve for key size=" + keySize);
+ }
+
+ ECParameterSpec params = ECCurves.getECParameterSpec(curveName);
+ if (params == null) {
+ throw new InvalidKeySpecException("No curve parameters available for " + curveName);
+ }
+
+ KeyPairGenerator gen = getKeyPairGenerator();
+ gen.initialize(params);
+ return gen.generateKeyPair();
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException {
+ if (SecurityUtils.hasEcc()) {
+ return SecurityUtils.getKeyPairGenerator("EC");
+ } else {
+ throw new NoSuchProviderException("ECC not supported");
+ }
+ }
+
// see rfc5480 section 2.2
public static final byte ECPOINT_UNCOMPRESSED_FORM_INDICATOR=0x04;
public static final byte ECPOINT_COMPRESSED_VARIANT_2=0x02;
[5/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
Posted by lg...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
index c4f808d..e8207ed 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
@@ -18,17 +18,24 @@
*/
package org.apache.sshd.common.config.keys;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAKey;
import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -51,11 +58,11 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class KeyUtils {
- private static final Map<String,PublicKeyEntryDecoder<? extends PublicKey>> byKeyTypeDecodersMap =
- new TreeMap<String, PublicKeyEntryDecoder<? extends PublicKey>>(String.CASE_INSENSITIVE_ORDER);
- private static final Map<Class<?>,PublicKeyEntryDecoder<? extends PublicKey>> byKeyClassDecodersMap =
- new HashMap<Class<?>, PublicKeyEntryDecoder<? extends PublicKey>>();
+public final class KeyUtils {
+ private static final Map<String,PublicKeyEntryDecoder<?,?>> byKeyTypeDecodersMap =
+ new TreeMap<String, PublicKeyEntryDecoder<?,?>>(String.CASE_INSENSITIVE_ORDER);
+ private static final Map<Class<?>,PublicKeyEntryDecoder<?,?>> byKeyClassDecodersMap =
+ new HashMap<Class<?>, PublicKeyEntryDecoder<?,?>>();
static {
registerPublicKeyEntryDecoder(RSAPublicKeyDecoder.INSTANCE);
@@ -67,18 +74,61 @@ public class KeyUtils {
throw new UnsupportedOperationException("No instance");
}
- public static void registerPublicKeyEntryDecoder(PublicKeyEntryDecoder<? extends PublicKey> decoder) {
+ /**
+ * @param keyType The key type - {@code OpenSSH} name - e.g., {@code ssh-rsa, ssh-dss}
+ * @param keySize The key size (in bits)
+ * @return A {@link KeyPair} of the specified type and size
+ * @throws GeneralSecurityException If failed to generate the key pair
+ * @see #getPublicKeyEntryDecoder(String)
+ * @see PublicKeyEntryDecoder#generateKeyPair(int)
+ */
+ public static KeyPair generateKeyPair(String keyType, int keySize) throws GeneralSecurityException {
+ PublicKeyEntryDecoder<?,?> decoder = getPublicKeyEntryDecoder(keyType);
+ if (decoder == null) {
+ throw new InvalidKeySpecException("No decoder for key type=" + keyType);
+ }
+
+ return decoder.generateKeyPair(keySize);
+ }
+
+ /**
+ * Performs a deep-clone of the original {@link KeyPair} - i.e., creates
+ * <U>new</U> public/private keys that are clones of the original one
+ * @param keyType The key type - {@code OpenSSH} name - e.g., {@code ssh-rsa, ssh-dss}
+ * @param kp The {@link KeyPair} to clone - ignored if {@code null}
+ * @return The cloned instance
+ * @throws GeneralSecurityException If failed to clone the pair
+ */
+ public static KeyPair cloneKeyPair(String keyType, KeyPair kp) throws GeneralSecurityException {
+ PublicKeyEntryDecoder<?,?> decoder = getPublicKeyEntryDecoder(keyType);
+ if (decoder == null) {
+ throw new InvalidKeySpecException("No decoder for key type=" + keyType);
+ }
+
+ return decoder.cloneKeyPair(kp);
+ }
+
+ /**
+ * @param decoder The decoder to register
+ * @throws IllegalArgumentException if no decoder or not key type or no
+ * supported names for the decoder
+ * @see PublicKeyEntryDecoder#getPublicKeyType()
+ * @see PublicKeyEntryDecoder#getSupportedTypeNames()
+ */
+ public static void registerPublicKeyEntryDecoder(PublicKeyEntryDecoder<?,?> decoder) {
ValidateUtils.checkNotNull(decoder, "No decoder specified", GenericUtils.EMPTY_OBJECT_ARRAY);
- Class<?> keyType = ValidateUtils.checkNotNull(decoder.getKeyType(), "No key type declared", GenericUtils.EMPTY_OBJECT_ARRAY);
+ Class<?> pubType = ValidateUtils.checkNotNull(decoder.getPublicKeyType(), "No public key type declared", GenericUtils.EMPTY_OBJECT_ARRAY);
+ Class<?> prvType = ValidateUtils.checkNotNull(decoder.getPrivateKeyType(), "No private key type declared", GenericUtils.EMPTY_OBJECT_ARRAY);
synchronized(byKeyClassDecodersMap) {
- byKeyClassDecodersMap.put(keyType, decoder);
+ byKeyClassDecodersMap.put(pubType, decoder);
+ byKeyClassDecodersMap.put(prvType, decoder);
}
Collection<String> names = ValidateUtils.checkNotNullAndNotEmpty(decoder.getSupportedTypeNames(), "No supported key type", GenericUtils.EMPTY_OBJECT_ARRAY);
synchronized(byKeyTypeDecodersMap) {
for (String n : names) {
- PublicKeyEntryDecoder<? extends PublicKey> prev = byKeyTypeDecodersMap.put(n, decoder);
+ PublicKeyEntryDecoder<?,?> prev = byKeyTypeDecodersMap.put(n, decoder);
if (prev != null) {
continue; // debug breakpoint
}
@@ -87,10 +137,11 @@ public class KeyUtils {
}
/**
- * @param keyType The {@code OpenSSH} key type string - ignored if {@code null}/empty
+ * @param keyType The {@code OpenSSH} key type string - e.g., {@code ssh-rsa, ssh-dss}
+ * - ignored if {@code null}/empty
* @return The registered {@link PublicKeyEntryDecoder} or {code null} if not found
*/
- public static PublicKeyEntryDecoder<? extends PublicKey> getPublicKeyEntryDecoder(String keyType) {
+ public static PublicKeyEntryDecoder<?,?> getPublicKeyEntryDecoder(String keyType) {
if (GenericUtils.isEmpty(keyType)) {
return null;
}
@@ -101,11 +152,11 @@ public class KeyUtils {
}
/**
- * @param key The {@link PublicKey} - ignored if {@code null}
+ * @param key The {@link Key} (public or private) - ignored if {@code null}
* @return The registered {@link PublicKeyEntryDecoder} for this key or {code null} if no match found
* @see #getPublicKeyEntryDecoder(Class)
*/
- public static PublicKeyEntryDecoder<? extends PublicKey> getPublicKeyEntryDecoder(PublicKey key) {
+ public static PublicKeyEntryDecoder<?,?> getPublicKeyEntryDecoder(Key key) {
if (key == null) {
return null;
} else {
@@ -114,27 +165,27 @@ public class KeyUtils {
}
/**
- * @param keyType The key {@link Class} - ignored if {@code null} or not a {@link PublicKey}
+ * @param keyType The key {@link Class} - ignored if {@code null} or not a {@link Key}
* compatible type
* @return The registered {@link PublicKeyEntryDecoder} or {code null} if no match found
*/
- public static PublicKeyEntryDecoder<? extends PublicKey> getPublicKeyEntryDecoder(Class<?> keyType) {
- if ((keyType == null) || (!PublicKey.class.isAssignableFrom(keyType))) {
+ public static PublicKeyEntryDecoder<?,?> getPublicKeyEntryDecoder(Class<?> keyType) {
+ if ((keyType == null) || (!Key.class.isAssignableFrom(keyType))) {
return null;
}
synchronized(byKeyTypeDecodersMap) {
{
- PublicKeyEntryDecoder<? extends PublicKey> decoder=byKeyClassDecodersMap.get(keyType);
+ PublicKeyEntryDecoder<?,?> decoder=byKeyClassDecodersMap.get(keyType);
if (decoder != null) {
return decoder;
}
}
// in case it is a derived class
- for (PublicKeyEntryDecoder<? extends PublicKey> decoder : byKeyClassDecodersMap.values()) {
- Class<?> t = decoder.getKeyType();
- if (t.isAssignableFrom(keyType)) {
+ for (PublicKeyEntryDecoder<?,?> decoder : byKeyClassDecodersMap.values()) {
+ Class<?> pubType = decoder.getPublicKeyType(), prvType = decoder.getPrivateKeyType();
+ if (pubType.isAssignableFrom(keyType) || prvType.isAssignableFrom(keyType)) {
return decoder;
}
}
@@ -157,14 +208,39 @@ public class KeyUtils {
try {
Buffer buffer = new ByteArrayBuffer();
buffer.putRawPublicKey(key);
- Digest md5 = BuiltinDigests.md5.create();
- md5.init();
- md5.update(buffer.array(), 0, buffer.wpos());
- byte[] data = md5.digest();
- return BufferUtils.printHex(data, 0, data.length, ':');
+ return getFingerPrint(buffer.array(), 0, buffer.wpos());
+ } catch(Exception e) {
+ return e.getClass().getSimpleName();
+ }
+ }
+
+ public static String getFingerPrint(String password) {
+ if (GenericUtils.isEmpty(password)) {
+ return null;
+ }
+
+ try {
+ return getFingerPrint(password.getBytes(StandardCharsets.UTF_8));
} catch(Exception e) {
- return "Unable to compute fingerprint";
+ return e.getClass().getSimpleName();
+ }
+ }
+
+ public static String getFingerPrint(byte ... buf) throws Exception {
+ return getFingerPrint(buf, 0, GenericUtils.length(buf));
+ }
+
+ public static String getFingerPrint(byte[] buf, int offset, int len) throws Exception {
+ if (len <= 0) {
+ return null;
}
+
+ Digest md5 = BuiltinDigests.md5.create();
+ md5.init();
+ md5.update(buf, offset, len);
+
+ byte[] data = md5.digest();
+ return BufferUtils.printHex(data, 0, data.length, ':');
}
/**
@@ -232,6 +308,72 @@ public class KeyUtils {
return null;
}
+ public static boolean compareKeyPairs(KeyPair k1, KeyPair k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ }
+
+ if (compareKeys(k1.getPublic(), k2.getPublic())
+ && compareKeys(k1.getPrivate(), k2.getPrivate())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean compareKeys(PrivateKey k1, PrivateKey k2) {
+ if ((k1 instanceof RSAPrivateKey) && (k2 instanceof RSAPrivateKey)) {
+ return compareRSAKeys(RSAPrivateKey.class.cast(k1), RSAPrivateKey.class.cast(k2));
+ } else if ((k1 instanceof DSAPrivateKey) && (k2 instanceof DSAPrivateKey)) {
+ return compareDSAKeys(DSAPrivateKey.class.cast(k1), DSAPrivateKey.class.cast(k2));
+ } else if ((k1 instanceof ECPrivateKey) && (k2 instanceof ECPrivateKey)) {
+ return compareECKeys(ECPrivateKey.class.cast(k1), ECPrivateKey.class.cast(k2));
+ } else {
+ return false; // either key is null or not of same class
+ }
+ }
+
+ public static boolean compareRSAKeys(RSAPrivateKey k1, RSAPrivateKey k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ } else if (Objects.equals(k1.getModulus(), k2.getModulus())
+ && Objects.equals(k1.getPrivateExponent(), k2.getPrivateExponent())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean compareDSAKeys(DSAPrivateKey k1, DSAPrivateKey k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ } else if (Objects.equals(k1.getX(), k2.getAlgorithm())
+ && compareDSAParams(k1.getParams(), k2.getParams())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean compareECKeys(ECPrivateKey k1, ECPrivateKey k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ } else if (Objects.equals(k1.getS(), k2.getS())
+ && compareECParams(k1.getParams(), k2.getParams())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public static boolean compareKeys(PublicKey k1, PublicKey k2) {
if ((k1 instanceof RSAPublicKey) && (k2 instanceof RSAPublicKey)) {
return compareRSAKeys(RSAPublicKey.class.cast(k1), RSAPublicKey.class.cast(k2));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
index 28708fb..cd3ec94 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
@@ -83,7 +83,7 @@ public class PublicKeyEntry implements Serializable {
*/
public PublicKey resolvePublicKey() throws IOException, GeneralSecurityException {
String kt = getKeyType();
- PublicKeyEntryDecoder<? extends PublicKey> decoder = KeyUtils.getPublicKeyEntryDecoder(kt);
+ PublicKeyEntryDecoder<?,?> decoder = KeyUtils.getPublicKeyEntryDecoder(kt);
if (decoder == null) {
throw new InvalidKeySpecException("No decoder registered for key type=" + kt);
}
@@ -228,7 +228,7 @@ public class PublicKeyEntry implements Serializable {
*/
public static final <A extends Appendable> A appendPublicKeyEntry(A sb, PublicKey key) throws IOException {
@SuppressWarnings("unchecked")
- PublicKeyEntryDecoder<PublicKey> decoder = (PublicKeyEntryDecoder<PublicKey>) KeyUtils.getPublicKeyEntryDecoder(key);
+ PublicKeyEntryDecoder<PublicKey,?> decoder = (PublicKeyEntryDecoder<PublicKey,?>) KeyUtils.getPublicKeyEntryDecoder(key);
if (decoder == null) {
throw new StreamCorruptedException("Cannot retrived decoder for key=" + key.getAlgorithm());
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
index fc43bb3..dbff853 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
@@ -23,6 +23,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Collection;
@@ -30,12 +34,18 @@ import java.util.Collection;
* Represents a decoder of an {@code OpenSSH} encoded key data
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface PublicKeyEntryDecoder<K extends PublicKey> {
+public interface PublicKeyEntryDecoder<PUB extends PublicKey,PRV extends PrivateKey> {
/**
* @return The {@link Class} of the {@link PublicKey} that is the result
* of decoding
*/
- Class<K> getKeyType();
+ Class<PUB> getPublicKeyType();
+
+ /**
+ * @return The {@link Class} of the {@link PrivateKey} that matches the
+ * public one
+ */
+ Class<PRV> getPrivateKeyType();
/**
* @return The {@link Collection} of {@code OpenSSH} key type names that
@@ -43,7 +53,44 @@ public interface PublicKeyEntryDecoder<K extends PublicKey> {
* <B>Caveat:</B> this collection may be un-modifiable...
*/
Collection<String> getSupportedTypeNames();
-
+
+ /**
+ * @param keySize Key size in bits
+ * @return A {@link KeyPair} with the specified key size
+ * @throws GeneralSecurityException if unable to generate the pair
+ */
+ KeyPair generateKeyPair(int keySize) throws GeneralSecurityException;
+
+ /**
+ * @param kp The {@link KeyPair} to be cloned - ignored if {@code null}
+ * @return A cloned pair (or {@code null} if no original pair)
+ * @throws GeneralSecurityException If failed to clone - e.g., provided key
+ * pair does not contain keys of the expected type
+ * @see #getPublicKeyType()
+ * @see #getPrivateKeyType()
+ */
+ KeyPair cloneKeyPair(KeyPair kp) throws GeneralSecurityException;
+
+ /**
+ * @param key The {@link PublicKey} to clone - ignored if {@code null}
+ * @return The cloned key (or {@code null} if no original key)
+ * @throws GeneralSecurityException If failed to clone the key
+ */
+ PUB clonePublicKey(PUB key) throws GeneralSecurityException;
+
+ /**
+ * @param key The {@link PrivateKey} to clone - ignored if {@code null}
+ * @return The cloned key (or {@code null} if no original key)
+ * @throws GeneralSecurityException If failed to clone the key
+ */
+ PRV clonePrivateKey(PRV key) throws GeneralSecurityException;
+
+ /**
+ * @return A {@link KeyPairGenerator} suitable for this decoder
+ * @throws GeneralSecurityException If failed to create the generator
+ */
+ KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException;
+
/**
* @param keyData The key data bytes in {@code OpenSSH} format (after
* BASE64 decoding) - ignored if {@code null}/empty
@@ -51,9 +98,9 @@ public interface PublicKeyEntryDecoder<K extends PublicKey> {
* @throws IOException If failed to decode the key
* @throws GeneralSecurityException If failed to generate the key
*/
- K decodePublicKey(byte ... keyData) throws IOException, GeneralSecurityException;
- K decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException;
- K decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException;
+ PUB decodePublicKey(byte ... keyData) throws IOException, GeneralSecurityException;
+ PUB decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException;
+ PUB decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException;
/**
* Encodes the {@link PublicKey} using the {@code OpenSSH} format - same
@@ -63,5 +110,11 @@ public interface PublicKeyEntryDecoder<K extends PublicKey> {
* @return The key type value - one of the {@link #getSupportedTypeNames()}
* @throws IOException If failed to generate the encoding
*/
- String encodePublicKey(OutputStream s, K key) throws IOException;
+ String encodePublicKey(OutputStream s, PUB key) throws IOException;
+
+ /**
+ * @return A {@link KeyFactory} suitable for the specific decoder type
+ * @throws GeneralSecurityException If failed to create one
+ */
+ KeyFactory getKeyFactoryInstance() throws GeneralSecurityException;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
index f1b5dcb..5927568 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
@@ -24,9 +24,14 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collections;
@@ -38,11 +43,11 @@ import org.apache.sshd.common.util.ValidateUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublicKey> {
+public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublicKey,RSAPrivateKey> {
public static final RSAPublicKeyDecoder INSTANCE = new RSAPublicKeyDecoder();
public RSAPublicKeyDecoder() {
- super(RSAPublicKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA)));
+ super(RSAPublicKey.class, RSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA)));
}
@Override
@@ -68,6 +73,43 @@ public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublic
}
@Override
+ public RSAPublicKey clonePublicKey(RSAPublicKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ } else {
+ return generatePublicKey(new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent()));
+ }
+ }
+
+ @Override
+ public RSAPrivateKey clonePrivateKey(RSAPrivateKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ }
+
+ if (!(key instanceof RSAPrivateCrtKey)) {
+ throw new InvalidKeyException("Cannot clone a non-RSAPrivateCrtKey: " + key.getClass().getSimpleName());
+ }
+
+ RSAPrivateCrtKey rsaPrv = (RSAPrivateCrtKey) key;
+ return generatePrivateKey(
+ new RSAPrivateCrtKeySpec(
+ rsaPrv.getModulus(),
+ rsaPrv.getPublicExponent(),
+ rsaPrv.getPrivateExponent(),
+ rsaPrv.getPrimeP(),
+ rsaPrv.getPrimeQ(),
+ rsaPrv.getPrimeExponentP(),
+ rsaPrv.getPrimeExponentQ(),
+ rsaPrv.getCrtCoefficient()));
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException {
+ return SecurityUtils.getKeyPairGenerator("RSA");
+ }
+
+ @Override
public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException {
return SecurityUtils.getKeyFactory("RSA");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
index 8f35ba7..61cfff0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
@@ -25,7 +25,7 @@ import java.nio.file.FileSystems;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Native file system factory. It uses the OS file system.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
index c1bb4e3..bad235f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
@@ -49,8 +49,8 @@ import java.util.Set;
import java.util.concurrent.ExecutorService;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
/**
* File system provider which provides a rooted file system.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java b/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
index 8d263e8..0ee8afe 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.future;
import java.lang.reflect.Array;
import java.util.concurrent.TimeUnit;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* A default implementation of {@link SshFuture}.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
index 0cb85f6..9d9b312 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.io;
import java.util.concurrent.ExecutorService;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
index a3d57eb..9abbaa4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
@@ -22,7 +22,7 @@ package org.apache.sshd.common.kex.dh;
import org.apache.sshd.common.digest.Digest;
import org.apache.sshd.common.kex.KeyExchange;
import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
index 03ba5f2..9a0aa73 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
@@ -23,9 +23,9 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
index 8453d25..dcb9e36 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
@@ -22,8 +22,8 @@ package org.apache.sshd.common.keyprovider;
import java.security.KeyPair;
import java.util.Map;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.common.util.ValidateUtils;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
index 6bc59f0..e84bbb4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.mac;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
index 7c2311e..4db74c0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
@@ -29,10 +29,10 @@ import java.nio.file.attribute.PosixFilePermission;
import java.util.Collection;
import java.util.Set;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
index efd7f46..1648b9e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
@@ -33,8 +33,8 @@ import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import org.apache.sshd.common.util.AbstractLoggingBean;
-import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
index b7d244e..45afa6e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
@@ -43,11 +43,11 @@ import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.file.util.MockPath;
import org.apache.sshd.common.scp.ScpTransferEventListener.FileOperation;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.DirectoryScanner;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.LimitInputStream;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
index 1d25411..ce0287d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
@@ -416,7 +416,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
sendEvent(SessionListener.Event.KeyEstablished);
synchronized (pendingPackets) {
if (!pendingPackets.isEmpty()) {
- log.info("Dequeing pending packets");
+ log.debug("Dequeing pending packets");
synchronized (encodeLock) {
PendingWriteFuture future;
while ((future = pendingPackets.poll()) != null) {
@@ -530,7 +530,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
synchronized (pendingPackets) {
if (kexState.get() != KEX_STATE_DONE) {
if (pendingPackets.isEmpty()) {
- log.info("Start flagging packets as pending until key exchange is done");
+ log.debug("Start flagging packets as pending until key exchange is done");
}
PendingWriteFuture future = new PendingWriteFuture(buffer);
pendingPackets.add(future);
@@ -1159,7 +1159,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
protected void negotiate() {
String[] guess = new String[SshConstants.PROPOSAL_MAX];
for (int i = 0; i < SshConstants.PROPOSAL_MAX; i++) {
- String paramName = SshConstants.PROPOSAL_KEX_NAMES[i];
+ String paramName = SshConstants.PROPOSAL_KEX_NAMES.get(i);
String clientParamValue = clientProposal[i];
String serverParamValue = serverProposal[i];
String[] c = clientParamValue.split(",");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java b/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
index 26764a7..fcabbe1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.session;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Task that iterates over all currently open {@link AbstractSession}s and checks each of them for timeouts. If
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
index 26abe3c..e0880d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.signature;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java b/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java
deleted file mode 100644
index 39131c8..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Serves as a common base class for the vast majority of classes that require
- * some kind of logging. Facilitates quick and easy replacement of the actual used
- * logger from one framework to another
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractLoggingBean {
- protected final Logger log;
-
- /**
- * Default constructor - creates a logger using the full class name
- */
- protected AbstractLoggingBean() {
- log = LoggerFactory.getLogger(getClass());
- }
-
- /**
- * Create a logger for instances of the same class for which we might
- * want to have a "discriminator" for them
- * @param discriminator The discriminator value
- */
- protected AbstractLoggingBean(String discriminator) {
- log = LoggerFactory.getLogger(getClass().getName() + "[" + discriminator + "]");
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
index 9710d57..a75f470 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
@@ -36,13 +36,17 @@ import org.apache.sshd.common.future.DefaultCloseFuture;
import org.apache.sshd.common.future.DefaultSshFuture;
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Utility class to help with {@link Closeable}s.
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class CloseableUtils {
+public final class CloseableUtils {
+ private CloseableUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
// TODO once JDK 8+ becomes the minimum for this project, make it a static method in the Closeable interface
public static void close(Closeable closeable) throws IOException {
@@ -349,6 +353,7 @@ public class CloseableUtils {
if (grace != null) {
grace.addListener(new SshFutureListener<CloseFuture>() {
@Override
+ @SuppressWarnings("synthetic-access")
public void operationComplete(CloseFuture future) {
if (state.compareAndSet(State.Graceful, State.Immediate)) {
doCloseImmediately();
@@ -438,8 +443,4 @@ public class CloseableUtils {
});
}
}
-
- private CloseableUtils() {
- throw new UnsupportedOperationException("No instance allowed");
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
index b89774f..48df9f4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
@@ -28,7 +28,11 @@ import java.util.EventListener;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class EventListenerUtils {
+public final class EventListenerUtils {
+ private EventListenerUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
/**
* Provides proxy wrapper around an {@link Iterable} container of listener
* interface implementation. <b>Note:</b> a listener interface is one whose
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
index 657a6ad..6d049e8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -35,11 +35,15 @@ import java.util.TreeSet;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class GenericUtils {
+public final class GenericUtils {
public static final byte[] EMPTY_BYTE_ARRAY={ };
public static final String[] EMPTY_STRING_ARRAY={ };
public static final Object[] EMPTY_OBJECT_ARRAY={ };
+ private GenericUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
public static final String trimToEmpty(String s) {
if (s == null) {
return "";
@@ -333,4 +337,27 @@ public class GenericUtils {
return s.subSequence(1, lastPos);
}
}
+
+ /**
+ * Used to "accumulate" exceptions of the <U>same type</U>. If the
+ * current exception is {@code null} then the new one becomes the current,
+ * otherwise the new one is added as a <U>suppressed</U> exception to the
+ * current one
+ * @param current The current exception
+ * @param extra The extra/new exception
+ * @return The resolved exception
+ * @see Throwable#addSuppressed(Throwable)
+ */
+ public static <T extends Throwable> T accumulateException(T current, T extra) {
+ if (current == null) {
+ return extra;
+ }
+
+ if ((extra == null) || (extra == current)) {
+ return current;
+ }
+
+ current.addSuppressed(extra);
+ return current;
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
deleted file mode 100644
index da17c22..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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.util;
-
-import java.io.Closeable;
-import java.io.EOFException;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.FileSystem;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.attribute.PosixFilePermission;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class IoUtils {
-
- public static final LinkOption[] EMPTY_OPTIONS = new LinkOption[0];
- private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
-
- public static LinkOption[] getLinkOptions(boolean followLinks) {
- if (followLinks) {
- return EMPTY_OPTIONS;
- } else { // return a clone that modifications to the array will not affect others
- return NO_FOLLOW_OPTIONS.clone();
- }
- }
-
- public static final int DEFAULT_COPY_SIZE=8192;
-
- public static long copy(InputStream source, OutputStream sink) throws IOException {
- return copy(source, sink, DEFAULT_COPY_SIZE);
- }
-
- public static long copy(InputStream source, OutputStream sink, int bufferSize) throws IOException {
- long nread = 0L;
- byte[] buf = new byte[bufferSize];
- int n;
- while ((n = source.read(buf)) > 0) {
- sink.write(buf, 0, n);
- nread += n;
- }
- return nread;
- }
-
- public static void closeQuietly(Closeable... closeables) {
- for (Closeable c : closeables) {
- try {
- if (c != null) {
- c.close();
- }
- } catch (IOException e) {
- // Ignore
- }
- }
- }
-
- public static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS = Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
-
- /**
- * @param fileName The file name to be evaluated - ignored if {@code null}/empty
- * @return {@code true} if the file ends in one of the {@link #WINDOWS_EXECUTABLE_EXTENSIONS}
- */
- public static boolean isWindowsExecutable(String fileName) {
- if ((fileName == null) || (fileName.length() <= 0)) {
- return false;
- }
- for (String suffix : WINDOWS_EXECUTABLE_EXTENSIONS) {
- if (fileName.endsWith(suffix)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * If the "posix" view is supported, then it returns
- * {@link Files#getPosixFilePermissions(Path, LinkOption...)}, otherwise
- * uses the {@link #getPermissionsFromFile(File)} method
- * @param path The {@link Path}
- * @return A {@link Set} of {@link PosixFilePermission}
- * @throws IOException If failed to access the file system in order to
- * retrieve the permissions
- */
- public static Set<PosixFilePermission> getPermissions(Path path) throws IOException {
- FileSystem fs = path.getFileSystem();
- Collection<String> views = fs.supportedFileAttributeViews();
- if (views.contains("posix")) {
- return Files.getPosixFilePermissions(path, getLinkOptions(false));
- } else {
- return getPermissionsFromFile(path.toFile());
- }
- }
-
- /**
- * @param f The {@link File} to be checked
- * @return A {@link Set} of {@link PosixFilePermission}s based on whether
- * the file is readable/writable/executable. If so, then <U>all</U> the
- * relevant permissions are set (i.e., owner, group and others)
- */
- public static Set<PosixFilePermission> getPermissionsFromFile(File f) {
- Set<PosixFilePermission> perms = EnumSet.noneOf(PosixFilePermission.class);
- if (f.canRead()) {
- perms.add(PosixFilePermission.OWNER_READ);
- perms.add(PosixFilePermission.GROUP_READ);
- perms.add(PosixFilePermission.OTHERS_READ);
- }
-
- if (f.canWrite()) {
- perms.add(PosixFilePermission.OWNER_WRITE);
- perms.add(PosixFilePermission.GROUP_WRITE);
- perms.add(PosixFilePermission.OTHERS_WRITE);
- }
-
- if (f.canExecute() || (OsUtils.isWin32() && isWindowsExecutable(f.getName()))) {
- perms.add(PosixFilePermission.OWNER_EXECUTE);
- perms.add(PosixFilePermission.GROUP_EXECUTE);
- perms.add(PosixFilePermission.OTHERS_EXECUTE);
- }
-
- return perms;
- }
-
- /**
- * If the "posix" view is supported, then it invokes
- * {@link Files#setPosixFilePermissions(Path, Set)}, otherwise
- * uses the {@link #setPermissionsToFile(File, Collection)} method
- * @param path The {@link Path}
- * @param perms The {@link Set} of {@link PosixFilePermission}s
- * @throws IOException If failed to access the file system
- */
- public static void setPermissions(Path path, Set<PosixFilePermission> perms) throws IOException {
- FileSystem fs = path.getFileSystem();
- Collection<String> views = fs.supportedFileAttributeViews();
- if (views.contains("posix")) {
- Files.setPosixFilePermissions(path, perms);
- } else {
- setPermissionsToFile(path.toFile(), perms);
- }
- }
-
- /**
- * @param f The {@link File}
- * @param perms A {@link Collection} of {@link PosixFilePermission}s to set on it.
- * <B>Note:</B> the file is set to readable/writable/executable not only by the
- * owner if <U>any</U> of relevant the owner/group/others permission is set
- */
- public static void setPermissionsToFile(File f, Collection<PosixFilePermission> perms) {
- boolean readable = perms != null &&
- (perms.contains(PosixFilePermission.OWNER_READ)
- || perms.contains(PosixFilePermission.GROUP_READ)
- || perms.contains(PosixFilePermission.OTHERS_READ));
- f.setReadable(readable, false);
-
- boolean writable = perms != null &&
- (perms.contains(PosixFilePermission.OWNER_WRITE)
- || perms.contains(PosixFilePermission.GROUP_WRITE)
- || perms.contains(PosixFilePermission.OTHERS_WRITE));
- f.setWritable(writable, false);
-
- boolean executable = perms != null &&
- (perms.contains(PosixFilePermission.OWNER_EXECUTE)
- || perms.contains(PosixFilePermission.GROUP_EXECUTE)
- || perms.contains(PosixFilePermission.OTHERS_EXECUTE));
- f.setExecutable(executable, false);
- }
-
- /**
- * <P>Checks if a file exists - <B>Note:</B> according to the
- * <A HREF="http://docs.oracle.com/javase/tutorial/essential/io/check.html">Java tutorial - Checking a File or Directory</A>:
- * </P></BR>
- * <PRE>
- * The methods in the Path class are syntactic, meaning that they operate
- * on the Path instance. But eventually you must access the file system
- * to verify that a particular Path exists, or does not exist. You can do
- * so with the exists(Path, LinkOption...) and the notExists(Path, LinkOption...)
- * methods. Note that !Files.exists(path) is not equivalent to Files.notExists(path).
- * When you are testing a file's existence, three results are possible:
- *
- * - The file is verified to exist.
- * - The file is verified to not exist.
- * - The file's status is unknown.
- *
- * This result can occur when the program does not have access to the file.
- * If both exists and notExists return false, the existence of the file cannot
- * be verified.
- * </PRE>
- * @param path The {@link Path} to be tested
- * @param options The {@link LinkOption}s to use
- * @return {@link Boolean#TRUE}/{@link Boolean#FALSE} or {@code null}
- * according to the file status as explained above
- */
- public static Boolean checkFileExists(Path path, LinkOption ... options) {
- if (Files.exists(path, options)) {
- return Boolean.TRUE;
- } else if (Files.notExists(path, options)) {
- return Boolean.FALSE;
- } else {
- return null;
- }
- }
-
- /**
- * Read the requested number of bytes or fail if there are not enough left.
- * @param input where to read input from
- * @param buffer destination
- * @throws IOException if there is a problem reading the file
- * @throws EOFException if the number of bytes read was incorrect
- */
- public static void readFully(InputStream input, byte[] buffer) throws IOException {
- readFully(input, buffer, 0, buffer.length);
- }
-
- /**
- * Read the requested number of bytes or fail if there are not enough left.
- * @param input where to read input from
- * @param buffer destination
- * @param offset initial offset into buffer
- * @param length length to read, must be >= 0
- * @throws IOException if there is a problem reading the file
- * @throws EOFException if the number of bytes read was incorrect
- */
- public static void readFully(InputStream input, byte[] buffer, int offset, int length) throws IOException {
- int actual = read(input, buffer, offset, length);
- if (actual != length) {
- throw new EOFException("Premature EOF - expected=" + length + ", actual=" + actual);
- }
- }
-
- /**
- * Read as many bytes as possible until EOF or achieved required length
- * @param input where to read input from
- * @param buffer destination
- * @return actual length read; may be less than requested if EOF was reached
- * @throws IOException if a read error occurs
- */
- public static int read(InputStream input, byte[] buffer) throws IOException {
- return read(input, buffer, 0, buffer.length);
- }
-
- /**
- * Read as many bytes as possible until EOF or achieved required length
- * @param input where to read input from
- * @param buffer destination
- * @param offset initial offset into buffer
- * @param length length to read - ignored if non-positive
- * @return actual length read; may be less than requested if EOF was reached
- * @throws IOException if a read error occurs
- */
- public static int read(InputStream input, byte[] buffer, int offset, int length) throws IOException {
- for (int remaining = length, curOffset = offset; remaining > 0; ) {
- int count = input.read(buffer, curOffset, remaining);
- if (count == (-1)) { // EOF before achieved required length
- return curOffset - offset;
- }
-
- remaining -= count;
- curOffset += count;
- }
-
- return length;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
index f693a8e..08f1d1b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
@@ -23,7 +23,7 @@ package org.apache.sshd.common.util;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class OsUtils {
+public final class OsUtils {
private static final boolean win32;
static {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
index 1bb460f..f23029d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
@@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SecurityUtils {
-
public static final String BOUNCY_CASTLE = "BC";
private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);
@@ -49,6 +48,10 @@ public class SecurityUtils {
private static boolean registrationDone;
private static Boolean hasEcc;
+ private SecurityUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
public static boolean hasEcc() {
if (hasEcc == null) {
try {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java
new file mode 100644
index 0000000..19ba9c4
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util;
+
+import java.util.Objects;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Transformer<I, O> {
+ // TODO in JDK-8 replace this with Function
+ /**
+ * @param input Input value
+ * @return Transformed output value
+ */
+ O transform(I input);
+
+ /**
+ * Invokes {@link Objects#toString(Object)} on the argument
+ */
+ Transformer<Object,String> TOSTRING=new Transformer<Object,String>() {
+ @Override
+ public String transform(Object input) {
+ return Objects.toString(input);
+ }
+ };
+
+ /**
+ * Returns {@link Enum#name()} or {@code null} if argument is {@code null}
+ */
+ Transformer<Enum<?>,String> ENUM_NAME_EXTRACTOR=new Transformer<Enum<?>,String>() {
+ @Override
+ public String transform(Enum<?> input) {
+ if (input == null) {
+ return null;
+ } else {
+ return input.name();
+ }
+ }
+ };
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
index 9e270ab..78e1fc1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
@@ -25,7 +25,11 @@ import java.util.Map;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class ValidateUtils {
+public final class ValidateUtils {
+ private ValidateUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
public static final <T> T checkNotNull(T t, String message, Object ... args) {
checkTrue(t != null, message, args);
return t;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
index 74ff9df..784daa7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
@@ -149,10 +149,6 @@ public abstract class Buffer implements Readable {
public abstract String getString(Charset charset);
- public byte[] getStringAsBytes() {
- return getBytes();
- }
-
public BigInteger getMPInt() {
return new BigInteger(getMPIntAsBytes());
}
@@ -189,42 +185,47 @@ public abstract class Buffer implements Readable {
public PublicKey getRawPublicKey() throws SshException {
try {
- PublicKey key;
String keyAlg = getString();
if (KeyPairProvider.SSH_RSA.equals(keyAlg)) {
BigInteger e = getMPInt();
BigInteger n = getMPInt();
KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
- key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
+ return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
} else if (KeyPairProvider.SSH_DSS.equals(keyAlg)) {
BigInteger p = getMPInt();
BigInteger q = getMPInt();
BigInteger g = getMPInt();
BigInteger y = getMPInt();
KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
- key = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP256.equals(keyAlg)) {
- key = getRawECKey("nistp256", ECCurves.EllipticCurves.nistp256);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP384.equals(keyAlg)) {
- key = getRawECKey("nistp384", ECCurves.EllipticCurves.nistp384);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP521.equals(keyAlg)) {
- key = getRawECKey("nistp521", ECCurves.EllipticCurves.nistp521);
+ return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
+ } else if (keyAlg.startsWith(ECCurves.ECDSA_SHA2_PREFIX)) {
+ String curveName = keyAlg.substring(ECCurves.ECDSA_SHA2_PREFIX.length());
+ ECParameterSpec params = ECCurves.getECParameterSpec(curveName);
+ return getRawECKey(curveName, params);
} else {
throw new NoSuchAlgorithmException("Unsupported raw public algorithm: " + keyAlg);
}
- return key;
} catch (GeneralSecurityException e) {
throw new SshException(e);
}
}
- protected PublicKey getRawECKey(String expectedCurve, ECParameterSpec spec) throws GeneralSecurityException, SshException {
+ protected PublicKey getRawECKey(String expectedCurve, ECParameterSpec spec) throws GeneralSecurityException {
String curveName = getString();
if (!expectedCurve.equals(curveName)) {
- throw new InvalidKeySpecException("Curve name does not match expected: " + curveName + " vs "
- + expectedCurve);
+ throw new InvalidKeySpecException("getRawECKey(" + expectedCurve + ") curve name does not match expected: " + curveName);
+ }
+
+ if (spec == null) {
+ throw new InvalidKeySpecException("getRawECKey(" + expectedCurve + ") missing curve parameters");
+ }
+
+ byte[] octets = getBytes();
+ ECPoint w = ECCurves.decodeECPoint(octets, spec.getCurve());
+ if (w == null) {
+ throw new InvalidKeySpecException("getRawECKey(" + expectedCurve + ") cannot retrieve W value");
}
- ECPoint w = ECCurves.decodeECPoint(getStringAsBytes(), spec.getCurve());
+
KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
return keyFactory.generatePublic(new ECPublicKeySpec(w, spec));
}
@@ -255,12 +256,10 @@ public abstract class Buffer implements Readable {
KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
pub = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
prv = keyFactory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g));
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP256.equals(keyAlg)) {
- return extractEC("nistp256", ECCurves.EllipticCurves.nistp256);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP384.equals(keyAlg)) {
- return extractEC("nistp384", ECCurves.EllipticCurves.nistp384);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP521.equals(keyAlg)) {
- return extractEC("nistp521", ECCurves.EllipticCurves.nistp521);
+ } else if (keyAlg.startsWith(ECCurves.ECDSA_SHA2_PREFIX)) {
+ String curveName = keyAlg.substring(ECCurves.ECDSA_SHA2_PREFIX.length());
+ ECParameterSpec params = ECCurves.getECParameterSpec(curveName);
+ return extractEC(curveName, params);
} else {
throw new NoSuchAlgorithmException("Unsupported key pair algorithm: " + keyAlg);
}
@@ -270,18 +269,22 @@ public abstract class Buffer implements Readable {
}
}
- protected KeyPair extractEC(String expectedCurveName, ECParameterSpec spec) throws GeneralSecurityException, SshException {
+ protected KeyPair extractEC(String expectedCurveName, ECParameterSpec spec) throws GeneralSecurityException {
String curveName = getString();
- byte[] groupBytes = getStringAsBytes();
+ if (!expectedCurveName.equals(curveName)) {
+ throw new InvalidKeySpecException("extractEC(" + expectedCurveName + ") mismatched curve name: " + curveName);
+ }
+
+ byte[] groupBytes = getBytes();
BigInteger exponent = getMPInt();
- if (!expectedCurveName.equals(curveName)) {
- throw new SshException("Expected curve " + expectedCurveName + " but was " + curveName);
+ if (spec == null) {
+ throw new InvalidKeySpecException("extractEC(" + expectedCurveName + ") missing parameters for curve");
}
ECPoint group = ECCurves.decodeECPoint(groupBytes, spec.getCurve());
if (group == null) {
- throw new InvalidKeySpecException("Couldn't decode EC group");
+ throw new InvalidKeySpecException("extractEC(" + expectedCurveName + ") couldn't decode EC group for curve");
}
KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java
new file mode 100644
index 0000000..ecb0144
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java
@@ -0,0 +1,94 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.nio.channels.Channel;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A {@code /dev/null} stream that can be closed - in which case it will throw
+ * {@link IOException}s if invoked after being closed
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class CloseableEmptyInputStream extends EmptyInputStream implements Channel {
+ private final AtomicBoolean open = new AtomicBoolean(true);
+
+ public CloseableEmptyInputStream() {
+ super();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return open.get();
+ }
+
+ @Override
+ public int available() throws IOException {
+ if (isOpen()) {
+ return super.available();
+ } else {
+ throw new IOException("available() stream is closed");
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (isOpen()) {
+ return super.read();
+ } else {
+ throw new IOException("read() stream is closed");
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (isOpen()) {
+ return super.read(b, off, len);
+ } else {
+ throw new IOException("read([])[" + off + "," + len + "] stream is closed");
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ if (isOpen()) {
+ return super.skip(n);
+ } else {
+ throw new IOException("skip(" + n + ") stream is closed");
+ }
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (isOpen()) {
+ super.reset();
+ } else {
+ throw new IOException("reset() stream is closed");
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (open.getAndSet(false)) {
+ return; // debug breakpoint
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java
new file mode 100644
index 0000000..1047a5f
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A {@code /dev/null} implementation - always open
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EmptyInputStream extends InputStream {
+ public static final EmptyInputStream DEV_NULL = new EmptyInputStream();
+
+ public EmptyInputStream() {
+ super();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return (-1);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return (-1);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return 0L;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ throw new UnsupportedOperationException("mark(" + readlimit + ") called despite the fact that markSupported=" + markSupported());
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ // ignored
+ }
+}