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/12/14 10:14:05 UTC
[1/4] mina-sshd git commit: [SSHD-613] Support a 'callback' method
for session password identities
Repository: mina-sshd
Updated Branches:
refs/heads/master 1539faa20 -> a26ef1549
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
new file mode 100644
index 0000000..1a760c3
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.auth;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sshd.util.test.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 PasswordIdentityProviderTest extends BaseTestSupport {
+ public PasswordIdentityProviderTest() {
+ super();
+ }
+
+ @Test
+ public void testMultiProvider() {
+ String[][] values = {
+ { getClass().getSimpleName(), getCurrentTestName() },
+ { new Date(System.currentTimeMillis()).toString() },
+ { getClass().getPackage().getName() }
+ };
+ List<String> expected = new ArrayList<>();
+ Collection<PasswordIdentityProvider> providers = new LinkedList<>();
+ for (String[] va : values) {
+ Collection<String> passwords = Arrays.asList(va);
+ expected.addAll(passwords);
+
+ PasswordIdentityProvider p = PasswordIdentityProvider.Utils.wrap(passwords);
+ assertProviderContents("Wrapped", p, passwords);
+ providers.add(p);
+ }
+
+ PasswordIdentityProvider p = PasswordIdentityProvider.Utils.multiProvider(providers);
+ assertProviderContents("Multi", p, expected);
+ }
+
+ private static void assertProviderContents(String message, PasswordIdentityProvider p, Iterable<String> expected) {
+ assertNotNull(message + ": no provider", p);
+ assertEquals(message, expected, p.loadPasswords());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java b/sshd-core/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
index 1289f91..1a55b6e 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
@@ -37,6 +37,7 @@ import java.util.Objects;
import org.apache.sshd.common.config.keys.BuiltinIdentities;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
@@ -139,7 +140,7 @@ public class BuiltinClientIdentitiesWatcherTest extends BaseTestSupport {
}
}
- private static void testMultipleFilesWatch(String phase, KeyPairProvider watcher, Collection<? extends KeyPair> expected) {
+ private static void testMultipleFilesWatch(String phase, KeyIdentityProvider watcher, Collection<? extends KeyPair> expected) {
Collection<? extends KeyPair> actual = (Collection<? extends KeyPair>) watcher.loadKeys();
assertEquals(phase + ": mismatched sizes", GenericUtils.size(expected), GenericUtils.size(actual));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java b/sshd-core/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
index b4941de..e392e86 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
@@ -30,7 +30,7 @@ import java.util.Map;
import org.apache.sshd.common.config.keys.BuiltinIdentities;
import org.apache.sshd.common.config.keys.IdentityUtils;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.common.util.io.IoUtils;
@@ -88,7 +88,7 @@ public class ClientIdentityTest extends BaseTestSupport {
}
}
- KeyPairProvider provider = IdentityUtils.createKeyPairProvider(ids, true /* supported only */);
+ KeyIdentityProvider provider = IdentityUtils.createKeyPairProvider(ids, true /* supported only */);
assertNotNull("No provider generated", provider);
Iterable<KeyPair> keys = provider.loadKeys();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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
deleted file mode 100644
index 8dd5d66..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
+++ /dev/null
@@ -1,144 +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.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.channel.Channel;
-import org.apache.sshd.common.channel.ChannelListener;
-import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.random.JceRandomFactory;
-import org.apache.sshd.common.random.Random;
-import org.apache.sshd.common.random.SingletonRandomFactory;
-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.util.test.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);
- Mockito.when(client.getSessionListenerProxy()).thenReturn(new SessionListener() {
- @Override
- public void sessionEvent(Session session, Event event) {
- // ignored
- }
-
- @Override
- public void sessionCreated(Session session) {
- // ignored
- }
-
- @Override
- public void sessionClosed(Session session) {
- // ignored
- }
- });
- Mockito.when(client.getChannelListenerProxy()).thenReturn(new ChannelListener() {
- @Override
- public void channelOpenSuccess(Channel channel) {
- // ignored
- }
-
- @Override
- public void channelOpenFailure(Channel channel, Throwable reason) {
- // ignored
- }
-
- @Override
- public void channelInitialized(Channel channel) {
- // ignored
- }
-
- @Override
- public void channelClosed(Channel channel) {
- // ignored
- }
- });
- Factory<Random> randomFactory = new SingletonRandomFactory(JceRandomFactory.INSTANCE);
- Mockito.when(client.getRandomFactory()).thenReturn(randomFactory);
-
- List<ServiceFactory> serviceFactories = Arrays.asList(
- ClientUserAuthServiceFactory.INSTANCE,
- ClientConnectionServiceFactory.INSTANCE
- );
- Mockito.when(client.getServiceFactories()).thenReturn(serviceFactories);
-
- try (ClientSession session = new ClientSessionImpl(client, Mockito.mock(IoSession.class)) {
- @Override
- protected void sendClientIdentification() {
- // ignored
- }
-
- @Override
- protected byte[] sendKexInit() throws IOException {
- return GenericUtils.EMPTY_BYTE_ARRAY;
- }
-
- @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/13818de0/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java b/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
index 3aec0e7..88fc25c 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
@@ -20,7 +20,6 @@ package org.apache.sshd.common.auth;
import java.io.IOException;
import java.security.KeyPair;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
@@ -32,12 +31,12 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.auth.PasswordIdentityProvider;
import org.apache.sshd.client.auth.UserInteraction;
import org.apache.sshd.client.future.AuthFuture;
-import org.apache.sshd.client.session.ClientConnectionServiceFactory;
import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.session.Session;
@@ -45,10 +44,6 @@ 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;
-import org.apache.sshd.deprecated.ClientUserAuthServiceOld;
-import org.apache.sshd.deprecated.UserAuthKeyboardInteractive;
-import org.apache.sshd.deprecated.UserAuthPassword;
-import org.apache.sshd.deprecated.UserAuthPublicKey;
import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.UserAuthKeyboardInteractiveFactory;
@@ -59,6 +54,8 @@ import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.keyboard.PromptEntry;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
+import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
+import org.apache.sshd.server.auth.pubkey.RejectAllPublickeyAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.session.ServerSessionImpl;
import org.apache.sshd.server.session.SessionFactory;
@@ -71,9 +68,6 @@ import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class AuthenticationTest extends BaseTestSupport {
-
- private static final String WELCOME = "Welcome to SSHD";
-
private SshServer sshd;
private int port;
@@ -84,8 +78,6 @@ public class AuthenticationTest extends BaseTestSupport {
@Before
public void setUp() throws Exception {
sshd = setupTestServer();
- PropertyResolverUtils.updateProperty(sshd, ServerFactoryManager.WELCOME_BANNER, WELCOME);
- PropertyResolverUtils.updateProperty(sshd, ServerFactoryManager.AUTH_METHODS, "publickey,password publickey,keyboard-interactive");
sshd.setSessionFactory(new SessionFactory(sshd) {
@Override
protected ServerSessionImpl doCreateSession(IoSession ioSession) throws Exception {
@@ -117,11 +109,6 @@ public class AuthenticationTest extends BaseTestSupport {
@Test
public void testChangeUser() throws Exception {
try (SshClient client = setupTestClient()) {
- client.setServiceFactories(Arrays.asList(
- new ClientUserAuthServiceOld.Factory(),
- ClientConnectionServiceFactory.INSTANCE
- ));
-
client.start();
try (ClientSession s = client.connect(null, TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
@@ -130,8 +117,13 @@ public class AuthenticationTest extends BaseTestSupport {
Collection<ClientSession.ClientSessionEvent> result = s.waitFor(mask, TimeUnit.SECONDS.toMillis(11L));
assertFalse("Timeout while waiting on session events", result.contains(ClientSession.ClientSessionEvent.TIMEOUT));
+ String password = "the-password";
for (String username : new String[]{"user1", "user2"}) {
- assertAuthenticationResult(username, authPassword(s, username, "the-password"), false);
+ try {
+ assertAuthenticationResult(username, authPassword(s, username, password), false);
+ } finally {
+ s.removePasswordIdentity(password);
+ }
}
// Note that WAIT_AUTH flag should be false, but since the internal
@@ -249,18 +241,21 @@ public class AuthenticationTest extends BaseTestSupport {
@Test
public void testAuthPasswordOnly() throws Exception {
try (SshClient client = setupTestClient()) {
- client.setServiceFactories(Arrays.asList(
- new ClientUserAuthServiceOld.Factory(),
- ClientConnectionServiceFactory.INSTANCE
- ));
- client.start();
+ sshd.setPasswordAuthenticator(RejectAllPasswordAuthenticator.INSTANCE);
+ client.start();
try (ClientSession s = client.connect(null, TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
Collection<ClientSession.ClientSessionEvent> result =
s.waitFor(EnumSet.of(ClientSession.ClientSessionEvent.CLOSED, ClientSession.ClientSessionEvent.WAIT_AUTH),
TimeUnit.SECONDS.toMillis(11L));
assertFalse("Timeout while waiting for session", result.contains(ClientSession.ClientSessionEvent.TIMEOUT));
- assertAuthenticationResult(getCurrentTestName(), authPassword(s, getCurrentTestName(), getCurrentTestName()), false);
+
+ String password = getCurrentTestName();
+ try {
+ assertAuthenticationResult(getCurrentTestName(), authPassword(s, getCurrentTestName(), password), false);
+ } finally {
+ s.removePasswordIdentity(password);
+ }
} finally {
client.stop();
}
@@ -270,10 +265,9 @@ public class AuthenticationTest extends BaseTestSupport {
@Test
public void testAuthKeyPassword() throws Exception {
try (SshClient client = setupTestClient()) {
- client.setServiceFactories(Arrays.asList(
- new ClientUserAuthServiceOld.Factory(),
- ClientConnectionServiceFactory.INSTANCE
- ));
+ sshd.setPublickeyAuthenticator(RejectAllPublickeyAuthenticator.INSTANCE);
+ sshd.setKeyboardInteractiveAuthenticator(KeyboardInteractiveAuthenticator.NONE);
+
client.start();
try (ClientSession s = client.connect(null, TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
@@ -283,22 +277,28 @@ public class AuthenticationTest extends BaseTestSupport {
assertFalse("Timeout while waiting for session", result.contains(ClientSession.ClientSessionEvent.TIMEOUT));
KeyPair pair = createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
- assertAuthenticationResult(UserAuthMethodFactory.PUBLIC_KEY, authPublicKey(s, getCurrentTestName(), pair), false);
- assertAuthenticationResult(UserAuthMethodFactory.PASSWORD, authPassword(s, getCurrentTestName(), getCurrentTestName()), true);
+ try {
+ assertAuthenticationResult(UserAuthMethodFactory.PUBLIC_KEY, authPublicKey(s, getCurrentTestName(), pair), false);
+ } finally {
+ s.removePublicKeyIdentity(pair);
+ }
+
+ String password = getCurrentTestName();
+ try {
+ assertAuthenticationResult(UserAuthMethodFactory.PASSWORD, authPassword(s, getCurrentTestName(), password), true);
+ } finally {
+ s.removePasswordIdentity(password);
+ }
} finally {
client.stop();
}
}
}
- @Test
+ @Test // see SSHD-612
public void testAuthDefaultKeyInteractive() throws Exception {
try (SshClient client = setupTestClient()) {
- client.setServiceFactories(Arrays.asList(
- new ClientUserAuthServiceOld.Factory(),
- ClientConnectionServiceFactory.INSTANCE
- ));
-
+ sshd.setPublickeyAuthenticator(RejectAllPublickeyAuthenticator.INSTANCE);
sshd.setKeyboardInteractiveAuthenticator(new DefaultKeyboardInteractiveAuthenticator() {
@Override
public InteractiveChallenge generateChallenge(ServerSession session, String username, String lang, String subMethods) {
@@ -345,8 +345,17 @@ public class AuthenticationTest extends BaseTestSupport {
assertFalse("Timeout while waiting for session", result.contains(ClientSession.ClientSessionEvent.TIMEOUT));
KeyPair pair = createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
- assertAuthenticationResult(UserAuthMethodFactory.PUBLIC_KEY, authPublicKey(s, getCurrentTestName(), pair), false);
- assertAuthenticationResult(UserAuthMethodFactory.KB_INTERACTIVE, authInteractive(s, getCurrentTestName(), getCurrentTestName()), true);
+ try {
+ assertAuthenticationResult(UserAuthMethodFactory.PUBLIC_KEY, authPublicKey(s, getCurrentTestName(), pair), false);
+ } finally {
+ s.removePublicKeyIdentity(pair);
+ }
+
+ try {
+ assertAuthenticationResult(UserAuthMethodFactory.KB_INTERACTIVE, authInteractive(s, getCurrentTestName(), getCurrentTestName()), true);
+ } finally {
+ s.setUserInteraction(null);
+ }
} finally {
client.stop();
}
@@ -554,27 +563,77 @@ public class AuthenticationTest extends BaseTestSupport {
}
}
+ @Test
+ public void testPasswordIdentityProviderPropagation() throws Exception {
+ try (SshClient client = setupTestClient()) {
+ final List<String> passwords = Collections.singletonList(getCurrentTestName());
+ final AtomicInteger loadCount = new AtomicInteger(0);
+ PasswordIdentityProvider provider = new PasswordIdentityProvider() {
+ @Override
+ public Iterable<String> loadPasswords() {
+ loadCount.incrementAndGet();
+ outputDebugMessage("loadPasswords - count=%s", loadCount);
+ return passwords;
+ }
+ };
+ client.setPasswordIdentityProvider(provider);
+
+ client.start();
+ try (ClientSession s = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ s.auth().verify(11L, TimeUnit.SECONDS);
+ assertEquals("Mismatched load passwords count", 1, loadCount.get());
+ assertSame("Mismatched passwords identity provider", provider, s.getPasswordIdentityProvider());
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
private static void assertAuthenticationResult(String message, AuthFuture future, boolean expected) throws IOException {
assertTrue(message + ": failed to get result on time", future.await(5L, TimeUnit.SECONDS));
assertEquals(message + ": mismatched authentication result", expected, future.isSuccess());
}
- private AuthFuture authPassword(ClientSession s, String user, String pswd) throws IOException {
+ private static AuthFuture authPassword(ClientSession s, String user, String pswd) throws IOException {
s.setUsername(user);
- return s.getService(ClientUserAuthServiceOld.class)
- .auth(new UserAuthPassword(s, "ssh-connection", pswd));
+ s.addPasswordIdentity(pswd);
+ return s.auth();
}
- private AuthFuture authInteractive(ClientSession s, String user, String pswd) throws IOException {
+ private static AuthFuture authInteractive(final ClientSession s, String user, String pswd) throws IOException {
s.setUsername(user);
- return s.getService(ClientUserAuthServiceOld.class)
- .auth(new UserAuthKeyboardInteractive(s, "ssh-connection", pswd));
+ final String[] response = {pswd};
+ s.setUserInteraction(new UserInteraction() {
+ @Override
+ public void welcome(ClientSession session, String banner, String lang) {
+ // ignored
+ }
+
+ @Override
+ public boolean isInteractionAllowed(ClientSession session) {
+ return true;
+ }
+
+ @Override
+ public String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+ assertSame("Mismatched session instance", s, session);
+ assertEquals("Mismatched prompt size", 1, GenericUtils.length(prompt));
+ assertTrue("Mismatched prompt: " + prompt[0], prompt[0].toLowerCase().contains("password"));
+ return response;
+ }
+
+ @Override
+ public String getUpdatedPassword(ClientSession session, String prompt, String lang) {
+ throw new UnsupportedOperationException("Unexpected password update request");
+ }
+ });
+ return s.auth();
}
- private AuthFuture authPublicKey(ClientSession s, String user, KeyPair pair) throws IOException {
+ private static AuthFuture authPublicKey(ClientSession s, String user, KeyPair pair) throws IOException {
s.setUsername(user);
- return s.getService(ClientUserAuthServiceOld.class)
- .auth(new UserAuthPublicKey(s, "ssh-connection", pair));
+ s.addPublicKeyIdentity(pair);
+ return s.auth();
}
public static class TestSession extends ServerSessionImpl {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java b/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java
index 033be14..1dec6e4 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java
@@ -50,6 +50,7 @@ import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier;
import org.apache.sshd.common.Factory;
import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.keyprovider.KeyPairProviderHolder;
import org.apache.sshd.common.random.Random;
@@ -99,7 +100,7 @@ public class Utils {
return getFirstKeyPair(ValidateUtils.checkNotNull(holder, "No holder").getKeyPairProvider());
}
- public static KeyPair getFirstKeyPair(KeyPairProvider provider) {
+ public static KeyPair getFirstKeyPair(KeyIdentityProvider provider) {
ValidateUtils.checkNotNull(provider, "No key pair provider");
Iterable<? extends KeyPair> pairs = ValidateUtils.checkNotNull(provider.loadKeys(), "No loaded keys");
Iterator<? extends KeyPair> iter = ValidateUtils.checkNotNull(pairs.iterator(), "No keys iterator");
@@ -130,7 +131,7 @@ public class Utils {
}
}
- private static <P extends KeyPairProvider> P validateKeyPairProvider(P provider) {
+ private static <P extends KeyIdentityProvider> P validateKeyPairProvider(P provider) {
ValidateUtils.checkNotNull(provider, "No provider");
// get the I/O out of the way
[3/4] mina-sshd git commit: Use more conservative buffer size
allocations
Posted by lg...@apache.org.
Use more conservative buffer size allocations
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/fa724c2f
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/fa724c2f
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/fa724c2f
Branch: refs/heads/master
Commit: fa724c2f1406b5f834cf802f7a41b6fe5461e96e
Parents: 13818de
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Mon Dec 14 10:48:05 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Mon Dec 14 10:48:05 2015 +0200
----------------------------------------------------------------------
.../client/channel/AbstractClientChannel.java | 2 +-
.../sshd/client/channel/ChannelDirectTcpip.java | 11 +--
.../apache/sshd/client/channel/ChannelExec.java | 2 +-
.../sshd/client/channel/ChannelShell.java | 2 +-
.../sshd/client/channel/ChannelSubsystem.java | 5 +-
.../channel/PtyCapableChannelSession.java | 6 +-
.../org/apache/sshd/client/kex/DHGClient.java | 2 +-
.../org/apache/sshd/client/kex/DHGEXClient.java | 2 +-
.../client/session/AbstractClientSession.java | 74 +++++++-------------
.../client/session/ClientConnectionService.java | 2 +-
.../common/forward/DefaultTcpipForwarder.java | 17 +++--
.../sshd/common/forward/TcpipClientChannel.java | 12 +++-
.../sshd/server/x11/X11ForwardSupport.java | 8 ++-
13 files changed, 68 insertions(+), 77 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/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 78003c9..0cc419c 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
@@ -285,7 +285,7 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C
log.debug("Send SSH_MSG_CHANNEL_OPEN on channel {}", this);
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN);
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN, type.length() + Integer.SIZE);
buffer.putString(type);
buffer.putInt(getId());
buffer.putInt(localWindow.getSize());
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
index 921b419..4f1aa99 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
@@ -70,18 +70,21 @@ public class ChannelDirectTcpip extends AbstractClientChannel {
openFuture = new DefaultOpenFuture(lock);
if (log.isDebugEnabled()) {
- log.debug("Send SSH_MSG_CHANNEL_OPEN on channel {}", getId());
+ log.debug("open({}) SSH_MSG_CHANNEL_OPEN", this);
}
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN);
+ String remoteName = remote.getHostName();
+ String localName = local.getHostName();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN,
+ type.length() + remoteName.length() + localName.length() + Long.SIZE);
buffer.putString(type);
buffer.putInt(getId());
buffer.putInt(localWindow.getSize());
buffer.putInt(localWindow.getPacketSize());
- buffer.putString(remote.getHostName());
+ buffer.putString(remoteName);
buffer.putInt(remote.getPort());
- buffer.putString(local.getHostName());
+ buffer.putString(localName);
buffer.putInt(local.getPort());
writePacket(buffer);
return openFuture;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
index 813b292..4079cb6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
@@ -48,7 +48,7 @@ public class ChannelExec extends PtyCapableChannelSession {
}
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, command.length() + Integer.SIZE);
buffer.putInt(getRecipient());
buffer.putString("exec");
buffer.putBoolean(false);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
index fb7b94e..d67ac60 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
@@ -44,7 +44,7 @@ public class ChannelShell extends PtyCapableChannelSession {
}
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Integer.SIZE);
buffer.putInt(getRecipient());
buffer.putString("shell");
buffer.putBoolean(false);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSubsystem.java
index 1880990..37434da 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSubsystem.java
@@ -59,11 +59,12 @@ public class ChannelSubsystem extends ChannelSession {
}
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+ String systemName = getSubsystem();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, systemName.length() + Integer.SIZE);
buffer.putInt(getRecipient());
buffer.putString("subsystem");
buffer.putBoolean(false);
- buffer.putString(getSubsystem());
+ buffer.putString(systemName);
writePacket(buffer);
super.doOpen();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
index 75ce2a4..cce09af 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
@@ -211,7 +211,7 @@ public class PtyCapableChannelSession extends ChannelSession {
ptyWidth = width;
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Long.SIZE);
buffer.putInt(getRecipient());
buffer.putString("window-change");
buffer.putBoolean(false);
@@ -229,7 +229,7 @@ public class PtyCapableChannelSession extends ChannelSession {
log.debug("doOpenPty({}) Send agent forwarding request", this);
}
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Long.SIZE);
buffer.putInt(getRecipient());
buffer.putString("auth-agent-req@openssh.com");
buffer.putBoolean(false);
@@ -242,7 +242,7 @@ public class PtyCapableChannelSession extends ChannelSession {
this, ptyType, ptyColumns, ptyLines, ptyHeight, ptyWidth, ptyModes);
}
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Byte.MAX_VALUE);
buffer.putInt(getRecipient());
buffer.putString("pty-req");
buffer.putBoolean(false);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
index c676c35..1d16973 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
@@ -87,7 +87,7 @@ public class DHGClient extends AbstractDHClientKeyExchange {
if (log.isDebugEnabled()) {
log.debug("init({})[{}] Send SSH_MSG_KEXDH_INIT", this, s);
}
- Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEXDH_INIT);
+ Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEXDH_INIT, e.length + Integer.SIZE);
buffer.putMPInt(e);
s.writePacket(buffer);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
index c521749..36feac4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
@@ -92,7 +92,7 @@ public class DHGEXClient extends AbstractDHClientKeyExchange {
if (log.isDebugEnabled()) {
log.debug("init({}) Send SSH_MSG_KEX_DH_GEX_REQUEST", s);
}
- Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST);
+ Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST, Integer.SIZE);
buffer.putInt(min);
buffer.putInt(prf);
buffer.putInt(max);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
index 76d042b..d5b6066 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
@@ -22,11 +22,12 @@ package org.apache.sshd.client.session;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.security.KeyPair;
-import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
+import org.apache.sshd.client.auth.PasswordIdentityProvider;
import org.apache.sshd.client.auth.UserAuth;
import org.apache.sshd.client.auth.UserInteraction;
import org.apache.sshd.client.channel.ChannelDirectTcpip;
@@ -58,46 +59,17 @@ import org.apache.sshd.common.util.ValidateUtils;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public abstract class AbstractClientSession 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;
- }
- }
- };
-
- private final List<Object> identities = new ArrayList<>();
+ private final List<Object> identities = new CopyOnWriteArrayList<>();
+ private final AuthenticationIdentitiesProvider identitiesProvider;
private ServerKeyVerifier serverKeyVerifier;
private UserInteraction userInteraction;
+ private PasswordIdentityProvider passwordIdentityProvider;
private List<NamedFactory<UserAuth>> userAuthFactories;
private ScpTransferEventListener scpListener;
protected AbstractClientSession(ClientFactoryManager factoryManager, IoSession ioSession) {
super(false, factoryManager, ioSession);
+ identitiesProvider = AuthenticationIdentitiesProvider.Utils.wrap(identities);
}
@Override
@@ -135,8 +107,19 @@ public abstract class AbstractClientSession extends AbstractSession implements C
this.userAuthFactories = userAuthFactories; // OK if null/empty - inherit from parent
}
- protected List<Object> getRegisteredIdentities() {
- return identities;
+ @Override
+ public AuthenticationIdentitiesProvider getRegisteredIdentities() {
+ return identitiesProvider;
+ }
+
+ @Override
+ public PasswordIdentityProvider getPasswordIdentityProvider() {
+ return resolveEffectiveProvider(PasswordIdentityProvider.class, passwordIdentityProvider, getFactoryManager().getPasswordIdentityProvider());
+ }
+
+ @Override
+ public void setPasswordIdentityProvider(PasswordIdentityProvider provider) {
+ passwordIdentityProvider = provider;
}
@Override
@@ -153,7 +136,8 @@ public abstract class AbstractClientSession extends AbstractSession implements C
return null;
}
- int index = findIdentityIndex(PASSWORD_IDENTITY_COMPARATOR, password);
+ int index = AuthenticationIdentitiesProvider.Utils.findIdentityIndex(
+ identities, AuthenticationIdentitiesProvider.Utils.PASSWORD_IDENTITY_COMPARATOR, password);
if (index >= 0) {
return (String) identities.remove(index);
} else {
@@ -180,7 +164,8 @@ public abstract class AbstractClientSession extends AbstractSession implements C
return null;
}
- int index = findIdentityIndex(KEYPAIR_IDENTITY_COMPARATOR, kp);
+ int index = AuthenticationIdentitiesProvider.Utils.findIdentityIndex(
+ identities, AuthenticationIdentitiesProvider.Utils.KEYPAIR_IDENTITY_COMPARATOR, kp);
if (index >= 0) {
return (KeyPair) identities.remove(index);
} else {
@@ -188,17 +173,6 @@ public abstract class AbstractClientSession extends AbstractSession implements C
}
}
- 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
public ClientChannel createChannel(String type) throws IOException {
return createChannel(type, null);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
index db400aa..356efbf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
@@ -72,7 +72,7 @@ public class ClientConnectionService extends AbstractConnectionService {
protected void sendHeartBeat() {
String request = PropertyResolverUtils.getStringProperty(session, ClientFactoryManager.HEARTBEAT_REQUEST, ClientFactoryManager.DEFAULT_KEEP_ALIVE_HEARTBEAT_STRING);
try {
- Buffer buf = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST);
+ Buffer buf = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, request.length() + Byte.SIZE);
buf.putString(request);
buf.putBoolean(false);
session.writePacket(buf);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
index f84523e..803bf1b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
@@ -149,16 +149,18 @@ public class DefaultTcpipForwarder extends AbstractInnerCloseable implements Tcp
ValidateUtils.checkNotNull(local, "Local address is null");
ValidateUtils.checkNotNull(remote, "Remote address is null");
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST);
+ String remoteHost = remote.getHostName();
+ int remotePort = remote.getPort();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, remoteHost.length() + Long.SIZE);
buffer.putString("tcpip-forward");
buffer.putBoolean(true);
- buffer.putString(remote.getHostName());
- buffer.putInt(remote.getPort());
+ buffer.putString(remoteHost);
+ buffer.putInt(remotePort);
Buffer result = session.request(buffer);
if (result == null) {
throw new SshException("Tcpip forwarding request denied by server");
}
- int port = (remote.getPort() == 0) ? result.getInt() : remote.getPort();
+ int port = (remotePort == 0) ? result.getInt() : remote.getPort();
// TODO: Is it really safe to only store the local address after the request ?
SshdSocketAddress prev;
synchronized (remoteToLocal) {
@@ -169,7 +171,7 @@ public class DefaultTcpipForwarder extends AbstractInnerCloseable implements Tcp
throw new IOException("Multiple remote port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev);
}
- SshdSocketAddress bound = new SshdSocketAddress(remote.getHostName(), port);
+ SshdSocketAddress bound = new SshdSocketAddress(remoteHost, port);
if (log.isDebugEnabled()) {
log.debug("startRemotePortForwarding(" + remote + " -> " + local + "): " + bound);
}
@@ -189,10 +191,11 @@ public class DefaultTcpipForwarder extends AbstractInnerCloseable implements Tcp
log.debug("stopRemotePortForwarding(" + remote + ") cancel forwarding to " + bound);
}
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST);
+ String remoteHost = remote.getHostName();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, remoteHost.length() + Long.SIZE);
buffer.putString("cancel-tcpip-forward");
buffer.putBoolean(false);
- buffer.putString(remote.getHostName());
+ buffer.putString(remoteHost);
buffer.putInt(remote.getPort());
session.writePacket(buffer);
} else {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
index a1a8f78..a5b4281 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
@@ -19,6 +19,7 @@
package org.apache.sshd.common.forward;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.apache.sshd.client.channel.AbstractClientChannel;
@@ -90,14 +91,19 @@ public class TcpipClientChannel extends AbstractClientChannel {
}
Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN);
+ InetAddress srcAddress = src.getAddress();
+ String srcHost = srcAddress.getHostAddress();
+ InetAddress dstAddress = dst.getAddress();
+ String dstHost = dstAddress.getHostAddress();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN,
+ type.length() + srcHost.length() + dstHost.length() + Long.SIZE);
buffer.putString(type);
buffer.putInt(getId());
buffer.putInt(localWindow.getSize());
buffer.putInt(localWindow.getPacketSize());
- buffer.putString(dst.getAddress().getHostAddress());
+ buffer.putString(dstHost);
buffer.putInt(dst.getPort());
- buffer.putString(src.getAddress().getHostAddress());
+ buffer.putString(srcHost);
buffer.putInt(src.getPort());
writePacket(buffer);
return openFuture;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/fa724c2f/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java b/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
index afa8735..96f0a43 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
@@ -21,6 +21,7 @@ package org.apache.sshd.server.x11;
import java.io.IOException;
import java.io.OutputStream;
import java.net.BindException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
@@ -201,12 +202,15 @@ public class X11ForwardSupport extends AbstractInnerCloseable implements IoHandl
log.debug("open({}) SSH_MSG_CHANNEL_OPEN", this);
}
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN);
+ InetAddress remoteAddress = remote.getAddress();
+ String remoteHost = remoteAddress.getHostAddress();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN,
+ remoteHost.length() + type.length() + Integer.SIZE);
buffer.putString(type);
buffer.putInt(getId());
buffer.putInt(localWindow.getSize());
buffer.putInt(localWindow.getPacketSize());
- buffer.putString(remote.getAddress().getHostAddress());
+ buffer.putString(remoteHost);
buffer.putInt(remote.getPort());
writePacket(buffer);
return openFuture;
[2/4] mina-sshd git commit: [SSHD-613] Support a 'callback' method
for session password identities
Posted by lg...@apache.org.
[SSHD-613] Support a 'callback' method for session password identities
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/13818de0
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/13818de0
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/13818de0
Branch: refs/heads/master
Commit: 13818de0c58decf8bf7e04f47517d35f9e6eb1c9
Parents: 1539faa
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Mon Dec 14 10:47:46 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Mon Dec 14 10:47:46 2015 +0200
----------------------------------------------------------------------
pom.xml | 2 +-
.../client/ClientAuthenticationManager.java | 41 +++-
.../java/org/apache/sshd/client/SshClient.java | 144 +++++++++++--
.../sshd/client/auth/AbstractUserAuth.java | 4 +-
.../auth/AuthenticationIdentitiesProvider.java | 141 +++++++++++++
.../client/auth/PasswordIdentityProvider.java | 146 ++++++++++++++
.../org/apache/sshd/client/auth/UserAuth.java | 5 +-
.../auth/UserAuthKeyboardInteractive.java | 16 +-
.../sshd/client/auth/UserAuthPassword.java | 41 ++--
.../sshd/client/auth/UserAuthPublicKey.java | 100 +++------
.../client/auth/pubkey/KeyAgentIdentity.java | 19 +-
.../client/auth/pubkey/KeyPairIdentity.java | 10 +-
.../auth/pubkey/SessionKeyPairIterator.java | 60 ++++++
.../auth/pubkey/SshAgentPublicKeyIterator.java | 73 +++++++
.../auth/pubkey/UserAuthPublicKeyIterator.java | 147 ++++++++++++++
.../sshd/client/session/ClientSession.java | 30 +--
.../sshd/client/session/ClientSessionImpl.java | 16 +-
.../client/session/ClientUserAuthService.java | 9 +-
.../common/keyprovider/KeyIdentityProvider.java | 149 ++++++++++++++
.../common/keyprovider/KeyPairProvider.java | 9 +-
.../apache/sshd/common/util/GenericUtils.java | 73 +++++++
.../server/session/ServerUserAuthService.java | 3 +-
.../client/ClientAuthenticationManagerTest.java | 201 +++++++++++++++++++
.../java/org/apache/sshd/client/ClientTest.java | 4 +-
.../auth/PasswordIdentityProviderTest.java | 69 +++++++
.../BuiltinClientIdentitiesWatcherTest.java | 3 +-
.../client/config/keys/ClientIdentityTest.java | 4 +-
.../client/session/ClientSessionImplTest.java | 144 -------------
.../sshd/common/auth/AuthenticationTest.java | 153 +++++++++-----
.../java/org/apache/sshd/util/test/Utils.java | 5 +-
30 files changed, 1435 insertions(+), 386 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 18697cf..d1fe10e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -530,7 +530,7 @@
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="AnonInnerLength">
- <property name="max" value="40" />
+ <property name="max" value="50" />
</module>
<module name="ExecutableStatementCount">
<property name="max" value="100" />
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
index de41b9a..ab1f154 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
@@ -19,18 +19,22 @@
package org.apache.sshd.client;
+import java.security.KeyPair;
import java.util.List;
+import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
+import org.apache.sshd.client.auth.PasswordIdentityProvider;
import org.apache.sshd.client.auth.UserAuth;
import org.apache.sshd.client.auth.UserInteraction;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.keyprovider.KeyPairProviderHolder;
/**
* Holds information required for the client to perform authentication with the server
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface ClientAuthenticationManager {
+public interface ClientAuthenticationManager extends KeyPairProviderHolder {
/**
* Ordered comma separated list of authentications methods.
@@ -51,6 +55,41 @@ public interface ClientAuthenticationManager {
*/
int DEFAULT_PASSWORD_PROMPTS = 3;
+ AuthenticationIdentitiesProvider getRegisteredIdentities();
+
+ PasswordIdentityProvider getPasswordIdentityProvider();
+ void setPasswordIdentityProvider(PasswordIdentityProvider provider);
+
+ /**
+ * @param password Password to be added - may not be {@code null}/empty.
+ * <B>Note:</B> this password is <U>in addition</U> to whatever passwords
+ * are available via the {@link PasswordIdentityProvider} (if any)
+ */
+ 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}
+ * <B>Note:</B> this key is <U>in addition</U> to whatever keys
+ * are available via the {@link org.apache.sshd.common.keyprovider.KeyIdentityProvider} (if any)
+ */
+ 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);
+
/**
* Retrieve the server key verifier to be used to check the key when connecting
* to an SSH server.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
index 9081d82..e64b4cb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
@@ -38,9 +38,11 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
@@ -49,6 +51,8 @@ import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.apache.sshd.agent.SshAgentFactory;
+import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
+import org.apache.sshd.client.auth.PasswordIdentityProvider;
import org.apache.sshd.client.auth.UserAuth;
import org.apache.sshd.client.auth.UserAuthKeyboardInteractiveFactory;
import org.apache.sshd.client.auth.UserAuthPasswordFactory;
@@ -178,9 +182,12 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
private HostConfigEntryResolver hostConfigEntryResolver;
private ClientIdentityLoader clientIdentityLoader;
private FilePasswordProvider filePasswordProvider;
+ private PasswordIdentityProvider passwordIdentityProvider;
+ private final List<Object> identities = new CopyOnWriteArrayList<>();
+ private final AuthenticationIdentitiesProvider identitiesProvider;
public SshClient() {
- super();
+ identitiesProvider = AuthenticationIdentitiesProvider.Utils.wrap(identities);
}
public SessionFactory getSessionFactory() {
@@ -252,6 +259,72 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
}
@Override
+ public AuthenticationIdentitiesProvider getRegisteredIdentities() {
+ return identitiesProvider;
+ }
+
+ @Override
+ public PasswordIdentityProvider getPasswordIdentityProvider() {
+ return passwordIdentityProvider;
+ }
+
+ @Override
+ public void setPasswordIdentityProvider(PasswordIdentityProvider provider) {
+ passwordIdentityProvider = provider;
+ }
+
+ @Override
+ public void addPasswordIdentity(String password) {
+ identities.add(ValidateUtils.checkNotNullAndNotEmpty(password, "No password provided"));
+ if (log.isDebugEnabled()) { // don't show the password in the log
+ log.debug("addPasswordIdentity({}) {}", this, KeyUtils.getFingerPrint(password));
+ }
+ }
+
+ @Override
+ public String removePasswordIdentity(String password) {
+ if (GenericUtils.isEmpty(password)) {
+ return null;
+ }
+
+ int index = AuthenticationIdentitiesProvider.Utils.findIdentityIndex(
+ identities, AuthenticationIdentitiesProvider.Utils.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");
+ ValidateUtils.checkNotNull(kp.getPublic(), "No public key");
+ ValidateUtils.checkNotNull(kp.getPrivate(), "No private key");
+
+ identities.add(kp);
+
+ if (log.isDebugEnabled()) {
+ log.debug("addPublicKeyIdentity({}) {}", this, KeyUtils.getFingerPrint(kp.getPublic()));
+ }
+ }
+
+ @Override
+ public KeyPair removePublicKeyIdentity(KeyPair kp) {
+ if (kp == null) {
+ return null;
+ }
+
+ int index = AuthenticationIdentitiesProvider.Utils.findIdentityIndex(
+ identities, AuthenticationIdentitiesProvider.Utils.KEYPAIR_IDENTITY_COMPARATOR, kp);
+ if (index >= 0) {
+ return (KeyPair) identities.remove(index);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
protected void checkConfig() {
super.checkConfig();
@@ -501,29 +574,18 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
session.setUsername(username);
if (useDefaultIdentities) {
- // check if session listener intervened
- KeyPairProvider kpSession = session.getKeyPairProvider();
- KeyPairProvider kpClient = ValidateUtils.checkNotNull(getKeyPairProvider(), "No default key-pair provider");
- if (kpSession == null) {
- session.setKeyPairProvider(kpClient);
- } else {
- if (kpSession != kpClient) {
- if (log.isDebugEnabled()) {
- log.debug("onConnectOperationComplete({}) key-pair provider override", session);
- }
- }
- }
+ setupDefaultSessionIdentities(session);
}
int numIds = GenericUtils.size(identities);
if (numIds > 0) {
if (log.isDebugEnabled()) {
- log.debug("onConnectOperationComplete({}@{}) adding {} identities", username, address, numIds);
+ log.debug("onConnectOperationComplete({}) adding {} identities", session, numIds);
}
for (KeyPair kp : identities) {
if (log.isTraceEnabled()) {
- log.trace("onConnectOperationComplete({}@{}) add identity type={}, fingerprint={}",
- username, address, KeyUtils.getKeyType(kp), KeyUtils.getFingerPrint(kp.getPublic()));
+ log.trace("onConnectOperationComplete({}) add identity type={}, fingerprint={}",
+ session, KeyUtils.getKeyType(kp), KeyUtils.getFingerPrint(kp.getPublic()));
}
session.addPublicKeyIdentity(kp);
}
@@ -532,6 +594,56 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
connectFuture.setSession(session);
}
+ protected void setupDefaultSessionIdentities(ClientSession session) {
+ // check if session listener intervened
+ KeyPairProvider kpSession = session.getKeyPairProvider();
+ KeyPairProvider kpClient = getKeyPairProvider();
+ if (kpSession == null) {
+ session.setKeyPairProvider(kpClient);
+ } else {
+ if (kpSession != kpClient) {
+ if (log.isDebugEnabled()) {
+ log.debug("setupDefaultSessionIdentities({}) key-pair provider override", session);
+ }
+ }
+ }
+
+ PasswordIdentityProvider passSession = session.getPasswordIdentityProvider();
+ PasswordIdentityProvider passClient = getPasswordIdentityProvider();
+ if (passSession == null) {
+ session.setPasswordIdentityProvider(passClient);
+ } else {
+ if (passSession != passClient) {
+ if (log.isDebugEnabled()) {
+ log.debug("setupDefaultSessionIdentities({}) password provider override", session);
+ }
+ }
+ }
+
+ AuthenticationIdentitiesProvider idsClient = getRegisteredIdentities();
+ for (Iterator<?> iter = GenericUtils.iteratorOf((idsClient == null) ? null : idsClient.loadIdentities()); iter.hasNext();) {
+ Object id = iter.next();
+ if (id instanceof String) {
+ if (log.isTraceEnabled()) {
+ log.trace("setupDefaultSessionIdentities({}) add password fingerprint={}",
+ session, KeyUtils.getFingerPrint(id.toString()));
+ }
+ session.addPasswordIdentity((String) id);
+ } else if (id instanceof KeyPair) {
+ KeyPair kp = (KeyPair) id;
+ if (log.isTraceEnabled()) {
+ log.trace("setupDefaultSessionIdentities({}) add identity type={}, fingerprint={}",
+ session, KeyUtils.getKeyType(kp), KeyUtils.getFingerPrint(kp.getPublic()));
+ }
+ session.addPublicKeyIdentity(kp);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("setupDefaultSessionIdentities({}) ignored identity={}", session, id);
+ }
+ }
+ }
+ }
+
protected IoConnector createConnector() {
return getIoServiceFactory().createConnector(getSessionFactory());
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
index 7cc3348..9b22eb7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
@@ -19,8 +19,6 @@
package org.apache.sshd.client.auth;
-import java.util.Collection;
-
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
@@ -58,7 +56,7 @@ public abstract class AbstractUserAuth extends AbstractLoggingBean implements Us
}
@Override
- public void init(ClientSession session, String service, Collection<?> identities) throws Exception {
+ public void init(ClientSession session, String service) throws Exception {
this.clientSession = ValidateUtils.checkNotNull(session, "No client session");
this.service = ValidateUtils.checkNotNullAndNotEmpty(service, "No service");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
new file mode 100644
index 0000000..2d0637b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
@@ -0,0 +1,141 @@
+/*
+ * 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.auth;
+
+import java.security.KeyPair;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface AuthenticationIdentitiesProvider extends KeyIdentityProvider, PasswordIdentityProvider {
+ /**
+ * @return All the currently available identities - passwords, keys, etc...
+ */
+ Iterable<?> loadIdentities();
+
+ /**
+ * A helper class for identity provider related operations
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ // CHECKSTYLE:OFF
+ final class Utils {
+ // CHECKSTYLE:ON
+ /**
+ * 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;
+ }
+ }
+ };
+
+ private Utils() {
+ throw new UnsupportedOperationException("No instance allowed");
+ }
+
+ public static int findIdentityIndex(List<?> identities, 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;
+ }
+
+ /**
+ * @param identities The {@link Iterable} identities - OK if {@code null}/empty
+ * @return An {@link AuthenticationIdentitiesProvider} wrapping the identities
+ */
+ public static AuthenticationIdentitiesProvider wrap(final Iterable<?> identities) {
+ return new AuthenticationIdentitiesProvider() {
+ @Override
+ public Iterable<KeyPair> loadKeys() {
+ return selectIdentities(KeyPair.class);
+ }
+
+ @Override
+ public Iterable<String> loadPasswords() {
+ return selectIdentities(String.class);
+ }
+
+ @Override
+ public Iterable<?> loadIdentities() {
+ return selectIdentities(Object.class);
+ }
+
+ // NOTE: returns a NEW Collection on every call so that the original
+ // identities remain unchanged
+ private <T> Collection<T> selectIdentities(Class<T> type) {
+ Collection<T> matches = null;
+ for (Iterator<?> iter = GenericUtils.iteratorOf(identities); iter.hasNext();) {
+ Object o = iter.next();
+ Class<?> t = o.getClass();
+ if (!type.isAssignableFrom(t)) {
+ continue;
+ }
+
+ if (matches == null) {
+ matches = new LinkedList<T>();
+ }
+
+ matches.add(type.cast(o));
+ }
+
+ return (matches == null) ? Collections.<T>emptyList() : matches;
+ }
+ };
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
new file mode 100644
index 0000000..26811db
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
@@ -0,0 +1,146 @@
+/*
+ * 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.auth;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Supplier;
+import org.apache.sshd.common.util.Transformer;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface PasswordIdentityProvider {
+ PasswordIdentityProvider EMPTY_PASSWORDS_PROVIDER = new PasswordIdentityProvider() {
+ @Override
+ public Iterable<String> loadPasswords() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public String toString() {
+ return "EMPTY";
+ }
+ };
+
+ /**
+ * @return The currently available passwords - never {@code null}
+ */
+ Iterable<String> loadPasswords();
+
+ /**
+ * A helper class for password identity provider related operations
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ // CHECKSTYLE:OFF
+ final class Utils {
+ // CHECKSTYLE:ON
+ public static final Transformer<PasswordIdentityProvider, Iterable<String>> LOADER =
+ new Transformer<PasswordIdentityProvider, Iterable<String>>() {
+ @Override
+ public Iterable<String> transform(PasswordIdentityProvider p) {
+ return (p == null) ? null : p.loadPasswords();
+ }
+ };
+
+ private Utils() {
+ throw new UnsupportedOperationException("No instance allowed");
+ }
+
+ public static Iterator<String> iteratorOf(ClientSession session) {
+ ValidateUtils.checkNotNull(session, "No session");
+ return iteratorOf(session.getRegisteredIdentities(), session.getPasswordIdentityProvider());
+ }
+
+ public static Iterator<String> iteratorOf(PasswordIdentityProvider identities, PasswordIdentityProvider passwords) {
+ return iteratorOf(resolvePasswordIdentityProvider(identities, passwords));
+ }
+
+ /**
+ * Resolves a non-{@code null} iterator of the available passwords
+ *
+ * @param provider The {@link PasswordIdentityProvider} - ignored if {@code null}
+ * @return A non-{@code null} iterator - which may be empty if no provider or no passwords
+ */
+ public static Iterator<String> iteratorOf(PasswordIdentityProvider provider) {
+ return GenericUtils.iteratorOf((provider == null) ? null : provider.loadPasswords());
+ }
+
+ public static PasswordIdentityProvider resolvePasswordIdentityProvider(PasswordIdentityProvider identities, PasswordIdentityProvider passwords) {
+ if ((passwords == null) || (identities == passwords)) {
+ return identities;
+ } else if (identities == null) {
+ return passwords;
+ } else {
+ return multiProvider(identities, passwords);
+ }
+ }
+
+ public static PasswordIdentityProvider multiProvider(PasswordIdentityProvider ... providers) {
+ return multiProvider(GenericUtils.isEmpty(providers) ? Collections.<PasswordIdentityProvider>emptyList() : Arrays.asList(providers));
+ }
+
+ public static PasswordIdentityProvider multiProvider(Collection<? extends PasswordIdentityProvider> providers) {
+ return wrap(iterableOf(providers));
+ }
+
+ public static Iterable<String> iterableOf(Collection<? extends PasswordIdentityProvider> providers) {
+ if (GenericUtils.isEmpty(providers)) {
+ return Collections.emptyList();
+ }
+
+ Collection<Supplier<Iterable<String>>> suppliers = new ArrayList<Supplier<Iterable<String>>>(providers.size());
+ for (final PasswordIdentityProvider p : providers) {
+ if (p == null) {
+ continue;
+ }
+
+ suppliers.add(new Supplier<Iterable<String>>() {
+ @Override
+ public Iterable<String> get() {
+ return p.loadPasswords();
+ }
+ });
+ }
+
+ if (GenericUtils.isEmpty(suppliers)) {
+ return Collections.emptyList();
+ }
+
+ return GenericUtils.multiIterableSuppliers(suppliers);
+ }
+
+ public static PasswordIdentityProvider wrap(final Iterable<String> passwords) {
+ return new PasswordIdentityProvider() {
+ @Override
+ public Iterable<String> loadPasswords() {
+ return passwords;
+ }
+ };
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuth.java
index 44a111a..633e761 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuth.java
@@ -18,8 +18,6 @@
*/
package org.apache.sshd.client.auth;
-import java.util.Collection;
-
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.client.session.ClientSessionHolder;
import org.apache.sshd.common.auth.UserAuthInstance;
@@ -34,10 +32,9 @@ public interface UserAuth extends ClientSessionHolder, UserAuthInstance<ClientSe
/**
* @param session The {@link ClientSession}
* @param service The requesting service name
- * @param identities The currently available identities - e.g., password, keys, etc.
* @throws Exception If failed to initialize the mechanism
*/
- void init(ClientSession session, String service, Collection<?> identities) throws Exception;
+ void init(ClientSession session, String service) throws Exception;
/**
* @param buffer The {@link Buffer} to process - {@code null} if not a response buffer,
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 1863379..9327236 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
@@ -18,11 +18,8 @@
*/
package org.apache.sshd.client.auth;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -87,16 +84,9 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
}
@Override
- public void init(ClientSession session, String service, Collection<?> identities) throws Exception {
- super.init(session, service, identities);
-
- List<String> pwds = new ArrayList<>();
- for (Object o : identities) {
- if (o instanceof String) {
- pwds.add((String) o);
- }
- }
- passwords = pwds.iterator();
+ public void init(ClientSession session, String service) throws Exception {
+ super.init(session, service);
+ passwords = PasswordIdentityProvider.Utils.iteratorOf(session);
maxTrials = PropertyResolverUtils.getIntProperty(session, ClientAuthenticationManager.PASSWORD_PROMPTS, ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS);
ValidateUtils.checkTrue(maxTrials > 0, "Non-positive max. trials: %d", maxTrials);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 449d10a..d4ed6f7 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
@@ -19,10 +19,7 @@
package org.apache.sshd.client.auth;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import java.util.Objects;
import org.apache.sshd.client.session.ClientSession;
@@ -32,8 +29,7 @@ import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
/**
- * TODO Add javadoc
- *
+ * Implements the "password" authentication mechanism
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class UserAuthPassword extends AbstractUserAuth {
@@ -47,34 +43,27 @@ public class UserAuthPassword extends AbstractUserAuth {
}
@Override
- public void init(ClientSession session, String service, Collection<?> identities) throws Exception {
- super.init(session, service, identities);
-
- List<String> pwds = new ArrayList<>();
- for (Object o : identities) {
- if (o instanceof String) {
- pwds.add((String) o);
- }
- }
- this.passwords = pwds.iterator();
+ public void init(ClientSession session, String service) throws Exception {
+ super.init(session, service);
+ passwords = PasswordIdentityProvider.Utils.iteratorOf(session);
}
@Override
protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
- if (passwords.hasNext()) {
- current = passwords.next();
- String username = session.getUsername();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
- username.length() + service.length() + getName().length() + current.length() + Integer.SIZE);
- sendPassword(buffer, session, current, current);
- return true;
- }
+ if ((passwords == null) || (!passwords.hasNext())) {
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] no more passwords to send", session, service);
+ }
- if (log.isDebugEnabled()) {
- log.debug("sendAuthDataRequest({})[{}] no more passwords to send", session, service);
+ return false;
}
- return false;
+ current = passwords.next();
+ String username = session.getUsername();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
+ username.length() + service.length() + getName().length() + current.length() + Integer.SIZE);
+ sendPassword(buffer, session, current, current);
+ return true;
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 8cbfddf..991c0d7 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
@@ -18,41 +18,27 @@
*/
package org.apache.sshd.client.auth;
+import java.io.Closeable;
import java.io.IOException;
-import java.security.KeyPair;
import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
-
-import org.apache.sshd.agent.SshAgent;
-import org.apache.sshd.agent.SshAgentFactory;
-import org.apache.sshd.client.auth.pubkey.KeyAgentIdentity;
-import org.apache.sshd.client.auth.pubkey.KeyPairIdentity;
import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator;
import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.kex.KeyExchange;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.Pair;
-import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
/**
- * TODO Add javadoc
- *
+ * Implements the "publickey" authentication mechanism
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class UserAuthPublicKey extends AbstractUserAuth {
public static final String NAME = UserAuthPublicKeyFactory.NAME;
- private SshAgent agent;
private Iterator<PublicKeyIdentity> keys;
private PublicKeyIdentity current;
@@ -61,51 +47,15 @@ public class UserAuthPublicKey extends AbstractUserAuth {
}
@Override
- public void init(ClientSession session, String service, Collection<?> identities) throws Exception {
- super.init(session, service, identities);
-
- List<PublicKeyIdentity> ids = new ArrayList<>();
- for (Object o : identities) {
- if (o instanceof KeyPair) {
- ids.add(new KeyPairIdentity(session, (KeyPair) o));
- }
- }
-
- FactoryManager manager = ValidateUtils.checkNotNull(session.getFactoryManager(), "No session factory manager");
- SshAgentFactory factory = manager.getAgentFactory();
- if (factory != null) {
- this.agent = ValidateUtils.checkNotNull(factory.createClient(manager), "No agent created");
- Collection<Pair<PublicKey, String>> agentKeys = agent.getIdentities();
- if (GenericUtils.size(agentKeys) > 0) {
- for (Pair<PublicKey, String> pair : agentKeys) {
- PublicKey key = pair.getFirst();
- if (log.isDebugEnabled()) {
- log.debug("init({}) add agent public key type={}: comment={}, fingerprint={}",
- session, pair.getSecond(), KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key));
- }
- ids.add(new KeyAgentIdentity(agent, key));
- }
- }
- } else {
- this.agent = null;
- }
-
- KeyPairProvider provider = session.getKeyPairProvider();
- if (provider != null) {
- for (KeyPair kp : provider.loadKeys()) {
- if (log.isDebugEnabled()) {
- log.debug("init({}) add provider public key type={}: {}",
- session, KeyUtils.getKeyType(kp), KeyUtils.getFingerPrint(kp.getPublic()));
- }
- ids.add(new KeyPairIdentity(session, kp));
- }
- }
- this.keys = ids.iterator();
+ public void init(ClientSession session, String service) throws Exception {
+ super.init(session, service);
+ releaseKeys(); // just making sure in case multiple calls to the method
+ keys = new UserAuthPublicKeyIterator(session);
}
@Override
protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
- if (!keys.hasNext()) {
+ if ((keys == null) || (!keys.hasNext())) {
if (log.isDebugEnabled()) {
log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
}
@@ -114,6 +64,10 @@ public class UserAuthPublicKey extends AbstractUserAuth {
}
current = keys.next();
+ if (log.isTraceEnabled()) {
+ log.trace("sendAuthDataRequest({})[{}] current key details: {}", session, service, current);
+ }
+
PublicKey key = current.getPublicKey();
String algo = KeyUtils.getKeyType(key);
String name = getName();
@@ -121,7 +75,6 @@ public class UserAuthPublicKey extends AbstractUserAuth {
log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST request {} type={} - fingerprint={}",
session, service, name, algo, KeyUtils.getFingerPrint(key));
}
-
Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
buffer.putString(session.getUsername());
buffer.putString(service);
@@ -145,7 +98,7 @@ public class UserAuthPublicKey extends AbstractUserAuth {
String algo = KeyUtils.getKeyType(key);
String name = getName();
if (log.isDebugEnabled()) {
- log.debug("processAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_PK_OK reply for {}: type={}, fingerprint={}",
+ log.debug("processAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_PK_OK reply {} type={} - fingerprint={}",
session, service, name, algo, KeyUtils.getFingerPrint(key));
}
@@ -181,16 +134,25 @@ public class UserAuthPublicKey extends AbstractUserAuth {
@Override
public void destroy() {
- if (agent != null) {
- try {
- agent.close();
- } catch (IOException e) {
- throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
- } finally {
- agent = null;
- }
+ try {
+ releaseKeys();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
+ }
+
+ super.destroy(); // for logging
+ }
- super.destroy(); // for logging
+ protected void releaseKeys() throws IOException {
+ try {
+ if (keys instanceof Closeable) {
+ if (log.isTraceEnabled()) {
+ log.trace("releaseKeys({}) closing {}", getClientSession(), keys);
+ }
+ ((Closeable) keys).close();
+ }
+ } finally {
+ keys = null;
}
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyAgentIdentity.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyAgentIdentity.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyAgentIdentity.java
index e8f09a3..a583e39 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyAgentIdentity.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyAgentIdentity.java
@@ -21,6 +21,7 @@ package org.apache.sshd.client.auth.pubkey;
import java.security.PublicKey;
import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.util.ValidateUtils;
/**
@@ -31,10 +32,12 @@ import org.apache.sshd.common.util.ValidateUtils;
public class KeyAgentIdentity implements PublicKeyIdentity {
private final SshAgent agent;
private final PublicKey key;
+ private final String comment;
- public KeyAgentIdentity(SshAgent agent, PublicKey key) {
+ public KeyAgentIdentity(SshAgent agent, PublicKey key, String comment) {
this.agent = ValidateUtils.checkNotNull(agent, "No signing agent");
this.key = ValidateUtils.checkNotNull(key, "No public key");
+ this.comment = comment;
}
@Override
@@ -42,8 +45,20 @@ public class KeyAgentIdentity implements PublicKeyIdentity {
return key;
}
+ public String getComment() {
+ return comment;
+ }
+
@Override
public byte[] sign(byte[] data) throws Exception {
- return agent.sign(key, data);
+ return agent.sign(getPublicKey(), data);
+ }
+
+ @Override
+ public String toString() {
+ PublicKey pubKey = getPublicKey();
+ return getClass().getSimpleName() + "[" + KeyUtils.getKeyType(pubKey) + "]"
+ + " fingerprint=" + KeyUtils.getFingerPrint(pubKey)
+ + ", comment=" + getComment();
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyPairIdentity.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyPairIdentity.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyPairIdentity.java
index e84195f..f24b65f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyPairIdentity.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/KeyPairIdentity.java
@@ -48,7 +48,7 @@ public class KeyPairIdentity implements PublicKeyIdentity {
@Override
public byte[] sign(byte[] data) throws Exception {
- String keyType = KeyUtils.getKeyType(pair);
+ String keyType = KeyUtils.getKeyType(getPublicKey());
Signature verifier = ValidateUtils.checkNotNull(
NamedFactory.Utils.create(manager.getSignatureFactories(), keyType),
"No signer could be located for key type=%s",
@@ -57,4 +57,12 @@ public class KeyPairIdentity implements PublicKeyIdentity {
verifier.update(data, 0, data.length);
return verifier.sign();
}
+
+ @Override
+ public String toString() {
+ PublicKey pubKey = getPublicKey();
+ return getClass().getSimpleName() + "[" + manager + "]"
+ + " type=" + KeyUtils.getKeyType(pubKey)
+ + ", fingerprint=" + KeyUtils.getFingerPrint(pubKey);
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SessionKeyPairIterator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SessionKeyPairIterator.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SessionKeyPairIterator.java
new file mode 100644
index 0000000..5ff50b4
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SessionKeyPairIterator.java
@@ -0,0 +1,60 @@
+/*
+ * 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.auth.pubkey;
+
+import java.security.KeyPair;
+import java.util.Iterator;
+
+import org.apache.sshd.common.kex.KexFactoryManager;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SessionKeyPairIterator implements Iterator<KeyPairIdentity> {
+
+ private final KexFactoryManager manager;
+ private final Iterator<KeyPair> keys;
+
+ public SessionKeyPairIterator(KexFactoryManager manager, Iterator<KeyPair> keys) {
+ this.manager = ValidateUtils.checkNotNull(manager, "No KEX factory manager");
+ this.keys = keys; // OK if null
+ }
+
+ @Override
+ public boolean hasNext() {
+ return (keys != null) && keys.hasNext();
+ }
+
+ @Override
+ public KeyPairIdentity next() {
+ return new KeyPairIdentity(manager, keys.next());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("No removal allowed");
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + manager + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SshAgentPublicKeyIterator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SshAgentPublicKeyIterator.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SshAgentPublicKeyIterator.java
new file mode 100644
index 0000000..8becc4b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/SshAgentPublicKeyIterator.java
@@ -0,0 +1,73 @@
+/*
+ * 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.auth.pubkey;
+
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.Iterator;
+
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.session.ClientSessionHolder;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SshAgentPublicKeyIterator implements Iterator<KeyAgentIdentity>, ClientSessionHolder {
+ private final ClientSession clientSession;
+ private final SshAgent agent;
+ private final Iterator<Pair<PublicKey, String>> keys;
+
+ public SshAgentPublicKeyIterator(ClientSession session, SshAgent agent) throws IOException {
+ this.clientSession = ValidateUtils.checkNotNull(session, "No session");
+ this.agent = ValidateUtils.checkNotNull(agent, "No agent");
+ keys = GenericUtils.iteratorOf(agent.getIdentities());
+ }
+
+ @Override
+ public ClientSession getClientSession() {
+ return clientSession;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return (keys != null) && keys.hasNext();
+ }
+
+ @Override
+ public KeyAgentIdentity next() {
+ Pair<PublicKey, String> kp = keys.next();
+ return new KeyAgentIdentity(agent, kp.getFirst(), kp.getSecond());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("No removal allowed");
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + getClientSession() + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyIterator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyIterator.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyIterator.java
new file mode 100644
index 0000000..83ed94c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyIterator.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.client.auth.pubkey;
+
+import java.io.IOException;
+import java.nio.channels.Channel;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.SshAgentFactory;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.session.ClientSessionHolder;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKeyIterator implements Iterator<PublicKeyIdentity>, ClientSessionHolder, Channel {
+
+ private final AtomicBoolean open = new AtomicBoolean(true);
+ private final ClientSession clientSession;
+ private final Iterator<Iterator<? extends PublicKeyIdentity>> iterators;
+ private Iterator<? extends PublicKeyIdentity> current;
+ private SshAgent agent;
+
+ public UserAuthPublicKeyIterator(ClientSession session) throws Exception {
+ clientSession = ValidateUtils.checkNotNull(session, "No session");
+
+ Collection<Iterator<? extends PublicKeyIdentity>> identities = new LinkedList<>();
+ identities.add(new SessionKeyPairIterator(session, KeyIdentityProvider.Utils.iteratorOf(session)));
+
+ FactoryManager manager = ValidateUtils.checkNotNull(session.getFactoryManager(), "No session factory manager");
+ SshAgentFactory factory = manager.getAgentFactory();
+ if (factory != null) {
+ try {
+ agent = ValidateUtils.checkNotNull(factory.createClient(manager), "No agent created");
+ identities.add(new SshAgentPublicKeyIterator(session, agent));
+ } catch (Exception e) {
+ try {
+ closeAgent();
+ } catch (Exception err) {
+ e.addSuppressed(err);
+ }
+
+ throw e;
+ }
+ }
+
+ iterators = GenericUtils.iteratorOf(identities);
+ current = nextIterator(iterators);
+ }
+
+ @Override
+ public ClientSession getClientSession() {
+ return clientSession;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (!isOpen()) {
+ return false;
+ }
+
+ return current != null;
+ }
+
+ @Override
+ public PublicKeyIdentity next() {
+ if (!isOpen()) {
+ throw new NoSuchElementException("Iterator is closed");
+ }
+
+ PublicKeyIdentity pki = current.next();
+ if (!current.hasNext()) {
+ current = nextIterator(iterators);
+ }
+ return pki;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("No removal allowed");
+ }
+
+ @Override
+ public boolean isOpen() {
+ return open.get();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (open.getAndSet(false)) {
+ closeAgent();
+ }
+ }
+
+ protected void closeAgent() throws IOException {
+ if (agent != null) {
+ try {
+ agent.close();
+ } finally {
+ agent = null;
+ }
+ }
+ }
+
+ protected Iterator<? extends PublicKeyIdentity> nextIterator(
+ Iterator<? extends Iterator<? extends PublicKeyIdentity>> available) {
+ while ((available != null) && available.hasNext()) {
+ Iterator<? extends PublicKeyIdentity> iter = available.next();
+ if (iter.hasNext()) {
+ return iter;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + getClientSession() + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 6ffb863..9506ee7 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
@@ -20,7 +20,6 @@ package org.apache.sshd.client.session;
import java.io.IOException;
import java.nio.file.FileSystem;
-import java.security.KeyPair;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -38,7 +37,6 @@ import org.apache.sshd.client.subsystem.sftp.SftpClient;
import org.apache.sshd.client.subsystem.sftp.SftpVersionSelector;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.future.KeyExchangeFuture;
-import org.apache.sshd.common.keyprovider.KeyPairProviderHolder;
import org.apache.sshd.common.scp.ScpTransferEventListener;
import org.apache.sshd.common.session.Session;
@@ -70,7 +68,7 @@ import org.apache.sshd.common.session.Session;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface ClientSession extends Session, KeyPairProviderHolder, ClientAuthenticationManager {
+public interface ClientSession extends Session, ClientAuthenticationManager {
enum ClientSessionEvent {
TIMEOUT,
CLOSED,
@@ -79,32 +77,6 @@ public interface ClientSession extends Session, KeyPairProviderHolder, ClientAut
}
/**
- * @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);
-
- /**
* Starts the authentication process.
* User identities will be tried until the server successfully authenticate the user.
* User identities must be provided before calling this method using
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 5a0a0f5..8166f2b 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
@@ -127,10 +127,7 @@ public class ClientSessionImpl extends AbstractClientSession {
ClientUserAuthService authService = getUserAuthService();
synchronized (lock) {
String serviceName = nextServiceName();
- authFuture = ValidateUtils.checkNotNull(
- authService.auth(getRegisteredIdentities(), serviceName),
- "No auth future generated by service=%s",
- serviceName);
+ authFuture = ValidateUtils.checkNotNull(authService.auth(serviceName), "No auth future generated by service=%s", serviceName);
return authFuture;
}
}
@@ -381,7 +378,7 @@ public class ClientSessionImpl extends AbstractClientSession {
@Override
protected void sendSessionEvent(SessionListener.Event event) throws IOException {
- if (event == SessionListener.Event.KeyEstablished) {
+ if (SessionListener.Event.KeyEstablished.equals(event)) {
sendInitialServiceRequest();
}
synchronized (lock) {
@@ -395,12 +392,13 @@ public class ClientSessionImpl extends AbstractClientSession {
return;
}
initialServiceRequestSent = true;
+ String serviceName = currentServiceFactory.getName();
if (log.isDebugEnabled()) {
- log.debug("sendInitialServiceRequest({}) Send SSH_MSG_SERVICE_REQUEST for {}",
- this, currentServiceFactory.getName());
+ log.debug("sendInitialServiceRequest({}) Send SSH_MSG_SERVICE_REQUEST for {}", this, serviceName);
}
- Buffer request = createBuffer(SshConstants.SSH_MSG_SERVICE_REQUEST);
- request.putString(currentServiceFactory.getName());
+
+ Buffer request = createBuffer(SshConstants.SSH_MSG_SERVICE_REQUEST, serviceName.length() + Byte.SIZE);
+ request.putString(serviceName);
writePacket(request);
// Assuming that MINA-SSHD only implements "explicit server authentication" it is permissible
// for the client's service to start sending data before the service-accept has been received.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 34c6cf5..ae5bf7a 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
@@ -36,6 +36,7 @@ import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.closeable.AbstractCloseable;
@@ -54,7 +55,6 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
private final ClientSessionImpl clientSession;
- private List<Object> identities;
private String service;
private List<NamedFactory<UserAuth>> authFactories;
@@ -115,9 +115,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
// ignored
}
- public AuthFuture auth(List<Object> identities, String service) throws IOException {
- this.identities = new ArrayList<>(identities);
- this.service = service;
+ public AuthFuture auth(String service) throws IOException {
+ this.service = ValidateUtils.checkNotNullAndNotEmpty(service, "No service");
ClientSession session = getClientSession();
String username = session.getUsername();
@@ -284,7 +283,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
log.debug("tryNext({}) attempting method={}", session, method);
}
- userAuth.init(session, service, identities);
+ userAuth.init(session, service);
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
new file mode 100644
index 0000000..9a153aa
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.keyprovider;
+
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Supplier;
+import org.apache.sshd.common.util.Transformer;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface KeyIdentityProvider {
+ KeyIdentityProvider EMPTY_KEYS_PROVIDER = new KeyIdentityProvider() {
+ @Override
+ public Iterable<KeyPair> loadKeys() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public String toString() {
+ return "EMPTY";
+ }
+ };
+
+ /**
+ * Load available keys.
+ *
+ * @return an {@link Iterable} instance of available keys - ignored if {@code null}
+ */
+ Iterable<KeyPair> loadKeys();
+
+ /**
+ * A helper class for key identity provider related operations
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ // CHECKSTYLE:OFF
+ final class Utils {
+ // CHECKSTYLE:ON
+ public static final Transformer<KeyIdentityProvider, Iterable<KeyPair>> LOADER =
+ new Transformer<KeyIdentityProvider, Iterable<KeyPair>>() {
+ @Override
+ public Iterable<KeyPair> transform(KeyIdentityProvider p) {
+ return (p == null) ? null : p.loadKeys();
+ }
+ };
+
+ private Utils() {
+ throw new UnsupportedOperationException("No instance allowed");
+ }
+
+ public static Iterator<KeyPair> iteratorOf(ClientSession session) {
+ ValidateUtils.checkNotNull(session, "No session");
+ return iteratorOf(session.getRegisteredIdentities(), session.getKeyPairProvider());
+ }
+
+ public static Iterator<KeyPair> iteratorOf(KeyIdentityProvider identities, KeyIdentityProvider keys) {
+ return iteratorOf(resolveKeyIdentityProvider(identities, keys));
+ }
+
+ /**
+ * Resolves a non-{@code null} iterator of the available keys
+ *
+ * @param provider The {@link KeyIdentityProvider} - ignored if {@code null}
+ * @return A non-{@code null} iterator - which may be empty if no provider or no keys
+ */
+ public static Iterator<KeyPair> iteratorOf(KeyIdentityProvider provider) {
+ return GenericUtils.iteratorOf((provider == null) ? null : provider.loadKeys());
+ }
+
+ public static KeyIdentityProvider resolveKeyIdentityProvider(KeyIdentityProvider identities, KeyIdentityProvider keys) {
+ if ((keys == null) || (identities == keys)) {
+ return identities;
+ } else if (identities == null) {
+ return keys;
+ } else {
+ return multiProvider(identities, keys);
+ }
+ }
+
+ public static KeyIdentityProvider multiProvider(KeyIdentityProvider ... providers) {
+ return multiProvider(GenericUtils.isEmpty(providers) ? Collections.<KeyIdentityProvider>emptyList() : Arrays.asList(providers));
+ }
+
+ public static KeyIdentityProvider multiProvider(Collection<? extends KeyIdentityProvider> providers) {
+ return wrap(iterableOf(providers));
+ }
+
+ public static Iterable<KeyPair> iterableOf(Collection<? extends KeyIdentityProvider> providers) {
+ if (GenericUtils.isEmpty(providers)) {
+ return Collections.emptyList();
+ }
+
+ Collection<Supplier<Iterable<KeyPair>>> suppliers = new ArrayList<Supplier<Iterable<KeyPair>>>(providers.size());
+ for (final KeyIdentityProvider p : providers) {
+ if (p == null) {
+ continue;
+ }
+
+ suppliers.add(new Supplier<Iterable<KeyPair>>() {
+ @Override
+ public Iterable<KeyPair> get() {
+ return p.loadKeys();
+ }
+ });
+ }
+
+ if (GenericUtils.isEmpty(suppliers)) {
+ return Collections.emptyList();
+ }
+
+ return GenericUtils.multiIterableSuppliers(suppliers);
+ }
+
+ public static KeyIdentityProvider wrap(final Iterable<KeyPair> keys) {
+ return new KeyIdentityProvider() {
+ @Override
+ public Iterable<KeyPair> loadKeys() {
+ return keys;
+ }
+ };
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
index a768a86..b4e7256 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
@@ -29,7 +29,7 @@ import org.apache.sshd.common.cipher.ECCurves;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface KeyPairProvider {
+public interface KeyPairProvider extends KeyIdentityProvider {
/**
* SSH identifier for RSA keys
@@ -83,13 +83,6 @@ public interface KeyPairProvider {
};
/**
- * Load available keys.
- *
- * @return an {@link Iterable} instance of available keys, never {@code null}
- */
- Iterable<KeyPair> loadKeys();
-
- /**
* Load a key of the specified type which can be "ssh-rsa", "ssh-dss", or
* "ecdsa-sha2-nistp{256,384,521}". If there is no key of this type, return
* {@code null}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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 ed5593e..ef06c54 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
@@ -31,6 +31,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
@@ -565,4 +566,76 @@ public final class GenericUtils {
}
};
}
+
+ /**
+ * Resolves to an always non-{@code null} iterator
+ *
+ * @param iterable The {@link Iterable} instance
+ * @return A non-{@code null} iterator which may be empty if no iterable
+ * instance or no iterator returned from it
+ * @see #iteratorOf(Iterator)
+ */
+ public static <T> Iterator<T> iteratorOf(Iterable<T> iterable) {
+ return iteratorOf((iterable == null) ? null : iterable.iterator());
+ }
+
+ /**
+ * Resolves to an always non-{@code null} iterator
+ *
+ * @param iter The {@link Iterator} instance
+ * @return A non-{@code null} iterator which may be empty if no iterator instance
+ * @see Collections#emptyIterator()
+ */
+ public static <T> Iterator<T> iteratorOf(Iterator<T> iter) {
+ return (iter == null) ? Collections.<T>emptyIterator() : iter;
+ }
+
+ public static <T> Iterable<T> multiIterableSuppliers(final Iterable<? extends Supplier<? extends Iterable<? extends T>>> providers) {
+ return new Iterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return new Iterator<T>() {
+ private final Iterator<? extends Supplier<? extends Iterable<? extends T>>> iter = iteratorOf(providers);
+ private Iterator<? extends T> current = nextIterator();
+
+ @Override
+ public boolean hasNext() {
+ return current != null;
+ }
+
+ @Override
+ public T next() {
+ if (current == null) {
+ throw new NoSuchElementException("No more elements");
+ }
+
+ T value = current.next();
+ if (!current.hasNext()) {
+ current = nextIterator();
+ }
+
+ return value;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+
+ private Iterator<? extends T> nextIterator() {
+ while (iter.hasNext()) {
+ Supplier<? extends Iterable<? extends T>> supplier = iter.next();
+ Iterator<? extends T> values = iteratorOf((supplier == null) ? null : supplier.get());
+ if (values.hasNext()) {
+ return values;
+ }
+ }
+
+ return null;
+ }
+ };
+ }
+
+ };
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
index 9d17c4d..518b319 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
@@ -65,7 +65,8 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
serverSession = (ServerSession) s;
maxAuthRequests = PropertyResolverUtils.getIntProperty(s, ServerAuthenticationManager.MAX_AUTH_REQUESTS, ServerAuthenticationManager.DEFAULT_MAX_AUTH_REQUESTS);
- List<NamedFactory<UserAuth>> factories = serverSession.getUserAuthFactories();
+ List<NamedFactory<UserAuth>> factories = ValidateUtils.checkNotNullAndNotEmpty(
+ serverSession.getUserAuthFactories(), "No user auth factories for %s", s);
userAuthFactories = new ArrayList<>(factories);
// Get authentication methods
authMethods = new ArrayList<>();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
new file mode 100644
index 0000000..2b6246d
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.IOException;
+import java.lang.reflect.Method;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import org.apache.sshd.client.auth.PasswordIdentityProvider;
+import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.channel.ChannelListener;
+import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.random.JceRandomFactory;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.random.SingletonRandomFactory;
+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.util.test.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 ClientAuthenticationManagerTest extends BaseTestSupport {
+ public ClientAuthenticationManagerTest() {
+ super();
+ }
+
+ @Test
+ public void testAddRemoveClientSessionIdentities() throws Exception {
+ try (ClientSession session = createMockClientSession()) {
+ testClientAuthenticationManager(session);
+ }
+ }
+
+ @Test
+ public void testAddRemoveSshClientIdentities() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ testClientAuthenticationManager(client);
+ }
+ }
+
+ @Test
+ public void testClientProvidersPropagation() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.setServiceFactories(SshClient.DEFAULT_SERVICE_FACTORIES);
+ client.setUserAuthFactories(SshClient.DEFAULT_USER_AUTH_FACTORIES);
+
+ try (ClientSession session = createMockClientSession(client)) {
+ for (Class<?> provider : new Class<?>[] {
+ PasswordIdentityProvider.class,
+ ServerKeyVerifier.class,
+ UserInteraction.class,
+ KeyPairProvider.class
+ }) {
+ testClientProvidersPropagation(provider, client, session);
+ }
+ }
+ }
+ }
+
+ private void testClientProvidersPropagation(Class<?> type, ClientAuthenticationManager client, ClientAuthenticationManager session) throws Exception {
+ String baseName = type.getSimpleName();
+ outputDebugMessage("testClientProvidersPropagation(%s)", baseName);
+ assertTrue(baseName + ": not an interface", type.isInterface());
+
+ Method getter = ClientAuthenticationManager.class.getMethod("get" + baseName);
+ Method setter = ClientAuthenticationManager.class.getMethod("set" + baseName, type);
+ Object clientProvider = Mockito.mock(type);
+ setter.invoke(client, clientProvider);
+ assertSame(baseName + ": mismatched client-only provider", clientProvider, getter.invoke(session));
+
+ Object sessionProvider = Mockito.mock(type);
+ setter.invoke(session, sessionProvider);
+ assertSame(baseName + ": mismatched session override provider", sessionProvider, getter.invoke(session));
+
+ setter.invoke(session, new Object[] { null });
+ assertSame(baseName + ": mismatched nullified session provider", clientProvider, getter.invoke(session));
+ }
+
+ private <M extends ClientAuthenticationManager> M testClientAuthenticationManager(M manager) {
+ {
+ String expected = getCurrentTestName();
+ assertNull("Unexpected initial password identity", manager.removePasswordIdentity(expected));
+ manager.addPasswordIdentity(expected);
+
+ String actual = manager.removePasswordIdentity(expected);
+ assertSame("Mismatched removed password identity", expected, actual);
+ assertNull("Password identity not removed", manager.removePasswordIdentity(expected));
+ }
+
+ {
+ KeyPair expected = new KeyPair(Mockito.mock(PublicKey.class), Mockito.mock(PrivateKey.class));
+ assertNull("Unexpected initial pubket identity", manager.removePublicKeyIdentity(expected));
+ manager.addPublicKeyIdentity(expected);
+
+ KeyPair actual = manager.removePublicKeyIdentity(expected);
+ assertSame("Mismatched removed pubkey identity", expected, actual);
+ assertNull("Pubkey identity not removed", manager.removePublicKeyIdentity(expected));
+ }
+
+ return manager;
+ }
+
+ private ClientSession createMockClientSession() throws Exception {
+ ClientFactoryManager client = Mockito.mock(ClientFactoryManager.class);
+ Mockito.when(client.getTcpipForwarderFactory()).thenReturn(DefaultTcpipForwarderFactory.INSTANCE);
+ Mockito.when(client.getSessionListenerProxy()).thenReturn(new SessionListener() {
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ // ignored
+ }
+
+ @Override
+ public void sessionCreated(Session session) {
+ // ignored
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ // ignored
+ }
+ });
+ Mockito.when(client.getChannelListenerProxy()).thenReturn(new ChannelListener() {
+ @Override
+ public void channelOpenSuccess(Channel channel) {
+ // ignored
+ }
+
+ @Override
+ public void channelOpenFailure(Channel channel, Throwable reason) {
+ // ignored
+ }
+
+ @Override
+ public void channelInitialized(Channel channel) {
+ // ignored
+ }
+
+ @Override
+ public void channelClosed(Channel channel) {
+ // ignored
+ }
+ });
+ Factory<Random> randomFactory = new SingletonRandomFactory(JceRandomFactory.INSTANCE);
+ Mockito.when(client.getRandomFactory()).thenReturn(randomFactory);
+
+ Mockito.when(client.getServiceFactories()).thenReturn(SshClient.DEFAULT_SERVICE_FACTORIES);
+ Mockito.when(client.getUserAuthFactories()).thenReturn(SshClient.DEFAULT_USER_AUTH_FACTORIES);
+ return createMockClientSession(client);
+ }
+
+ private ClientSession createMockClientSession(ClientFactoryManager client) throws Exception {
+ return new ClientSessionImpl(client, Mockito.mock(IoSession.class)) {
+ @Override
+ protected void sendClientIdentification() {
+ // ignored
+ }
+
+ @Override
+ protected byte[] sendKexInit() throws IOException {
+ return GenericUtils.EMPTY_BYTE_ARRAY;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // ignored
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/13818de0/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
index 26fb505..4d1b9a7 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
@@ -363,7 +363,7 @@ public class ClientTest extends BaseTestSupport {
channel.setIn(inPipe);
channel.setOut(out);
channel.setErr(err);
- channel.open().verify(3L, TimeUnit.SECONDS);
+ channel.open().verify(6L, TimeUnit.SECONDS);
break; // 1st success means all methods have been invoked
}
} catch (IOException e) {
@@ -1295,7 +1295,7 @@ public class ClientTest extends BaseTestSupport {
channel.open().verify(9L, TimeUnit.SECONDS);
AbstractSession cs = (AbstractSession) session;
- Buffer buffer = cs.createBuffer(SshConstants.SSH_MSG_DISCONNECT);
+ Buffer buffer = cs.createBuffer(SshConstants.SSH_MSG_DISCONNECT, Integer.SIZE);
buffer.putInt(SshConstants.SSH2_DISCONNECT_BY_APPLICATION);
buffer.putString("Cancel");
buffer.putString(""); // TODO add language tag
[4/4] mina-sshd git commit: [SSHD-612] Cannot attempt new
authentication on same session if current one fails
Posted by lg...@apache.org.
[SSHD-612] Cannot attempt new authentication on same session if current one fails
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/a26ef154
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/a26ef154
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/a26ef154
Branch: refs/heads/master
Commit: a26ef1549dde1df7e5cee53b46961c1a49ba74b0
Parents: fa724c2
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Mon Dec 14 11:13:51 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Mon Dec 14 11:13:51 2015 +0200
----------------------------------------------------------------------
.../client/session/ClientUserAuthService.java | 53 +++++++++++++++-----
1 file changed, 41 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a26ef154/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 ae5bf7a..23c1b4b 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
@@ -19,9 +19,11 @@
package org.apache.sshd.client.session;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.client.ClientAuthenticationManager;
import org.apache.sshd.client.auth.UserAuth;
@@ -51,17 +53,15 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
* The AuthFuture that is being used by the current auth request. This encodes the state.
* isSuccess -> authenticated, else if isDone -> server waiting for user auth, else authenticating.
*/
- private final AuthFuture authFuture;
+ private final AtomicReference<AuthFuture> authFutureHolder = new AtomicReference<>();
private final ClientSessionImpl clientSession;
+ private final List<String> clientMethods;
+ private final List<NamedFactory<UserAuth>> authFactories;
private String service;
-
- private List<NamedFactory<UserAuth>> authFactories;
- private List<String> clientMethods;
private List<String> serverMethods;
private UserAuth userAuth;
-
private int currentMethod;
public ClientUserAuthService(Session s) {
@@ -69,8 +69,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
throw new IllegalStateException("Client side service used on server side");
}
clientSession = (ClientSessionImpl) s;
- authFuture = new DefaultAuthFuture(clientSession.getLock());
- authFactories = clientSession.getUserAuthFactories();
+ authFactories = ValidateUtils.checkNotNullAndNotEmpty(
+ clientSession.getUserAuthFactories(), "No user auth factories for %s", s);
clientMethods = new ArrayList<>();
String prefs = PropertyResolverUtils.getString(s, ClientAuthenticationManager.PREFERRED_AUTHS);
@@ -116,14 +116,38 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
}
public AuthFuture auth(String service) throws IOException {
- this.service = ValidateUtils.checkNotNullAndNotEmpty(service, "No service");
+ this.service = ValidateUtils.checkNotNullAndNotEmpty(service, "No service name");
ClientSession session = getClientSession();
- String username = session.getUsername();
+ // check if any previous future in use
+ AuthFuture authFuture = new DefaultAuthFuture(clientSession.getLock());
+ AuthFuture currentFuture = authFutureHolder.getAndSet(authFuture);
+ if (currentFuture != null) {
+ if (currentFuture.isDone()) {
+ if (log.isDebugEnabled()) {
+ log.debug("auth({})[{}] request new authentication", session, service);
+ }
+ } else {
+ currentFuture.setException(new InterruptedIOException("New authentication started before previous completed"));
+ }
+ }
+
+ // start from scratch
+ serverMethods = null;
+ currentMethod = 0;
+ if (userAuth != null) {
+ try {
+ userAuth.destroy();
+ } finally {
+ userAuth = null;
+ }
+ }
+
if (log.isDebugEnabled()) {
log.debug("auth({})[{}] send SSH_MSG_USERAUTH_REQUEST for 'none'", session, service);
}
+ String username = session.getUsername();
Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, username.length() + service.length() + Integer.SIZE);
buffer.putString(username);
buffer.putString(service);
@@ -136,9 +160,10 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
@Override
public void process(int cmd, Buffer buffer) throws Exception {
ClientSession session = getClientSession();
- if (this.authFuture.isSuccess()) {
+ AuthFuture authFuture = ValidateUtils.checkNotNull(authFutureHolder.get(), "No current future");
+ if (authFuture.isSuccess()) {
throw new IllegalStateException("UserAuth message delivered to authenticated client");
- } else if (this.authFuture.isDone()) {
+ } else if (authFuture.isDone()) {
if (log.isDebugEnabled()) {
log.debug("process({}) Ignoring random message - cmd={}",
session, SshConstants.getCommandMessageName(cmd));
@@ -184,6 +209,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
}
session.setAuthenticated();
((ClientSessionImpl) session).switchToNextService();
+
+ AuthFuture authFuture = ValidateUtils.checkNotNull(authFutureHolder.get(), "No current future");
// Will wake up anyone sitting in waitFor
authFuture.setAuthed(true);
return;
@@ -270,6 +297,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
}
// also wake up anyone sitting in waitFor
+ AuthFuture authFuture = ValidateUtils.checkNotNull(authFutureHolder.get(), "No current future");
authFuture.setException(new SshException(SshConstants.SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, "No more authentication methods available"));
return;
}
@@ -289,7 +317,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
@Override
protected void preClose() {
- if (!authFuture.isDone()) {
+ AuthFuture authFuture = authFutureHolder.get();
+ if ((authFuture != null) && (!authFuture.isDone())) {
authFuture.setException(new SshException("Session is closed"));
}