You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/06/09 15:53:20 UTC
[5/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
index c4f808d..e8207ed 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
@@ -18,17 +18,24 @@
*/
package org.apache.sshd.common.config.keys;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAKey;
import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -51,11 +58,11 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class KeyUtils {
- private static final Map<String,PublicKeyEntryDecoder<? extends PublicKey>> byKeyTypeDecodersMap =
- new TreeMap<String, PublicKeyEntryDecoder<? extends PublicKey>>(String.CASE_INSENSITIVE_ORDER);
- private static final Map<Class<?>,PublicKeyEntryDecoder<? extends PublicKey>> byKeyClassDecodersMap =
- new HashMap<Class<?>, PublicKeyEntryDecoder<? extends PublicKey>>();
+public final class KeyUtils {
+ private static final Map<String,PublicKeyEntryDecoder<?,?>> byKeyTypeDecodersMap =
+ new TreeMap<String, PublicKeyEntryDecoder<?,?>>(String.CASE_INSENSITIVE_ORDER);
+ private static final Map<Class<?>,PublicKeyEntryDecoder<?,?>> byKeyClassDecodersMap =
+ new HashMap<Class<?>, PublicKeyEntryDecoder<?,?>>();
static {
registerPublicKeyEntryDecoder(RSAPublicKeyDecoder.INSTANCE);
@@ -67,18 +74,61 @@ public class KeyUtils {
throw new UnsupportedOperationException("No instance");
}
- public static void registerPublicKeyEntryDecoder(PublicKeyEntryDecoder<? extends PublicKey> decoder) {
+ /**
+ * @param keyType The key type - {@code OpenSSH} name - e.g., {@code ssh-rsa, ssh-dss}
+ * @param keySize The key size (in bits)
+ * @return A {@link KeyPair} of the specified type and size
+ * @throws GeneralSecurityException If failed to generate the key pair
+ * @see #getPublicKeyEntryDecoder(String)
+ * @see PublicKeyEntryDecoder#generateKeyPair(int)
+ */
+ public static KeyPair generateKeyPair(String keyType, int keySize) throws GeneralSecurityException {
+ PublicKeyEntryDecoder<?,?> decoder = getPublicKeyEntryDecoder(keyType);
+ if (decoder == null) {
+ throw new InvalidKeySpecException("No decoder for key type=" + keyType);
+ }
+
+ return decoder.generateKeyPair(keySize);
+ }
+
+ /**
+ * Performs a deep-clone of the original {@link KeyPair} - i.e., creates
+ * <U>new</U> public/private keys that are clones of the original one
+ * @param keyType The key type - {@code OpenSSH} name - e.g., {@code ssh-rsa, ssh-dss}
+ * @param kp The {@link KeyPair} to clone - ignored if {@code null}
+ * @return The cloned instance
+ * @throws GeneralSecurityException If failed to clone the pair
+ */
+ public static KeyPair cloneKeyPair(String keyType, KeyPair kp) throws GeneralSecurityException {
+ PublicKeyEntryDecoder<?,?> decoder = getPublicKeyEntryDecoder(keyType);
+ if (decoder == null) {
+ throw new InvalidKeySpecException("No decoder for key type=" + keyType);
+ }
+
+ return decoder.cloneKeyPair(kp);
+ }
+
+ /**
+ * @param decoder The decoder to register
+ * @throws IllegalArgumentException if no decoder or not key type or no
+ * supported names for the decoder
+ * @see PublicKeyEntryDecoder#getPublicKeyType()
+ * @see PublicKeyEntryDecoder#getSupportedTypeNames()
+ */
+ public static void registerPublicKeyEntryDecoder(PublicKeyEntryDecoder<?,?> decoder) {
ValidateUtils.checkNotNull(decoder, "No decoder specified", GenericUtils.EMPTY_OBJECT_ARRAY);
- Class<?> keyType = ValidateUtils.checkNotNull(decoder.getKeyType(), "No key type declared", GenericUtils.EMPTY_OBJECT_ARRAY);
+ Class<?> pubType = ValidateUtils.checkNotNull(decoder.getPublicKeyType(), "No public key type declared", GenericUtils.EMPTY_OBJECT_ARRAY);
+ Class<?> prvType = ValidateUtils.checkNotNull(decoder.getPrivateKeyType(), "No private key type declared", GenericUtils.EMPTY_OBJECT_ARRAY);
synchronized(byKeyClassDecodersMap) {
- byKeyClassDecodersMap.put(keyType, decoder);
+ byKeyClassDecodersMap.put(pubType, decoder);
+ byKeyClassDecodersMap.put(prvType, decoder);
}
Collection<String> names = ValidateUtils.checkNotNullAndNotEmpty(decoder.getSupportedTypeNames(), "No supported key type", GenericUtils.EMPTY_OBJECT_ARRAY);
synchronized(byKeyTypeDecodersMap) {
for (String n : names) {
- PublicKeyEntryDecoder<? extends PublicKey> prev = byKeyTypeDecodersMap.put(n, decoder);
+ PublicKeyEntryDecoder<?,?> prev = byKeyTypeDecodersMap.put(n, decoder);
if (prev != null) {
continue; // debug breakpoint
}
@@ -87,10 +137,11 @@ public class KeyUtils {
}
/**
- * @param keyType The {@code OpenSSH} key type string - ignored if {@code null}/empty
+ * @param keyType The {@code OpenSSH} key type string - e.g., {@code ssh-rsa, ssh-dss}
+ * - ignored if {@code null}/empty
* @return The registered {@link PublicKeyEntryDecoder} or {code null} if not found
*/
- public static PublicKeyEntryDecoder<? extends PublicKey> getPublicKeyEntryDecoder(String keyType) {
+ public static PublicKeyEntryDecoder<?,?> getPublicKeyEntryDecoder(String keyType) {
if (GenericUtils.isEmpty(keyType)) {
return null;
}
@@ -101,11 +152,11 @@ public class KeyUtils {
}
/**
- * @param key The {@link PublicKey} - ignored if {@code null}
+ * @param key The {@link Key} (public or private) - ignored if {@code null}
* @return The registered {@link PublicKeyEntryDecoder} for this key or {code null} if no match found
* @see #getPublicKeyEntryDecoder(Class)
*/
- public static PublicKeyEntryDecoder<? extends PublicKey> getPublicKeyEntryDecoder(PublicKey key) {
+ public static PublicKeyEntryDecoder<?,?> getPublicKeyEntryDecoder(Key key) {
if (key == null) {
return null;
} else {
@@ -114,27 +165,27 @@ public class KeyUtils {
}
/**
- * @param keyType The key {@link Class} - ignored if {@code null} or not a {@link PublicKey}
+ * @param keyType The key {@link Class} - ignored if {@code null} or not a {@link Key}
* compatible type
* @return The registered {@link PublicKeyEntryDecoder} or {code null} if no match found
*/
- public static PublicKeyEntryDecoder<? extends PublicKey> getPublicKeyEntryDecoder(Class<?> keyType) {
- if ((keyType == null) || (!PublicKey.class.isAssignableFrom(keyType))) {
+ public static PublicKeyEntryDecoder<?,?> getPublicKeyEntryDecoder(Class<?> keyType) {
+ if ((keyType == null) || (!Key.class.isAssignableFrom(keyType))) {
return null;
}
synchronized(byKeyTypeDecodersMap) {
{
- PublicKeyEntryDecoder<? extends PublicKey> decoder=byKeyClassDecodersMap.get(keyType);
+ PublicKeyEntryDecoder<?,?> decoder=byKeyClassDecodersMap.get(keyType);
if (decoder != null) {
return decoder;
}
}
// in case it is a derived class
- for (PublicKeyEntryDecoder<? extends PublicKey> decoder : byKeyClassDecodersMap.values()) {
- Class<?> t = decoder.getKeyType();
- if (t.isAssignableFrom(keyType)) {
+ for (PublicKeyEntryDecoder<?,?> decoder : byKeyClassDecodersMap.values()) {
+ Class<?> pubType = decoder.getPublicKeyType(), prvType = decoder.getPrivateKeyType();
+ if (pubType.isAssignableFrom(keyType) || prvType.isAssignableFrom(keyType)) {
return decoder;
}
}
@@ -157,14 +208,39 @@ public class KeyUtils {
try {
Buffer buffer = new ByteArrayBuffer();
buffer.putRawPublicKey(key);
- Digest md5 = BuiltinDigests.md5.create();
- md5.init();
- md5.update(buffer.array(), 0, buffer.wpos());
- byte[] data = md5.digest();
- return BufferUtils.printHex(data, 0, data.length, ':');
+ return getFingerPrint(buffer.array(), 0, buffer.wpos());
+ } catch(Exception e) {
+ return e.getClass().getSimpleName();
+ }
+ }
+
+ public static String getFingerPrint(String password) {
+ if (GenericUtils.isEmpty(password)) {
+ return null;
+ }
+
+ try {
+ return getFingerPrint(password.getBytes(StandardCharsets.UTF_8));
} catch(Exception e) {
- return "Unable to compute fingerprint";
+ return e.getClass().getSimpleName();
+ }
+ }
+
+ public static String getFingerPrint(byte ... buf) throws Exception {
+ return getFingerPrint(buf, 0, GenericUtils.length(buf));
+ }
+
+ public static String getFingerPrint(byte[] buf, int offset, int len) throws Exception {
+ if (len <= 0) {
+ return null;
}
+
+ Digest md5 = BuiltinDigests.md5.create();
+ md5.init();
+ md5.update(buf, offset, len);
+
+ byte[] data = md5.digest();
+ return BufferUtils.printHex(data, 0, data.length, ':');
}
/**
@@ -232,6 +308,72 @@ public class KeyUtils {
return null;
}
+ public static boolean compareKeyPairs(KeyPair k1, KeyPair k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ }
+
+ if (compareKeys(k1.getPublic(), k2.getPublic())
+ && compareKeys(k1.getPrivate(), k2.getPrivate())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean compareKeys(PrivateKey k1, PrivateKey k2) {
+ if ((k1 instanceof RSAPrivateKey) && (k2 instanceof RSAPrivateKey)) {
+ return compareRSAKeys(RSAPrivateKey.class.cast(k1), RSAPrivateKey.class.cast(k2));
+ } else if ((k1 instanceof DSAPrivateKey) && (k2 instanceof DSAPrivateKey)) {
+ return compareDSAKeys(DSAPrivateKey.class.cast(k1), DSAPrivateKey.class.cast(k2));
+ } else if ((k1 instanceof ECPrivateKey) && (k2 instanceof ECPrivateKey)) {
+ return compareECKeys(ECPrivateKey.class.cast(k1), ECPrivateKey.class.cast(k2));
+ } else {
+ return false; // either key is null or not of same class
+ }
+ }
+
+ public static boolean compareRSAKeys(RSAPrivateKey k1, RSAPrivateKey k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ } else if (Objects.equals(k1.getModulus(), k2.getModulus())
+ && Objects.equals(k1.getPrivateExponent(), k2.getPrivateExponent())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean compareDSAKeys(DSAPrivateKey k1, DSAPrivateKey k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ } else if (Objects.equals(k1.getX(), k2.getAlgorithm())
+ && compareDSAParams(k1.getParams(), k2.getParams())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean compareECKeys(ECPrivateKey k1, ECPrivateKey k2) {
+ if (Objects.equals(k1, k2)) {
+ return true;
+ } else if ((k1 == null) || (k2 == null)) {
+ return false; // both null is covered by Objects#equals
+ } else if (Objects.equals(k1.getS(), k2.getS())
+ && compareECParams(k1.getParams(), k2.getParams())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public static boolean compareKeys(PublicKey k1, PublicKey k2) {
if ((k1 instanceof RSAPublicKey) && (k2 instanceof RSAPublicKey)) {
return compareRSAKeys(RSAPublicKey.class.cast(k1), RSAPublicKey.class.cast(k2));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
index 28708fb..cd3ec94 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
@@ -83,7 +83,7 @@ public class PublicKeyEntry implements Serializable {
*/
public PublicKey resolvePublicKey() throws IOException, GeneralSecurityException {
String kt = getKeyType();
- PublicKeyEntryDecoder<? extends PublicKey> decoder = KeyUtils.getPublicKeyEntryDecoder(kt);
+ PublicKeyEntryDecoder<?,?> decoder = KeyUtils.getPublicKeyEntryDecoder(kt);
if (decoder == null) {
throw new InvalidKeySpecException("No decoder registered for key type=" + kt);
}
@@ -228,7 +228,7 @@ public class PublicKeyEntry implements Serializable {
*/
public static final <A extends Appendable> A appendPublicKeyEntry(A sb, PublicKey key) throws IOException {
@SuppressWarnings("unchecked")
- PublicKeyEntryDecoder<PublicKey> decoder = (PublicKeyEntryDecoder<PublicKey>) KeyUtils.getPublicKeyEntryDecoder(key);
+ PublicKeyEntryDecoder<PublicKey,?> decoder = (PublicKeyEntryDecoder<PublicKey,?>) KeyUtils.getPublicKeyEntryDecoder(key);
if (decoder == null) {
throw new StreamCorruptedException("Cannot retrived decoder for key=" + key.getAlgorithm());
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
index fc43bb3..dbff853 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
@@ -23,6 +23,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Collection;
@@ -30,12 +34,18 @@ import java.util.Collection;
* Represents a decoder of an {@code OpenSSH} encoded key data
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface PublicKeyEntryDecoder<K extends PublicKey> {
+public interface PublicKeyEntryDecoder<PUB extends PublicKey,PRV extends PrivateKey> {
/**
* @return The {@link Class} of the {@link PublicKey} that is the result
* of decoding
*/
- Class<K> getKeyType();
+ Class<PUB> getPublicKeyType();
+
+ /**
+ * @return The {@link Class} of the {@link PrivateKey} that matches the
+ * public one
+ */
+ Class<PRV> getPrivateKeyType();
/**
* @return The {@link Collection} of {@code OpenSSH} key type names that
@@ -43,7 +53,44 @@ public interface PublicKeyEntryDecoder<K extends PublicKey> {
* <B>Caveat:</B> this collection may be un-modifiable...
*/
Collection<String> getSupportedTypeNames();
-
+
+ /**
+ * @param keySize Key size in bits
+ * @return A {@link KeyPair} with the specified key size
+ * @throws GeneralSecurityException if unable to generate the pair
+ */
+ KeyPair generateKeyPair(int keySize) throws GeneralSecurityException;
+
+ /**
+ * @param kp The {@link KeyPair} to be cloned - ignored if {@code null}
+ * @return A cloned pair (or {@code null} if no original pair)
+ * @throws GeneralSecurityException If failed to clone - e.g., provided key
+ * pair does not contain keys of the expected type
+ * @see #getPublicKeyType()
+ * @see #getPrivateKeyType()
+ */
+ KeyPair cloneKeyPair(KeyPair kp) throws GeneralSecurityException;
+
+ /**
+ * @param key The {@link PublicKey} to clone - ignored if {@code null}
+ * @return The cloned key (or {@code null} if no original key)
+ * @throws GeneralSecurityException If failed to clone the key
+ */
+ PUB clonePublicKey(PUB key) throws GeneralSecurityException;
+
+ /**
+ * @param key The {@link PrivateKey} to clone - ignored if {@code null}
+ * @return The cloned key (or {@code null} if no original key)
+ * @throws GeneralSecurityException If failed to clone the key
+ */
+ PRV clonePrivateKey(PRV key) throws GeneralSecurityException;
+
+ /**
+ * @return A {@link KeyPairGenerator} suitable for this decoder
+ * @throws GeneralSecurityException If failed to create the generator
+ */
+ KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException;
+
/**
* @param keyData The key data bytes in {@code OpenSSH} format (after
* BASE64 decoding) - ignored if {@code null}/empty
@@ -51,9 +98,9 @@ public interface PublicKeyEntryDecoder<K extends PublicKey> {
* @throws IOException If failed to decode the key
* @throws GeneralSecurityException If failed to generate the key
*/
- K decodePublicKey(byte ... keyData) throws IOException, GeneralSecurityException;
- K decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException;
- K decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException;
+ PUB decodePublicKey(byte ... keyData) throws IOException, GeneralSecurityException;
+ PUB decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException;
+ PUB decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException;
/**
* Encodes the {@link PublicKey} using the {@code OpenSSH} format - same
@@ -63,5 +110,11 @@ public interface PublicKeyEntryDecoder<K extends PublicKey> {
* @return The key type value - one of the {@link #getSupportedTypeNames()}
* @throws IOException If failed to generate the encoding
*/
- String encodePublicKey(OutputStream s, K key) throws IOException;
+ String encodePublicKey(OutputStream s, PUB key) throws IOException;
+
+ /**
+ * @return A {@link KeyFactory} suitable for the specific decoder type
+ * @throws GeneralSecurityException If failed to create one
+ */
+ KeyFactory getKeyFactoryInstance() throws GeneralSecurityException;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
index f1b5dcb..5927568 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/RSAPublicKeyDecoder.java
@@ -24,9 +24,14 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collections;
@@ -38,11 +43,11 @@ import org.apache.sshd.common.util.ValidateUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublicKey> {
+public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublicKey,RSAPrivateKey> {
public static final RSAPublicKeyDecoder INSTANCE = new RSAPublicKeyDecoder();
public RSAPublicKeyDecoder() {
- super(RSAPublicKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA)));
+ super(RSAPublicKey.class, RSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA)));
}
@Override
@@ -68,6 +73,43 @@ public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublic
}
@Override
+ public RSAPublicKey clonePublicKey(RSAPublicKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ } else {
+ return generatePublicKey(new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent()));
+ }
+ }
+
+ @Override
+ public RSAPrivateKey clonePrivateKey(RSAPrivateKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ }
+
+ if (!(key instanceof RSAPrivateCrtKey)) {
+ throw new InvalidKeyException("Cannot clone a non-RSAPrivateCrtKey: " + key.getClass().getSimpleName());
+ }
+
+ RSAPrivateCrtKey rsaPrv = (RSAPrivateCrtKey) key;
+ return generatePrivateKey(
+ new RSAPrivateCrtKeySpec(
+ rsaPrv.getModulus(),
+ rsaPrv.getPublicExponent(),
+ rsaPrv.getPrivateExponent(),
+ rsaPrv.getPrimeP(),
+ rsaPrv.getPrimeQ(),
+ rsaPrv.getPrimeExponentP(),
+ rsaPrv.getPrimeExponentQ(),
+ rsaPrv.getCrtCoefficient()));
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException {
+ return SecurityUtils.getKeyPairGenerator("RSA");
+ }
+
+ @Override
public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException {
return SecurityUtils.getKeyFactory("RSA");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
index 8f35ba7..61cfff0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemFactory.java
@@ -25,7 +25,7 @@ import java.nio.file.FileSystems;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Native file system factory. It uses the OS file system.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
index c1bb4e3..bad235f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
@@ -49,8 +49,8 @@ import java.util.Set;
import java.util.concurrent.ExecutorService;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
/**
* File system provider which provides a rooted file system.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java b/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
index 8d263e8..0ee8afe 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/future/DefaultSshFuture.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.future;
import java.lang.reflect.Array;
import java.util.concurrent.TimeUnit;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* A default implementation of {@link SshFuture}.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
index 0cb85f6..9d9b312 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactoryFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.io;
import java.util.concurrent.ExecutorService;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
index a3d57eb..9abbaa4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
@@ -22,7 +22,7 @@ package org.apache.sshd.common.kex.dh;
import org.apache.sshd.common.digest.Digest;
import org.apache.sshd.common.kex.KeyExchange;
import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
index 03ba5f2..9a0aa73 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
@@ -23,9 +23,9 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
index 8453d25..dcb9e36 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/MappedKeyPairProvider.java
@@ -22,8 +22,8 @@ package org.apache.sshd.common.keyprovider;
import java.security.KeyPair;
import java.util.Map;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.common.util.ValidateUtils;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
index 6bc59f0..e84bbb4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/mac/MacFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.mac;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
index 7c2311e..4db74c0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpSourceStreamResolver.java
@@ -29,10 +29,10 @@ import java.nio.file.attribute.PosixFilePermission;
import java.util.Collection;
import java.util.Set;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
index efd7f46..1648b9e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/LocalFileScpTargetStreamResolver.java
@@ -33,8 +33,8 @@ import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import org.apache.sshd.common.util.AbstractLoggingBean;
-import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
index b7d244e..45afa6e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
@@ -43,11 +43,11 @@ import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.file.util.MockPath;
import org.apache.sshd.common.scp.ScpTransferEventListener.FileOperation;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.DirectoryScanner;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.LimitInputStream;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
index 1d25411..ce0287d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
@@ -416,7 +416,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
sendEvent(SessionListener.Event.KeyEstablished);
synchronized (pendingPackets) {
if (!pendingPackets.isEmpty()) {
- log.info("Dequeing pending packets");
+ log.debug("Dequeing pending packets");
synchronized (encodeLock) {
PendingWriteFuture future;
while ((future = pendingPackets.poll()) != null) {
@@ -530,7 +530,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
synchronized (pendingPackets) {
if (kexState.get() != KEX_STATE_DONE) {
if (pendingPackets.isEmpty()) {
- log.info("Start flagging packets as pending until key exchange is done");
+ log.debug("Start flagging packets as pending until key exchange is done");
}
PendingWriteFuture future = new PendingWriteFuture(buffer);
pendingPackets.add(future);
@@ -1159,7 +1159,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
protected void negotiate() {
String[] guess = new String[SshConstants.PROPOSAL_MAX];
for (int i = 0; i < SshConstants.PROPOSAL_MAX; i++) {
- String paramName = SshConstants.PROPOSAL_KEX_NAMES[i];
+ String paramName = SshConstants.PROPOSAL_KEX_NAMES.get(i);
String clientParamValue = clientProposal[i];
String serverParamValue = serverProposal[i];
String[] c = clientParamValue.split(",");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java b/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
index 26764a7..fcabbe1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/SessionTimeoutListener.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.session;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Task that iterates over all currently open {@link AbstractSession}s and checks each of them for timeouts. If
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
index 26abe3c..e0880d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.signature;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java b/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java
deleted file mode 100644
index 39131c8..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/AbstractLoggingBean.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.common.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Serves as a common base class for the vast majority of classes that require
- * some kind of logging. Facilitates quick and easy replacement of the actual used
- * logger from one framework to another
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractLoggingBean {
- protected final Logger log;
-
- /**
- * Default constructor - creates a logger using the full class name
- */
- protected AbstractLoggingBean() {
- log = LoggerFactory.getLogger(getClass());
- }
-
- /**
- * Create a logger for instances of the same class for which we might
- * want to have a "discriminator" for them
- * @param discriminator The discriminator value
- */
- protected AbstractLoggingBean(String discriminator) {
- log = LoggerFactory.getLogger(getClass().getName() + "[" + discriminator + "]");
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
index 9710d57..a75f470 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/CloseableUtils.java
@@ -36,13 +36,17 @@ import org.apache.sshd.common.future.DefaultCloseFuture;
import org.apache.sshd.common.future.DefaultSshFuture;
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Utility class to help with {@link Closeable}s.
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class CloseableUtils {
+public final class CloseableUtils {
+ private CloseableUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
// TODO once JDK 8+ becomes the minimum for this project, make it a static method in the Closeable interface
public static void close(Closeable closeable) throws IOException {
@@ -349,6 +353,7 @@ public class CloseableUtils {
if (grace != null) {
grace.addListener(new SshFutureListener<CloseFuture>() {
@Override
+ @SuppressWarnings("synthetic-access")
public void operationComplete(CloseFuture future) {
if (state.compareAndSet(State.Graceful, State.Immediate)) {
doCloseImmediately();
@@ -438,8 +443,4 @@ public class CloseableUtils {
});
}
}
-
- private CloseableUtils() {
- throw new UnsupportedOperationException("No instance allowed");
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
index b89774f..48df9f4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
@@ -28,7 +28,11 @@ import java.util.EventListener;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class EventListenerUtils {
+public final class EventListenerUtils {
+ private EventListenerUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
/**
* Provides proxy wrapper around an {@link Iterable} container of listener
* interface implementation. <b>Note:</b> a listener interface is one whose
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
index 657a6ad..6d049e8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -35,11 +35,15 @@ import java.util.TreeSet;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class GenericUtils {
+public final class GenericUtils {
public static final byte[] EMPTY_BYTE_ARRAY={ };
public static final String[] EMPTY_STRING_ARRAY={ };
public static final Object[] EMPTY_OBJECT_ARRAY={ };
+ private GenericUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
public static final String trimToEmpty(String s) {
if (s == null) {
return "";
@@ -333,4 +337,27 @@ public class GenericUtils {
return s.subSequence(1, lastPos);
}
}
+
+ /**
+ * Used to "accumulate" exceptions of the <U>same type</U>. If the
+ * current exception is {@code null} then the new one becomes the current,
+ * otherwise the new one is added as a <U>suppressed</U> exception to the
+ * current one
+ * @param current The current exception
+ * @param extra The extra/new exception
+ * @return The resolved exception
+ * @see Throwable#addSuppressed(Throwable)
+ */
+ public static <T extends Throwable> T accumulateException(T current, T extra) {
+ if (current == null) {
+ return extra;
+ }
+
+ if ((extra == null) || (extra == current)) {
+ return current;
+ }
+
+ current.addSuppressed(extra);
+ return current;
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
deleted file mode 100644
index da17c22..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.common.util;
-
-import java.io.Closeable;
-import java.io.EOFException;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.FileSystem;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.attribute.PosixFilePermission;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class IoUtils {
-
- public static final LinkOption[] EMPTY_OPTIONS = new LinkOption[0];
- private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
-
- public static LinkOption[] getLinkOptions(boolean followLinks) {
- if (followLinks) {
- return EMPTY_OPTIONS;
- } else { // return a clone that modifications to the array will not affect others
- return NO_FOLLOW_OPTIONS.clone();
- }
- }
-
- public static final int DEFAULT_COPY_SIZE=8192;
-
- public static long copy(InputStream source, OutputStream sink) throws IOException {
- return copy(source, sink, DEFAULT_COPY_SIZE);
- }
-
- public static long copy(InputStream source, OutputStream sink, int bufferSize) throws IOException {
- long nread = 0L;
- byte[] buf = new byte[bufferSize];
- int n;
- while ((n = source.read(buf)) > 0) {
- sink.write(buf, 0, n);
- nread += n;
- }
- return nread;
- }
-
- public static void closeQuietly(Closeable... closeables) {
- for (Closeable c : closeables) {
- try {
- if (c != null) {
- c.close();
- }
- } catch (IOException e) {
- // Ignore
- }
- }
- }
-
- public static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS = Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
-
- /**
- * @param fileName The file name to be evaluated - ignored if {@code null}/empty
- * @return {@code true} if the file ends in one of the {@link #WINDOWS_EXECUTABLE_EXTENSIONS}
- */
- public static boolean isWindowsExecutable(String fileName) {
- if ((fileName == null) || (fileName.length() <= 0)) {
- return false;
- }
- for (String suffix : WINDOWS_EXECUTABLE_EXTENSIONS) {
- if (fileName.endsWith(suffix)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * If the "posix" view is supported, then it returns
- * {@link Files#getPosixFilePermissions(Path, LinkOption...)}, otherwise
- * uses the {@link #getPermissionsFromFile(File)} method
- * @param path The {@link Path}
- * @return A {@link Set} of {@link PosixFilePermission}
- * @throws IOException If failed to access the file system in order to
- * retrieve the permissions
- */
- public static Set<PosixFilePermission> getPermissions(Path path) throws IOException {
- FileSystem fs = path.getFileSystem();
- Collection<String> views = fs.supportedFileAttributeViews();
- if (views.contains("posix")) {
- return Files.getPosixFilePermissions(path, getLinkOptions(false));
- } else {
- return getPermissionsFromFile(path.toFile());
- }
- }
-
- /**
- * @param f The {@link File} to be checked
- * @return A {@link Set} of {@link PosixFilePermission}s based on whether
- * the file is readable/writable/executable. If so, then <U>all</U> the
- * relevant permissions are set (i.e., owner, group and others)
- */
- public static Set<PosixFilePermission> getPermissionsFromFile(File f) {
- Set<PosixFilePermission> perms = EnumSet.noneOf(PosixFilePermission.class);
- if (f.canRead()) {
- perms.add(PosixFilePermission.OWNER_READ);
- perms.add(PosixFilePermission.GROUP_READ);
- perms.add(PosixFilePermission.OTHERS_READ);
- }
-
- if (f.canWrite()) {
- perms.add(PosixFilePermission.OWNER_WRITE);
- perms.add(PosixFilePermission.GROUP_WRITE);
- perms.add(PosixFilePermission.OTHERS_WRITE);
- }
-
- if (f.canExecute() || (OsUtils.isWin32() && isWindowsExecutable(f.getName()))) {
- perms.add(PosixFilePermission.OWNER_EXECUTE);
- perms.add(PosixFilePermission.GROUP_EXECUTE);
- perms.add(PosixFilePermission.OTHERS_EXECUTE);
- }
-
- return perms;
- }
-
- /**
- * If the "posix" view is supported, then it invokes
- * {@link Files#setPosixFilePermissions(Path, Set)}, otherwise
- * uses the {@link #setPermissionsToFile(File, Collection)} method
- * @param path The {@link Path}
- * @param perms The {@link Set} of {@link PosixFilePermission}s
- * @throws IOException If failed to access the file system
- */
- public static void setPermissions(Path path, Set<PosixFilePermission> perms) throws IOException {
- FileSystem fs = path.getFileSystem();
- Collection<String> views = fs.supportedFileAttributeViews();
- if (views.contains("posix")) {
- Files.setPosixFilePermissions(path, perms);
- } else {
- setPermissionsToFile(path.toFile(), perms);
- }
- }
-
- /**
- * @param f The {@link File}
- * @param perms A {@link Collection} of {@link PosixFilePermission}s to set on it.
- * <B>Note:</B> the file is set to readable/writable/executable not only by the
- * owner if <U>any</U> of relevant the owner/group/others permission is set
- */
- public static void setPermissionsToFile(File f, Collection<PosixFilePermission> perms) {
- boolean readable = perms != null &&
- (perms.contains(PosixFilePermission.OWNER_READ)
- || perms.contains(PosixFilePermission.GROUP_READ)
- || perms.contains(PosixFilePermission.OTHERS_READ));
- f.setReadable(readable, false);
-
- boolean writable = perms != null &&
- (perms.contains(PosixFilePermission.OWNER_WRITE)
- || perms.contains(PosixFilePermission.GROUP_WRITE)
- || perms.contains(PosixFilePermission.OTHERS_WRITE));
- f.setWritable(writable, false);
-
- boolean executable = perms != null &&
- (perms.contains(PosixFilePermission.OWNER_EXECUTE)
- || perms.contains(PosixFilePermission.GROUP_EXECUTE)
- || perms.contains(PosixFilePermission.OTHERS_EXECUTE));
- f.setExecutable(executable, false);
- }
-
- /**
- * <P>Checks if a file exists - <B>Note:</B> according to the
- * <A HREF="http://docs.oracle.com/javase/tutorial/essential/io/check.html">Java tutorial - Checking a File or Directory</A>:
- * </P></BR>
- * <PRE>
- * The methods in the Path class are syntactic, meaning that they operate
- * on the Path instance. But eventually you must access the file system
- * to verify that a particular Path exists, or does not exist. You can do
- * so with the exists(Path, LinkOption...) and the notExists(Path, LinkOption...)
- * methods. Note that !Files.exists(path) is not equivalent to Files.notExists(path).
- * When you are testing a file's existence, three results are possible:
- *
- * - The file is verified to exist.
- * - The file is verified to not exist.
- * - The file's status is unknown.
- *
- * This result can occur when the program does not have access to the file.
- * If both exists and notExists return false, the existence of the file cannot
- * be verified.
- * </PRE>
- * @param path The {@link Path} to be tested
- * @param options The {@link LinkOption}s to use
- * @return {@link Boolean#TRUE}/{@link Boolean#FALSE} or {@code null}
- * according to the file status as explained above
- */
- public static Boolean checkFileExists(Path path, LinkOption ... options) {
- if (Files.exists(path, options)) {
- return Boolean.TRUE;
- } else if (Files.notExists(path, options)) {
- return Boolean.FALSE;
- } else {
- return null;
- }
- }
-
- /**
- * Read the requested number of bytes or fail if there are not enough left.
- * @param input where to read input from
- * @param buffer destination
- * @throws IOException if there is a problem reading the file
- * @throws EOFException if the number of bytes read was incorrect
- */
- public static void readFully(InputStream input, byte[] buffer) throws IOException {
- readFully(input, buffer, 0, buffer.length);
- }
-
- /**
- * Read the requested number of bytes or fail if there are not enough left.
- * @param input where to read input from
- * @param buffer destination
- * @param offset initial offset into buffer
- * @param length length to read, must be >= 0
- * @throws IOException if there is a problem reading the file
- * @throws EOFException if the number of bytes read was incorrect
- */
- public static void readFully(InputStream input, byte[] buffer, int offset, int length) throws IOException {
- int actual = read(input, buffer, offset, length);
- if (actual != length) {
- throw new EOFException("Premature EOF - expected=" + length + ", actual=" + actual);
- }
- }
-
- /**
- * Read as many bytes as possible until EOF or achieved required length
- * @param input where to read input from
- * @param buffer destination
- * @return actual length read; may be less than requested if EOF was reached
- * @throws IOException if a read error occurs
- */
- public static int read(InputStream input, byte[] buffer) throws IOException {
- return read(input, buffer, 0, buffer.length);
- }
-
- /**
- * Read as many bytes as possible until EOF or achieved required length
- * @param input where to read input from
- * @param buffer destination
- * @param offset initial offset into buffer
- * @param length length to read - ignored if non-positive
- * @return actual length read; may be less than requested if EOF was reached
- * @throws IOException if a read error occurs
- */
- public static int read(InputStream input, byte[] buffer, int offset, int length) throws IOException {
- for (int remaining = length, curOffset = offset; remaining > 0; ) {
- int count = input.read(buffer, curOffset, remaining);
- if (count == (-1)) { // EOF before achieved required length
- return curOffset - offset;
- }
-
- remaining -= count;
- curOffset += count;
- }
-
- return length;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
index f693a8e..08f1d1b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/OsUtils.java
@@ -23,7 +23,7 @@ package org.apache.sshd.common.util;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class OsUtils {
+public final class OsUtils {
private static final boolean win32;
static {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
index 1bb460f..f23029d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
@@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SecurityUtils {
-
public static final String BOUNCY_CASTLE = "BC";
private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);
@@ -49,6 +48,10 @@ public class SecurityUtils {
private static boolean registrationDone;
private static Boolean hasEcc;
+ private SecurityUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
public static boolean hasEcc() {
if (hasEcc == null) {
try {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java
new file mode 100644
index 0000000..19ba9c4
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/Transformer.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.util;
+
+import java.util.Objects;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Transformer<I, O> {
+ // TODO in JDK-8 replace this with Function
+ /**
+ * @param input Input value
+ * @return Transformed output value
+ */
+ O transform(I input);
+
+ /**
+ * Invokes {@link Objects#toString(Object)} on the argument
+ */
+ Transformer<Object,String> TOSTRING=new Transformer<Object,String>() {
+ @Override
+ public String transform(Object input) {
+ return Objects.toString(input);
+ }
+ };
+
+ /**
+ * Returns {@link Enum#name()} or {@code null} if argument is {@code null}
+ */
+ Transformer<Enum<?>,String> ENUM_NAME_EXTRACTOR=new Transformer<Enum<?>,String>() {
+ @Override
+ public String transform(Enum<?> input) {
+ if (input == null) {
+ return null;
+ } else {
+ return input.name();
+ }
+ }
+ };
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
index 9e270ab..78e1fc1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
@@ -25,7 +25,11 @@ import java.util.Map;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class ValidateUtils {
+public final class ValidateUtils {
+ private ValidateUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
public static final <T> T checkNotNull(T t, String message, Object ... args) {
checkTrue(t != null, message, args);
return t;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
index 74ff9df..784daa7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
@@ -149,10 +149,6 @@ public abstract class Buffer implements Readable {
public abstract String getString(Charset charset);
- public byte[] getStringAsBytes() {
- return getBytes();
- }
-
public BigInteger getMPInt() {
return new BigInteger(getMPIntAsBytes());
}
@@ -189,42 +185,47 @@ public abstract class Buffer implements Readable {
public PublicKey getRawPublicKey() throws SshException {
try {
- PublicKey key;
String keyAlg = getString();
if (KeyPairProvider.SSH_RSA.equals(keyAlg)) {
BigInteger e = getMPInt();
BigInteger n = getMPInt();
KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
- key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
+ return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
} else if (KeyPairProvider.SSH_DSS.equals(keyAlg)) {
BigInteger p = getMPInt();
BigInteger q = getMPInt();
BigInteger g = getMPInt();
BigInteger y = getMPInt();
KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
- key = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP256.equals(keyAlg)) {
- key = getRawECKey("nistp256", ECCurves.EllipticCurves.nistp256);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP384.equals(keyAlg)) {
- key = getRawECKey("nistp384", ECCurves.EllipticCurves.nistp384);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP521.equals(keyAlg)) {
- key = getRawECKey("nistp521", ECCurves.EllipticCurves.nistp521);
+ return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
+ } else if (keyAlg.startsWith(ECCurves.ECDSA_SHA2_PREFIX)) {
+ String curveName = keyAlg.substring(ECCurves.ECDSA_SHA2_PREFIX.length());
+ ECParameterSpec params = ECCurves.getECParameterSpec(curveName);
+ return getRawECKey(curveName, params);
} else {
throw new NoSuchAlgorithmException("Unsupported raw public algorithm: " + keyAlg);
}
- return key;
} catch (GeneralSecurityException e) {
throw new SshException(e);
}
}
- protected PublicKey getRawECKey(String expectedCurve, ECParameterSpec spec) throws GeneralSecurityException, SshException {
+ protected PublicKey getRawECKey(String expectedCurve, ECParameterSpec spec) throws GeneralSecurityException {
String curveName = getString();
if (!expectedCurve.equals(curveName)) {
- throw new InvalidKeySpecException("Curve name does not match expected: " + curveName + " vs "
- + expectedCurve);
+ throw new InvalidKeySpecException("getRawECKey(" + expectedCurve + ") curve name does not match expected: " + curveName);
+ }
+
+ if (spec == null) {
+ throw new InvalidKeySpecException("getRawECKey(" + expectedCurve + ") missing curve parameters");
+ }
+
+ byte[] octets = getBytes();
+ ECPoint w = ECCurves.decodeECPoint(octets, spec.getCurve());
+ if (w == null) {
+ throw new InvalidKeySpecException("getRawECKey(" + expectedCurve + ") cannot retrieve W value");
}
- ECPoint w = ECCurves.decodeECPoint(getStringAsBytes(), spec.getCurve());
+
KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
return keyFactory.generatePublic(new ECPublicKeySpec(w, spec));
}
@@ -255,12 +256,10 @@ public abstract class Buffer implements Readable {
KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
pub = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
prv = keyFactory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g));
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP256.equals(keyAlg)) {
- return extractEC("nistp256", ECCurves.EllipticCurves.nistp256);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP384.equals(keyAlg)) {
- return extractEC("nistp384", ECCurves.EllipticCurves.nistp384);
- } else if (KeyPairProvider.ECDSA_SHA2_NISTP521.equals(keyAlg)) {
- return extractEC("nistp521", ECCurves.EllipticCurves.nistp521);
+ } else if (keyAlg.startsWith(ECCurves.ECDSA_SHA2_PREFIX)) {
+ String curveName = keyAlg.substring(ECCurves.ECDSA_SHA2_PREFIX.length());
+ ECParameterSpec params = ECCurves.getECParameterSpec(curveName);
+ return extractEC(curveName, params);
} else {
throw new NoSuchAlgorithmException("Unsupported key pair algorithm: " + keyAlg);
}
@@ -270,18 +269,22 @@ public abstract class Buffer implements Readable {
}
}
- protected KeyPair extractEC(String expectedCurveName, ECParameterSpec spec) throws GeneralSecurityException, SshException {
+ protected KeyPair extractEC(String expectedCurveName, ECParameterSpec spec) throws GeneralSecurityException {
String curveName = getString();
- byte[] groupBytes = getStringAsBytes();
+ if (!expectedCurveName.equals(curveName)) {
+ throw new InvalidKeySpecException("extractEC(" + expectedCurveName + ") mismatched curve name: " + curveName);
+ }
+
+ byte[] groupBytes = getBytes();
BigInteger exponent = getMPInt();
- if (!expectedCurveName.equals(curveName)) {
- throw new SshException("Expected curve " + expectedCurveName + " but was " + curveName);
+ if (spec == null) {
+ throw new InvalidKeySpecException("extractEC(" + expectedCurveName + ") missing parameters for curve");
}
ECPoint group = ECCurves.decodeECPoint(groupBytes, spec.getCurve());
if (group == null) {
- throw new InvalidKeySpecException("Couldn't decode EC group");
+ throw new InvalidKeySpecException("extractEC(" + expectedCurveName + ") couldn't decode EC group for curve");
}
KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java
new file mode 100644
index 0000000..ecb0144
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/CloseableEmptyInputStream.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.util.io;
+
+import java.io.IOException;
+import java.nio.channels.Channel;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A {@code /dev/null} stream that can be closed - in which case it will throw
+ * {@link IOException}s if invoked after being closed
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class CloseableEmptyInputStream extends EmptyInputStream implements Channel {
+ private final AtomicBoolean open = new AtomicBoolean(true);
+
+ public CloseableEmptyInputStream() {
+ super();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return open.get();
+ }
+
+ @Override
+ public int available() throws IOException {
+ if (isOpen()) {
+ return super.available();
+ } else {
+ throw new IOException("available() stream is closed");
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (isOpen()) {
+ return super.read();
+ } else {
+ throw new IOException("read() stream is closed");
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (isOpen()) {
+ return super.read(b, off, len);
+ } else {
+ throw new IOException("read([])[" + off + "," + len + "] stream is closed");
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ if (isOpen()) {
+ return super.skip(n);
+ } else {
+ throw new IOException("skip(" + n + ") stream is closed");
+ }
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (isOpen()) {
+ super.reset();
+ } else {
+ throw new IOException("reset() stream is closed");
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (open.getAndSet(false)) {
+ return; // debug breakpoint
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java
new file mode 100644
index 0000000..1047a5f
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/EmptyInputStream.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A {@code /dev/null} implementation - always open
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EmptyInputStream extends InputStream {
+ public static final EmptyInputStream DEV_NULL = new EmptyInputStream();
+
+ public EmptyInputStream() {
+ super();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return (-1);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return (-1);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return 0L;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ throw new UnsupportedOperationException("mark(" + readlimit + ") called despite the fact that markSupported=" + markSupported());
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ // ignored
+ }
+}