update to OpenJDK 21, update to Grdle 8.4, add key parameter for loading private key by classloader

stable 4.1.0
Jörg Prante 9 months ago
parent 4eff2cd434
commit 2b879107d7

1
.gitignore vendored

@ -15,6 +15,7 @@ logs
*~
.secret
build
**/*.key
**/*.crt
**/*.pkcs8
**/*.gz

@ -4,9 +4,10 @@ plugins {
id "pmd"
id 'maven-publish'
id 'signing'
id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
id "com.github.spotbugs" version "5.0.14"
id "org.cyclonedx.bom" version "1.7.2"
id "io.github.gradle-nexus.publish-plugin" version "2.0.0-rc-1"
id "com.github.spotbugs" version "6.0.0-beta.3"
id "org.cyclonedx.bom" version "1.7.4"
id "org.xbib.gradle.plugin.asciidoctor" version "3.0.0"
}
wrapper {
@ -30,14 +31,14 @@ ext {
}
subprojects {
apply from: rootProject.file('gradle/ide/idea.gradle')
//apply from: rootProject.file('gradle/ide/idea.gradle')
apply from: rootProject.file('gradle/repositories/maven.gradle')
apply from: rootProject.file('gradle/compile/java.gradle')
apply from: rootProject.file('gradle/test/junit5.gradle')
apply from: rootProject.file('gradle/publish/maven.gradle')
apply from: rootProject.file('gradle/quality/checkstyle.gradle')
apply from: rootProject.file('gradle/quality/pmd.gradle')
apply from: rootProject.file('gradle/quality/spotbugs.gradle')
//apply from: rootProject.file('gradle/quality/spotbugs.gradle')
}
apply from: rootProject.file('gradle/publish/sonatype.gradle')
apply from: rootProject.file('gradle/publish/forgejo.gradle')

@ -49,11 +49,11 @@ import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyCollectionOf;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -330,7 +330,7 @@ public class FTPFileSystemTest extends AbstractFTPFileSystemTest {
try (OutputStream input = getFileSystem().newOutputStream(createPath("/foo/bar"), options)) {
// don't do anything with the stream, there's a separate test for that
} finally {
verify(getExceptionFactory()).createNewOutputStreamException(eq("/foo/bar"), eq(553), anyString(), anyCollectionOf(OpenOption.class));
verify(getExceptionFactory()).createNewOutputStreamException(eq("/foo/bar"), eq(553), anyString(), anyList());
assertSame(foo, getFileSystemEntry("/foo"));
assertSame(bar, getFileSystemEntry("/foo/bar"));
}
@ -347,7 +347,7 @@ public class FTPFileSystemTest extends AbstractFTPFileSystemTest {
try (OutputStream input = getFileSystem().newOutputStream(createPath("/foo/bar"), options)) {
// don't do anything with the stream, there's a separate test for that
} finally {
verify(getExceptionFactory()).createNewOutputStreamException(eq("/foo/bar"), eq(553), anyString(), anyCollectionOf(OpenOption.class));
verify(getExceptionFactory()).createNewOutputStreamException(eq("/foo/bar"), eq(553), anyString(), anyList());
assertSame(foo, getFileSystemEntry("/foo"));
assertSame(bar, getFileSystemEntry("/foo/bar"));
}
@ -427,8 +427,7 @@ public class FTPFileSystemTest extends AbstractFTPFileSystemTest {
try (OutputStream input = getFileSystem().newOutputStream(createPath("/foo"), options)) {
// don't do anything with the stream, there's a separate test for that
} finally {
verify(getExceptionFactory(), never()).createNewOutputStreamException(anyString(), anyInt(), anyString(),
anyCollectionOf(OpenOption.class));
verify(getExceptionFactory(), never()).createNewOutputStreamException(anyString(), anyInt(), anyString(), anyList());
assertSame(foo, getFileSystemEntry("/foo"));
assertEquals(0, getChildCount("/foo"));
}
@ -443,8 +442,7 @@ public class FTPFileSystemTest extends AbstractFTPFileSystemTest {
try (OutputStream input = getFileSystem().newOutputStream(createPath("/foo"), options)) {
// don't do anything with the stream, there's a separate test for that
} finally {
verify(getExceptionFactory(), never()).createNewOutputStreamException(anyString(), anyInt(), anyString(),
anyCollectionOf(OpenOption.class));
verify(getExceptionFactory(), never()).createNewOutputStreamException(anyString(), anyInt(), anyString(), anyList());
assertSame(foo, getFileSystemEntry("/foo"));
assertEquals(0, getChildCount("/foo"));
}
@ -693,7 +691,7 @@ public class FTPFileSystemTest extends AbstractFTPFileSystemTest {
try {
getFileSystem().copy(createPath("/foo/bar"), createPath("/baz/bar"), options);
} finally {
verify(getExceptionFactory()).createNewOutputStreamException(eq("/baz/bar"), eq(553), anyString(), anyCollectionOf(OpenOption.class));
verify(getExceptionFactory()).createNewOutputStreamException(eq("/baz/bar"), eq(553), anyString(), anyList());
assertSame(foo, getFileSystemEntry("/foo"));
assertSame(bar, getFileSystemEntry("/foo/bar"));
assertNull(getFileSystemEntry("/baz"));

@ -2755,7 +2755,7 @@ public class FTPClient extends FTP implements Configurable {
* happen when parserKey is neither
* the fully qualified class name of a class
* implementing the interface
* {@link }FTPFileEntryParser}
* {@link FTPFileEntryParser}
* nor a string containing one of the recognized keys
* mapping to such a parser or if class loader
* security issues prevent its being loaded.

@ -7,7 +7,7 @@ module org.xbib.files.sftp.fs {
exports org.apache.sshd.fs;
exports org.apache.sshd.fs.spi;
requires org.xbib.files;
requires transitive org.xbib.files.sftp;
requires org.xbib.files.sftp;
provides FileSystemProvider with SftpFileSystemProvider;
provides FileServiceProvider with SFTPFileServiceProvider;
requires java.logging;

@ -83,6 +83,7 @@ import org.apache.sshd.common.auth.BasicCredentialsImpl;
import org.apache.sshd.common.auth.BasicCredentialsProvider;
import org.apache.sshd.common.auth.MutableBasicCredentials;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.keyprovider.ClassLoadableResourceKeyPairProvider;
import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.NumberUtils;
@ -197,12 +198,13 @@ public class SftpFileSystemProvider extends FileSystemProvider {
if (port <= 0) {
port = SshConstants.DEFAULT_PORT;
}
Object o = env.get("username");
String username = o instanceof String ? (String) o : o != null ? o.toString() : null;
o = env.get("password");
char[] password = o instanceof char[] ? (char[]) o : o instanceof String ? ((String)o).toCharArray() : null;
if (env.containsKey("key")) {
clientInstance.setKeyIdentityProvider(new ClassLoadableResourceKeyPairProvider(env.get("key").toString()));
}
boolean disableServerKeys = "true".equals(env.get("disableServerKeys"));
if (disableServerKeys) {
clientInstance.setServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE);
@ -280,7 +282,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
if (session != null) {
try {
session.close();
} catch (IOException t) {
} catch (Exception t) {
e.addSuppressed(t);
}
}

@ -4,23 +4,11 @@ import org.junit.jupiter.api.Test;
import org.xbib.files.FileService;
import java.io.IOException;
import java.security.Provider;
import java.security.Security;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.logging.Logger;
public class FileServiceProviderTest {
static {
// load bouncy castle provider (and other security providers)
for (Provider p : ServiceLoader.load(Provider.class)) {
if (Security.getProvider(p.getName()) == null) {
Security.addProvider(p);
}
}
}
@Test
public void testSFTP() throws IOException {
Map<String, ?> env = Map.of("username", "joerg");

@ -0,0 +1,22 @@
package org.apache.sshd.fs.test;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.logging.Logger;
import org.junit.jupiter.api.Test;
import org.xbib.files.FileService;
public class SftpClientTest {
@Test
public void testSFTP() throws IOException {
String targetURLString = "sftp://fernleihe-test.hbz-nrw.de:22";
String targetIdString = "malva";
URI uri = URI.create(targetURLString);
FileService fs = FileService.newInstance(targetURLString,
Map.of("username", targetIdString,
"key", uri.getHost() + "/" + targetIdString + ".key"));
fs.list(".").forEach(p -> Logger.getAnonymousLogger().info(p.toString()));
}
}

@ -75,7 +75,6 @@ import org.apache.sshd.common.Factory;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.ServiceFactory;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.helpers.AbstractFactoryManager;
@ -732,7 +731,6 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
} else if (id instanceof KeyPair) {
KeyPair kp = (KeyPair) id;
session.addPublicKeyIdentity(kp);
} else {
}
}
}

@ -34,7 +34,7 @@ import org.apache.sshd.common.util.GenericUtils;
public interface PasswordIdentityProvider {
/**
* An &quot;empty&quot implementation of {@link PasswordIdentityProvider} that returns and empty group of passwords
* An &quot;empty&quot; implementation of {@link PasswordIdentityProvider} that returns and empty group of passwords
*/
PasswordIdentityProvider EMPTY_PASSWORDS_PROVIDER = new PasswordIdentityProvider() {
@Override

@ -20,6 +20,7 @@
package org.apache.sshd.client.impl;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.SocketAddress;
import java.security.KeyPair;
@ -82,12 +83,16 @@ public class SimpleSftpClientImpl implements SimpleSftpClient {
SimpleClient client = getClient();
ClientSession session = sessionProvider.apply(client);
try {
SftpClient sftp = createSftpClient(session);
session = null; // disable auto-close at finally block
return sftp;
SftpClient sftpClient = createSftpClient(session);
session = null;
return sftpClient;
} finally {
if (session != null) {
session.close();
try {
session.close();
} catch (Exception e) {
throw new IOException(e);
}
}
}
}

@ -23,8 +23,8 @@ import org.apache.sshd.common.CoreModuleProperties;
/**
* Provides a way to implement proxied connections where some metadata about the client is sent <U>before</U> the actual
* SSH protocol is executed - e.g., the <A HREF=@http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt">PROXY
* protocol</A>. The implementor should use the {@code IoSession#write(Buffer)} method to send any packets with the
* SSH protocol is executed - e.g., the http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt PROXY
* protocol. The implementor should use the {@code IoSession#write(Buffer)} method to send any packets with the
* meta-data.
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>

@ -18,13 +18,8 @@
*/
package org.apache.sshd.client.session;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PublicKey;
import java.time.Duration;

@ -125,8 +125,8 @@ public abstract class AbstractSimpleClientSessionCreator extends AbstractSimpleC
if (session != null) {
try {
session.close();
} catch (IOException e) {
err = GenericUtils.accumulateException(err, e);
} catch (Exception e) {
err = GenericUtils.accumulateException(err, new IOException(e));
}
}
}

@ -33,7 +33,7 @@ import org.apache.sshd.common.future.SshFutureListener;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public interface Closeable extends Channel {
public interface Closeable extends AutoCloseable {
/**
* Close this resource asynchronously and return a future. Resources support two closing modes: a graceful mode
@ -76,13 +76,12 @@ public interface Closeable extends Channel {
*/
boolean isClosing();
@Override
default boolean isOpen() {
return !(isClosed() || isClosing());
}
@Override
default void close() throws IOException {
default void close() throws Exception {
Closeable.close(this);
}

@ -44,9 +44,6 @@ public final class CoreModuleProperties {
public static final Property<String> PROXY_AUTH_CHANNEL_TYPE
= Property.string("ssh-agent-factory-proxy-auth-channel-type", "auth-agent-req@openssh.com");
/**
* See {@link org.apache.sshd.agent.local.ProxyAgentFactory#getChannelForwardingFactories}
*/
public static final Property<Boolean> PREFER_UNIX_AGENT
= Property.bool("ssh-prefer-unix-agent", OsUtils.isUNIX());
@ -147,8 +144,6 @@ public final class CoreModuleProperties {
/**
* Whether to ignore invalid identities files when pre-initializing the client session
*
* @see ClientIdentityLoader#isValidLocation(NamedResource)
*/
public static final Property<Boolean> IGNORE_INVALID_IDENTITIES
= Property.bool("ignore-invalid-identities", true);
@ -579,105 +574,84 @@ public final class CoreModuleProperties {
public static final Property<String> MODULI_URL
= Property.string("moduli-url");
/**
* See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
*/
public static final Property<String> KB_SERVER_INTERACTIVE_NAME
= Property.string("kb-server-interactive-name", "Password authentication");
/**
* See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
*/
public static final Property<String> KB_SERVER_INTERACTIVE_INSTRUCTION
= Property.string("kb-server-interactive-instruction", "");
/**
* See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
*/
public static final Property<String> KB_SERVER_INTERACTIVE_LANG
= Property.string("kb-server-interactive-language", "en-US");
/**
* See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
*/
public static final Property<String> KB_SERVER_INTERACTIVE_PROMPT
= Property.string("kb-server-interactive-prompt", "Password: ");
/**
* See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
*/
public static final Property<Boolean> KB_SERVER_INTERACTIVE_ECHO_PROMPT
= Property.bool("kb-server-interactive-echo-prompt", false);
/**
* Maximum amount of extended (a.k.a. STDERR) data allowed to be accumulated until a {@link ChannelDataReceiver} for
* Maximum amount of extended (a.k.a. STDERR) data allowed to be accumulated until a ChannelDataReceiver for
* the data is registered
*/
public static final Property<Integer> MAX_EXTDATA_BUFSIZE
= Property.integer("channel-session-max-extdata-bufsize", 0);
/**
* See {@link org.apache.sshd.server.kex.DHGEXServer}.
*/
public static final Property<Integer> PROP_DHGEX_SERVER_MIN_KEY
= Property.integer("dhgex-server-min");
/**
* See {@link org.apache.sshd.server.kex.DHGEXServer}.
*/
public static final Property<Integer> PROP_DHGEX_SERVER_MAX_KEY
= Property.integer("dhgex-server-max");
/**
* Value used by the {@link org.apache.sshd.server.shell.InvertedShellWrapper} to control the &quot;busy-wait&quot;
* Value used to control the &quot;busy-wait&quot;
* sleep time (millis) on the pumping loop if nothing was pumped - must be <U>positive</U>.
*/
public static final Property<Duration> PUMP_SLEEP_TIME
= Property.duration("inverted-shell-wrapper-pump-sleep", Duration.ofMillis(1));
/**
* Value used by the {@link org.apache.sshd.server.shell.InvertedShellWrapper} to control copy buffer size.
* Value used to control copy buffer size.
*/
public static final Property<Integer> BUFFER_SIZE
= Property.integer("inverted-shell-wrapper-buffer-size", IoUtils.DEFAULT_COPY_SIZE);
/**
* Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control the channel open
* Configuration value to control the channel open
* timeout.
*/
public static final Property<Duration> X11_OPEN_TIMEOUT
= Property.duration("x11-fwd-open-timeout", Duration.ofSeconds(30L));
/**
* Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control from which X11
* Configuration value to control from which X11
* display number to start looking for a free value.
*/
public static final Property<Integer> X11_DISPLAY_OFFSET
= Property.integer("x11-fwd-display-offset", 10);
/**
* Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control up to which (but not
* Configuration value to control up to which (but not
* including) X11 display number to look or a free value.
*/
public static final Property<Integer> X11_MAX_DISPLAYS
= Property.integer("x11-fwd-max-display", 1000);
/**
* Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control the base port number
* Configuration value to control the base port number
* for the X11 display number socket binding.
*/
public static final Property<Integer> X11_BASE_PORT
= Property.integer("x11-fwd-base-port", 6000);
/**
* Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control the host used to bind
* Configuration value to control the host used to bind
* to for the X11 display when looking for a free port.
*/
public static final Property<String> X11_BIND_HOST
= Property.string("x11-fwd-bind-host", SshdSocketAddress.LOCALHOST_IPV4);
/**
* Configuration value for the {@link org.apache.sshd.server.forward.TcpipServerChannel} to control the higher
* theshold for the data to be buffered waiting to be sent. If the buffered data size reaches this value, the
* Configuration value to control the higher
* threshold for the data to be buffered waiting to be sent. If the buffered data size reaches this value, the
* session will pause reading until the data length goes below the
* {@link #TCPIP_SERVER_CHANNEL_BUFFER_SIZE_THRESHOLD_LOW} threshold.
*/

@ -23,9 +23,6 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Duration;
import org.apache.sshd.common.Property;
import org.apache.sshd.common.PropertyResolver;
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.common.util.io.IoUtils;
@ -41,8 +38,6 @@ public final class SftpModuleProperties {
* Used to indicate the {@link Charset} (or its name) for decoding referenced files/folders names - extracted from
* the client session when 1st initialized.
*
* @see SftpClient#getNameDecodingCharset()
* @see SftpClient#setNameDecodingCharset(Charset)
*/
public static final Property<Charset> NAME_DECODING_CHARSET
= Property.charset("sftp-name-decoding-charset", StandardCharsets.UTF_8);
@ -54,45 +49,26 @@ public final class SftpModuleProperties {
public static final Property<Duration> SFTP_CHANNEL_OPEN_TIMEOUT
= Property.duration("sftp-channel-open-timeout", Duration.ofSeconds(15L));
/**
* See {@link org.apache.sshd.sftp.client.fs.SftpFileSystem}.
*/
public static final Property<Integer> POOL_SIZE
= Property.integer("sftp-fs-pool-size", 8);
/**
* See {@link org.apache.sshd.sftp.client.fs.SftpFileSystemProvider}.
*/
public static final Property<Integer> READ_BUFFER_SIZE
= Property.integer("sftp-fs-read-buffer-size");
/**
* See {@link org.apache.sshd.sftp.client.fs.SftpFileSystemProvider}.
*/
public static final Property<Integer> WRITE_BUFFER_SIZE
= Property.integer("sftp-fs-write-buffer-size");
/**
* See {@link org.apache.sshd.sftp.client.fs.SftpFileSystemProvider}.
*/
public static final Property<Duration> CONNECT_TIME
= Property.duration("sftp-fs-connect-time", Duration.ofSeconds(15L));
/**
* See {@link org.apache.sshd.sftp.client.fs.SftpFileSystemProvider}.
*/
public static final Property<Duration> AUTH_TIME
= Property.duration("sftp-fs-auth-time", Duration.ofSeconds(15L));
/**
* See {@link org.apache.sshd.sftp.client.fs.SftpFileSystemProvider}.
*/
public static final Property<Charset> NAME_DECODER_CHARSET
= Property.charset("sftp-fs-name-decoder-charset", StandardCharsets.UTF_8);
/**
* Property used to avoid large buffers when
* {@link org.apache.sshd.sftp.client.impl.AbstractSftpClient#write(SftpClient.Handle, long, byte[], int, int)} is
* invoked with a large buffer size.
*/
public static final Property<Integer> WRITE_CHUNK_SIZE
@ -122,25 +98,22 @@ public final class SftpModuleProperties {
/**
* Allows controlling reports of which client extensions are supported (and reported via &quot;support&quot; and
* &quot;support2&quot; server extensions) as a comma-separate list of names. <B>Note:</B> requires overriding the
* {@link AbstractSftpSubsystemHelper#executeExtendedCommand(Buffer, int, String)} command accordingly. If empty
* command accordingly. If empty
* string is set then no server extensions are reported
*
* @see AbstractSftpSubsystemHelper#DEFAULT_SUPPORTED_CLIENT_EXTENSIONS
*/
public static final Property<String> CLIENT_EXTENSIONS
= Property.string("sftp-client-extensions");
/**
* Comma-separated list of which {@code OpenSSH} extensions are reported and what version is reported for each -
* format: {@code name=version}. If empty value set, then no such extensions are reported. Otherwise, the
* {@link AbstractSftpSubsystemHelper#DEFAULT_OPEN_SSH_EXTENSIONS} are used
* format: {@code name=version}. If empty value set, then no such extensions are reported.
*/
public static final Property<String> OPENSSH_EXTENSIONS
= Property.string("sftp-openssh-extensions");
/**
* Comma separate list of {@code SSH_ACL_CAP_xxx} names - where name can be without the prefix. If not defined then
* {@link AbstractSftpSubsystemHelper#DEFAULT_ACL_SUPPORTED_MASK} is used
* Comma separate list of {@code SSH_ACL_CAP_xxx} names - where name can be without the prefix.
*/
public static final Property<String> ACL_SUPPORTED_MASK
= Property.string("sftp-acl-supported-mask");
@ -152,7 +125,7 @@ public final class SftpModuleProperties {
= Property.string("sftp-newline", IoUtils.EOL);
/**
* Force the use of a max. packet length for {@link AbstractSftpSubsystemHelper#doRead(Buffer, int)} protection
* Force the use of a max. packet length for protection
* against malicious packets
*/
public static final Property<Integer> MAX_READDATA_PACKET_LENGTH
@ -187,9 +160,6 @@ public final class SftpModuleProperties {
/**
* Max. rounds to attempt to create a unique file handle - if all handles already in use after these many rounds,
* then an exception is thrown
*
* @see SftpSubsystem#generateFileHandle(Path)
* @see #DEFAULT_FILE_HANDLE_ROUNDS
*/
public static final Property<Integer> MAX_FILE_HANDLE_RAND_ROUNDS
= Property.validating(
@ -200,8 +170,7 @@ public final class SftpModuleProperties {
});
/**
* Maximum amount of data allocated for listing the contents of a directory in any single invocation of
* {@link SftpSubsystem#doReadDir(Buffer, int)}
* Maximum amount of data allocated for listing the contents of a directory in any single invocation
*/
public static final Property<Integer> MAX_READDIR_DATA_SIZE
= Property.integer("sftp-max-readdir-data-size", 16 * 1024);

@ -36,7 +36,6 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import org.apache.sshd.common.AttributeRepository;
import org.apache.sshd.common.Closeable;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.PropertyResolver;
@ -100,7 +99,7 @@ public abstract class AbstractChannel extends AbstractInnerCloseable implements
private int id = -1;
private int recipient = -1;
private Session sessionInstance;
private CloseableExecutorService executor;
private final CloseableExecutorService executor;
private final List<RequestHandler<Channel>> requestHandlers = new CopyOnWriteArrayList<>();
private final Window localWindow;

@ -704,7 +704,7 @@ public final class KeyUtils {
* @param expected The expected fingerprint if {@code null} or empty then returns a failure with the default
* fingerprint.
* @param key the {@link PublicKey} - if {@code null} then returns null.
* @return SimpleImmutableEntry<Boolean, String> - key is success indicator, value is actual fingerprint,
* @return SimpleImmutableEntry - key is success indicator, value is actual fingerprint,
* {@code null} if no key.
* @see #getDefaultFingerPrintFactory()
* @see #checkFingerPrint(String, Factory, PublicKey)
@ -718,7 +718,7 @@ public final class KeyUtils {
* fingerprint.
* @param f The {@link Factory} to be used to generate the default {@link Digest} for the key
* @param key the {@link PublicKey} - if {@code null} then returns null.
* @return SimpleImmutableEntry<Boolean, String> - key is success indicator, value is actual fingerprint,
* @return SimpleImmutableEntry - key is success indicator, value is actual fingerprint,
* {@code null} if no key.
*/
public static SimpleImmutableEntry<Boolean, String> checkFingerPrint(
@ -731,7 +731,7 @@ public final class KeyUtils {
* fingerprint.
* @param d The {@link Digest} to be used to generate the default fingerprint for the key
* @param key the {@link PublicKey} - if {@code null} then returns null.
* @return SimpleImmutableEntry<Boolean, String> - key is success indicator, value is actual fingerprint,
* @return SimpleImmutableEntry - key is success indicator, value is actual fingerprint,
* {@code null} if no key.
*/
public static SimpleImmutableEntry<Boolean, String> checkFingerPrint(String expected, Digest d, PublicKey key) {

@ -47,6 +47,7 @@ import org.apache.sshd.common.util.security.SecurityUtils;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public abstract class AbstractResourceKeyPairProvider<R> extends AbstractKeyPairProvider {
private FilePasswordProvider passwordFinder;
/*
* NOTE: the map is case insensitive even for Linux, as it is (very) bad practice to have 2 key files that differ

@ -165,7 +165,7 @@ public final class OsUtils {
}
/**
* Remove {@code Windows} domain and/or group prefix as well as &quot;(User);&quot suffix
* Remove {@code Windows} domain and/or group prefix as well as &quot;(User);&quot; suffix
*
* @param user The original username - ignored if {@code null}/empty
* @return The canonical user - unchanged if {@code Unix} O/S

@ -63,13 +63,13 @@ public interface BufferPublicKeyParser<PUB extends PublicKey> {
OpenSSHCertPublicKeyParser.INSTANCE));
/**
* @param keyType The key type - e.g., &quot;ssh-rsa&quot, &quot;ssh-dss&quot;
* @param keyType The key type - e.g., ssh-rsa, ssh-dss
* @return {@code true} if this key type is supported by the parser
*/
boolean isKeyTypeSupported(String keyType);
/**
* @param keyType The key type - e.g., &quot;ssh-rsa&quot, &quot;ssh-dss&quot;
* @param keyType The key type - e.g., ssh-rsa, ssh-dss
* @param buffer The {@link Buffer} containing the encoded raw public key
* @return The decoded {@link PublicKey}
* @throws GeneralSecurityException If failed to generate the key

@ -78,10 +78,6 @@ public final class Builder implements ObjectBuilder<Closeable> {
return this;
}
public Builder sequential(Object id, Iterable<Closeable> closeables) {
return close(new SequentialCloseable(id, lock, closeables));
}
public Builder parallel(Closeable... closeables) {
if (closeables.length == 1) {
close(closeables[0]);

@ -18,6 +18,8 @@
*/
package org.apache.sshd.common.util.closeable;
import java.io.IOException;
import java.io.UncheckedIOException;
import org.apache.sshd.common.Closeable;
/**
@ -25,4 +27,12 @@ import org.apache.sshd.common.Closeable;
*/
public abstract class IoBaseCloseable implements Closeable {
@Override
public void close() {
try {
Closeable.close(this);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

@ -42,7 +42,7 @@ public class SequentialCloseable extends SimpleCloseable {
@Override
protected void doClose(boolean immediately) {
Iterator<? extends Closeable> iterator = closeables.iterator();
SshFutureListener<CloseFuture> listener = new SshFutureListener<CloseFuture>() {
SshFutureListener<CloseFuture> listener = new SshFutureListener<>() {
@SuppressWarnings("synthetic-access")
@Override
public void operationComplete(CloseFuture previousFuture) {

@ -76,7 +76,7 @@ public class DERWriter extends FilterOutputStream {
}
/**
* The integer is always considered to be positive, so if the first byte is < 0, we pad with a zero to make it
* The integer is always considered to be positive, so if the first byte is &lt; 0, we pad with a zero to make it
* positive
*
* @param bytes {@link BigInteger} bytes
@ -87,7 +87,7 @@ public class DERWriter extends FilterOutputStream {
}
/**
* The integer is always considered to be positive, so if the first byte is < 0, we pad with a zero to make it
* The integer is always considered to be positive, so if the first byte is &lt; 0, we pad with a zero to make it
* positive
*
* @param bytes {@link BigInteger} bytes

@ -111,7 +111,7 @@ public final class SecurityUtils {
/**
* The min. key size value used for testing whether Diffie-Hellman Group Exchange is supported or not. According to
* <A HREF="https://tools.ietf.org/html/rfc4419">RFC 4419</A> section 3: &quot;Servers and clients SHOULD support
* groups with a modulus length of k bits, where 1024 <= k <= 8192&quot;. </code>
* groups with a modulus length of k bits, where 1024 &lt;= k &lt;= 8192&quot;. </code>
*
* <B>Note: this has been amended by <A HREF="https://tools.ietf.org/html/rfc8270">RFC 8270</A>
*/
@ -384,7 +384,6 @@ public final class SecurityUtils {
if (REGISTRATION_STATE_HOLDER.get()) {
return;
}
String regsList = System.getProperty(SECURITY_PROVIDER_REGISTRARS,
GenericUtils.join(DEFAULT_SECURITY_PROVIDER_REGISTRARS, ','));
boolean bouncyCastleRegistered = false;
@ -475,13 +474,11 @@ public final class SecurityUtils {
if (parser == null) {
throw new NoSuchProviderException("No registered key-pair resource parser");
}
Collection<KeyPair> ids = parser.loadKeyPairs(session, resourceKey, provider, inputStream);
int numLoaded = GenericUtils.size(ids);
if (numLoaded <= 0) {
return null;
}
return ids;
}

@ -19,16 +19,27 @@
package org.apache.sshd.common.util.threads;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.Closeable;
public interface CloseableExecutorService extends ExecutorService, Closeable {
default boolean awaitTermination(Duration timeout) throws InterruptedException {
default boolean awaitTermination(Duration timeout) throws InterruptedException {
Objects.requireNonNull(timeout, "No timeout specified");
return awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS);
}
@Override
default void close() {
try {
Closeable.close(this);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

@ -120,7 +120,6 @@ public class DavPropertyNameSet extends PropContainer
* in order to successfully add the given entry.
* @return true if contentEntry is an instance of <code>DavPropertyName</code>
* that could be added to this set. False otherwise.
* @see PropContainer#addContent(Object)
*/
@Override
public boolean addContent(PropEntry contentEntry) {

@ -1,5 +1,5 @@
group = org.xbib
name = files
version = 4.0.0
version = 4.1.0
org.gradle.warning.mode = ALL

@ -2,21 +2,14 @@
apply plugin: 'java-library'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
modularity.inferModulePath.set(true)
withSourcesJar()
withJavadocJar()
}
compileJava {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
compileTestJava {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
jar {
manifest {
attributes('Implementation-Version': project.version)
@ -24,7 +17,9 @@ jar {
}
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xlint:all,-exports')
options.fork = true
options.forkOptions.jvmArgs += ['-Duser.language=en','-Duser.country=US']
options.compilerArgs.add('-Xlint:all')
options.encoding = 'UTF-8'
}

Binary file not shown.

@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

22
gradlew vendored

@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -130,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -198,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \

@ -15,10 +15,10 @@ pluginManagement {
dependencyResolutionManagement {
versionCatalogs {
libs {
version('gradle', '8.1.1')
version('gradle', '8.4')
version('groovy', '4.0.12')
version('junit', '5.9.3')
version('net', '3.2.0')
version('junit', '5.10.0')
version('net', '4.0.0')
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')
library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit')
library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit')
@ -27,8 +27,8 @@ dependencyResolutionManagement {
library('junit4', 'junit', 'junit').version('4.13.2')
library('net-security', 'org.xbib', 'net-security').versionRef('net')
library('mockftpserver', 'org.mockftpserver', 'MockFtpServer').version('2.7.1')
library('mockito-core', 'org.mockito', 'mockito-core').version('3.7.7')
library('mockito-junit-jupiter', 'org.mockito', 'mockito-junit-jupiter').version('3.7.7')
library('mockito-core', 'org.mockito', 'mockito-core').version('5.6.0')
library('mockito-junit-jupiter', 'org.mockito', 'mockito-junit-jupiter').version('5.6.0')
}
}
}

Loading…
Cancel
Save