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 2016/01/05 07:05:46 UTC
[1/3] mina-sshd git commit: [SSHD-620] Add support for 'hostbased'
authentication
Repository: mina-sshd
Updated Branches:
refs/heads/master cbff09df7 -> 18335089d
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java
new file mode 100644
index 0000000..6792c51
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.auth.hostbased;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class StaticHostBasedAuthenticator extends AbstractLoggingBean implements HostBasedAuthenticator {
+ private final boolean acceptance;
+
+ public StaticHostBasedAuthenticator(boolean acceptance) {
+ this.acceptance = acceptance;
+ }
+
+ public final boolean isAccepted() {
+ return acceptance;
+ }
+
+ @Override
+ public final boolean authenticate(ServerSession session, String username, PublicKey clientHostKey,
+ String clientHostName, String clientUsername, List<X509Certificate> certificates) {
+ boolean accepted = isAccepted();
+ if (accepted) {
+ handleAcceptance(session, username, clientHostKey, clientHostName, clientUsername, certificates);
+ } else {
+ handleRejection(session, username, clientHostKey, clientHostName, clientUsername, certificates);
+ }
+
+ return accepted;
+ }
+
+ protected void handleAcceptance(ServerSession session, String username, PublicKey clientHostKey,
+ String clientHostName, String clientUsername, List<X509Certificate> certificates) {
+ // accepting without really checking is dangerous, thus the warning
+ log.warn("authenticate({}[{}]: accepted without checking {}@{} key={} fingerprint={}",
+ username, session, clientUsername, clientHostName, KeyUtils.getKeyType(clientHostKey), KeyUtils.getFingerPrint(clientHostKey));
+
+ }
+
+ protected void handleRejection(ServerSession session, String username, PublicKey clientHostKey,
+ String clientHostName, String clientUsername, List<X509Certificate> certificates) {
+ if (log.isDebugEnabled()) {
+ log.debug("authenticate({}[{}]: rejected {}@{} key={} fingerprint={}",
+ username, session, clientUsername, clientHostName, KeyUtils.getKeyType(clientHostKey), KeyUtils.getFingerPrint(clientHostKey));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
new file mode 100644
index 0000000..607bb36
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.auth.hostbased;
+
+import java.io.ByteArrayInputStream;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBased extends AbstractUserAuth implements SignatureFactoriesManager {
+ public static final String NAME = UserAuthHostBasedFactory.NAME;
+
+ private List<NamedFactory<Signature>> factories;
+
+ public UserAuthHostBased() {
+ this(null);
+ }
+
+ public UserAuthHostBased(List<NamedFactory<Signature>> factories) {
+ super(NAME);
+ this.factories = factories; // OK if null/empty
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+ ValidateUtils.checkTrue(init, "Instance not initialized");
+
+ int dataLen = buffer.available();
+ String username = getUsername();
+ ServerSession session = getSession();
+ String keyType = buffer.getString();
+ int keyLen = buffer.getInt();
+ int keyOffset = buffer.rpos();
+
+ Buffer buf = new ByteArrayBuffer(buffer.array(), keyOffset, keyLen, true);
+ PublicKey clientKey = buf.getRawPublicKey();
+ List<X509Certificate> certs = Collections.<X509Certificate>emptyList();
+ if (buf.available() > 0) {
+ CertificateFactory cf = SecurityUtils.getCertificateFactory("X.509");
+ certs = new ArrayList<>();
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(), buf.rpos(), buf.available())) {
+ X509Certificate c = (X509Certificate) cf.generateCertificate(bais);
+ certs.add(c);
+ }
+ }
+
+ buffer.rpos(keyOffset + keyLen);
+ String clientHostName = buffer.getString();
+ String clientUsername = buffer.getString();
+
+ byte[] signature = buffer.getBytes();
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) authenticate key type={}, fingerprint={}, client={}@{}, num-certs={}",
+ username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+ clientUsername, clientHostName, GenericUtils.size(certs));
+ }
+
+ HostBasedAuthenticator authenticator = session.getHostBasedAuthenticator();
+ if (authenticator == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - no authenticator",
+ username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+ clientUsername, clientHostName, GenericUtils.size(certs));
+ }
+ return Boolean.FALSE;
+ }
+
+ boolean authed = authenticator.authenticate(session, username, clientKey, clientHostName, clientUsername, certs);
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - authentication result: {}",
+ username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+ clientUsername, clientHostName, GenericUtils.size(certs), authed);
+ }
+ if (!authed) {
+ return Boolean.FALSE;
+ }
+
+ // verify signature
+ Collection<NamedFactory<Signature>> factories =
+ ValidateUtils.checkNotNullAndNotEmpty(
+ SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
+ "No signature factories for session=%s",
+ session);
+ Signature verifier = ValidateUtils.checkNotNull(
+ NamedFactory.Utils.create(factories, keyType),
+ "No verifier located for algorithm=%s",
+ keyType);
+ verifier.initVerifier(clientKey);
+
+ byte[] id = session.getSessionId();
+ buf = new ByteArrayBuffer(dataLen + id.length + Long.SIZE, false);
+ buf.putBytes(id);
+ buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ buf.putString(username);
+ buf.putString(getService());
+ buf.putString(getName());
+ buf.putString(keyType);
+ buf.putInt(keyLen);
+ // copy the key + certificates
+ buf.putRawBytes(buffer.array(), keyOffset, keyLen);
+ buf.putString(clientHostName);
+ buf.putString(clientUsername);
+
+ if (log.isTraceEnabled()) {
+ log.trace("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - verification data: {}",
+ username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+ clientUsername, clientHostName, GenericUtils.size(certs), buf.printHex());
+ log.trace("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - expected signature: {}",
+ username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+ clientUsername, clientHostName, GenericUtils.size(certs), BufferUtils.printHex(signature));
+ }
+
+ verifier.update(buf.array(), buf.rpos(), buf.available());
+ if (!verifier.verify(signature)) {
+ throw new Exception("Key verification failed");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - verified signature",
+ username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+ clientUsername, clientHostName, GenericUtils.size(certs));
+ }
+ return Boolean.TRUE;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java
new file mode 100644
index 0000000..9eaec57
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.auth.hostbased;
+
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBasedFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+ public static final String NAME = HOST_BASED;
+ public static final UserAuthHostBasedFactory INSTANCE = new UserAuthHostBasedFactory() {
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return null;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ if (!GenericUtils.isEmpty(factories)) {
+ throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
+ }
+ }
+ };
+
+ private List<NamedFactory<Signature>> factories;
+
+ public UserAuthHostBasedFactory() {
+ this(null);
+ }
+
+ public UserAuthHostBasedFactory(List<NamedFactory<Signature>> factories) {
+ super(NAME);
+ this.factories = factories; // OK if null/empty
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ public UserAuthHostBased create() {
+ return new UserAuthHostBased(getSignatureFactories());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
new file mode 100644
index 0000000..009ddb4
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.server.auth.keyboard;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * Issue a "keyboard-interactive" command according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractive extends AbstractUserAuth {
+ public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
+
+ public UserAuthKeyboardInteractive() {
+ super(NAME);
+ }
+
+ @Override
+ protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+ ServerSession session = getServerSession();
+ String username = getUsername();
+ KeyboardInteractiveAuthenticator auth = session.getKeyboardInteractiveAuthenticator();
+ if (init) {
+ String lang = buffer.getString();
+ String subMethods = buffer.getString();
+ if (auth == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive authenticator to generate challenge",
+ username, session, subMethods, lang);
+ }
+ return false;
+ }
+
+ InteractiveChallenge challenge = auth.generateChallenge(session, getUsername(), lang, subMethods);
+ if (challenge == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive challenge generated",
+ username, session, subMethods, lang);
+ }
+ return false;
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{})[methods={}, lang={}] challenge name={}, instruction={}, lang={}, num. prompts={}",
+ username, session, subMethods, lang,
+ challenge.getInteractionName(), challenge.getInteractionInstruction(),
+ challenge.getLanguageTag(), GenericUtils.size(challenge.getPrompts()));
+ }
+
+ // Prompt for password
+ buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, BufferUtils.clear(buffer));
+ challenge.append(buffer);
+ session.writePacket(buffer);
+ return null;
+ } else {
+ int cmd = buffer.getUByte();
+ if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE) {
+ throw new SshException("Received unexpected message: " + SshConstants.getCommandMessageName(cmd));
+ }
+
+ int num = buffer.getInt();
+ List<String> responses = (num <= 0) ? Collections.<String>emptyList() : new ArrayList<String>(num);
+ for (int index = 0; index < num; index++) {
+ String value = buffer.getString();
+ if (log.isTraceEnabled()) {
+ log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
+ }
+ responses.add(value);
+ }
+
+ if (auth == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
+ username, session, num);
+ }
+ return false;
+ }
+
+ boolean authed = auth.authenticate(session, username, responses);
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) authenticate {} responses result: {}",
+ username, session, num, authed);
+ }
+
+ return authed;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
new file mode 100644
index 0000000..7166d24
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.server.auth.keyboard;
+
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
+ public static final String NAME = KB_INTERACTIVE;
+ public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
+
+ public UserAuthKeyboardInteractiveFactory() {
+ super(NAME);
+ }
+
+ @Override
+ public UserAuthKeyboardInteractive create() {
+ return new UserAuthKeyboardInteractive();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java
new file mode 100644
index 0000000..35704bc
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.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.server.auth.password;
+
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPassword extends AbstractUserAuth {
+ public static final String NAME = UserAuthPasswordFactory.NAME;
+
+ public UserAuthPassword() {
+ super(NAME);
+ }
+
+ @Override
+ public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+ ValidateUtils.checkTrue(init, "Instance not initialized");
+
+ boolean newPassword = buffer.getBoolean();
+ String password = buffer.getString();
+ if (newPassword) {
+ return handleClientPasswordChangeRequest(buffer, getServerSession(), getUsername(), password, buffer.getString());
+ } else {
+ return checkPassword(buffer, getServerSession(), getUsername(), password);
+ }
+ }
+
+ /**
+ * Invokes the configured {@link PasswordAuthenticator} and returns the result.
+ * If {@link PasswordChangeRequiredException} thrown by the authenticator then
+ * {@link #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)}
+ * is invoked
+ *
+ * @param buffer The received {@link Buffer} to be re-used if need to send
+ * a password change request
+ * @param session The {@link ServerSession} through which the request was received
+ * @param username The username
+ * @param password The password
+ * @return The authentication result - if {@code null} then exception was handled
+ * internally and authentication is still in progress
+ * @throws Exception If internal error during authentication (exception for
+ * {@link PasswordChangeRequiredException} which is handled internally)
+ * @see #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)
+ */
+ protected Boolean checkPassword(Buffer buffer, ServerSession session, String username, String password) throws Exception {
+ PasswordAuthenticator auth = session.getPasswordAuthenticator();
+ if (auth == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("checkPassword({}) no password authenticator", session);
+ }
+ return false;
+ }
+
+ try {
+ boolean authed = auth.authenticate(username, password, session);
+ if (log.isDebugEnabled()) {
+ log.debug("checkPassword({}) authentication result: {}", session, authed);
+ }
+ return authed;
+ } catch (PasswordChangeRequiredException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("checkPassword({}) password change required: {}", session, e.getMessage());
+ }
+ return handleServerPasswordChangeRequest(buffer, session, username, password, e);
+ }
+ }
+
+ /**
+ * Invoked when the client sends a {@code SSH_MSG_USERAUTH_REQUEST} indicating
+ * a password change. Throws {@link UnsupportedOperationException} by default
+ *
+ * @param buffer The {@link Buffer} to re-use in order to respond
+ * @param session The associated {@link ServerSession}
+ * @param username The username
+ * @param oldPassword The old password
+ * @param newPassword The new password
+ * @return Password change and authentication result - {@code null} means
+ * authentication incomplete - i.e., handler has sent some extra query.
+ * @throws Exception If failed to handle the request.
+ */
+ protected Boolean handleClientPasswordChangeRequest(
+ Buffer buffer, ServerSession session, String username, String oldPassword, String newPassword)
+ throws Exception {
+ throw new UnsupportedOperationException("Password change not supported");
+ }
+
+ /**
+ * Invoked by {@link #checkPassword(Buffer, ServerSession, String, String)}
+ * when a {@link PasswordChangeRequiredException} was thrown by the authenticator.
+ * By default it re-throws the original exception.
+ *
+ * @param buffer The received {@link Buffer} to be re-used if need to send
+ * a password change request
+ * @param session The {@link ServerSession} through which the request was received
+ * @param username The username
+ * @param password The (rejected) password
+ * @param e The original thrown exception
+ * @return {@code null} by default to indicate incomplete authentication
+ * @throws Exception If failed to dispatch the message
+ */
+ protected Boolean handleServerPasswordChangeRequest(
+ Buffer buffer, ServerSession session, String username, String password, PasswordChangeRequiredException e)
+ throws Exception {
+ String prompt = e.getPrompt();
+ String lang = e.getLanguage();
+ if (log.isDebugEnabled()) {
+ log.debug("handlePasswordChangeRequest({}) password change required - prompt={}, lang={}",
+ session, prompt, lang);
+ }
+
+ buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, buffer);
+ buffer.putString(prompt);
+ buffer.putString(lang);
+ session.writePacket(buffer);
+ return null; // authentication incomplete
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java
new file mode 100644
index 0000000..322f552
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.server.auth.password;
+
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
+ public static final String NAME = PASSWORD;
+ public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
+
+ public UserAuthPasswordFactory() {
+ super(NAME);
+ }
+
+ @Override
+ public UserAuthPassword create() {
+ return new UserAuthPassword();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
new file mode 100644
index 0000000..7540747
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.server.auth.pubkey;
+
+import java.security.PublicKey;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+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;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
+ public static final String NAME = UserAuthPublicKeyFactory.NAME;
+
+ private List<NamedFactory<Signature>> factories;
+
+ public UserAuthPublicKey() {
+ this(null);
+ }
+
+ public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
+ super(NAME);
+ this.factories = factories; // OK if null/empty
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+ ValidateUtils.checkTrue(init, "Instance not initialized");
+
+ boolean hasSig = buffer.getBoolean();
+ String alg = buffer.getString();
+ int oldLim = buffer.wpos();
+ int oldPos = buffer.rpos();
+ int len = buffer.getInt();
+ buffer.wpos(buffer.rpos() + len);
+
+ ServerSession session = getServerSession();
+ String username = getUsername();
+ PublicKey key = buffer.getRawPublicKey();
+ Collection<NamedFactory<Signature>> factories =
+ ValidateUtils.checkNotNullAndNotEmpty(
+ SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
+ "No signature factories for session=%s",
+ session);
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) verify key type={}, factories={}, fingerprint={}",
+ username, session, alg, NamedResource.Utils.getNames(factories), KeyUtils.getFingerPrint(key));
+ }
+
+ Signature verifier = ValidateUtils.checkNotNull(
+ NamedFactory.Utils.create(factories, alg),
+ "No verifier located for algorithm=%s",
+ alg);
+ verifier.initVerifier(key);
+ buffer.wpos(oldLim);
+
+ byte[] sig = hasSig ? buffer.getBytes() : null;
+ PublickeyAuthenticator authenticator = session.getPublickeyAuthenticator();
+ if (authenticator == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={} - no authenticator",
+ username, session, alg, KeyUtils.getFingerPrint(key));
+ }
+ return Boolean.FALSE;
+ }
+
+ boolean authed = authenticator.authenticate(username, key, session);
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={} - authentication result: {}",
+ username, session, alg, KeyUtils.getFingerPrint(key), authed);
+ }
+ if (!authed) {
+ return Boolean.FALSE;
+ }
+
+ if (!hasSig) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) send SSH_MSG_USERAUTH_PK_OK for key type={}, fingerprint={}",
+ username, session, alg, KeyUtils.getFingerPrint(key));
+ }
+
+ Buffer buf = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PK_OK, BufferUtils.clear(buffer));
+ buf.putString(alg);
+ buf.putRawBytes(buffer.array(), oldPos, 4 + len);
+ session.writePacket(buf);
+ return null;
+ }
+
+ // verify signature
+ byte[] id = session.getSessionId();
+ String service = getService();
+ String name = getName();
+ Buffer buf = new ByteArrayBuffer(id.length + username.length() + service.length() + name.length()
+ + alg.length() + ByteArrayBuffer.DEFAULT_SIZE + Long.SIZE, false);
+ buf.putBytes(id);
+ buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ buf.putString(username);
+ buf.putString(service);
+ buf.putString(name);
+ buf.putBoolean(true);
+ buf.putString(alg);
+ buffer.rpos(oldPos);
+ buffer.wpos(oldPos + 4 + len);
+ buf.putBuffer(buffer);
+
+ if (log.isTraceEnabled()) {
+ log.trace("doAuth({}@{}) key type={}, fingerprint={} - verification data={}",
+ username, session, alg, KeyUtils.getFingerPrint(key), buf.printHex());
+ log.trace("doAuth({}@{}) key type={}, fingerprint={} - expected signature={}",
+ username, session, alg, KeyUtils.getFingerPrint(key), BufferUtils.printHex(sig));
+ }
+
+ verifier.update(buf.array(), buf.rpos(), buf.available());
+ if (!verifier.verify(sig)) {
+ throw new Exception("Key verification failed");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={} - verified",
+ username, session, alg, KeyUtils.getFingerPrint(key));
+ }
+
+ return Boolean.TRUE;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java
new file mode 100644
index 0000000..d53a02a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.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.server.auth.pubkey;
+
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+ public static final String NAME = PUBLIC_KEY;
+ public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return null;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ if (!GenericUtils.isEmpty(factories)) {
+ throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
+ }
+ }
+ };
+
+ private List<NamedFactory<Signature>> factories;
+
+ public UserAuthPublicKeyFactory() {
+ this(null);
+ }
+
+ public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
+ super(NAME);
+ this.factories = factories; // OK if null/empty
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ public UserAuthPublicKey create() {
+ return new UserAuthPublicKey(getSignatureFactories());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
index 2e76a7a..9abfb5b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
@@ -27,6 +27,7 @@ import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.auth.UserAuth;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
@@ -39,6 +40,7 @@ public abstract class AbstractServerSession extends AbstractSession implements S
private PublickeyAuthenticator publickeyAuthenticator;
private KeyboardInteractiveAuthenticator interactiveAuthenticator;
private GSSAuthenticator gssAuthenticator;
+ private HostBasedAuthenticator hostBasedAuthenticator;
private List<NamedFactory<UserAuth>> userAuthFactories;
protected AbstractServerSession(ServerFactoryManager factoryManager, IoSession ioSession) {
@@ -91,6 +93,16 @@ public abstract class AbstractServerSession extends AbstractSession implements S
}
@Override
+ public HostBasedAuthenticator getHostBasedAuthenticator() {
+ return resolveEffectiveProvider(HostBasedAuthenticator.class, hostBasedAuthenticator, getFactoryManager().getHostBasedAuthenticator());
+ }
+
+ @Override
+ public void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator) {
+ this.hostBasedAuthenticator = hostBasedAuthenticator;
+ }
+
+ @Override
public List<NamedFactory<UserAuth>> getUserAuthFactories() {
return resolveEffectiveFactories(UserAuth.class, userAuthFactories, getFactoryManager().getUserAuthFactories());
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java b/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
index de55c78..d6a4561 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
@@ -33,9 +33,9 @@ import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.SshServer;
-import org.apache.sshd.server.auth.UserAuthPublicKeyFactory;
import org.apache.sshd.server.auth.pubkey.CachingPublicKeyAuthenticator;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.util.test.BaseTestSupport;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
index cc8e780..f06b43f 100644
--- a/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
@@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.server.ServerFactoryManager;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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
index 2b6246d..b2148f2 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
@@ -24,8 +24,9 @@ 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.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.client.session.ClientSessionImpl;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
index b2aec0d..da4b770 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
@@ -29,7 +29,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 4d1b9a7..b414835 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
@@ -48,11 +48,11 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
-import org.apache.sshd.client.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.client.auth.UserAuthPasswordFactory;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.UserAuthPasswordFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.channel.ClientChannel;
@@ -98,6 +98,8 @@ import org.apache.sshd.common.util.io.NoCloseOutputStream;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.channel.ChannelSessionFactory;
@@ -918,21 +920,8 @@ public class ClientTest extends BaseTestSupport {
@Test
public void testPublicKeyAuth() throws Exception {
- client.start();
-
- try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
- assertNotNull("Client session creation not signalled", clientSessionHolder.get());
- KeyPair pair = createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
- session.addPublicKeyIdentity(pair);
- session.auth().verify(5L, TimeUnit.SECONDS);
- } finally {
- client.stop();
- }
- assertNull("Session closure not signalled", clientSessionHolder.get());
- }
-
- @Test
- public void testPublicKeyAuthNew() throws Exception {
+ sshd.setPasswordAuthenticator(RejectAllPasswordAuthenticator.INSTANCE);
+ sshd.setKeyboardInteractiveAuthenticator(KeyboardInteractiveAuthenticator.NONE);
client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKeyFactory.INSTANCE));
client.start();
@@ -974,7 +963,7 @@ public class ClientTest extends BaseTestSupport {
@Test
public void testPasswordAuthNew() throws Exception {
- client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPasswordFactory()));
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPasswordFactory.INSTANCE));
client.start();
try (ClientSession session = createTestClientSession()) {
@@ -987,7 +976,7 @@ public class ClientTest extends BaseTestSupport {
@Test
public void testPasswordAuthNewWithFailureOnFirstIdentity() throws Exception {
- client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPasswordFactory()));
+ client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPasswordFactory.INSTANCE));
client.start();
try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
@@ -1035,7 +1024,7 @@ public class ClientTest extends BaseTestSupport {
final Collection<String> mismatchedPrompts = new LinkedList<String>();
client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthKeyboardInteractiveFactory() {
@Override
- public UserAuth create() {
+ public UserAuthKeyboardInteractive create() {
return new UserAuthKeyboardInteractive() {
@Override
protected boolean useCurrentPassword(String password, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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
index 1a760c3..9ed8497 100644
--- 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
@@ -26,6 +26,7 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.util.test.BaseTestSupport;
import org.junit.FixMethodOrder;
import org.junit.Test;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 cde7f8d..afaa8a5 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
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.SocketAddress;
import java.security.KeyPair;
import java.security.PublicKey;
+import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -34,14 +35,16 @@ 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.UserAuth;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.hostbased.HostKeyIdentityProvider;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
@@ -54,15 +57,16 @@ import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.SshServer;
-import org.apache.sshd.server.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.server.auth.UserAuthPasswordFactory;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.keyboard.InteractiveChallenge;
import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.keyboard.PromptEntry;
+import org.apache.sshd.server.auth.keyboard.UserAuthKeyboardInteractiveFactory;
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.password.UserAuthPasswordFactory;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
import org.apache.sshd.server.auth.pubkey.RejectAllPublickeyAuthenticator;
import org.apache.sshd.server.session.ServerSession;
@@ -164,10 +168,10 @@ public class AuthenticationTest extends BaseTestSupport {
final AtomicInteger changesCount = new AtomicInteger(0);
sshd.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.server.auth.UserAuth>>singletonList(
- new org.apache.sshd.server.auth.UserAuthPasswordFactory() {
+ new org.apache.sshd.server.auth.password.UserAuthPasswordFactory() {
@Override
- public org.apache.sshd.server.auth.UserAuth create() {
- return new org.apache.sshd.server.auth.UserAuthPassword() {
+ public org.apache.sshd.server.auth.password.UserAuthPassword create() {
+ return new org.apache.sshd.server.auth.password.UserAuthPassword() {
@Override
protected Boolean handleClientPasswordChangeRequest(
Buffer buffer, ServerSession session, String username, String oldPassword, String newPassword)
@@ -214,10 +218,10 @@ public class AuthenticationTest extends BaseTestSupport {
final AtomicInteger sentCount = new AtomicInteger(0);
client.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.client.auth.UserAuth>>singletonList(
- new org.apache.sshd.client.auth.UserAuthPasswordFactory() {
+ new org.apache.sshd.client.auth.password.UserAuthPasswordFactory() {
@Override
- public org.apache.sshd.client.auth.UserAuth create() {
- return new org.apache.sshd.client.auth.UserAuthPassword() {
+ public org.apache.sshd.client.auth.password.UserAuthPassword create() {
+ return new org.apache.sshd.client.auth.password.UserAuthPassword() {
@Override
protected void sendPassword(Buffer buffer, ClientSession session, String oldPassword, String newPassword) throws IOException {
int count = sentCount.incrementAndGet();
@@ -315,14 +319,14 @@ public class AuthenticationTest extends BaseTestSupport {
assertEquals("Mismatched user language",
PropertyResolverUtils.getStringProperty(
client,
- org.apache.sshd.client.auth.UserAuthKeyboardInteractive.INTERACTIVE_LANGUAGE_TAG,
- org.apache.sshd.client.auth.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_LANGUAGE_TAG),
+ org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.INTERACTIVE_LANGUAGE_TAG,
+ org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_LANGUAGE_TAG),
lang);
assertEquals("Mismatched client sub-methods",
PropertyResolverUtils.getStringProperty(
client,
- org.apache.sshd.client.auth.UserAuthKeyboardInteractive.INTERACTIVE_SUBMETHODS,
- org.apache.sshd.client.auth.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_SUBMETHODS),
+ org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.INTERACTIVE_SUBMETHODS,
+ org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_SUBMETHODS),
subMethods);
InteractiveChallenge challenge = super.generateChallenge(session, username, lang, subMethods);
@@ -639,7 +643,7 @@ public class AuthenticationTest extends BaseTestSupport {
});
// allow only EC keys for public key authentication
- org.apache.sshd.client.auth.UserAuthPublicKeyFactory factory = new org.apache.sshd.client.auth.UserAuthPublicKeyFactory();
+ org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory factory = new org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory();
factory.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(BuiltinSignatures.nistp256, BuiltinSignatures.nistp384, BuiltinSignatures.nistp521));
client.setUserAuthFactories(Collections.<NamedFactory<UserAuth>>singletonList(factory));
@@ -653,6 +657,45 @@ public class AuthenticationTest extends BaseTestSupport {
}
}
+ @Test
+ public void testHostBasedAuthentication() throws Exception {
+ final String CLIENT_USERNAME = getClass().getSimpleName();
+ final String CLIENT_HOSTNAME = SshdSocketAddress.toAddressString(SshdSocketAddress.getFirstExternalNetwork4Address());
+ final KeyPair CLIENT_HOSTKEY = Utils.generateKeyPair("RSA", 1024);
+ final AtomicInteger invocationCount = new AtomicInteger(0);
+ sshd.setHostBasedAuthenticator(new HostBasedAuthenticator() {
+ @Override
+ public boolean authenticate(ServerSession session, String username,
+ PublicKey clientHostKey, String clientHostName, String clientUsername, List<X509Certificate> certificates) {
+ invocationCount.incrementAndGet();
+ return CLIENT_USERNAME.equals(clientUsername)
+ && CLIENT_HOSTNAME.equals(clientHostName)
+ && KeyUtils.compareKeys(CLIENT_HOSTKEY.getPublic(), clientHostKey);
+ }
+ });
+ sshd.setPasswordAuthenticator(RejectAllPasswordAuthenticator.INSTANCE);
+ sshd.setKeyboardInteractiveAuthenticator(KeyboardInteractiveAuthenticator.NONE);
+ sshd.setPublickeyAuthenticator(RejectAllPublickeyAuthenticator.INSTANCE);
+ sshd.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.server.auth.UserAuth>>singletonList(org.apache.sshd.server.auth.hostbased.UserAuthHostBasedFactory.INSTANCE));
+
+ try (SshClient client = setupTestClient()) {
+ org.apache.sshd.client.auth.hostbased.UserAuthHostBasedFactory factory =
+ new org.apache.sshd.client.auth.hostbased.UserAuthHostBasedFactory();
+ // TODO factory.setClientHostname(CLIENT_HOSTNAME);
+ factory.setClientUsername(CLIENT_USERNAME);
+ factory.setClientHostKeys(HostKeyIdentityProvider.Utils.wrap(CLIENT_HOSTKEY));
+
+ client.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.client.auth.UserAuth>>singletonList(factory));
+ client.start();
+ try (ClientSession s = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ s.auth().verify(11L, TimeUnit.SECONDS);
+ assertEquals("Mismatched authenticator invocation count", 1, invocationCount.get());
+ } 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());
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
index fc3ddec..f4acfc0 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
@@ -20,7 +20,7 @@ package org.apache.sshd.deprecated;
import java.io.IOException;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.future.DefaultAuthFuture;
import org.apache.sshd.client.session.ClientSessionImpl;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
index 6d84719..ba58e64 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
@@ -23,7 +23,7 @@ import java.security.PublicKey;
import java.util.Iterator;
import org.apache.sshd.agent.SshAgent;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.client.session.ClientSessionImpl;
import org.apache.sshd.common.SshConstants;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
index 9201607..8b62602 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
@@ -21,7 +21,7 @@ package org.apache.sshd.deprecated;
import java.io.IOException;
import java.util.Arrays;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.util.buffer.Buffer;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
index 43b8cfc..3c1ddca 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
@@ -21,7 +21,7 @@ package org.apache.sshd.deprecated;
import java.io.IOException;
import java.security.KeyPair;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
index f21e070..aed700d 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
@@ -41,7 +41,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.client.ClientAuthenticationManager;
import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.channel.ClientChannel;
[3/3] mina-sshd git commit: [SSHD-620] Add support for 'hostbased'
authentication
Posted by lg...@apache.org.
[SSHD-620] Add support for 'hostbased' authentication
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/18335089
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/18335089
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/18335089
Branch: refs/heads/master
Commit: 18335089d97a76c1aec74b4c082f9a3a2bfb3517
Parents: cbff09d
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue Jan 5 08:05:18 2016 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue Jan 5 08:05:18 2016 +0200
----------------------------------------------------------------------
.../client/ClientAuthenticationManager.java | 4 +-
.../java/org/apache/sshd/client/SshClient.java | 13 +-
.../auth/AuthenticationIdentitiesProvider.java | 1 +
.../client/auth/PasswordIdentityProvider.java | 146 ---------
.../auth/UserAuthKeyboardInteractive.java | 304 ------------------
.../UserAuthKeyboardInteractiveFactory.java | 36 ---
.../sshd/client/auth/UserAuthPassword.java | 135 --------
.../client/auth/UserAuthPasswordFactory.java | 36 ---
.../sshd/client/auth/UserAuthPublicKey.java | 179 -----------
.../client/auth/UserAuthPublicKeyFactory.java | 72 -----
.../sshd/client/auth/UserInteraction.java | 110 -------
.../auth/hostbased/HostKeyIdentityProvider.java | 93 ++++++
.../auth/hostbased/UserAuthHostBased.java | 202 ++++++++++++
.../hostbased/UserAuthHostBasedFactory.java | 86 ++++++
.../keyboard/UserAuthKeyboardInteractive.java | 306 +++++++++++++++++++
.../UserAuthKeyboardInteractiveFactory.java | 38 +++
.../client/auth/keyboard/UserInteraction.java | 110 +++++++
.../auth/password/PasswordIdentityProvider.java | 146 +++++++++
.../client/auth/password/UserAuthPassword.java | 137 +++++++++
.../auth/password/UserAuthPasswordFactory.java | 38 +++
.../client/auth/pubkey/UserAuthPublicKey.java | 178 +++++++++++
.../auth/pubkey/UserAuthPublicKeyFactory.java | 73 +++++
.../client/session/AbstractClientSession.java | 4 +-
.../client/session/ClientUserAuthService.java | 2 +-
.../apache/sshd/common/SshdSocketAddress.java | 299 ++++++++++++++++++
.../sshd/common/auth/UserAuthMethodFactory.java | 5 +
.../apache/sshd/common/util/NumberUtils.java | 32 +-
.../apache/sshd/common/util/SecurityUtils.java | 12 +
.../server/ServerAuthenticationManager.java | 23 +-
.../java/org/apache/sshd/server/SshServer.java | 12 +
.../auth/UserAuthKeyboardInteractive.java | 116 -------
.../UserAuthKeyboardInteractiveFactory.java | 36 ---
.../sshd/server/auth/UserAuthNoneFactory.java | 2 +-
.../sshd/server/auth/UserAuthPassword.java | 142 ---------
.../server/auth/UserAuthPasswordFactory.java | 36 ---
.../sshd/server/auth/UserAuthPublicKey.java | 161 ----------
.../server/auth/UserAuthPublicKeyFactory.java | 72 -----
.../AcceptAllHostBasedAuthenticator.java | 31 ++
.../auth/hostbased/HostBasedAuthenticator.java | 45 +++
.../RejectAllHostBasedAuthenticator.java | 31 ++
.../hostbased/StaticHostBasedAuthenticator.java | 72 +++++
.../auth/hostbased/UserAuthHostBased.java | 173 +++++++++++
.../hostbased/UserAuthHostBasedFactory.java | 74 +++++
.../keyboard/UserAuthKeyboardInteractive.java | 115 +++++++
.../UserAuthKeyboardInteractiveFactory.java | 38 +++
.../server/auth/password/UserAuthPassword.java | 141 +++++++++
.../auth/password/UserAuthPasswordFactory.java | 38 +++
.../server/auth/pubkey/UserAuthPublicKey.java | 166 ++++++++++
.../auth/pubkey/UserAuthPublicKeyFactory.java | 73 +++++
.../server/session/AbstractServerSession.java | 12 +
.../apache/sshd/SinglePublicKeyAuthTest.java | 2 +-
.../java/org/apache/sshd/WelcomeBannerTest.java | 2 +-
.../client/ClientAuthenticationManagerTest.java | 5 +-
.../sshd/client/ClientSessionListenerTest.java | 2 +-
.../java/org/apache/sshd/client/ClientTest.java | 35 +--
.../auth/PasswordIdentityProviderTest.java | 1 +
.../sshd/common/auth/AuthenticationTest.java | 73 ++++-
.../deprecated/ClientUserAuthServiceOld.java | 2 +-
.../apache/sshd/deprecated/UserAuthAgent.java | 2 +-
.../deprecated/UserAuthKeyboardInteractive.java | 2 +-
.../sshd/deprecated/UserAuthPublicKey.java | 2 +-
.../java/org/apache/sshd/server/ServerTest.java | 2 +-
62 files changed, 2887 insertions(+), 1649 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 ab1f154..c48701b 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
@@ -23,9 +23,9 @@ 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.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.keyprovider.KeyPairProviderHolder;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 e8da138..8375c89 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
@@ -56,12 +56,12 @@ 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;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
+import org.apache.sshd.client.auth.password.UserAuthPasswordFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.channel.ClientChannel;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
@@ -1029,6 +1029,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
break;
}
+ i++;
continue;
}
@@ -1109,7 +1110,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
try {
if (socksPort >= 0) {
- session.startDynamicPortForwarding(new SshdSocketAddress("localhost", socksPort));
+ session.startDynamicPortForwarding(new SshdSocketAddress(SshdSocketAddress.LOCALHOST_NAME, socksPort));
Thread.sleep(Long.MAX_VALUE);
} else {
ClientChannel channel;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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
index 2d0637b..56ef102 100644
--- 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
@@ -27,6 +27,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
import org.apache.sshd.common.util.GenericUtils;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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
deleted file mode 100644
index 26811db..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
+++ /dev/null
@@ -1,146 +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.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/18335089/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
deleted file mode 100644
index 9327236..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
+++ /dev/null
@@ -1,304 +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.auth;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.sshd.client.ClientAuthenticationManager;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.PropertyResolverUtils;
-import org.apache.sshd.common.SshConstants;
-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.buffer.BufferUtils;
-
-/**
- * Manages a "keyboard-interactive" exchange according to
- * <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractive extends AbstractUserAuth {
- public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
-
- public static final String INTERACTIVE_LANGUAGE_TAG = "kb-client-interactive-language-tag";
-
- /*
- * As per RFC-4256:
- *
- * The language tag is deprecated and SHOULD be the empty string. It
- * may be removed in a future revision of this specification. Instead,
- * the server SHOULD select the language to be used based on the tags
- * communicated during key exchange
- */
- public static final String DEFAULT_INTERACTIVE_LANGUAGE_TAG = "";
-
- public static final String INTERACTIVE_SUBMETHODS = "kb-client-interactive-sub-methods";
-
- /*
- * As per RFC-4256:
- *
- * The submethods field is included so the user can give a hint of which
- * actual methods he wants to use. It is a comma-separated list of
- * authentication submethods (software or hardware) that the user
- * prefers. If the client has knowledge of the submethods preferred by
- * the user, presumably through a configuration setting, it MAY use the
- * submethods field to pass this information to the server. Otherwise,
- * it MUST send the empty string.
- *
- * The actual names of the submethods is something the user and the
- * server need to agree upon.
- *
- * Server interpretation of the submethods field is implementation-
- * dependent.
- */
- public static final String DEFAULT_INTERACTIVE_SUBMETHODS = "";
-
- private final AtomicBoolean requestPending = new AtomicBoolean(false);
- private final AtomicInteger trialsCount = new AtomicInteger(0);
- private Iterator<String> passwords;
- private int maxTrials;
-
- public UserAuthKeyboardInteractive() {
- super(NAME);
- }
-
- @Override
- 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);
- }
-
- @Override
- protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
- String name = getName();
- if (requestPending.get()) {
- if (log.isDebugEnabled()) {
- log.debug("sendAuthDataRequest({})[{}] no reply for previous request for {}",
- session, service, name);
- }
- return false;
- }
-
- if (!verifyTrialsCount(session, service, SshConstants.SSH_MSG_USERAUTH_REQUEST, trialsCount.get(), maxTrials)) {
- return false;
- }
-
- String username = session.getUsername();
- String lang = getExchangeLanguageTag(session);
- String subMethods = getExchangeSubMethods(session);
- if (log.isDebugEnabled()) {
- log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST for {}: lang={}, methods={}",
- session, service, name, lang, subMethods);
- }
-
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
- username.length() + service.length() + name.length()
- + GenericUtils.length(lang) + GenericUtils.length(subMethods)
- + Long.SIZE /* a bit extra for the lengths */);
- buffer.putString(username);
- buffer.putString(service);
- buffer.putString(name);
- buffer.putString(lang);
- buffer.putString(subMethods);
- requestPending.set(true);
- session.writePacket(buffer);
- return true;
- }
-
- @Override
- protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
- if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST) {
- throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
- + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
- }
-
- requestPending.set(false);
-
- if (!verifyTrialsCount(session, service, cmd, trialsCount.incrementAndGet(), maxTrials)) {
- return false;
- }
-
- String name = buffer.getString();
- String instruction = buffer.getString();
- String lang = buffer.getString();
- int num = buffer.getInt();
- if (log.isDebugEnabled()) {
- log.debug("processAuthDataRequest({})[{}] SSH_MSG_USERAUTH_INFO_REQUEST name={}, instruction={}, language={}, num-prompts={}",
- session, service, name, instruction, lang, num);
- }
-
- String[] prompt = new String[num];
- boolean[] echo = new boolean[num];
- for (int i = 0; i < num; i++) {
- // according to RFC4256: "The prompt field(s) MUST NOT be empty strings."
- prompt[i] = buffer.getString();
- echo[i] = buffer.getBoolean();
- }
-
- if (log.isTraceEnabled()) {
- log.trace("processAuthDataRequest({})[{}] Prompt: {}", session, service, Arrays.toString(prompt));
- log.trace("processAuthDataRequest({})[{}] Echo: {}", session, service, Arrays.toString(echo));
- }
-
- String[] rep = getUserResponses(name, instruction, lang, prompt, echo);
- if (rep == null) {
- if (log.isDebugEnabled()) {
- log.debug("processAuthDataRequest({})[{}] no responses for {}", session, service, name);
- }
- return false;
- }
-
- /*
- * According to RFC4256:
- *
- * If the num-responses field does not match the num-prompts
- * field in the request message, the server MUST send a failure
- * message.
- *
- * However it is the server's (!) responsibility to fail, so we only warn...
- */
- if (num != rep.length) {
- log.warn("processAuthDataRequest({})[{}] Mismatched prompts ({}) vs. responses count ({})",
- session, service, num, rep.length);
- }
-
- buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, BufferUtils.clear(buffer));
- buffer.putInt(rep.length);
- for (int index = 0; index < rep.length; index++) {
- String r = rep[index];
- if (log.isTraceEnabled()) {
- log.trace("processAuthDataRequest({})[{}] response #{}: {}", session, service, index + 1, r);
- }
- buffer.putString(r);
- }
-
- session.writePacket(buffer);
- return true;
- }
-
- protected String getExchangeLanguageTag(ClientSession session) {
- return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_LANGUAGE_TAG, DEFAULT_INTERACTIVE_LANGUAGE_TAG);
- }
-
- protected String getExchangeSubMethods(ClientSession session) {
- return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_SUBMETHODS, DEFAULT_INTERACTIVE_SUBMETHODS);
- }
-
- protected String getCurrentPasswordCandidate() {
- if ((passwords != null) && passwords.hasNext()) {
- return passwords.next();
- } else {
- return null;
- }
- }
-
- protected boolean verifyTrialsCount(ClientSession session, String service, int cmd, int nbTrials, int maxAllowed) {
- if (log.isDebugEnabled()) {
- log.debug("verifyTrialsCount({})[{}] cmd={} - {} out of {}",
- session, service, getAuthCommandName(cmd), nbTrials, maxAllowed);
- }
-
- return nbTrials <= maxAllowed;
- }
-
- /**
- * @param name The interaction name - may be empty
- * @param instruction The instruction - may be empty
- * @param lang The language tag - may be empty
- * @param prompt The prompts - may be empty
- * @param echo Whether to echo the response for the prompt or not - same
- * length as the prompts
- * @return The response for each prompt - if {@code null} then the assumption
- * is that some internal error occurred and no response is sent. <B>Note:</B>
- * according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
- * the number of responses should be <U>exactly</U> the same as the number
- * of prompts. However, since it is the <U>server's</U> responsibility to
- * enforce this we do not validate the response (other than logging it as
- * a warning...)
- */
- protected String[] getUserResponses(String name, String instruction, String lang, String[] prompt, boolean[] echo) {
- ClientSession session = getClientSession();
- int num = GenericUtils.length(prompt);
- if (num == 0) {
- if (log.isDebugEnabled()) {
- log.debug("getUserResponses({}) no prompts for interaction={}", session, name);
- }
- return GenericUtils.EMPTY_STRING_ARRAY;
- }
-
- String candidate = getCurrentPasswordCandidate();
- if (useCurrentPassword(candidate, name, instruction, lang, prompt, echo)) {
- if (log.isDebugEnabled()) {
- log.debug("getUserResponses({}) use password candidate for interaction={}", session, name);
- }
- return new String[]{candidate};
- }
-
- UserInteraction ui = session.getUserInteraction();
- if ((ui != null) && ui.isInteractionAllowed(session)) {
- return ui.interactive(session, name, instruction, lang, prompt, echo);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("getUserResponses({}) no user interaction for name={}", session, name);
- }
-
- return null;
- }
-
- protected boolean useCurrentPassword(String password, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
- int num = GenericUtils.length(prompt);
- if ((num != 1) || (password == null) || echo[0]) {
- return false;
- }
-
- // check that prompt is something like "XXX password YYY:"
- String value = GenericUtils.trimToEmpty(prompt[0]).toLowerCase();
- int passPos = value.lastIndexOf("password");
- if (passPos < 0) { // no password keyword in prompt
- return false;
- }
-
- int sepPos = value.lastIndexOf(':');
- if (sepPos <= passPos) { // no prompt separator or separator before the password keyword
- return false;
- }
-
- return true;
- }
-
- public static String getAuthCommandName(int cmd) {
- switch(cmd) {
- case SshConstants.SSH_MSG_USERAUTH_REQUEST:
- return "SSH_MSG_USERAUTH_REQUEST";
- case SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST:
- return "SSH_MSG_USERAUTH_INFO_REQUEST";
- default:
- return SshConstants.getCommandMessageName(cmd);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java
deleted file mode 100644
index 5cf1068..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java
+++ /dev/null
@@ -1,36 +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.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
- public static final String NAME = KB_INTERACTIVE;
- public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
-
- public UserAuthKeyboardInteractiveFactory() {
- super(NAME);
- }
-
- @Override
- public UserAuth create() {
- return new UserAuthKeyboardInteractive();
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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
deleted file mode 100644
index d4ed6f7..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ /dev/null
@@ -1,135 +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.auth;
-
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Objects;
-
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-
-/**
- * Implements the "password" authentication mechanism
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPassword extends AbstractUserAuth {
- public static final String NAME = UserAuthPasswordFactory.NAME;
-
- private Iterator<String> passwords;
- private String current;
-
- public UserAuthPassword() {
- super(NAME);
- }
-
- @Override
- 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 == null) || (!passwords.hasNext())) {
- if (log.isDebugEnabled()) {
- log.debug("sendAuthDataRequest({})[{}] no more passwords to send", session, service);
- }
-
- 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
- protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
- if (cmd != SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
- throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
- + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
- }
-
- String prompt = buffer.getString();
- String lang = buffer.getString();
- UserInteraction ui = session.getUserInteraction();
- if ((ui != null) && ui.isInteractionAllowed(session)) {
- String password = ui.getUpdatedPassword(session, prompt, lang);
- if (GenericUtils.isEmpty(password)) {
- if (log.isDebugEnabled()) {
- log.debug("processAuthDataRequest({})[{}] No updated password for prompt={}, lang={}",
- session, service, prompt, lang);
- }
- } else {
- sendPassword(buffer, session, password, password);
- return true;
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug("processAuthDataRequest({})[{}] no UI for password change request for prompt={}, lang={}",
- session, service, prompt, lang);
- }
- }
-
- return false;
- }
-
- /**
- * Sends the password via a {@code SSH_MSG_USERAUTH_REQUEST} message.
- * If old and new password are not the same then it requests a password
- * modification from the server (which may be denied if the server does
- * not support this feature).
- *
- * @param buffer The {@link Buffer} to re-use for sending the message
- * @param session The target {@link ClientSession}
- * @param oldPassword The previous password
- * @param newPassword The new password
- * @throws IOException If failed to send the message.
- */
- protected void sendPassword(Buffer buffer, ClientSession session, String oldPassword, String newPassword) throws IOException {
- String username = session.getUsername();
- String service = getService();
- String name = getName();
- boolean modified = !Objects.equals(oldPassword, newPassword);
- if (log.isDebugEnabled()) {
- log.debug("sendPassword({})[{}] send SSH_MSG_USERAUTH_REQUEST for {} - modified={}",
- session, service, name, modified);
- }
-
- buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
- buffer.putString(username);
- buffer.putString(service);
- buffer.putString(name);
- buffer.putBoolean(modified);
- // see RFC-4252 section 8
- buffer.putString(oldPassword);
- if (modified) {
- buffer.putString(newPassword);
- }
- session.writePacket(buffer);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java
deleted file mode 100644
index 14ecfb0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java
+++ /dev/null
@@ -1,36 +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.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
- public static final String NAME = PASSWORD;
- public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
-
- public UserAuthPasswordFactory() {
- super(NAME);
- }
-
- @Override
- public UserAuth create() {
- return new UserAuthPassword();
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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
deleted file mode 100644
index f800cad..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ /dev/null
@@ -1,179 +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.auth;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.security.PublicKey;
-import java.util.Iterator;
-import java.util.List;
-
-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.NamedFactory;
-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.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-
-/**
- * Implements the "publickey" authentication mechanism
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
- public static final String NAME = UserAuthPublicKeyFactory.NAME;
-
- private Iterator<PublicKeyIdentity> keys;
- private PublicKeyIdentity current;
- private List<NamedFactory<Signature>> factories;
-
- public UserAuthPublicKey() {
- this(null);
- }
-
- public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
- super(NAME);
- this.factories = factories; // OK if null/empty
- }
-
- @Override
- public List<NamedFactory<Signature>> getSignatureFactories() {
- return factories;
- }
-
- @Override
- public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
- this.factories = factories;
- }
-
- @Override
- 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, this);
- }
-
- @Override
- protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
- if ((keys == null) || (!keys.hasNext())) {
- if (log.isDebugEnabled()) {
- log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
- }
-
- return false;
- }
-
- 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();
- if (log.isDebugEnabled()) {
- 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);
- buffer.putString(name);
- buffer.putBoolean(false);
- buffer.putString(algo);
- buffer.putPublicKey(key);
- session.writePacket(buffer);
- return true;
- }
-
- @Override
- protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
- if (cmd != SshConstants.SSH_MSG_USERAUTH_PK_OK) {
- throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
- + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
- }
-
- PublicKey key = current.getPublicKey();
- String algo = KeyUtils.getKeyType(key);
- String name = getName();
- if (log.isDebugEnabled()) {
- log.debug("processAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_PK_OK reply {} type={} - fingerprint={}",
- session, service, name, algo, KeyUtils.getFingerPrint(key));
- }
-
- String username = session.getUsername();
- buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
- buffer.putString(username);
- buffer.putString(service);
- buffer.putString(name);
- buffer.putBoolean(true);
- buffer.putString(algo);
- buffer.putPublicKey(key);
-
- Buffer bs = new ByteArrayBuffer();
- KeyExchange kex = session.getKex();
- bs.putBytes(kex.getH());
- bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- bs.putString(username);
- bs.putString(service);
- bs.putString(name);
- bs.putBoolean(true);
- bs.putString(algo);
- bs.putPublicKey(key);
-
- byte[] sig = current.sign(bs.getCompactData());
- bs = new ByteArrayBuffer(algo.length() + sig.length + Long.SIZE, false);
- bs.putString(algo);
- bs.putBytes(sig);
- buffer.putBytes(bs.array(), bs.rpos(), bs.available());
-
- session.writePacket(buffer);
- return true;
- }
-
- @Override
- public void destroy() {
- try {
- releaseKeys();
- } catch (IOException e) {
- throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
- }
-
- 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/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java
deleted file mode 100644
index f7ccd54..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java
+++ /dev/null
@@ -1,72 +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.auth;
-
-import java.util.List;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.GenericUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
- public static final String NAME = PUBLIC_KEY;
- public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
- @Override
- public List<NamedFactory<Signature>> getSignatureFactories() {
- return null;
- }
-
- @Override
- public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
- if (!GenericUtils.isEmpty(factories)) {
- throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
- }
- }
- };
-
- private List<NamedFactory<Signature>> factories;
-
- public UserAuthPublicKeyFactory() {
- this(null);
- }
-
- public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
- super(NAME);
- this.factories = factories; // OK if null/empty
- }
-
- @Override
- public List<NamedFactory<Signature>> getSignatureFactories() {
- return factories;
- }
-
- @Override
- public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
- this.factories = factories;
- }
-
- @Override
- public UserAuth create() {
- return new UserAuthPublicKey(getSignatureFactories());
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java
deleted file mode 100644
index 700055a..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java
+++ /dev/null
@@ -1,110 +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.auth;
-
-import org.apache.sshd.client.session.ClientSession;
-
-/**
- * Interface used by the ssh client to communicate with the end user.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- * @see <a href="https://www.ietf.org/rfc/rfc4256.txt">RFC 4256</A>
- */
-public interface UserInteraction {
- /**
- * A useful "placeholder" that indicates that no interaction is expected.
- * <B>Note:</B> throws {@link IllegalStateException} is any of the interaction
- * methods is called
- */
- UserInteraction NONE = new UserInteraction() {
- @Override
- public boolean isInteractionAllowed(ClientSession session) {
- return false;
- }
-
- @Override
- public void welcome(ClientSession session, String banner, String lang) {
- // ignored
- }
-
- @Override
- public String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
- throw new IllegalStateException("interactive(" + session + ")[" + name + "] unexpected call");
- }
-
- @Override
- public String getUpdatedPassword(ClientSession session, String prompt, String lang) {
- throw new IllegalStateException("getUpdatedPassword(" + session + ")[" + prompt + "] unexpected call");
- }
-
- @Override
- public String toString() {
- return "NONE";
- }
- };
-
- /**
- *
- * @param session The {@link ClientSession}
- * @return {@code true} if user interaction allowed for this session
- */
- boolean isInteractionAllowed(ClientSession session);
-
- /**
- * Displays the welcome banner to the user.
- *
- * @param session The {@link ClientSession} through which the banner was received
- * @param banner The welcome banner
- * @param lang The banner language code - may be empty
- */
- void welcome(ClientSession session, String banner, String lang);
-
- /**
- * Invoked when "keyboard-interactive" authentication mechanism
- * is used in order to provide responses for the server's challenges
- * (a.k.a. prompts)
- *
- * @param session The {@link ClientSession} through which the request was received
- * @param name The interaction name (may be empty)
- * @param instruction The instruction (may be empty)
- * @param lang The language for the data (may be empty)
- * @param prompt The prompts to be displayed (may be empty)
- * @param echo For each prompt whether to echo the user's response
- * @return The replies - <B>Note:</B> the protocol states that the number
- * of replies should be <U>exactly</U> the same as the number of prompts,
- * however we do not enforce it since it is defined as the <U>server's</U>
- * job to check and manage this violation.
- */
- String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo);
-
- /**
- * Invoked when the server returns an {@code SSH_MSG_USERAUTH_PASSWD_CHANGEREQ}
- * response indicating that the password should be changed - e.g., expired or
- * not strong enough (as per the server's policy).
- *
- * @param session The {@link ClientSession} through which the request was received
- * @param prompt The server's prompt (may be empty)
- * @param lang The prompt's language (may be empty)
- * @return The password to use - if {@code null}/empty then no updated
- * password was provided - thus failing the authentication via passwords
- * (<B>Note:</B> authentication might still succeed via some other means -
- * be it other passwords, public keys, etc...)
- */
- String getUpdatedPassword(ClientSession session, String prompt, String lang);
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java
new file mode 100644
index 0000000..7819422
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java
@@ -0,0 +1,93 @@
+/*
+ * 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.hostbased;
+
+import java.security.KeyPair;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface HostKeyIdentityProvider {
+ /**
+ * @return The host keys as a {@link Pair} of key + certificates (which can be {@code null}/empty)
+ */
+ Iterable<Pair<KeyPair, List<X509Certificate>>> loadHostKeys();
+
+ /**
+ * 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
+ private Utils() {
+ throw new UnsupportedOperationException("No instance allowed");
+ }
+
+ public static Iterator<Pair<KeyPair, List<X509Certificate>>> iteratorOf(HostKeyIdentityProvider provider) {
+ return GenericUtils.iteratorOf((provider == null) ? null : provider.loadHostKeys());
+ }
+
+ public static HostKeyIdentityProvider wrap(KeyPair ... pairs) {
+ return wrap(GenericUtils.isEmpty(pairs) ? Collections.<KeyPair>emptyList() : Arrays.asList(pairs));
+ }
+
+ public static HostKeyIdentityProvider wrap(final Iterable<? extends KeyPair> pairs) {
+ return new HostKeyIdentityProvider() {
+ @Override
+ public Iterable<Pair<KeyPair, List<X509Certificate>>> loadHostKeys() {
+ return new Iterable<Pair<KeyPair, List<X509Certificate>>>() {
+ @Override
+ public Iterator<Pair<KeyPair, List<X509Certificate>>> iterator() {
+ final Iterator<? extends KeyPair> iter = GenericUtils.iteratorOf(pairs);
+ return new Iterator<Pair<KeyPair, List<X509Certificate>>>() {
+
+ @Override
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ @Override
+ public Pair<KeyPair, List<X509Certificate>> next() {
+ KeyPair kp = iter.next();
+ return new Pair<KeyPair, List<X509Certificate>>(kp, Collections.<X509Certificate>emptyList());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("No removal allowed");
+ }
+ };
+ }
+ };
+ }
+
+ };
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java
new file mode 100644
index 0000000..a8313f3
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java
@@ -0,0 +1,202 @@
+/*
+ * 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.hostbased;
+
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.OsUtils;
+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;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBased extends AbstractUserAuth implements SignatureFactoriesManager {
+ public static final String NAME = UserAuthHostBasedFactory.NAME;
+
+ private Iterator<Pair<KeyPair, List<X509Certificate>>> keys;
+ private final HostKeyIdentityProvider clientHostKeys;
+ private List<NamedFactory<Signature>> factories;
+ private String clientUsername;
+ private String clientHostname;
+
+ public UserAuthHostBased(HostKeyIdentityProvider clientHostKeys) {
+ super(NAME);
+ this.clientHostKeys = clientHostKeys; // OK if null
+ }
+
+ @Override
+ public void init(ClientSession session, String service) throws Exception {
+ super.init(session, service);
+ keys = HostKeyIdentityProvider.Utils.iteratorOf(clientHostKeys); // in case multiple calls to the method
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ public String getClientUsername() {
+ return clientUsername;
+ }
+
+ public void setClientUsername(String clientUsername) {
+ this.clientUsername = clientUsername;
+ }
+
+ public String getClientHostname() {
+ return clientHostname;
+ }
+
+ public void setClientHostname(String clientHostname) {
+ this.clientHostname = clientHostname;
+ }
+
+ @Override
+ protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+ if ((keys == null) || (!keys.hasNext())) {
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
+ }
+
+ return false;
+ }
+
+ Pair<KeyPair, List<X509Certificate>> keyInfo = keys.next();
+ KeyPair kp = keyInfo.getFirst();
+ PublicKey pub = kp.getPublic();
+ String keyType = KeyUtils.getKeyType(pub);
+ if (log.isTraceEnabled()) {
+ log.trace("sendAuthDataRequest({})[{}] current key details: type={}, fingerprint={}",
+ session, service, keyType, KeyUtils.getFingerPrint(pub));
+ }
+
+ Collection<NamedFactory<Signature>> factories =
+ ValidateUtils.checkNotNullAndNotEmpty(
+ SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
+ "No signature factories for session=%s",
+ session);
+ Signature verifier = ValidateUtils.checkNotNull(
+ NamedFactory.Utils.create(factories, keyType),
+ "No signer could be located for key type=%s",
+ keyType);
+
+ byte[] id = session.getSessionId();
+ String username = session.getUsername();
+ String clientUsername = resolveClientUsername();
+ String clientHostname = resolveClientHostname();
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] client={}@{}",
+ session, service, clientUsername, clientHostname);
+ }
+
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
+ id.length + username.length() + service.length() + clientUsername.length() + clientHostname.length()
+ + keyType.length() + ByteArrayBuffer.DEFAULT_SIZE + Long.SIZE);
+ buffer.clear();
+
+ buffer.putRawPublicKey(pub);
+
+ List<X509Certificate> certs = keyInfo.getSecond();
+ if (GenericUtils.size(certs) > 0) {
+ for (X509Certificate c : certs) {
+ // TODO make sure this yields DER encoding
+ buffer.putRawBytes(c.getEncoded());
+ }
+ }
+ byte[] keyBytes = buffer.getCompactData();
+
+ buffer.clear();
+ buffer.putBytes(id);
+ buffer.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ buffer.putString(username);
+ buffer.putString(getService());
+ buffer.putString(getName());
+ buffer.putString(keyType);
+ buffer.putBytes(keyBytes);
+ buffer.putString(clientHostname);
+ buffer.putString(clientUsername);
+
+ verifier.initSigner(kp.getPrivate());
+ verifier.update(buffer.array(), buffer.rpos(), buffer.available());
+ byte[] signature = verifier.sign();
+ if (log.isTraceEnabled()) {
+ log.trace("sendAuthDataRequest({})[{}] type={}, fingerprint={}, client={}@{}: signature={}",
+ session, service, keyType, KeyUtils.getFingerPrint(pub),
+ clientUsername, clientHostname, BufferUtils.printHex(signature));
+ }
+
+ buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, buffer);
+ buffer.putString(username);
+ buffer.putString(getService());
+ buffer.putString(getName());
+ buffer.putString(keyType);
+ buffer.putBytes(keyBytes);
+ buffer.putString(clientHostname);
+ buffer.putString(clientUsername);
+ buffer.putBytes(signature);
+
+ session.writePacket(buffer);
+ return true;
+ }
+
+ @Override
+ protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+ int cmd = buffer.getUByte();
+ throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+ + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+ }
+
+ protected String resolveClientUsername() {
+ String value = getClientUsername();
+ return GenericUtils.isEmpty(value) ? OsUtils.getCurrentUser() : value;
+ }
+
+ protected String resolveClientHostname() {
+ String value = getClientHostname();
+ if (GenericUtils.isEmpty(value)) {
+ value = SshdSocketAddress.toAddressString(SshdSocketAddress.getFirstExternalNetwork4Address());
+ }
+
+ return GenericUtils.isEmpty(value) ? SshdSocketAddress.LOCALHOST_IP : value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java
new file mode 100644
index 0000000..8ead888
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java
@@ -0,0 +1,86 @@
+/*
+ * 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.hostbased;
+
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBasedFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+ public static final String NAME = HOST_BASED;
+
+ private List<NamedFactory<Signature>> factories;
+ private HostKeyIdentityProvider clientHostKeys;
+ private String clientUsername;
+ private String clientHostname;
+
+ public UserAuthHostBasedFactory() {
+ super(NAME);
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ public HostKeyIdentityProvider getClientHostKeys() {
+ return clientHostKeys;
+ }
+
+ public void setClientHostKeys(HostKeyIdentityProvider clientHostKeys) {
+ this.clientHostKeys = clientHostKeys;
+ }
+
+ public String getClientUsername() {
+ return clientUsername;
+ }
+
+ public void setClientUsername(String clientUsername) {
+ this.clientUsername = clientUsername;
+ }
+
+ public String getClientHostname() {
+ return clientHostname;
+ }
+
+ public void setClientHostname(String clientHostname) {
+ this.clientHostname = clientHostname;
+ }
+
+ @Override
+ public UserAuthHostBased create() {
+ UserAuthHostBased auth = new UserAuthHostBased(getClientHostKeys());
+ auth.setClientHostname(getClientHostname());
+ auth.setClientUsername(getClientUsername());
+ auth.setSignatureFactories(getSignatureFactories());
+ return auth;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
new file mode 100644
index 0000000..608f451
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
@@ -0,0 +1,306 @@
+/*
+ * 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.keyboard;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.client.ClientAuthenticationManager;
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.SshConstants;
+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.buffer.BufferUtils;
+
+/**
+ * Manages a "keyboard-interactive" exchange according to
+ * <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractive extends AbstractUserAuth {
+ public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
+
+ public static final String INTERACTIVE_LANGUAGE_TAG = "kb-client-interactive-language-tag";
+
+ /*
+ * As per RFC-4256:
+ *
+ * The language tag is deprecated and SHOULD be the empty string. It
+ * may be removed in a future revision of this specification. Instead,
+ * the server SHOULD select the language to be used based on the tags
+ * communicated during key exchange
+ */
+ public static final String DEFAULT_INTERACTIVE_LANGUAGE_TAG = "";
+
+ public static final String INTERACTIVE_SUBMETHODS = "kb-client-interactive-sub-methods";
+
+ /*
+ * As per RFC-4256:
+ *
+ * The submethods field is included so the user can give a hint of which
+ * actual methods he wants to use. It is a comma-separated list of
+ * authentication submethods (software or hardware) that the user
+ * prefers. If the client has knowledge of the submethods preferred by
+ * the user, presumably through a configuration setting, it MAY use the
+ * submethods field to pass this information to the server. Otherwise,
+ * it MUST send the empty string.
+ *
+ * The actual names of the submethods is something the user and the
+ * server need to agree upon.
+ *
+ * Server interpretation of the submethods field is implementation-
+ * dependent.
+ */
+ public static final String DEFAULT_INTERACTIVE_SUBMETHODS = "";
+
+ private final AtomicBoolean requestPending = new AtomicBoolean(false);
+ private final AtomicInteger trialsCount = new AtomicInteger(0);
+ private Iterator<String> passwords;
+ private int maxTrials;
+
+ public UserAuthKeyboardInteractive() {
+ super(NAME);
+ }
+
+ @Override
+ 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);
+ }
+
+ @Override
+ protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+ String name = getName();
+ if (requestPending.get()) {
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] no reply for previous request for {}",
+ session, service, name);
+ }
+ return false;
+ }
+
+ if (!verifyTrialsCount(session, service, SshConstants.SSH_MSG_USERAUTH_REQUEST, trialsCount.get(), maxTrials)) {
+ return false;
+ }
+
+ String username = session.getUsername();
+ String lang = getExchangeLanguageTag(session);
+ String subMethods = getExchangeSubMethods(session);
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST for {}: lang={}, methods={}",
+ session, service, name, lang, subMethods);
+ }
+
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
+ username.length() + service.length() + name.length()
+ + GenericUtils.length(lang) + GenericUtils.length(subMethods)
+ + Long.SIZE /* a bit extra for the lengths */);
+ buffer.putString(username);
+ buffer.putString(service);
+ buffer.putString(name);
+ buffer.putString(lang);
+ buffer.putString(subMethods);
+ requestPending.set(true);
+ session.writePacket(buffer);
+ return true;
+ }
+
+ @Override
+ protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+ int cmd = buffer.getUByte();
+ if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST) {
+ throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+ + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+ }
+
+ requestPending.set(false);
+
+ if (!verifyTrialsCount(session, service, cmd, trialsCount.incrementAndGet(), maxTrials)) {
+ return false;
+ }
+
+ String name = buffer.getString();
+ String instruction = buffer.getString();
+ String lang = buffer.getString();
+ int num = buffer.getInt();
+ if (log.isDebugEnabled()) {
+ log.debug("processAuthDataRequest({})[{}] SSH_MSG_USERAUTH_INFO_REQUEST name={}, instruction={}, language={}, num-prompts={}",
+ session, service, name, instruction, lang, num);
+ }
+
+ String[] prompt = new String[num];
+ boolean[] echo = new boolean[num];
+ for (int i = 0; i < num; i++) {
+ // according to RFC4256: "The prompt field(s) MUST NOT be empty strings."
+ prompt[i] = buffer.getString();
+ echo[i] = buffer.getBoolean();
+ }
+
+ if (log.isTraceEnabled()) {
+ log.trace("processAuthDataRequest({})[{}] Prompt: {}", session, service, Arrays.toString(prompt));
+ log.trace("processAuthDataRequest({})[{}] Echo: {}", session, service, Arrays.toString(echo));
+ }
+
+ String[] rep = getUserResponses(name, instruction, lang, prompt, echo);
+ if (rep == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("processAuthDataRequest({})[{}] no responses for {}", session, service, name);
+ }
+ return false;
+ }
+
+ /*
+ * According to RFC4256:
+ *
+ * If the num-responses field does not match the num-prompts
+ * field in the request message, the server MUST send a failure
+ * message.
+ *
+ * However it is the server's (!) responsibility to fail, so we only warn...
+ */
+ if (num != rep.length) {
+ log.warn("processAuthDataRequest({})[{}] Mismatched prompts ({}) vs. responses count ({})",
+ session, service, num, rep.length);
+ }
+
+ buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, BufferUtils.clear(buffer));
+ buffer.putInt(rep.length);
+ for (int index = 0; index < rep.length; index++) {
+ String r = rep[index];
+ if (log.isTraceEnabled()) {
+ log.trace("processAuthDataRequest({})[{}] response #{}: {}", session, service, index + 1, r);
+ }
+ buffer.putString(r);
+ }
+
+ session.writePacket(buffer);
+ return true;
+ }
+
+ protected String getExchangeLanguageTag(ClientSession session) {
+ return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_LANGUAGE_TAG, DEFAULT_INTERACTIVE_LANGUAGE_TAG);
+ }
+
+ protected String getExchangeSubMethods(ClientSession session) {
+ return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_SUBMETHODS, DEFAULT_INTERACTIVE_SUBMETHODS);
+ }
+
+ protected String getCurrentPasswordCandidate() {
+ if ((passwords != null) && passwords.hasNext()) {
+ return passwords.next();
+ } else {
+ return null;
+ }
+ }
+
+ protected boolean verifyTrialsCount(ClientSession session, String service, int cmd, int nbTrials, int maxAllowed) {
+ if (log.isDebugEnabled()) {
+ log.debug("verifyTrialsCount({})[{}] cmd={} - {} out of {}",
+ session, service, getAuthCommandName(cmd), nbTrials, maxAllowed);
+ }
+
+ return nbTrials <= maxAllowed;
+ }
+
+ /**
+ * @param name The interaction name - may be empty
+ * @param instruction The instruction - may be empty
+ * @param lang The language tag - may be empty
+ * @param prompt The prompts - may be empty
+ * @param echo Whether to echo the response for the prompt or not - same
+ * length as the prompts
+ * @return The response for each prompt - if {@code null} then the assumption
+ * is that some internal error occurred and no response is sent. <B>Note:</B>
+ * according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
+ * the number of responses should be <U>exactly</U> the same as the number
+ * of prompts. However, since it is the <U>server's</U> responsibility to
+ * enforce this we do not validate the response (other than logging it as
+ * a warning...)
+ */
+ protected String[] getUserResponses(String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+ ClientSession session = getClientSession();
+ int num = GenericUtils.length(prompt);
+ if (num == 0) {
+ if (log.isDebugEnabled()) {
+ log.debug("getUserResponses({}) no prompts for interaction={}", session, name);
+ }
+ return GenericUtils.EMPTY_STRING_ARRAY;
+ }
+
+ String candidate = getCurrentPasswordCandidate();
+ if (useCurrentPassword(candidate, name, instruction, lang, prompt, echo)) {
+ if (log.isDebugEnabled()) {
+ log.debug("getUserResponses({}) use password candidate for interaction={}", session, name);
+ }
+ return new String[]{candidate};
+ }
+
+ UserInteraction ui = session.getUserInteraction();
+ if ((ui != null) && ui.isInteractionAllowed(session)) {
+ return ui.interactive(session, name, instruction, lang, prompt, echo);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("getUserResponses({}) no user interaction for name={}", session, name);
+ }
+
+ return null;
+ }
+
+ protected boolean useCurrentPassword(String password, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+ int num = GenericUtils.length(prompt);
+ if ((num != 1) || (password == null) || echo[0]) {
+ return false;
+ }
+
+ // check that prompt is something like "XXX password YYY:"
+ String value = GenericUtils.trimToEmpty(prompt[0]).toLowerCase();
+ int passPos = value.lastIndexOf("password");
+ if (passPos < 0) { // no password keyword in prompt
+ return false;
+ }
+
+ int sepPos = value.lastIndexOf(':');
+ if (sepPos <= passPos) { // no prompt separator or separator before the password keyword
+ return false;
+ }
+
+ return true;
+ }
+
+ public static String getAuthCommandName(int cmd) {
+ switch(cmd) {
+ case SshConstants.SSH_MSG_USERAUTH_REQUEST:
+ return "SSH_MSG_USERAUTH_REQUEST";
+ case SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST:
+ return "SSH_MSG_USERAUTH_INFO_REQUEST";
+ default:
+ return SshConstants.getCommandMessageName(cmd);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
new file mode 100644
index 0000000..86bf005
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.keyboard;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
+ public static final String NAME = KB_INTERACTIVE;
+ public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
+
+ public UserAuthKeyboardInteractiveFactory() {
+ super(NAME);
+ }
+
+ @Override
+ public UserAuthKeyboardInteractive create() {
+ return new UserAuthKeyboardInteractive();
+ }
+}
\ No newline at end of file
[2/3] mina-sshd git commit: [SSHD-620] Add support for 'hostbased'
authentication
Posted by lg...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java
new file mode 100644
index 0000000..5d0fddd
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java
@@ -0,0 +1,110 @@
+/*
+ * 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.keyboard;
+
+import org.apache.sshd.client.session.ClientSession;
+
+/**
+ * Interface used by the ssh client to communicate with the end user.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <a href="https://www.ietf.org/rfc/rfc4256.txt">RFC 4256</A>
+ */
+public interface UserInteraction {
+ /**
+ * A useful "placeholder" that indicates that no interaction is expected.
+ * <B>Note:</B> throws {@link IllegalStateException} is any of the interaction
+ * methods is called
+ */
+ UserInteraction NONE = new UserInteraction() {
+ @Override
+ public boolean isInteractionAllowed(ClientSession session) {
+ return false;
+ }
+
+ @Override
+ public void welcome(ClientSession session, String banner, String lang) {
+ // ignored
+ }
+
+ @Override
+ public String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+ throw new IllegalStateException("interactive(" + session + ")[" + name + "] unexpected call");
+ }
+
+ @Override
+ public String getUpdatedPassword(ClientSession session, String prompt, String lang) {
+ throw new IllegalStateException("getUpdatedPassword(" + session + ")[" + prompt + "] unexpected call");
+ }
+
+ @Override
+ public String toString() {
+ return "NONE";
+ }
+ };
+
+ /**
+ *
+ * @param session The {@link ClientSession}
+ * @return {@code true} if user interaction allowed for this session
+ */
+ boolean isInteractionAllowed(ClientSession session);
+
+ /**
+ * Displays the welcome banner to the user.
+ *
+ * @param session The {@link ClientSession} through which the banner was received
+ * @param banner The welcome banner
+ * @param lang The banner language code - may be empty
+ */
+ void welcome(ClientSession session, String banner, String lang);
+
+ /**
+ * Invoked when "keyboard-interactive" authentication mechanism
+ * is used in order to provide responses for the server's challenges
+ * (a.k.a. prompts)
+ *
+ * @param session The {@link ClientSession} through which the request was received
+ * @param name The interaction name (may be empty)
+ * @param instruction The instruction (may be empty)
+ * @param lang The language for the data (may be empty)
+ * @param prompt The prompts to be displayed (may be empty)
+ * @param echo For each prompt whether to echo the user's response
+ * @return The replies - <B>Note:</B> the protocol states that the number
+ * of replies should be <U>exactly</U> the same as the number of prompts,
+ * however we do not enforce it since it is defined as the <U>server's</U>
+ * job to check and manage this violation.
+ */
+ String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo);
+
+ /**
+ * Invoked when the server returns an {@code SSH_MSG_USERAUTH_PASSWD_CHANGEREQ}
+ * response indicating that the password should be changed - e.g., expired or
+ * not strong enough (as per the server's policy).
+ *
+ * @param session The {@link ClientSession} through which the request was received
+ * @param prompt The server's prompt (may be empty)
+ * @param lang The prompt's language (may be empty)
+ * @return The password to use - if {@code null}/empty then no updated
+ * password was provided - thus failing the authentication via passwords
+ * (<B>Note:</B> authentication might still succeed via some other means -
+ * be it other passwords, public keys, etc...)
+ */
+ String getUpdatedPassword(ClientSession session, String prompt, String lang);
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java
new file mode 100644
index 0000000..cd9e4f3
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/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.password;
+
+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/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java
new file mode 100644
index 0000000..3db61be
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java
@@ -0,0 +1,137 @@
+/*
+ * 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.password;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Objects;
+
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+
+/**
+ * Implements the "password" authentication mechanism
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPassword extends AbstractUserAuth {
+ public static final String NAME = UserAuthPasswordFactory.NAME;
+
+ private Iterator<String> passwords;
+ private String current;
+
+ public UserAuthPassword() {
+ super(NAME);
+ }
+
+ @Override
+ 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 == null) || (!passwords.hasNext())) {
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] no more passwords to send", session, service);
+ }
+
+ 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
+ protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+ int cmd = buffer.getUByte();
+ if (cmd != SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
+ throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+ + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+ }
+
+ String prompt = buffer.getString();
+ String lang = buffer.getString();
+ UserInteraction ui = session.getUserInteraction();
+ if ((ui != null) && ui.isInteractionAllowed(session)) {
+ String password = ui.getUpdatedPassword(session, prompt, lang);
+ if (GenericUtils.isEmpty(password)) {
+ if (log.isDebugEnabled()) {
+ log.debug("processAuthDataRequest({})[{}] No updated password for prompt={}, lang={}",
+ session, service, prompt, lang);
+ }
+ } else {
+ sendPassword(buffer, session, password, password);
+ return true;
+ }
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("processAuthDataRequest({})[{}] no UI for password change request for prompt={}, lang={}",
+ session, service, prompt, lang);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sends the password via a {@code SSH_MSG_USERAUTH_REQUEST} message.
+ * If old and new password are not the same then it requests a password
+ * modification from the server (which may be denied if the server does
+ * not support this feature).
+ *
+ * @param buffer The {@link Buffer} to re-use for sending the message
+ * @param session The target {@link ClientSession}
+ * @param oldPassword The previous password
+ * @param newPassword The new password
+ * @throws IOException If failed to send the message.
+ */
+ protected void sendPassword(Buffer buffer, ClientSession session, String oldPassword, String newPassword) throws IOException {
+ String username = session.getUsername();
+ String service = getService();
+ String name = getName();
+ boolean modified = !Objects.equals(oldPassword, newPassword);
+ if (log.isDebugEnabled()) {
+ log.debug("sendPassword({})[{}] send SSH_MSG_USERAUTH_REQUEST for {} - modified={}",
+ session, service, name, modified);
+ }
+
+ buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
+ buffer.putString(username);
+ buffer.putString(service);
+ buffer.putString(name);
+ buffer.putBoolean(modified);
+ // see RFC-4252 section 8
+ buffer.putString(oldPassword);
+ if (modified) {
+ buffer.putString(newPassword);
+ }
+ session.writePacket(buffer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java
new file mode 100644
index 0000000..b52206c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.password;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
+ public static final String NAME = PASSWORD;
+ public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
+
+ public UserAuthPasswordFactory() {
+ super(NAME);
+ }
+
+ @Override
+ public UserAuthPassword create() {
+ return new UserAuthPassword();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java
new file mode 100644
index 0000000..95bec60
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java
@@ -0,0 +1,178 @@
+/*
+ * 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.Closeable;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+
+/**
+ * Implements the "publickey" authentication mechanism
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
+ public static final String NAME = UserAuthPublicKeyFactory.NAME;
+
+ private Iterator<PublicKeyIdentity> keys;
+ private PublicKeyIdentity current;
+ private List<NamedFactory<Signature>> factories;
+
+ public UserAuthPublicKey() {
+ this(null);
+ }
+
+ public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
+ super(NAME);
+ this.factories = factories; // OK if null/empty
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ 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, this);
+ }
+
+ @Override
+ protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+ if ((keys == null) || (!keys.hasNext())) {
+ if (log.isDebugEnabled()) {
+ log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
+ }
+
+ return false;
+ }
+
+ 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();
+ if (log.isDebugEnabled()) {
+ 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);
+ buffer.putString(name);
+ buffer.putBoolean(false);
+ buffer.putString(algo);
+ buffer.putPublicKey(key);
+ session.writePacket(buffer);
+ return true;
+ }
+
+ @Override
+ protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+ int cmd = buffer.getUByte();
+ if (cmd != SshConstants.SSH_MSG_USERAUTH_PK_OK) {
+ throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+ + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+ }
+
+ PublicKey key = current.getPublicKey();
+ String algo = KeyUtils.getKeyType(key);
+ String name = getName();
+ if (log.isDebugEnabled()) {
+ log.debug("processAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_PK_OK reply {} type={} - fingerprint={}",
+ session, service, name, algo, KeyUtils.getFingerPrint(key));
+ }
+
+ String username = session.getUsername();
+ buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
+ buffer.putString(username);
+ buffer.putString(service);
+ buffer.putString(name);
+ buffer.putBoolean(true);
+ buffer.putString(algo);
+ buffer.putPublicKey(key);
+
+ byte[] id = session.getSessionId();
+ Buffer bs = new ByteArrayBuffer(id.length + username.length() + service.length() + name.length()
+ + algo.length() + ByteArrayBuffer.DEFAULT_SIZE + Long.SIZE, false);
+ bs.putBytes(id);
+ bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ bs.putString(username);
+ bs.putString(service);
+ bs.putString(name);
+ bs.putBoolean(true);
+ bs.putString(algo);
+ bs.putPublicKey(key);
+
+ byte[] sig = current.sign(bs.getCompactData());
+ bs = new ByteArrayBuffer(algo.length() + sig.length + Long.SIZE, false);
+ bs.putString(algo);
+ bs.putBytes(sig);
+ buffer.putBytes(bs.array(), bs.rpos(), bs.available());
+
+ session.writePacket(buffer);
+ return true;
+ }
+
+ @Override
+ public void destroy() {
+ try {
+ releaseKeys();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
+ }
+
+ 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/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java
new file mode 100644
index 0000000..176df0a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.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.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+ public static final String NAME = PUBLIC_KEY;
+ public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return null;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ if (!GenericUtils.isEmpty(factories)) {
+ throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
+ }
+ }
+ };
+
+ private List<NamedFactory<Signature>> factories;
+
+ public UserAuthPublicKeyFactory() {
+ this(null);
+ }
+
+ public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
+ super(NAME);
+ this.factories = factories; // OK if null/empty
+ }
+
+ @Override
+ public List<NamedFactory<Signature>> getSignatureFactories() {
+ return factories;
+ }
+
+ @Override
+ public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ public UserAuthPublicKey create() {
+ return new UserAuthPublicKey(getSignatureFactories());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 d5b6066..3e5c12e 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
@@ -27,9 +27,9 @@ 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.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.client.channel.ChannelDirectTcpip;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ChannelSubsystem;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 521da96..f13f8f7 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
@@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.client.ClientAuthenticationManager;
import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.future.DefaultAuthFuture;
import org.apache.sshd.common.NamedFactory;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java b/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
index e9b8856..8b8a507 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
@@ -18,11 +18,21 @@
*/
package org.apache.sshd.common;
+import java.net.Inet4Address;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
import java.net.SocketAddress;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.List;
import java.util.Objects;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.NumberUtils;
import org.apache.sshd.common.util.ValidateUtils;
/**
@@ -45,14 +55,39 @@ import org.apache.sshd.common.util.ValidateUtils;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SshdSocketAddress extends SocketAddress {
+ public static final String LOCALHOST_NAME = "localhost";
public static final String LOCALHOST_IP = "127.0.0.1";
public static final String IP_ANYADDR = "0.0.0.0";
+ // 10.0.0.0 - 10.255.255.255
+ public static final String PRIVATE_CLASS_A_PREFIX = "10.";
+ // 172.16.0.0 - 172.31.255.255
+ public static final String PRIVATE_CLASS_B_PREFIX = "172.";
+ // 192.168.0.0 - 192.168.255.255
+ public static final String PRIVATE_CLASS_C_PREFIX = "192.168.";
+ // 100.64.0.0 - 100.127.255.255
+ public static final String CARRIER_GRADE_NAT_PREFIX = "100.";
+ // The IPv4 broadcast address
+ public static final String BROADCAST_ADDRESS = "255.255.255.255";
+
/**
* A dummy placeholder that can be used instead of {@code null}s
*/
public static final SshdSocketAddress LOCALHOST_ADDRESS = new SshdSocketAddress(LOCALHOST_IP, 0);
+ /**
+ * Compares {@link InetAddress}-es according to their {@link InetAddress#getHostAddress()}
+ * value case <U>insensitive</U>
+ */
+ public static final Comparator<InetAddress> BY_HOST_ADDRESS = new Comparator<InetAddress>() {
+ @Override
+ public int compare(InetAddress a1, InetAddress a2) {
+ String n1 = GenericUtils.trimToEmpty(toAddressString(a1));
+ String n2 = GenericUtils.trimToEmpty(toAddressString(a2));
+ return String.CASE_INSENSITIVE_ORDER.compare(n1, n2);
+ }
+ };
+
private static final long serialVersionUID = 6461645947151952729L;
private final String hostName;
@@ -113,4 +148,268 @@ public class SshdSocketAddress extends SocketAddress {
public int hashCode() {
return Objects.hashCode(getHostName()) + getPort();
}
+
+
+ /**
+ * Returns the first external network address assigned to this
+ * machine or null if one is not found.
+ * @return Inet4Address associated with an external interface
+ * DevNote: We actually return InetAddress here, as Inet4Addresses are final and cannot be mocked.
+ */
+ public static InetAddress getFirstExternalNetwork4Address() {
+ List<? extends InetAddress> addresses = getExternalNetwork4Addresses();
+ return (GenericUtils.size(addresses) > 0) ? addresses.get(0) : null;
+ }
+
+ /**
+ * @return a {@link List} of local network addresses which are not multicast
+ * or localhost sorted according to {@link #BY_HOST_ADDRESS}
+ */
+ public static List<InetAddress> getExternalNetwork4Addresses() {
+ List<InetAddress> addresses = new ArrayList<InetAddress>();
+ try {
+ for (Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); (nets != null) && nets.hasMoreElements();) {
+ NetworkInterface netint = nets.nextElement();
+ /* TODO - uncomment when 1.5 compatibility no longer required
+ if (!netint.isUp()) {
+ continue; // ignore non-running interfaces
+ }
+ */
+
+ for (Enumeration<InetAddress> inetAddresses = netint.getInetAddresses(); (inetAddresses != null) && inetAddresses.hasMoreElements();) {
+ InetAddress inetAddress = inetAddresses.nextElement();
+ if (isValidHostAddress(inetAddress)) {
+ addresses.add(inetAddress);
+ }
+ }
+ }
+ } catch (SocketException e) {
+ // swallow
+ }
+
+ if (GenericUtils.size(addresses) > 1) {
+ Collections.sort(addresses, BY_HOST_ADDRESS);
+ }
+
+ return addresses;
+ }
+
+ /**
+ * @param addr The {@link InetAddress} to be verified
+ * @return <P><code>true</code> if the address is:</P></BR>
+ * <UL>
+ * <LI>Not <code>null</code></LI>
+ * <LI>An {@link Inet4Address}</LI>
+ * <LI>Not link local</LI>
+ * <LI>Not a multicast</LI>
+ * <LI>Not a loopback</LI>
+ * </UL>
+ * @see InetAddress#isLinkLocalAddress()
+ * @see InetAddress#isMulticastAddress()
+ * @see InetAddress#isMulticastAddress()
+ */
+ public static boolean isValidHostAddress(InetAddress addr) {
+ if (addr == null) {
+ return false;
+ }
+
+ if (addr.isLinkLocalAddress()) {
+ return false;
+ }
+
+ if (addr.isMulticastAddress()) {
+ return false;
+ }
+
+ if (!(addr instanceof Inet4Address)) {
+ return false;
+ }
+
+ if (isLoopback(addr)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param addr The {@link InetAddress} to be considered
+ * @return <code>true</code> if the address is a loopback one.
+ * <B>Note:</B> if {@link InetAddress#isLoopbackAddress()}
+ * returns <code>false</code> the address <U>string</U> is checked
+ * @see #toAddressString(InetAddress)
+ * @see #isLoopback(String)
+ */
+ public static boolean isLoopback(InetAddress addr) {
+ if (addr == null) {
+ return false;
+ }
+
+ if (addr.isLoopbackAddress()) {
+ return true;
+ }
+
+ String ip = toAddressString(addr);
+ return isLoopback(ip);
+ }
+
+ /**
+ * @param ip IP value to be tested
+ * @return <code>true</code> if the IP is "localhost" or
+ * "127.x.x.x".
+ */
+ public static boolean isLoopback(String ip) {
+ if (GenericUtils.isEmpty(ip)) {
+ return false;
+ }
+
+ if (LOCALHOST_NAME.equals(ip) || LOCALHOST_IP.equals(ip)) {
+ return true;
+ }
+
+ String[] values = GenericUtils.split(ip, '.');
+ if (GenericUtils.length(values) != 4) {
+ return false;
+ }
+
+ for (int index = 0; index < values.length; index++) {
+ String val = values[index];
+ if (!isValidIPv4AddressComponent(val)) {
+ return false;
+ }
+
+ if (index == 0) {
+ int number = Integer.parseInt(val);
+ if (number != 127) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static String toAddressString(InetAddress addr) {
+ String ip = (addr == null) ? null : addr.toString();
+ if (GenericUtils.isEmpty(ip)) {
+ return null;
+ } else {
+ return ip.replaceAll(".*/", "");
+ }
+ }
+
+ public static final boolean isIPv4Address(String addr) {
+ if (GenericUtils.isEmpty(addr)) {
+ return false;
+ }
+
+ String[] comps = GenericUtils.split(addr, '.');
+ if (GenericUtils.length(comps) != 4) {
+ return false;
+ }
+
+ for (String c : comps) {
+ if (!isValidIPv4AddressComponent(c)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the address is one of the allocated private blocks
+ * @param addr The address string
+ * @return {@code true} if this is one of the allocated private
+ * blocks. <B>Note:</B> it assumes that the address string is
+ * indeed an IPv4 address
+ * @see #isIPv4Address(String)
+ * @see #PRIVATE_CLASS_A_PREFIX
+ * @see #PRIVATE_CLASS_B_PREFIX
+ * @see #PRIVATE_CLASS_C_PREFIX
+ * @see <A HREF="http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces">Wiki page</A>
+ */
+ public static final boolean isPrivateIPv4Address(String addr) {
+ if (GenericUtils.isEmpty(addr)) {
+ return false;
+ }
+
+ if (addr.startsWith(PRIVATE_CLASS_A_PREFIX) || addr.startsWith(PRIVATE_CLASS_C_PREFIX)) {
+ return true;
+ }
+
+ // for 172.x.x.x we need further checks
+ if (!addr.startsWith(PRIVATE_CLASS_B_PREFIX)) {
+ return false;
+ }
+
+ int nextCompPos = addr.indexOf('.', PRIVATE_CLASS_B_PREFIX.length());
+ if (nextCompPos <= PRIVATE_CLASS_B_PREFIX.length()) {
+ return false;
+ }
+
+ String value = addr.substring(PRIVATE_CLASS_B_PREFIX.length(), nextCompPos);
+ if (!isValidIPv4AddressComponent(value)) {
+ return false;
+ }
+
+ int v = Integer.parseInt(value);
+ return (v >= 16) && (v <= 31);
+ }
+
+ /**
+ * @param addr The address to be checked
+ * @return {@code true} if the address is in the 100.64.0.0/10 range
+ * @see <A HREF="http://tools.ietf.org/html/rfc6598">RFC6598</A>
+ */
+ public static final boolean isCarrierGradeNatIPv4Address(String addr) {
+ if (GenericUtils.isEmpty(addr)) {
+ return false;
+ }
+
+ if (!addr.startsWith(CARRIER_GRADE_NAT_PREFIX)) {
+ return false;
+ }
+
+ int nextCompPos = addr.indexOf('.', CARRIER_GRADE_NAT_PREFIX.length());
+ if (nextCompPos <= CARRIER_GRADE_NAT_PREFIX.length()) {
+ return false;
+ }
+
+ String value = addr.substring(CARRIER_GRADE_NAT_PREFIX.length(), nextCompPos);
+ if (!isValidIPv4AddressComponent(value)) {
+ return false;
+ }
+
+ int v = Integer.parseInt(value);
+ return (v >= 64) && (v <= 127);
+ }
+
+ /**
+ * <P>Checks if the provided argument is a valid IPv4 address component:</P></BR>
+ * <UL>
+ * <LI>Not {@code null}/empty</LI>
+ * <LI>Has at most 3 <U>digits</U></LI>
+ * <LI>Its value is ≤ 255</LI>
+ * </UL>
+ * @param c The {@link CharSequence} to be validate
+ * @return {@code true} if valid IPv4 address component
+ */
+ public static final boolean isValidIPv4AddressComponent(CharSequence c) {
+ if (GenericUtils.isEmpty(c) || (c.length() > 3)) {
+ return false;
+ }
+
+ char ch = c.charAt(0);
+ if ((ch < '0') || (ch > '9')) {
+ return false;
+ }
+
+ if (!NumberUtils.isIntegerNumber(c)) {
+ return false;
+ }
+
+ int v = Integer.parseInt(c.toString());
+ return (v >= 0) && (v <= 255);
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
index f2b2a30..9b632e7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
@@ -43,5 +43,10 @@ public interface UserAuthMethodFactory<M> extends NamedFactory<M> {
* Keyboard interactive authentication method
*/
String KB_INTERACTIVE = "keyboard-interactive";
+
+ /**
+ * Host-based authentication method
+ */
+ String HOST_BASED = "hostbased";
}
//CHECKSTYLE:ON
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
index 0c61c03..b859386 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
@@ -274,12 +274,40 @@ public final class NumberUtils {
if (len <= 0) {
return Collections.emptyList();
}
-
+
List<Integer> l = new ArrayList<>(len);
for (int v : values) {
l.add(Integer.valueOf(v));
}
-
+
return l;
}
+
+ /**
+ * Checks if optional sign and all others are '0'-'9'
+ * @param cs The {@link CharSequence} to check
+ * @return {@code true} if valid integer number
+ */
+ public static boolean isIntegerNumber(CharSequence cs) {
+ if (GenericUtils.isEmpty(cs)) {
+ return false;
+ }
+
+ for (int index = 0; index < cs.length(); index++) {
+ char c = cs.charAt(0);
+ if ((c >= '0') && (c <= '9')) {
+ continue;
+ }
+
+ if ((c == '+') || (c == '-')) {
+ if (index == 0) {
+ continue;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
index 4ab6389..03efdfb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
@@ -34,6 +34,7 @@ import java.security.MessageDigest;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Signature;
+import java.security.cert.CertificateFactory;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
@@ -592,4 +593,15 @@ public final class SecurityUtils {
return Signature.getInstance(algorithm, providerName);
}
}
+
+ public static synchronized CertificateFactory getCertificateFactory(String type) throws GeneralSecurityException {
+ register();
+
+ String providerName = getSecurityProvider();
+ if (GenericUtils.isEmpty(providerName)) {
+ return CertificateFactory.getInstance(type);
+ } else {
+ return CertificateFactory.getInstance(type, providerName);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
index 99c075a..de6eef0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
@@ -26,14 +26,15 @@ import java.util.List;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.server.auth.UserAuth;
-import org.apache.sshd.server.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.server.auth.UserAuthPasswordFactory;
-import org.apache.sshd.server.auth.UserAuthPublicKeyFactory;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.keyboard.UserAuthKeyboardInteractiveFactory;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
+import org.apache.sshd.server.auth.password.UserAuthPasswordFactory;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
/**
* Holds providers and helpers related to the server side authentication process
@@ -67,7 +68,7 @@ public interface ServerAuthenticationManager {
* {@code null}), then client authentication requests based on keys will be
* rejected.
*
- * @return the <code>PublickeyAuthenticator</code> or {@code null}
+ * @return the {@link PublickeyAuthenticator} or {@code null}
*/
PublickeyAuthenticator getPublickeyAuthenticator();
void setPasswordAuthenticator(PasswordAuthenticator passwordAuthenticator);
@@ -78,7 +79,7 @@ public interface ServerAuthenticationManager {
* {@code null}), then client authentication requests based on passwords
* will be rejected.
*
- * @return the <code>PasswordAuthenticator</code> or {@code null}
+ * @return the {@link PasswordAuthenticator} or {@code null}
*/
PasswordAuthenticator getPasswordAuthenticator();
void setPublickeyAuthenticator(PublickeyAuthenticator publickeyAuthenticator);
@@ -100,11 +101,21 @@ public interface ServerAuthenticationManager {
* {@code null}), then client authentication requests based on gssapi
* will be rejected.
*
- * @return the <code>GSSAuthenticator</code> or {@code null}
+ * @return the {@link GSSAuthenticator} or {@code null}
*/
GSSAuthenticator getGSSAuthenticator();
void setGSSAuthenticator(GSSAuthenticator gssAuthenticator);
+ /**
+ * Retrieve the {@code HostBasedAuthenticator} to be used by the SSH server. If
+ * no authenticator has been configured (i.e. this method returns {@code null}),
+ * then client authentication requests based on this method will be rejected.
+ *
+ * @return the {@link HostBasedAuthenticator} or {@code null}
+ */
+ HostBasedAuthenticator getHostBasedAuthenticator();
+ void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator);
+
// CHECKSTYLE:OFF
final class Utils {
// CHECKSTYLE:ON
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index 9fc121e..2c63f26 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -46,6 +46,7 @@ import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.server.auth.UserAuth;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator;
@@ -116,6 +117,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
private PasswordAuthenticator passwordAuthenticator;
private PublickeyAuthenticator publickeyAuthenticator;
private KeyboardInteractiveAuthenticator interactiveAuthenticator;
+ private HostBasedAuthenticator hostBasedAuthenticator;
private GSSAuthenticator gssAuthenticator;
public SshServer() {
@@ -229,6 +231,16 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
}
@Override
+ public HostBasedAuthenticator getHostBasedAuthenticator() {
+ return hostBasedAuthenticator;
+ }
+
+ @Override
+ public void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator) {
+ this.hostBasedAuthenticator = hostBasedAuthenticator;
+ }
+
+ @Override
public void setTcpipForwardingFilter(ForwardingFilter forwardingFilter) {
this.tcpipForwardingFilter = forwardingFilter;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
deleted file mode 100644
index 9639929..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
+++ /dev/null
@@ -1,116 +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.server.auth;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.server.auth.keyboard.InteractiveChallenge;
-import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
-import org.apache.sshd.server.session.ServerSession;
-
-/**
- * Issue a "keyboard-interactive" command according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractive extends AbstractUserAuth {
- public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
-
- public UserAuthKeyboardInteractive() {
- super(NAME);
- }
-
- @Override
- protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
- ServerSession session = getServerSession();
- String username = getUsername();
- KeyboardInteractiveAuthenticator auth = session.getKeyboardInteractiveAuthenticator();
- if (init) {
- String lang = buffer.getString();
- String subMethods = buffer.getString();
- if (auth == null) {
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive authenticator to generate challenge",
- username, session, subMethods, lang);
- }
- return false;
- }
-
- InteractiveChallenge challenge = auth.generateChallenge(session, getUsername(), lang, subMethods);
- if (challenge == null) {
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive challenge generated",
- username, session, subMethods, lang);
- }
- return false;
- }
-
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{})[methods={}, lang={}] challenge name={}, instruction={}, lang={}, num. prompts={}",
- username, session, subMethods, lang,
- challenge.getInteractionName(), challenge.getInteractionInstruction(),
- challenge.getLanguageTag(), GenericUtils.size(challenge.getPrompts()));
- }
-
- // Prompt for password
- buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, BufferUtils.clear(buffer));
- challenge.append(buffer);
- session.writePacket(buffer);
- return null;
- } else {
- int cmd = buffer.getUByte();
- if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE) {
- throw new SshException("Received unexpected message: " + SshConstants.getCommandMessageName(cmd));
- }
-
- int num = buffer.getInt();
- List<String> responses = (num <= 0) ? Collections.<String>emptyList() : new ArrayList<String>(num);
- for (int index = 0; index < num; index++) {
- String value = buffer.getString();
- if (log.isTraceEnabled()) {
- log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
- }
- responses.add(value);
- }
-
- if (auth == null) {
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
- username, session, num);
- }
- return false;
- }
-
- boolean authed = auth.authenticate(session, username, responses);
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) authenticate {} responses result: {}",
- username, session, num, authed);
- }
-
- return authed;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java
deleted file mode 100644
index 41defa0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java
+++ /dev/null
@@ -1,36 +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.server.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
- public static final String NAME = KB_INTERACTIVE;
- public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
-
- public UserAuthKeyboardInteractiveFactory() {
- super(NAME);
- }
-
- @Override
- public UserAuth create() {
- return new UserAuthKeyboardInteractive();
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
index d1290b8..e42db13 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
@@ -30,7 +30,7 @@ public class UserAuthNoneFactory extends AbstractUserAuthFactory {
}
@Override
- public UserAuth create() {
+ public UserAuthNone create() {
return new UserAuthNone();
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
deleted file mode 100644
index b0e72d4..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
+++ /dev/null
@@ -1,142 +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.server.auth;
-
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.server.auth.password.PasswordAuthenticator;
-import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
-import org.apache.sshd.server.session.ServerSession;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPassword extends AbstractUserAuth {
- public static final String NAME = UserAuthPasswordFactory.NAME;
-
- public UserAuthPassword() {
- super(NAME);
- }
-
- @Override
- public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
- ValidateUtils.checkTrue(init, "Instance not initialized");
-
- boolean newPassword = buffer.getBoolean();
- String password = buffer.getString();
- if (newPassword) {
- return handleClientPasswordChangeRequest(buffer, getServerSession(), getUsername(), password, buffer.getString());
- } else {
- return checkPassword(buffer, getServerSession(), getUsername(), password);
- }
- }
-
- /**
- * Invokes the configured {@link PasswordAuthenticator} and returns the result.
- * If {@link PasswordChangeRequiredException} thrown by the authenticator then
- * {@link #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)}
- * is invoked
- *
- * @param buffer The received {@link Buffer} to be re-used if need to send
- * a password change request
- * @param session The {@link ServerSession} through which the request was received
- * @param username The username
- * @param password The password
- * @return The authentication result - if {@code null} then exception was handled
- * internally and authentication is still in progress
- * @throws Exception If internal error during authentication (exception for
- * {@link PasswordChangeRequiredException} which is handled internally)
- * @see #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)
- */
- protected Boolean checkPassword(Buffer buffer, ServerSession session, String username, String password) throws Exception {
- PasswordAuthenticator auth = session.getPasswordAuthenticator();
- if (auth == null) {
- if (log.isDebugEnabled()) {
- log.debug("checkPassword({}) no password authenticator", session);
- }
- return false;
- }
-
- try {
- boolean authed = auth.authenticate(username, password, session);
- if (log.isDebugEnabled()) {
- log.debug("checkPassword({}) authentication result: {}", session, authed);
- }
- return authed;
- } catch (PasswordChangeRequiredException e) {
- if (log.isDebugEnabled()) {
- log.debug("checkPassword({}) password change required: {}", session, e.getMessage());
- }
- return handleServerPasswordChangeRequest(buffer, session, username, password, e);
- }
- }
-
- /**
- * Invoked when the client sends a {@code SSH_MSG_USERAUTH_REQUEST} indicating
- * a password change. Throws {@link UnsupportedOperationException} by default
- *
- * @param buffer The {@link Buffer} to re-use in order to respond
- * @param session The associated {@link ServerSession}
- * @param username The username
- * @param oldPassword The old password
- * @param newPassword The new password
- * @return Password change and authentication result - {@code null} means
- * authentication incomplete - i.e., handler has sent some extra query.
- * @throws Exception If failed to handle the request.
- */
- protected Boolean handleClientPasswordChangeRequest(
- Buffer buffer, ServerSession session, String username, String oldPassword, String newPassword)
- throws Exception {
- throw new UnsupportedOperationException("Password change not supported");
- }
-
- /**
- * Invoked by {@link #checkPassword(Buffer, ServerSession, String, String)}
- * when a {@link PasswordChangeRequiredException} was thrown by the authenticator.
- * By default it re-throws the original exception.
- *
- * @param buffer The received {@link Buffer} to be re-used if need to send
- * a password change request
- * @param session The {@link ServerSession} through which the request was received
- * @param username The username
- * @param password The (rejected) password
- * @param e The original thrown exception
- * @return {@code null} by default to indicate incomplete authentication
- * @throws Exception If failed to dispatch the message
- */
- protected Boolean handleServerPasswordChangeRequest(
- Buffer buffer, ServerSession session, String username, String password, PasswordChangeRequiredException e)
- throws Exception {
- String prompt = e.getPrompt();
- String lang = e.getLanguage();
- if (log.isDebugEnabled()) {
- log.debug("handlePasswordChangeRequest({}) password change required - prompt={}, lang={}",
- session, prompt, lang);
- }
-
- buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, buffer);
- buffer.putString(prompt);
- buffer.putString(lang);
- session.writePacket(buffer);
- return null; // authentication incomplete
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java
deleted file mode 100644
index e402912..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java
+++ /dev/null
@@ -1,36 +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.server.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
- public static final String NAME = PASSWORD;
- public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
-
- public UserAuthPasswordFactory() {
- super(NAME);
- }
-
- @Override
- public UserAuth create() {
- return new UserAuthPassword();
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
deleted file mode 100644
index f9a93ec..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
+++ /dev/null
@@ -1,161 +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.server.auth;
-
-import java.security.PublicKey;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-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;
-import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
-import org.apache.sshd.server.session.ServerSession;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
- public static final String NAME = UserAuthPublicKeyFactory.NAME;
-
- private List<NamedFactory<Signature>> factories;
-
- public UserAuthPublicKey() {
- this(null);
- }
-
- public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
- super(NAME);
- this.factories = factories; // OK if null/empty
- }
-
- @Override
- public List<NamedFactory<Signature>> getSignatureFactories() {
- return factories;
- }
-
- @Override
- public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
- this.factories = factories;
- }
-
- @Override
- public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
- ValidateUtils.checkTrue(init, "Instance not initialized");
-
- boolean hasSig = buffer.getBoolean();
- String alg = buffer.getString();
- int oldLim = buffer.wpos();
- int oldPos = buffer.rpos();
- int len = buffer.getInt();
- buffer.wpos(buffer.rpos() + len);
-
- ServerSession session = getServerSession();
- String username = getUsername();
- PublicKey key = buffer.getRawPublicKey();
- Collection<NamedFactory<Signature>> factories =
- ValidateUtils.checkNotNullAndNotEmpty(
- SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
- "No signature factories for session=%s",
- session);
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) verify key type={}, factories={}, fingerprint={}",
- username, session, alg, NamedResource.Utils.getNames(factories), KeyUtils.getFingerPrint(key));
- }
-
- Signature verifier = ValidateUtils.checkNotNull(
- NamedFactory.Utils.create(factories, alg),
- "No verifier located for algorithm=%s",
- alg);
- verifier.initVerifier(key);
- buffer.wpos(oldLim);
-
- byte[] sig = hasSig ? buffer.getBytes() : null;
- PublickeyAuthenticator authenticator = session.getPublickeyAuthenticator();
- if (authenticator == null) {
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) key type={}, fingerprint={} - no authenticator",
- username, session, alg, KeyUtils.getFingerPrint(key));
- }
- return false;
- }
-
- boolean authed = authenticator.authenticate(username, key, session);
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) key type={}, fingerprint={} - authentication result: {}",
- username, session, alg, KeyUtils.getFingerPrint(key), authed);
- }
- if (!authed) {
- return Boolean.FALSE;
- }
-
- if (!hasSig) {
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) send SSH_MSG_USERAUTH_PK_OK for key type={}, fingerprint={}",
- username, session, alg, KeyUtils.getFingerPrint(key));
- }
-
- Buffer buf = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PK_OK, BufferUtils.clear(buffer));
- buf.putString(alg);
- buf.putRawBytes(buffer.array(), oldPos, 4 + len);
- session.writePacket(buf);
- return null;
- }
-
- // verify signature
- Buffer buf = new ByteArrayBuffer();
- buf.putBytes(session.getKex().getH());
- buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- buf.putString(username);
- buf.putString(getService());
- buf.putString(getName());
- buf.putBoolean(true);
- buf.putString(alg);
- buffer.rpos(oldPos);
- buffer.wpos(oldPos + 4 + len);
- buf.putBuffer(buffer);
- verifier.update(buf.array(), buf.rpos(), buf.available());
- if (log.isTraceEnabled()) {
- log.trace("doAuth({}@{}) key type={}, fingerprint={} - verification data={}",
- username, session, alg, KeyUtils.getFingerPrint(key), buf.printHex());
- log.trace("doAuth({}@{}) key type={}, fingerprint={} - expected signature={}",
- username, session, alg, KeyUtils.getFingerPrint(key), BufferUtils.printHex(sig));
- }
-
- if (!verifier.verify(sig)) {
- throw new Exception("Key verification failed");
- }
-
- if (log.isDebugEnabled()) {
- log.debug("doAuth({}@{}) key type={}, fingerprint={} - verified",
- username, session, alg, KeyUtils.getFingerPrint(key));
- }
-
- return Boolean.TRUE;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java
deleted file mode 100644
index 72b8519..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java
+++ /dev/null
@@ -1,72 +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.server.auth;
-
-import java.util.List;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.GenericUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
- public static final String NAME = PUBLIC_KEY;
- public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
- @Override
- public List<NamedFactory<Signature>> getSignatureFactories() {
- return null;
- }
-
- @Override
- public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
- if (!GenericUtils.isEmpty(factories)) {
- throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
- }
- }
- };
-
- private List<NamedFactory<Signature>> factories;
-
- public UserAuthPublicKeyFactory() {
- this(null);
- }
-
- public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
- super(NAME);
- this.factories = factories; // OK if null/empty
- }
-
- @Override
- public List<NamedFactory<Signature>> getSignatureFactories() {
- return factories;
- }
-
- @Override
- public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
- this.factories = factories;
- }
-
- @Override
- public UserAuth create() {
- return new UserAuthPublicKey(getSignatureFactories());
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java
new file mode 100644
index 0000000..ef49a31
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.auth.hostbased;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class AcceptAllHostBasedAuthenticator extends StaticHostBasedAuthenticator {
+ public static final AcceptAllHostBasedAuthenticator INSTANCE = new AcceptAllHostBasedAuthenticator();
+
+ private AcceptAllHostBasedAuthenticator() {
+ super(true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java
new file mode 100644
index 0000000..37d2d3d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.auth.hostbased;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * Invoked when "hostbased" authentication is used
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://www.ietf.org/rfc/rfc4252.txt">RFC 4252 - section 9</A>
+ */
+public interface HostBasedAuthenticator {
+ /**
+ * @param session The {@link ServerSession} through which the request was received
+ * @param username The username attempting to login
+ * @param clientHostKey The remote client's host {@link PublicKey}
+ * @param clientHostName The reported remote client's host name
+ * @param clientUsername The remote client username
+ * @param certificates Associated {@link X509Certificate}s - may be {@code null}/empty
+ * @return {@code true} whether authentication is allowed to proceed
+ */
+ boolean authenticate(ServerSession session, String username,
+ PublicKey clientHostKey, String clientHostName, String clientUsername, List<X509Certificate> certificates);
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java
new file mode 100644
index 0000000..8d5eb14
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.auth.hostbased;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class RejectAllHostBasedAuthenticator extends StaticHostBasedAuthenticator {
+ public static final RejectAllHostBasedAuthenticator INSTANCE = new RejectAllHostBasedAuthenticator();
+
+ private RejectAllHostBasedAuthenticator() {
+ super(false);
+ }
+}