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 2019/02/10 12:02:57 UTC

[mina-sshd] branch master updated (aa8f1e8 -> 3007311)

This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git.


    from aa8f1e8  Exclude RemoteSystemsTempFiles from assembly artifacts
     new ab893e5  [SSHD-872] Split changes documentation into separate files according to version number
     new 3007311  [SSHD-871] Split README file into several documentation files

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGES.md                          |  188 +---
 README.md                           | 2126 +----------------------------------
 CHANGES.md => docs/changes/2.2.0.md |    7 +-
 docs/cli.md                         |   54 +
 docs/client-setup.md                |  155 +++
 docs/commands.md                    |  174 +++
 docs/dependencies.md                |  112 ++
 docs/event-listeners.md             |  247 ++++
 docs/extensions.md                  |   68 ++
 docs/files-parsing.md               |  135 +++
 docs/git.md                         |   84 ++
 docs/internals.md                   |  284 +++++
 docs/port-forwarding.md             |   36 +
 docs/scp.md                         |   96 ++
 docs/security-providers.md          |   95 ++
 docs/server-setup.md                |  139 +++
 docs/sftp.md                        |  423 +++++++
 pom.xml                             |    5 +-
 18 files changed, 2127 insertions(+), 2301 deletions(-)
 copy CHANGES.md => docs/changes/2.2.0.md (97%)
 create mode 100644 docs/cli.md
 create mode 100644 docs/client-setup.md
 create mode 100644 docs/commands.md
 create mode 100644 docs/dependencies.md
 create mode 100644 docs/event-listeners.md
 create mode 100644 docs/extensions.md
 create mode 100644 docs/files-parsing.md
 create mode 100644 docs/git.md
 create mode 100644 docs/internals.md
 create mode 100644 docs/port-forwarding.md
 create mode 100644 docs/scp.md
 create mode 100644 docs/security-providers.md
 create mode 100644 docs/server-setup.md
 create mode 100644 docs/sftp.md


[mina-sshd] 02/02: [SSHD-871] Split README file into several documentation files

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 300731164bd88e21b4919cae82a2ee3204a6ffbf
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Tue Feb 5 11:56:43 2019 +0200

    [SSHD-871] Split README file into several documentation files
---
 README.md                  | 2126 +-------------------------------------------
 docs/cli.md                |   54 ++
 docs/client-setup.md       |  155 ++++
 docs/commands.md           |  174 ++++
 docs/dependencies.md       |  112 +++
 docs/event-listeners.md    |  247 +++++
 docs/extensions.md         |   68 ++
 docs/files-parsing.md      |  135 +++
 docs/git.md                |   84 ++
 docs/internals.md          |  284 ++++++
 docs/port-forwarding.md    |   36 +
 docs/scp.md                |   96 ++
 docs/security-providers.md |   95 ++
 docs/server-setup.md       |  139 +++
 docs/sftp.md               |  423 +++++++++
 15 files changed, 2119 insertions(+), 2109 deletions(-)

diff --git a/README.md b/README.md
index e193475..22f24c0 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,8 @@ leverage [Apache MINA](http://mina.apache.org), a scalable and high performance
 aim at being a replacement for the SSH client or SSH server from Unix operating systems, but rather provides support for Java
 based applications requiring SSH support.
 
+# [Release notes](./CHANGES.md)
+
 # Core requirements
 
 * Java 8+ (as of version 1.3)
@@ -17,155 +19,6 @@ based applications requiring SSH support.
 The code only requires the core abstract [slf4j-api](https://mvnrepository.com/artifact/org.slf4j/slf4j-api) module. The actual
 implementation of the logging API can be selected from the many existing adaptors.
 
-# Optional dependencies
-
-
-## [Bouncy Castle](https://www.bouncycastle.org/)
-
-
-Required mainly for writing keys to PEM files or for special keys/ciphers/etc. that are not part of the standard
-[Java Cryptography Extension](https://en.wikipedia.org/wiki/Java_Cryptography_Extension). See
-[Java Cryptography Architecture (JCA) Reference Guide](https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html)
-for key classes and explanations as to how _Bouncy Castle_ is plugged in (other security providers).
-
-**Caveat**: If _Bouncy Castle_ modules are registered, then the code will use its implementation of the ciphers,
-keys, signatures, etc. rather than the default JCE provided in the JVM.
-
- **Note:**
-
- - The security provider can also be registered for keys/ciphers/etc. that are already supported by the standard JCE as a **replacement** for them.
-
-
- - The _BouncyCastle_ code can also be used to load keys from PEM files instead or in parallel with the built-in code that
-already parses the standard PEM formats for the default JCE supported key types.
-
-
-- One can use the `BouncyCastleKeyPairResourceParser` to load standard PEM files instead of the core one - either directly
-or via `SecurityUtils#setKeyPairResourceParser` for **global** usage - even without registering or enabling the provider.
-
-
- - The required _Maven_ module(s) are defined as `optional` so must be added as an **explicit** dependency in order to be included in the classpath:
-
-
-```xml
-
-    <dependency>
-        <groupId>org.bouncycastle</groupId>
-        <artifactId>bcpg-jdk15on</artifactId>
-    </dependency>
-    <dependency>
-        <groupId>org.bouncycastle</groupId>
-        <artifactId>bcpkix-jdk15on</artifactId>
-    </dependency>
-
-```
-
-## NIO2 default socket factory replacements
-
-Optional dependency to enable choosing between NIO asynchronous sockets (the default - for improved performance), and "legacy" sockets.
-**Note:** the required Maven module(s) are defined as `optional` so must be added as an **explicit** dependency in order to be included
-in the classpath.
-
-### [MINA core](https://mina.apache.org/mina-project/)
-
-```xml
-
-    <dependency>
-        <groupId>org.apache.mina</groupId>
-        <artifactId>mina-core</artifactId>
-            <!-- see SSHD POM for latest tested known version of MINA core -->
-        <version>2.0.17</version>
-    </dependency>
-
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-mina</artifactId>
-        <version>...same as sshd-core...</version>
-    </dependency>
-
-```
-
-### [Netty](https://netty.io/)
-
-Another a NIO client server framework option that can be used as a replacement for the default NIO asynchronous sockets core
-implementation. This is also an **optional** dependency and must be add explicitly via the `sshd-netty` artifact.
-
-```xml
-
-    <dependency>
-        <groupId>io.netty</groupId>
-        <artifactId>netty-transport</artifactId>
-        <version>...Netty version...</version>
-    </dependency>
-    <dependency>
-        <groupId>io.netty</groupId>
-        <artifactId>netty-handler</artifactId>
-        <version>...Netty version...</version>
-    </dependency>
-
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-netty</artifactId>
-        <version>...same as sshd-core...</version>
-    </dependency>
-
-```
-
-### Selecting an `IoServiceFactoryFactory`
-
-As part of the their initialization, both client and server code require the specification of a `IoServiceFactoryFactory`
-that is used to initialize network connections.
-
-```java
-
-    SshServer server = ...create server instance...
-    server.setIoServiceFactoryFactory(new MyIoServiceFactoryFactory());
-
-    SshClient client = ... create client instance ...
-    client.setIoServiceFactoryFactory(new MyIoServiceFactoryFactory());
-
-```
-
-If not set explicitly during the client/server setup code, then a factory is automatically detected and selected when the
-client/server is `#start()`-ed. The used `IoServiceFactoryFactory` is a **singleton** that is lazy created the 1st time
-`DefaultIoServiceFactoryFactory#create` is invoked. The selection process is as follows:
-
-* The `org.apache.sshd.common.io.IoServiceFactoryFactory` system property is examined for a factory specification. The
-specification can be either a **fully-qualified** class name or one of the `BuiltinIoServiceFactoryFactories` values.
-
-* If no specific factory is specified, then the [ServiceLoader#load](https://docs.oracle.com/javase/tutorial/ext/basics/spi.html#register-service-providers)
-mechanism is used to detect and instantiate any registered services in any `META-INF\services\org.apache.sshd.common.io.IoServiceFactoryFactory`
-location in the classpath. If **exactly one** implementation was instantiated, then it is used. If several such implementations are found then
-an exception is thrown.
-
-* Otherwise, the built-in `Nio2ServiceFactoryFactory` is used.
-
-**Note:** the default command line scripts for SSH/SCP/SFTP client/server are set up to use NIO2 as their default provider,
-unless overridden via the `-io` command line option. The `org.apache.sshd.common.io.IoServiceFactoryFactory` system property does
-not apply for the command line wrappers since they look only for the `-io` option and use it to initialize the client/server **explicitly**
-before starting the client/server. Therefore, the default selection process described in this section does not apply for them.
-
-## [ed25519-java](https://github.com/str4d/ed25519-java)
-
-
-Required for supporting [ssh-ed25519](https://tools.ietf.org/html/draft-bjh21-ssh-ed25519-02) keys
-and [ed25519-sha-512](https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02) signatures. **Note:**
-the required Maven module(s) are defined as `optional` so must be added as an **explicit** dependency in
-order to be included in the classpath:
-
-
-```xml
-
-        <!-- For ed25519 support -->
-    <dependency>
-        <groupId>net.i2p.crypto</groupId>
-        <artifactId>eddsa</artifactId>
-    </dependency>
-
-```
-
-The code contains support for reading _ed25519_ [OpenSSH formatted private keys](https://issues.apache.org/jira/browse/SSHD-703).
-
 # Basic artifacts structure
 
 * *sshd-common* - contains basic classes used throughout the project as well as code that does not require client or server network support.
@@ -194,1979 +47,34 @@ The code contains support for reading _ed25519_ [OpenSSH formatted private keys]
 * *sshd-contrib* - **experimental** code that is currently under review and may find its way into one of the other artifacts
 (or become an entirely new artifact - e.g., *sshd-putty* evolved this way).
 
-# Set up an SSH client in 5 minutes
-
-SSHD is designed to easily allow setting up and using an SSH client in a few simple steps. The client needs to be configured
-and then started before it can be used to connect to an SSH server. There are a few simple steps for creating a client
-instance - for more details refer to the `SshClient` class.
-
-## Creating an instance of the `SshClient` class
-
-This is simply done by calling
-
-```java
-
-    SshClient client = SshClient.setupDefaultClient();
-
-```
-
-The call will create an instance with a default configuration suitable for most use cases - including ciphers,
-compression, MACs, key exchanges, signatures, etc... If your code requires some special configuration, one can
-look at the code for `setupDefaultClient` and `checkConfig` as a reference for available options and configure
-the SSH client the way you need.
-
-## Set up client side security
-
-The SSH client contains some security related configuration that one needs to consider
-
-### `ServerKeyVerifier`
-
-`client.setServerKeyVerifier(...);` sets up the server key verifier. As part of the SSH connection initialization
-protocol, the server proves its "identity" by presenting a public key. The client can examine the key (e.g., present
-it to the user via some UI) and decide whether to trust the server and continue with the connection setup. By default
-the client is initialized with an `AcceptAllServerKeyVerifier` that simply logs a warning that an un-verified server
-key was accepted. There are other out-of-the-box verifiers available in the code:
-
-* `RejectAllServerKeyVerifier` - rejects all server key - usually used in tests or as a fallback verifier if none
-of it predecesors validated the server key
-
-
-* `RequiredServerKeyVerifier` - accepts only **one** specific server key (similar to certificate pinning for SSL)
-
-
-* `KnownHostsServerKeyVerifier` - uses the [known_hosts](https://en.wikibooks.org/wiki/OpenSSH/Client_Configuration_Files#Public_Keys_from_other_Hosts_.E2.80.93_.7E.2F.ssh.2Fknown_hosts)
-file to validate the server key. One can use this class + some existing code to **update** the file when new servers are detected and their keys are accepted.
-
-
-Of course, one can implement the verifier in whatever other manner is suitable for the specific code needs.
-
-### ClientIdentityLoader/KeyPairProvider
-
-One can set up the public/private keys to be used in case a password-less authentication is needed. By default, the client is configured to automatically
-detect and use the identity files residing in the user's *~/.ssh* folder (e.g., *id_rsa*, *id_ecdsa*) and present them as part of the authentication process.
-**Note:** if the identity files are encrypted via a password, one must configure a `FilePasswordProvider` so that the code can decrypt them before using
-and presenting them to the server as part of the authentication process. Reading key files in PEM format (including encrypted ones) is supported by default
-for the standard keys and formats. Using additional non-standard special features requires that the [Bouncy Castle](https://www.bouncycastle.org/) supporting
-artifacts be available in the code's classpath.
-
-#### Providing passwords for encrypted key files
-
-The `FilePasswordProvider` is required for all private key files that are encrypted and being loaded (not just the "identity" ones). If the user
-knows ahead of time that the file being currently decoded is not encrypted, a *null* provider may be used (if the file turns out to be encrypted
-though an exception will be thrown in this case).
-
-The `FilePasswordProvider`has support for a **retry mechanism** via its `handleDecodeAttemptResult`. When the code detects an encrypted private key,
-it will start a loop where it prompts for the password, attempts to decode the key using the provided password and then informs the provider of
-the outcome - success or failure. If failure is signaled, then the provider can decide whether to retry using a new password, abort (with exception)
-or ignore. If the provider chooses to ignore the failure, then the code will make a best effort to proceed without the (undecoded) key.
-
-The invoked methods are provided with a `NamedResource` that provides an indication of the key source "name" that is being attempted. This name
-can be used in order to prompt the user interactively and provide a useful "hint" as to the password that needs to be provided. Furthermore, the
-vast majority of the provided `NamedResource`-s also implement `IoResource` - which means that the code can find out what type of resource
-is being attempted - e.g., a file [Path](https://docs.oracle.com/javase/8/docs/api/index.html?java/nio/file/Path.html),
-a [URL](https://docs.oracle.com/javase/8/docs/api/java/net/URL.html), a [URI](https://docs.oracle.com/javase/8/docs/api/java/net/URI.html),
-etc. - and modify it's behavior accordingly.
-
-#### OpenSSH file format support
-
-The code supports [OpenSSH](http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?rev=1.1&content-type=text/x-cvsweb-markup)
-formatted files without any specific extra artifacts (although for reading _ed25519_ keys one needs to add the _EdDSA_ support artifacts). For
-**encrypted** files only the the `bcrypt` key derivation function (KDF) is [currently supported](https://issues.apache.org/jira/browse/SSHD-708).
-In this context, the maximum allowed number of rounds has been set to ~255 in order to protect the decryption process from
-malformed or malicious data. However, since the protocol allows for 2^31 values, it is possible to modify the default by
-calling `BCryptKdfOptions#setMaxAllowedRounds()` **programmatically** at any time - please note that
-
-* The setting is **global** - i.e., affects all decryption attempts from then on and not just for the current SSH session or thread.
-
-* The setting value is never allowed to be non-positive - any attempt to set such a value programmatically
-throws an exception.
-
-The usual _OpenSSH_ default seems to be 16, but users can ask for more (or less) by generating an encrypted key via
-[`ssh-keygen -a NNN`](http://man7.org/linux/man-pages/man1/ssh-keygen.1.html). However, this comes at a cost:
-
->> -a rounds
->>
->>    When saving a private key this option specifies the number of
->>    KDF (key derivation function) rounds used.  Higher numbers
->>    result in slower passphrase verification
-
-Various discussions on the net seem to indicate that 64 is the value at which many computers start to slow down noticeably, so
-our default limit seems quite suitable (and beyond) for most cases we are likely to encounter "in the wild".
-
-### UserInteraction
-
-This interface is required for full support of `keyboard-interactive` authentication protocol as described in [RFC 4256](https://www.ietf.org/rfc/rfc4256.txt).
-The client can handle a simple password request from the server, but if more complex challenge-response interaction is required, then this interface must be
-provided - including support for `SSH_MSG_USERAUTH_PASSWD_CHANGEREQ` as described in [RFC 4252 section 8](https://www.ietf.org/rfc/rfc4252.txt).
-
-While RFC-4256 support is the primary purpose of this interface, it can also be used to retrieve the server's welcome banner as described
-in [RFC 4252 section 5.4](https://www.ietf.org/rfc/rfc4252.txt) as well as its initial identification string as described
-in [RFC 4253 section 4.2](https://tools.ietf.org/html/rfc4253#section-4.2).
-
-## Using the `SshClient` to connect to a server
-
-Once the `SshClient` instance is properly configured it needs to be `start()`-ed in order to connect to a server.
-**Note:** one can use a single `SshClient` instance to connnect to multiple servers as well as modifying the default
-configuration (ciphers, MACs, keys, etc.) on a per-session manner (see more in the *Advanced usage* section).
-Furthermore, one can change almost any configured `SshClient` parameter - although its influence on currently established
-sessions depends on the actual changed configuration. Here is how a typical usage would look like
-
-```java
-
-    SshClient client = SshClient.setupDefaultClient();
-    // override any default configuration...
-    client.setSomeConfiguration(...);
-    client.setOtherConfiguration(...);
-    client.start();
-
-        // using the client for multiple sessions...
-        try (ClientSession session = client.connect(user, host, port)
-                    .verify(...timeout...)
-                    .getSession()) {
-            session.addPasswordIdentity(...password..); // for password-based authentication
-            // or
-            session.addPublicKeyIdentity(...key-pair...); // for password-less authentication
-            // Note: can add BOTH password AND public key identities - depends on the client/server security setup
-
-            session.auth().verify(...timeout...);
-            // start using the session to run commands, do SCP/SFTP, create local/remote port forwarding, etc...
-        }
-
-        // NOTE: this is just an example - one can open multiple concurrent sessions using the same client.
-        //      No need to close the previous session before establishing a new one
-        try (ClientSession anotherSession = client.connect(otherUser, otherHost, port)
-                    .verify(...timeout...)
-                    .getSession()) {
-            anotherSession.addPasswordIdentity(...password..); // for password-based authentication
-            anotherSession.addPublicKeyIdentity(...key-pair...); // for password-less authentication
-            anotherSession.auth().verify(...timeout...);
-            // start using the session to run commands, do SCP/SFTP, create local/remote port forwarding, etc...
-        }
-
-    // exiting in an orderly fashion once the code no longer needs to establish SSH session
-    // NOTE: this can/should be done when the application exits.
-    client.stop();
-
-```
-
-# Embedding an SSHD server instance in 5 minutes
-
-SSHD is designed to be easily embedded in your application as an SSH server. The embedded SSH server needs
-to be configured before it can be started. Essentially, there are a few simple steps for creating the
-server - for more details refer to the `SshServer` class.
-
-## Creating an instance of the `SshServer` class
-
-Creating an instance of `SshServer` is as simple as creating a new object
-
-```java
-
-    SshServer sshd = SshServer.setUpDefaultServer();
-
-```
-
-It will configure the server with sensible defaults for ciphers, macs, key exchange algorithm, etc...
-If different behavior is required, one should consult the code of the `setUpDefaultServer` as well as
-`checkConfig` methods as a reference for available options and configure the SSH server the way it is needed.
-
-## Configuring the server instance
-
-There are a few things that need to be configured on the server before being able to actually use it:
-
-* Port - `sshd.setPort(22);` - sets the listen port for the server instance. If not set explicitly then a
-**random** free port is selected by the O/S. In any case, once the server is `start()`-ed one can query the
-instance as to the assigned port via `sshd.getPort()`.
-
-
-In this context, the listen bind address can also be specified explicitly via `sshd.setHost(...some IP address...)`
-that causes the server to bind to a specific network address rather than **all** addresses (the default). Using
-`"0.0.0.0"` as the bind address is also tantamount to binding to all addresses.
-
-
-* `KeyPairProvider` - `sshd.setKeyPairProvider(...);` - sets the host's private keys used for key exchange with
-clients as well as representing the host's "identities". There are several choices - one can load keys from standard
-PEM files or generate them in the code.  It's usually a good idea to save generated keys, so that if the SSHD server
-is restarted, the same keys will be used to authenticate the server and avoid the warning the clients might get if
-the host keys are modified. **Note**: saving key files in PEM format requires  that the [Bouncy Castle](https://www.bouncycastle.org/)
-supporting artifacts be available in the code's classpath.
-
-
-* `ShellFactory` - That's the part one usually has to write to customize the SSHD server. The shell factory will
-be used to create a new shell each time a user logs in and wants to run an interactive shell. SSHD provides a simple
-implementation that you can use if you want. This implementation will create a process and delegate everything to it,
-so it's mostly useful to launch the OS native shell. E.g.,
-
-
-```java
-
-    sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" }));
-
-```
-
-
-There is an out-of-the-box `InteractiveProcessShellFactory` that detects the O/S and spawns the relevant shell. Note
-that the `ShellFactory` is not required. If none is configured, any request for an interactive shell will be denied to clients.
-
-
-* `CommandFactory` - The `CommandFactory` provides the ability to run a **single** direct command at a time instead
-of an interactive session (it also uses a **different** channel type than shells). It can be used **in addition** to the `ShellFactory`.
-
-
-SSHD provides a `CommandFactory` to support SCP that can be configured in the following way:
-
-
-```java
-
-    sshd.setCommandFactory(new ScpCommandFactory());
-
-```
-
-One can also use the `ScpCommandFactory` on top of one's own `CommandFactory` by placing the command factory as a **delegate**
-of the `ScpCommandFactory`. The `ScpCommandFactory` will intercept SCP commands and execute them by itself, while passing all
-other commands to the delegate `CommandFactory`
-
-
-```java
+# [Optional dependencies](./docs/dependencies.md)
 
-    sshd.setCommandFactory(new ScpCommandFactory(myCommandFactory));
+# Quick reference
 
-```
+## [Set up an SSH client in 5 minutes](./docs/client-setup.md)
 
-Note that using a `CommandFactory` is also **optional**. If none is configured, any direct command sent by clients will be rejected.
-
-## Server side security setup
-
-The SSHD server security layer has to be customized to suit your needs. This layer is pluggable and uses the following interfaces:
-
-* `PasswordAuthenticator` for password based authentication - [RFC 4252 section 8](https://www.ietf.org/rfc/rfc4252.txt)
-* `PublickeyAuthenticator` for key based authentication - [RFC 4252 section 7](https://www.ietf.org/rfc/rfc4252.txt)
-* `HostBasedAuthenticator` for host based authentication - [RFC 4252 section 9](https://www.ietf.org/rfc/rfc4252.txt)
-* `KeyboardInteractiveAuthenticator` for user interactive authentication - [RFC 4256](https://www.ietf.org/rfc/rfc4256.txt)
-
-
-These custom classes can be configured on the SSHD server using the respective setter methods:
-
-
-```java
-
-    sshd.setPasswordAuthenticator(new MyPasswordAuthenticator());
-    sshd.setPublickeyAuthenticator(new MyPublickeyAuthenticator());
-    sshd.setKeyboardInteractiveAuthenticator(new MyKeyboardInteractiveAuthenticator());
-    ...etc...
-
-```
-
-Several useful implementations are available that can be used as-is or extended in order to provide some custom behavior. In any
-case, the default initializations are:
-
-* `DefaultAuthorizedKeysAuthenticator` - uses the _authorized_keys_ file the same way as the SSH daemon does
-* `DefaultKeyboardInteractiveAuthenticator` - for password-based or interactive authentication. **Note:** this authenticator
-requires a `PasswordAuthenticator` to be configured since it delegates some of the functionality to it.
-
-## Configuring ciphers, macs, digest...
-
-SSH supports pluggable factories to define various configuration parts such as ciphers, digests, key exchange, etc...
-The list of supported implementations can be changed to suit one's needs, or one can also implement one's own factories.
-
-Configuring supported factories can be done with the following code:
-
-```java
-
-    sshd.setCipherFactories(Arrays.asList(BuiltinCiphers.aes256ctr, BuiltinCiphers.aes192ctr, BuiltinCiphers.aes128ctr));
-    sshd.setKeyExchangeFactories(Arrays.asList(new MyKex1(), new MyKex2(), BuiltinKeyExchange.A, ...etc...));
-
-```
-
-One can configure other security components using built-in factories the same way. It is important to remember though
-that the **order** of the factories is important as it affects the key exchange phase where the client and server decide
-what options to use out of each peer's reported preferences.
-
-## Starting the Server
-
-Once we have configured the server, one need only call `sshd.start();`. **Note**: once the server is started, all of the
-configurations (except the port) can still be *overridden* while the server is running (caveat emptor). In such cases,
-only **new** clients that connect to the server after the change will be affected - with the exception of the negotiation
-options (keys, macs, ciphers, etc...) which take effect the next time keys are re-exchanged, that can affect live sessions
-and not only new ones.
+## [Embedding an SSHD server instance in 5 minutes](./docs/server-setup.md)
 
 # SSH functionality breakdown
 
-## Security providers setup
-
-While the code supports _BouncyCastle_ and _EdDSA_ security providers out-of-the-box,
-it also provides a way to [add security providers](https://issues.apache.org/jira/browse/SSHD-713) via the `SecurityProviderRegistrar`
-interface implementation. In order to add support for a new security provider one needs to implement the registrar interface and make
-the code aware of it.
-
-### Default/built-in security provider registrars
-
-The code contains built-in security provider registrars for _BouncyCastle_ and _EdDSA_ (a.k.a. `ed25519`). It automatically detects
-the existence of the required artifacts (since they are optional dependencies) and executes the respective security provider registration.
-This behavior is controlled by the `org.apache.sshd.security.registrars` system property. This property contains a comma-separated list
-of **fully-qualified** class names implementing the `SecurityProviderRegistrar` interface and assumed to contain a default **public**
-no-arguments constructor. The code automatically parses the list and attempts to instantiate and invoke the registrar.
-
-**Note:**
-
-
-- The registration code automatically parses the configured registrars list and instantiates them. In this context, one can use the
-special `none` value to indicate that the code should not attempt to automatically register the default providers.
-
-- A registrar instance might be created but eventually discarded and not invoked if it is disabled, unsupported or already registered
-programmatically via `SecurityUtils#registerSecurityProvider`.
-
-
-- The registration attempt is a **one-shot** deal - i.e., once the registrars list is parsed and successfully resolved, any modifications
-to the registered security providers must be done **programatically**. One can call `SecurityUtils#isRegistrationCompleted()` to find out
-if the registration phase has already been executed.
-
-
-- The registrars are consulted in the same **order** as they were initially registered - either programmatically or via the system property
-configuration. Therefore, if two or more registrars support the same algorithm, then the earlier registered one will be used.
-
-
-- If no matching registrar was found, then the default security provider is used. If none set, the JCE defaults are invoked. The default
-security provider can be configured either via the `org.apache.sshd.security.defaultProvider` system property or by programmatically
-invoking `SecurityUtils#setDefaultProviderChoice`. **Note:** if the system property option is used, then it is assumed to contain a security
-provider's **name** (rather than its `Provider` class name...).
-
-
-- If programmatic selection of the default security provider choice is required, then the code flow must ensure that
-`SecurityUtils#setDefaultProviderChoice` is called before **any** security entity (e.g., ciphers, keys, etc...) are
-required. Theoretically, one could change the choice after ciphers have been been requested but before keys were generated
-(e.g....), but it is dangerous and may yield unpredictable behavior.
-
-
-### Implementing a new security provider registrar
-
-See `AbstractSecurityProviderRegistrar` helper class for a default implementation of most of the required functionality, as
-well as the existing implementations for _BouncyCastle_ and _EdDSA_ for examples of how to implement it. The most important
-issues to consider when adding such an implementation are:
-
-* Try using reflection API to detect the existence of the registered provider class and/or instantiate it. The main reason
-for this recommendation is that it isolates the code from a direct dependency on the provider's classes and makes class loading
-issue less likely.
-
-
-* Decide whether to use the provider's name or instance when creating security related entities such as ciphers, keys, etc...
-**Note:** the default preference is to use the provider name, thus registering via `Security.addProvider` call. In order to
-change that, either register the instance yourself or override the `isNamedProviderUsed` method. In this context, **cache**
-the generated `Provider` instance if the instance rather than the name is used. **Note:** using only the provider instance
-instead of the name is a rather new feature and has not been fully tested. It is possible though to decide and use it anyway
-as long as it can be configurably disabled.
-
-
-* The default implementation provides fine-grained control over the declared supported security entities - ciphers, signatures,
-key generators, etc... By default, it is done via consulting a system property composed of `org.apache.sshd.security.provider`,
-followed by the security provider name and the relevant security entity - e.g., `org.apache.sshd.security.provider.BC.KeyFactory`
-is assumed to contain a comma-separated list of supported `KeyFactory` algorithms.
-
-**Note:**
-
-
-* The same naming convention can be used to enable/disable the registrar - even if supported - e.g.,
-`org.apache.sshd.security.provider.BC.enabled=false` disables the _BouncyCastle_ registrar.
-
-
-* One can use `all` or `*` to specify that all entities of the specified type are supported - e.g.,
-`org.apache.sshd.security.provider.BC.MessageDigest=all`. In this context, one can override the
-`getDefaultSecurityEntitySupportValue` method if no fine-grained configuration is required per-entity type,
-
-
-* The result of an `isXxxSupported` call is/should be **cached** (see `AbstractSecurityProviderRegistrar`).
-
-
-* For ease of implementation, all support query calls are routed to the `isSecurityEntitySupported` method
-so that one can concentrate all the configuration in a single method. This is done for **convenience**
-reasons - the code will invoke the correct support query as per the type of entity it needs. E.g., if it
-needs a cipher, it will invoke `isCipherSupported` - which by default will invoke `isSecurityEntitySupported`
-with the `Cipher` class as its argument.
-
-
-* Specifically for **ciphers** the argument to the support query contains a **transformation** (e.g., `AES/CBC/NoPadding`)
-so one should take that into account when parsing the input argument to decide which cipher is referenced - see
-`SecurityProviderRegistrar.getEffectiveSecurityEntityName(Class<?>, String)` helper method
-
-
-## `FileSystemFactory` usage
-
-This interface is used to provide "file"-related services - e.g., SCP and SFTP - although it can be used for remote command execution
-as well (see the section about commands and the `Aware` interfaces). The default implementation is a `NativeFileSystemFactory`
-that simply exposes the [FileSystems.getDefault()](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystems.html#getDefault)
-result. However, for "sandboxed" implementations one can use the `VirtualFileSystemFactory`. This implementation provides a way for
-deciding what is the logged-in user's file system view and then use a `RootedFileSystemProvider` in order to provide a "sandboxed"
-file system where the logged-in user can access only the files under the specified root and no others.
-
-```java
-
-    SshServer sshd = SshServer.setupDefaultServer();
-    sshd.setFileSystemFactory(new VirtualFileSystemFactory() {
-        @Override
-        protected Path computeRootDir(Session session) throws IOException  {
-            String username = session.getUsername(); // or any other session related parameter
-            Path path = resolveUserHome(username);
-            return path;
-        }
-    });
-
-```
-
-The usage of a `FileSystemFactory` is not limited though to the server only - the `ScpClient` implementation also uses
-it in order to retrieve the *local* path for upload/download-ing files/folders. This means that the client side can also
-be tailored to present different views for different clients
-
-## `ExecutorService`-s
-
-The framework requires from time to time spawning some threads in order to function correctly - e.g., commands, SFTP subsystem,
-port forwarding (among others) require such support. By default, the framework will allocate an [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
-for each specific purpose and then shut it down when the module has completed its work - e.g., session was closed. Note that
-SSHD uses the `CloseableExecutorService` interface instead of the usual `ExecutorService` in order to provide graceful shutdown.
-Users may provide their own `CloseableExecutorService`(s) instead of the internally auto-allocated ones - e.g., in order to
-control the max. spawned threads, stack size, track threads, etc... but they can leverage the `SshThreadPoolExecutor` implementation
-which should cover most use cases.
-
-Users who want to provide their own `ExecutorService` and not use `SshThreadPoolExecutor` should wrap it as a `NoCloseExecutor`
-and take care of shutting it down when SSHD is done with (provided, of course, that the user's own code does not need it to
-remain active afterwards...).
-
-```java
-
-    /*
-     * An example user-provided executor service for SFTP - there are other such locations.
-     * By default, the SftpSubsystem implementation creates a single-threaded executor
-     * for each session, uses it to spawn the SFTP command handler and shuts
-     * it down when the command is destroyed
-     */
-    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
-        .withExecutorService(new NoCloseExecutor(mySuperDuperExecutorService))
-        .build();
-    SshServer sshd = SshServer.setupDefaultServer();
-    sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(factory));
-
-```
-
-If a single `CloseableExecutorService` is shared between several services, it needs to be wrapped with the
-`ThreadUtils.noClose(executor)` method.
-
-```java
-    CloseableExecutorService sharedService = ...obtain/create an instance...;
-
-    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
-        .withExecutorService(ThreadUtils.noClose(sharedService))
-        .build();
-
-   ChannelAgentForwarding forward = new ChannelAgentForwarding(ThreadUtils.noClose(sharedService));
-```
-
-**Note:** Do not share the instance returned by `ThreadUtils.noClose` between services as it interferes with
-the graceful closing mechanism. Use a new wrapper instance for each service.
-
-## Remote command execution
-
-All command execution - be it shell or single command - boils down to a `Command` instance being created, initialized and then
-started. In this context, it is **crucial** to notice that the command's `start()` method implementation **must spawn a new thread** - even
-for the simplest or most trivial command. Any attempt to communicate via the established session will most likely **fail** since
-the packets processing thread may be blocked by this call. **Note:** one might get away with executing some command in the
-context of the thread that called the `start()` method, but it is **extremely dangerous** and should not be attempted.
-
-The command execution code can communicate with the peer client via the input/output/error streams that are provided as
-part of the command initialization process. Once the command is done, it should call the `ExitCallback#onExit` method to indicate
-that it has finished. The framework will then take care of propagating the exit code, closing the session and (eventually) `destroy()`-ing
-the command. **Note**: the command may not assume that it is done until its `destroy()` method is called - i.e., it should not
-release or null-ify any of its internal state even if `onExit()` was called.
-
-Upon calling the `onExit` method the code sends an [SSH_MSG_CHANNEL_EOF](https://tools.ietf.org/html/rfc4254#section-5.3) message,
-and the provided result status code is sent as an `exit-status` message as described in [RFC4254 - section 6.10](https://tools.ietf.org/html/rfc4254#section-6.10).
-The provided message is simply logged at DEBUG level.
-
-```java
-
-    // A simple command implementation example
-    class MyCommand implements Command, Runnable {
-        private InputStream in;
-        private OutputStream out, err;
-        private ExitCallback callback;
-
-        public MyCommand() {
-            super();
-        }
-
-        @Override
-        public void setInputStream(InputStream in) {
-            this.in = in;
-        }
-
-        @Override
-        public void setOutputStream(OutputStream out) {
-            this.out = out;
-        }
-
-        @Override
-        public void setErrorStream(OutputStream err) {
-            this.err = err;
-        }
-
-        @Override
-        public void setExitCallback(ExitCallback callback) {
-            this.callback = callback;
-        }
-
-        @Override
-        public void start(Environment env) throws IOException {
-            spawnHandlerThread(this);
-        }
-
-        @Override
-        public void run() {
-            while(true) {
-                try {
-                    String cmd = readCommand(in);
-                    if ("exit".equals(cmd)) {
-                        break;
-                    }
-
-                    handleCommand(cmd, out);
-                } catch (Exception e) {
-                    writeError(err, e);
-                    callback.onExit(-1, e.getMessage());
-                    return;
-            }
-
-            callback.onExit(0);
-        }
-    }
-```
-
-### `Aware` interfaces
-
-Once created, the `Command` instance is checked to see if it implements one of the `Aware` interfaces that enables
-injecting some dynamic data before the command is `start()`-ed.
-
-* `SessionAware` - Injects the `Session` instance through which the command request was received.
-
-* `ChannelSessionAware` - Injects the `ChannelSession` instance through which the command request was received.
-
-* `FileSystemAware` - Injects the result of consulting the `FileSystemFactory` as to the [FileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html)
-associated with this command.
-
-
-### Data stream(s) sizing consideration
-
-Some commands may send/receive large amounts of data over their STDIN/STDOUT/STDERR streams. Since (by default) the sending mechanism in SSHD is
-**asynchronous** it may cause _Out of memory_ errors due to one side (client/server) generating `SSH_MSG_CHANNEL_DATA` or `SSH_MSG_CHANNEL_EXTENDED_DATA`
-at a much higher rate than the other side can consume. This leads to a build-up of a packets backlog that eventually consumes all available memory
-(as described in [SSHD-754](https://issues.apache.org/jira/browse/SSHD-754) and [SSHD-768](https://issues.apache.org/jira/browse/SSHD-768)). As of
-version 1.7 one can register a `ChannelStreamPacketWriterResolver` at the client/server/session/channel level that can enable the user to replace
-the raw channel with some throttling mechanism that will be used for stream packets. Such an (experimental) example is the `ThrottlingPacketWriter`
-available in the `sshd-contrib` module. **Note:** if the `ChannelStreamPacketWriterResolver` returns a wrapper instance instead of a `Channel` then
-it will be **closed** automatically when the stream using it is closed.
-
-## SCP
-
-Both client-side and server-side SCP are supported. Starting from version 2.0, the SCP related code is located in the `sshd-scp` module, so you need
-to add this additional dependency to your maven project:
-
-```xml
-
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-sscp</artifactId>
-        <version>...same as sshd-core...</version>
-    </dependency>
-
-```
-
-### Client-side SCP
-
-In order to obtain an `ScpClient` one needs to use an `ScpClientCreator`:
-
-```java
-
-ClientSession session = ... obtain an instance ...
-ScpClientCreator creator = ... obtain an instance ...
-ScpClient client = creator.createScpClient(session);
-
-```
-
-A default `ScpClientCreator` instance is provided as part of the module - see `ScpClientCreator.instance()`
-
-#### ScpFileOpener(s)
-
-As part of the `ScpClientCreator`, the SCP module also uses a `ScpFileOpener` instance in order to access
-the local files. The default implementation simply opens an [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html)
-or [OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html) on the requested local path. However,
-the user may replace it and intercept the calls - e.g., for logging, monitoring transfer progess, wrapping/filtering the streams, etc...
-The user may attach a default opener that will be automatically attached to **all** clients created unless specifically overridden:
-
-```java
-
-/**
- * Example of using a non-default opener for monitoring and reporting on transfer progress
- */
-public class ScpTransferProgressMonitor extends DefaultScpFileOpener {
-    public static ScpTransferProgressMonitor MONITOR = new ScpTransferProgressMonitor();
-
-    public ScpTransferProgressMonitor() {
-        super();
-    }
-
-    @Override
-    public InputStream openRead(
-            Session session, Path file, long size, Set<PosixFilePermission> permissions, OpenOption... options)
-                throws IOException {
-        return new MyProgressReportingInputStream(super.openRead(session, file, size, permissions, options), size /* how much is expected */);
-    }
-
-    @Override
-    public OutputStream openWrite(
-            Session session, Path file, long size, Set<PosixFilePermission> permissions, OpenOption... options)
-                throws IOException {
-        return new MyProgressReportingOutputStream(super.openWrite(session, file, size, permissions, options), size /* how much is expected */);
-    }
-}
-
-ClientSession session = ... obtain an instance ...
-ScpClientCreator creator = ... obtain an instance ...
-creator.setScpFileOpener(ScpTransferProgressMonitor.INSTANCE);
-
-ScpClient client1 = creator.createScpClient(session);   // <<== automatically uses ScpTransferProgressMonitor
-ScpClient client2 = creator.createScpClient(session, new SomeOtherOpener());   // <<== uses SomeOtherOpener instead of ScpTransferProgressMonitor
-
-```
-
-**Note:** due to SCP protocol limitations one cannot change the **size** of the input/output since it is passed as part of the command
-**before** the file opener is invoked - so there are a few limitations on what one can do within this interface implementation.
-
-#### ScpTransferEventListener(s)
-
-The `ScpClientCreator` can also be used to attach a default `ScpTransferEventListener` that will be attached to
-**all** created SCP client instances through that creator - unless specifically overridden:
-
-```java
-
-ClientSession session = ... obtain an instance ...
-ScpClientCreator creator = ... obtain an instance ...
-creator.setScpTransferEventListener(new MySuperDuperListener());
-
-ScpClient client1 = creator.createScpClient(session);   // <<== automatically uses MySuperDuperListener
-ScpClient client2 = creator.createScpClient(session, new SomeOtherListener());   // <<== uses SomeOtherListener instead of MySuperDuperListener
-
-```
-
-### Server-side SCP
-
-The `ScpCommandFactory` allows users to attach an `ScpFileOpener` and/or `ScpTransferEventListener` having the same behavior as the client - i.e.,
-monitoring and intervention on the accessed local files.
-
-## SFTP
-
-Both client-side and server-side SFTP are supported. Starting from version 2.0, the SFTP related code is located
-in the `sshd-sftp` artifact, so one needs to add this additional dependency to one's maven project:
-
-```xml
-
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-sftp</artifactId>
-        <version>...same as sshd-core...</version>
-    </dependency>
-
-```
-
-### Server-side SFTP
-
-On the server side, the following code needs to be added:
-
-```java
-
-    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
-        .build();
-    server.setSubsystemFactories(Collections.singletonList(factory));
-
-```
-
-### `SftpEventListener`
-
-(See above more details...) - users may register an `SftpEventListener` (or more...) in the `SftpSubsystemFactory` in
-order to monitor and even intervene in the susbsytem's functionality.
-
-### Client-side SFTP
-
-In order to obtain an `SftpClient` instance one needs to use an `SftpClientFactory`:
-
-
-```java
-
-    ClientSession session = ...obtain session...
-    SftpClientFactory factory = ...obtain factory...
-    SftpClient client = factory.createSftpClient(session);
-
-```
-
-A default client factory implementations is provided in the module - see `SftpClientFactory.instance()`
-
-
-### Using a custom `SftpClientFactory`
-
-The code creates `SftpClient`-s and `SftpFileSystem`-s using a default built-in `SftpClientFactory` instance (see
-`DefaultSftpClientFactory`). Users may choose to use a custom factory in order to provide their own
-implementations - e.g., in order to override some default behavior - e.g.:
-
-```java
-
-    SshClient client = ... setup client...
-
-    try (ClientSession session = client.connect(user, host, port).verify(timeout).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth.verify(timeout);
-
-        // User-specific factory
-        try (SftpClient sftp = MySpecialSessionSftpClientFactory.INSTANCE.createSftpClient(session)) {
-            ... instance created through SpecialSessionSftpClientFactory ...
-        }
-    }
-
-```
-
-### Version selection via `SftpVersionSelector`
-
-
-The SFTP subsystem code supports versions 3-6 (inclusive), and by default attempts to negotiate the **highest**
-possible one - on both client and server code. The user can intervene and force a specific version or a narrower
-range.
-
-
-```java
-
-    SftpVersionSelector myVersionSelector = new SftpVersionSelector() {
-        @Override
-        public int selectVersion(ClientSession session, int current, List<Integer> available) {
-            int selectedVersion = ...run some logic to decide...;
-            return selectedVersion;
-        }
-    };
-
-    try (ClientSession session = client.connect(user, host, port).verify(timeout).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth.verify(timeout);
-
-        SftpClientFactory factory = SftpClientFactory.instance();
-        try (SftpClient sftp = factory.createSftpClient(session, myVersionSelector)) {
-            ... do SFTP related stuff...
-        }
-    }
-
-```
-
-On the server side, version selection restriction is more complex - please remember that the **client** chooses
-the version, and all we can do at the server is require a **specific** version via the `SftpSubsystem#SFTP_VERSION`
-configuration key. For more advanced restrictions one needs to sub-class `SftpSubSystem` and provide a non-default
-`SftpSubsystemFactory` that uses the sub-classed code.
-
-### Using `SftpFileSystemProvider` to create an `SftpFileSystem`
-
-
-The code automatically registers the `SftpFileSystemProvider` as the handler for `sftp://` URL(s). Such URLs are
-interpreted as remote file locations and automatically exposed to the user as [Path](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html)
-objects. In effect, this allows the code to "mount" a remote directory via SFTP and treat it as if it were local using
-standard [java.nio](https://docs.oracle.com/javase/8/docs/api/java/nio/package-frame.html) calls like any "ordinary" file
-system.
-
-```java
-
-    // Direct URI
-    Path remotePath = Paths.get(new URI("sftp://user:password@host/some/remote/path"));
-    // Releasing the file-system once no longer necessary
-    try (FileSystem fs = remotePath.getFileSystem()) {
-        ... work with the remote path...
-    }
-
-    // "Mounting" a file system
-    URI uri = SftpFileSystemProvider.createFileSystemURI(host, port, username, password);
-    try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
-        Path remotePath = fs.getPath("/some/remote/path");
-        ...
-    }
-
-    // Full programmatic control
-    SshClient client = ...setup and start the SshClient instance...
-    SftpFileSystemProvider provider = new SftpFileSystemProvider(client);
-    URI uri = SftpFileSystemProvider.createFileSystemURI(host, port, username, password);
-    try (FileSystem fs = provider.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
-        Path remotePath = fs.getPath("/some/remote/path");
-    }
-
-```
-
- The obtained `Path` instance can be used in exactly the same way as any other "regular" one:
-
-
- ```java
-
-    try (InputStream input = Files.newInputStream(remotePath)) {
-        ...read from remote file...
-    }
-
-    try (DirectoryStream<Path> ds = Files.newDirectoryStream(remoteDir)) {
-        for (Path remoteFile : ds) {
-            if (Files.isRegularFile(remoteFile)) {
-                System.out.println("Delete " + remoteFile + " size=" + Files.size(remoteFile));
-                Files.delete(remoteFile);
-            } else if (Files.isDirectory(remoteFile)) {
-                System.out.println(remoteFile + " - directory");
-            }
-        }
-    }
-```
-
-It is highly recommended to `close()` the mounted file system once no longer necessary in order to release the
-associated SFTP session sooner rather than later - e.g., via a `try-with-resource` code block.
-
-**Caveat:** Due to URI encoding of the username/password as a basic authentication, the system currently
-does not allow colon (`:`) in either one in order to avoid parsing confusion. See [RFC 3986 - section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1):
-
->> Use of the format "user:password" in the userinfo field is
->> deprecated ... Applications may choose to ignore or reject such
->> data when it is received as part of a reference...
-
-#### Configuring the `SftpFileSystemProvider`
-
-When "mounting" a new file system one can provide extra configuration parameters using either the
-environment map in the [FileSystems#newFileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystems.html#newFileSystem)
-method or via the URI query parameters. See the `SftpFileSystemProvider` for the available
-configuration keys and values.
-
-
-```java
-
-    // Using explicit parameters
-    Map<String, Object> params = new HashMap<>();
-    params.put("param1", value1);
-    params.put("param2", value2);
-    ...etc...
-
-    URI uri = SftpFileSystemProvider.createFileSystemURI(host, port, username, password);
-    try (FileSystem fs = FileSystems.newFileSystem(uri, params)) {
-        Path remotePath = fs.getPath("/some/remote/path");
-        ... work with the remote path...
-    }
-
-    // Using URI parameters
-    Path remotePath = Paths.get(new URI("sftp://user:password@host/some/remote/path?param1=value1&param2=value2..."));
-    // Releasing the file-system once no longer necessary
-    try (FileSystem fs = remotePath.getFileSystem()) {
-        ... work with the remote path...
-    }
-
-```
-
-**Note**: if **both** options are used then the URI parameters **override** the environment ones
-
-
-```java
-
-    Map<String, Object> params = new HashMap<>();
-    params.put("param1", value1);
-    params.put("param2", value2);
-
-    // The value of 'param1' is overridden in the URI
-    try (FileSystem fs = FileSystems.newFileSystem(new URI("sftp://user:password@host/some/remote/path?param1=otherValue1", params)) {
-        Path remotePath = fs.getPath("/some/remote/path");
-        ... work with the remote path...
-    }
-
-```
-
-#### Configuring the client session used to create an `SftpFileSystem`
-
-It is possible to register a `SftpFileSystemClientSessionInitializer` with the provider instead of the default one
-and thus better control the `ClientSession` used to generate the file-system instance. The default implementation
-simply connects and authenticates before creating a default `SftpFileSystem` instance. Users may wish
-to override some options or provide their own - e.g., execute a password-less authentication instead of
-the (default) password-based one:
-
-```java
-
-    SftpFileSystemProvider provider = ... obtain/create a provider ...
-    provider.setSftpFileSystemClientSessionInitializer(new SftpFileSystemClientSessionInitializer() {
-        @Override
-        public void authenticateClientSession(
-                SftpFileSystemProvider provider, SftpFileSystemInitializationContext context, ClientSession session)
-                    throws IOException {
-            /*
-             * Set up password-less login instead of password-based using the specified key
-             *
-             * Note: if SSH client and/or session already have a KeyPairProvider set up and the code
-             * knows that these keys are already registered with the remote server, then no need to
-             * add the public key identitiy - can simply call sesssion.auth().verify(context.getMaxAuthTime()).
-             */
-            KeyPair kp = ... obtain a registered key-pair...
-            session.addPublicKeyIdentity(kp);
-            return sesssion.auth().verify(context.getMaxAuthTime());
-        }
-    });
-
-```
-
-#### Tracking accessed locations via `SftpFileSystemAccessor`
-
-One can override the default `SftpFileSystemAccessor` and thus be able to track all opened files and folders
-throughout the SFTP server subsystem code. The accessor is registered/overwritten in via the `SftpSubSystemFactory`:
-
-```java
-
-    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
-        .withFileSystemAccessor(new MySftpFileSystemAccessor())
-        .build();
-    server.setSubsystemFactories(Collections.singletonList(factory));
-
-```
-
-### SFTP sent/received names encoding
-
-By default, the SFTP client uses UTF-8 to encode/decode any referenced file/folder name. However, some servers do not properly encode such names,
-and thus the "visible" names by the client become corrupted, or even worse - cause an exception upon decoding attempt. The `SftpClient` exposes
-a `get/setNameDecodingCharset` method which enables the user to modify the charset - even while the SFTP session is in progress - e.g.:
-
-```java
-
-    try (SftpClient client = ...obtain an instance...) {
-        client.setNameDecodingCharset(Charset.forName("ISO-8859-8"));
-        for (DirEntry entry : client.readDir(...some path...)) {
-            ...handle entry assuming ISO-8859-8 encoded names...
-        }
-
-        client.setNameDecodingCharset(Charset.forName("ISO-8859-4"));
-        for (DirEntry entry : client.readDir(...some other path...)) {
-            ...handle entry assuming ISO-8859-4 encoded names...
-        }
-    }
-
-```
-
-The initial charset can be pre-configured on the client/session by using the `sftp-name-decoding-charset` property - if none specified then
-UTF-8 is used. **Note:** the value can be a charset name or a `java.nio.charset.Charset` instance - e.g.:
-
-```java
-
-    SshClient client = ... setup/obtain an instance...
-    // default for ALL SFTP clients obtained through this client
-    PropertyResolverUtils.updateProperty(client, SftpClient.NAME_DECODING_CHARSET, "ISO-8859-8");
-
-    try (ClientSession session = client.connect(...)) {
-         // default for ALL SFTP clients obtained through the session - overrides client setting
-         PropertyResolverUtils.updateProperty(session, SftpClient.NAME_DECODING_CHARSET, "ISO-8859-4");
-         session.authenticate(...);
-
-         SftpClientFactory factory = SftpClientFactory.instance();
-         try (SftpClient sftp = factory.createSftpClient(session)) {
-             for (DirEntry entry : sftp.readDir(...some path...)) {
-                 ...handle entry assuming ISO-8859-4 (inherited from the session) encoded names...
-             }
-
-             // override the inherited default from the session
-             sftp.setNameDecodingCharset(Charset.forName("ISO-8859-1"));
-
-             for (DirEntry entry : sftp.readDir(...some other path...)) {
-                 ...handle entry assuming ISO-8859-1 encoded names...
-             }
-         }
-    }
-
-```
-
-Both client and server support several of the SFTP extensions specified in various drafts:
-
-* `supported` - [DRAFT 05 - section 4.4](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-05.tx)
-* `supported2` - [DRAFT 13 section 5.4](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-10)
-* `versions` - [DRAFT 09 Section 4.6](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
-* `vendor-id` - [DRAFT 09 - section 4.4](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
-* `acl-supported` - [DRAFT 11 - section 5.4](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-11)
-* `newline` - [DRAFT 09 Section 4.3](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
-* `md5-hash`, `md5-hash-handle` - [DRAFT 09 - section 9.1.1](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
-* `check-file-handle`, `check-file-name` - [DRAFT 09 - section 9.1.2](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
-* `copy-file`, `copy-data` - [DRAFT 00 - sections 6, 7](http://tools.ietf.org/id/draft-ietf-secsh-filexfer-extensions-00.txt)
-* `space-available` - [DRAFT 09 - section 9.3](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
-
-Furthermore several [OpenSSH SFTP extensions](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL) are also supported:
-
-* `fsync@openssh.com`
-* `fstatvfs@openssh.com`
-* `hardlink@openssh.com`
-* `posix-rename@openssh.com`
-* `statvfs@openssh.com`
-
-
-On the server side, the reported standard extensions are configured via the `SftpSubsystem.CLIENT_EXTENSIONS_PROP` configuration
-key, and the _OpenSSH_ ones via the `SftpSubsystem.OPENSSH_EXTENSIONS_PROP`.
-
-On the client side, all the supported extensions are classes that implement `SftpClientExtension`. These classes can be used
-to query the client whether the remote server supports the specific extension and then obtain a parser for its contents. Users
-can easily add support for more extensions in a similar manner as the existing ones by implementing an appropriate `ExtensionParser`
-and then registering it at the `ParserUtils` - see the existing ones for details how this can be achieved.
-
-
-```java
-
-    // properietary/special extension parser
-    ParserUtils.registerExtension(new MySpecialExtension());
-
-    try (ClientSession session = client.connect(username, host, port).verify(timeout).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth().verify(timeout);
-
-        SftpClientFactory factory = SftpClientFactory.instance();
-        try (SftpClient sftp = factory.createSftpClient(session)) {
-            Map<String, byte[]> extensions = sftp.getServerExtensions();
-            // Key=extension name, value=registered parser instance
-            Map<String, ?> data = ParserUtils.parse(extensions);
-            for (Map.Entry<String, ?> de : data.entrySet()) {
-                String extName = de.getKey();
-                Object extValue = de.getValue();
-                if (SftpConstants.EXT_ACL_SUPPORTED.equalsIgnoreCase(extName)) {
-                    AclCapabilities capabilities = (AclCapabilities) extValue;
-                    ...see what other information can be gleaned from it...
-                } else if (SftpConstants.EXT_VERSIONS.equalsIgnoreCase(extName)) {
-                    Versions versions = (Versions) extValue;
-                    ...see what other information can be gleaned from it...
-                } else if ("my-special-extension".equalsIgnoreCase(extName)) {
-                    MySpecialExtension special = (MySpecialExtension) extValue;
-                    ...see what other information can be gleaned from it...
-                } // ...etc....
-            }
-        }
-    }
-
-```
-
-One can skip all the conditional code if a specific known extension is required:
-
-
-```java
-
-    try (ClientSession session = client.connect(username, host, port).verify(timeout).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth().verify(timeout);
-
-        SftpClientFactory factory = SftpClientFactory.instance();
-        try (SftpClient sftp = factory.createSftpClient(session)) {
-            // Returns null if extension is not supported by remote server
-            SpaceAvailableExtension space = sftp.getExtension(SpaceAvailableExtension.class);
-            if (space != null) {
-                ...use it...
-            }
-        }
-    }
-
-```
-
-### Internal exceptions and error message handling
-
-If an exception is thrown during processing of an SFTP command, then the exception is translated into a `SSH_FXP_STATUS` message
-using a registered `SftpErrorStatusDataHandler`. The default implementation provides a short description of the failure based on the thrown
-exception type. However, users may override it when creating the `SftpSubsystemFactory` and provide their own codes and/or messages - e.g.,
-for debugging one can register a `DetailedSftpErrorStatusDataHandler` (see `sshd-contrib`) that "leaks" more information in the generated message.
-
-If the registered handler implements `ChannelSessionAware` then it will also be informed of the registered `ChannelSession` when it is
-provided to the `SftpSubsystem` itself. This can be used to register an extended data writer that can handle data sent via the STDERR
-channel. **Note:** this feature is allowed according to [SFTP version 4 - section 3.1](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-3.1):
-
->> Packets are sent and received on stdout and stdin. Data sent on stderr by the server SHOULD be considered debug
->> or supplemental error information, and MAY be displayed to the user.
-
-however, the current code provides no built-in support for this feature.
-
-If registering an extended data writer then one should take care of any race conditions that may occur where (extended) data
-may arrive before the handler is informed of the existence of the `ChannelSession`. For this purpose one should configure a
-reasonable buffer size by setting the `channel-session-max-extdata-bufsize` property. This way, if any data arrives before the
-extended data handler is registered it will be buffered (up to the specified max. size). **Note:** if a buffer size is configured
-but no extended data handler is registered when channel is spawning the command then an exception will occur.
-
-## Port forwarding
-
-### Standard port forwarding
-
-Port forwarding as specified in [RFC 4254 - section 7](https://tools.ietf.org/html/rfc4254#section-7) is fully
-supported by the client and server. From the client side, this capability is exposed via the `start/stopLocal/RemotePortForwarding`
-method. The key player in this capability is the configured `ForwardingFilter` that controls this feature - on **both** sides - client
-and server. By default, this capability is **disabled** - i.e., the user must provide an implementation and call the appropriate
-`setForwardingFilter` method on the client/server.
-
-The code contains 2 simple implementations - an accept-all and a reject-all one that can be used for these trivial
-policies. **Note:** setting a _null_ filter is equivalent to rejecting all such attempts.
-
-### SOCKS
-
-The code implements a [SOCKS](https://en.wikipedia.org/wiki/SOCKS) proxy for versions 4 and 5. The proxy capability is
-invoked via the `start/stopDynamicPortForwarding` methods.
-
-### Proxy agent
-
-The code provides to some extent an SSH proxy agent via the available `SshAgentFactory` implementations. As of latest version
-both [Secure Shell Authentication Agent Protocol Draft 02](https://tools.ietf.org/html/draft-ietf-secsh-agent-02) and its
-[OpenSSH](https://www.libssh.org/features/) equivalent are supported. **Note:** in order to support this feature the
-[Apache Portable Runtime Library](https://apr.apache.org/) needs to be added to the Maven dependencies:
-
-```xml
-
-    <dependency>
-        <groupId>tomcat</groupId>
-        <artifactId>tomcat-apr</artifactId>
-    </dependency>
-
-```
-
-**Note:** Since the portable runtime library uses **native** code, one needs to also make sure that the appropriate _.dll/.so_ library
-is available in the LD\_LIBRARY\_PATH.
-
-# Advanced configuration and interaction
-
-## Properties and inheritance model
-The code's behavior is highly customizable not only via non-default implementations of interfaces but also as far as
-the **parameters** that govern its behavior - e.g., timeouts, min./max. values, allocated memory size, etc... All the
-customization related code flow implements a **hierarchical** `PropertyResolver` inheritance model where the "closest"
-entity is consulted first, and then its "owner", and so on until the required value is found. If the entire hierarchy
-yielded no specific result, then some pre-configured default is used. E.g., if a channel requires some parameter in order
-to decide how to behave, then the following configuration hierarchy is consulted:
-
-* The channel-specific configuration
-* The "owning" session configuration
-* The "owning" client/server instance configuration
-* The system properties - **Note:** any configuration value required by the code can be provided via a system property bearing
-the `org.apache.sshd.config` prefix - see `SyspropsMapWrapper` for the implementation details.
-
-
-### Using the inheritance model for fine-grained/targeted configuration
-
-As previously mentioned, this hierarchical lookup model is not limited to "simple" configuration values (strings, integers, etc.), but
-used also for **interfaces/implementations** such as cipher/MAC/compression/authentication/etc. factories - the exception being that
-the system properties are not consulted in such a case. This code behavior provides highly customizable fine-grained/targeted control
-of the code's behavior - e.g., one could impose usage of specific ciphers/authentication methods/etc. or present different public key
-"identities"/welcome banner behavior/etc., based on address, username or whatever other decision parameter is deemed relevant by the
-user's code. This can be done on __both__ sides of the connection - client or server. E.g., the client could present different keys
-based on the server's address/identity string/welcome banner, or the server could accept only specific types of authentication methods
-based on the client's address/username/etc... This can be done in conjunction with the usage of the various `EventListener`-s provided
-by the code (see below).
-
-One of the code locations where this behavior can be leveraged is when the server provides __file-based__ services (SCP, SFTP) in
-order to provide a different/limited view of the available files based on the username - see the section dealing with `FileSystemFactory`-ies.
-
-## Welcome banner configuration
-
-According to [RFC 4252 - section 5.4](https://tools.ietf.org/html/rfc4252#section-5.4) the server may send a welcome
-banner message during the authentication process. Both the message contents and the phase at which it is sent can be
-configured/customized.
-
-### Welcome banner content customization
-
-The welcome banner contents are controlled by the `ServerAuthenticationManager.WELCOME_BANNER` configuration
-key - there are several possible values for this key:
-
-* A simple string - in which case its contents are the welcome banner.
-
-
-* A file [URI](https://docs.oracle.com/javase/8/docs/api/java/net/URI.html) - or a string starting with `"file:/"` followed by the file path - see below.
-
-
-* A [URL](https://docs.oracle.com/javase/8/docs/api/java/net/URL.html) - or a string containing "://" - in which
-case the [URL#openStream()](https://docs.oracle.com/javase/8/docs/api/java/net/URL.html#openStream) method is invoked
-and its contents are read.
-
-
-* A [File](https://docs.oracle.com/javase/8/docs/api/java/io/File.html) or
-a [Path](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html) - in this case, the file's contents are __re-loaded__ every time it is required and sent as the banner contents.
-
-
-* The special value `ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE` which generates a combined "random art" of
-all the server's keys as described in `Perrig A.` and `Song D.`-s article
-[Hash Visualization: a New Technique to improve Real-World Security](http://sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf) - _International Workshop on Cryptographic Techniques and E-Commerce (CrypTEC '99)_
-
-
-* One can also override the `ServerUserAuthService#resolveWelcomeBanner` method and use whatever other content customization one sees fit.
-
-**Note:**
-
-
-1. If any of the sources yields an empty string or is missing (in the case of a resource) then no welcome banner message is sent.
-
-2. If the banner is loaded from a file or URL resource, then one can configure the [Charset](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html) used to convert the file's contents into a string via the `ServerAuthenticationManager.WELCOME_BANNER_CHARSET` configuration key (default=`UTF-8`).
-
-3. In this context, see also the `ServerAuthenticationManager.WELCOME_BANNER_LANGUAGE` configuration key - which
-provides control over the declared language tag, although most clients seem to ignore it.
-
-
-### Welcome banner sending phase
-
-According to [RFC 4252 - section 5.4](https://tools.ietf.org/html/rfc4252#section-5.4):
-
-> The SSH server may send an SSH_MSG_USERAUTH_BANNER message at any time after this authentication protocol starts and before authentication is successful.
-
-
-The code contains a `WelcomeBannerPhase` enumeration that can be used to configure via the `ServerAuthenticationManager.WELCOME_BANNER_PHASE`
-configuration key the authentication phase at which the welcome banner is sent (see also the `ServerAuthenticationManager.DEFAULT_BANNER_PHASE` value).
-In this context, note that if the `NEVER` phase is configured, no banner will be sent even if one has been configured via one of the methods mentioned previously.
-
-
-## `HostConfigEntryResolver`
-
-This interface provides the ability to intervene during the connection and authentication phases and "re-write"
-the user's original parameters. The `DefaultConfigFileHostEntryResolver` instance used to set up the default
-client instance follows the [SSH config file](https://www.digitalocean.com/community/tutorials/how-to-configure-custom-connection-options-for-your-ssh-client)
-standards, but the interface can be replaced so as to implement whatever proprietary logic is required.
-
-
-```java
-
-    SshClient client = SshClient.setupDefaultClient();
-    client.setHostConfigEntryResolver(new MyHostConfigEntryResolver());
-    client.start();
-
-    /*
-     * The resolver might decide to connect to some host2/port2 using user2 and password2
-     * (or maybe using some key instead of the password).
-     */
-    try (ClientSession session = client.connect(user1, host1, port1).verify(...timeout...).getSession()) {
-        session.addPasswordIdentity(...password1...);
-        session.auth().verify(...timeout...);
-    }
-```
-
-
-## `SshConfigFileReader`
-
-Can be used to read various standard SSH [client](http://linux.die.net/man/5/ssh_config)
-or [server](http://manpages.ubuntu.com/manpages/precise/en/man5/sshd_config.5.html) configuration files
-and initialize the client/server respectively. Including (among other things), bind address, ciphers,
-signature, MAC(s), KEX protocols, compression, welcome banner, etc..
-
-## Event listeners
-
-The code supports registering many types of event listeners that enable receiving notifications about important events
-as well as sometimes intervening in the way these events are handled. All listener interfaces extend `SshdEventListener`
-so they can be easily detected and distinguished from other `EventListener`(s).
-
-In general, event listeners are **cumulative** - e.g., any channel event listeners registered on the `SshClient/Server` are
-automatically added to all sessions, *in addition* to any such listeners registered on the `Session`, as well as any specific
-listeners registered on a specific `Channel` - e.g.,
-
-
-```java
-
-    // Any channel event will be signalled to ALL the registered listeners
-    sshClient/Server.addChannelListener(new Listener1());
-    sshClient/Server.addSessionListener(new SessionListener() {
-        @Override
-        public void sessionCreated(Session session) {
-            session.addChannelListener(new Listener2());
-            session.addChannelListener(new ChannelListener() {
-                @Override
-                public void channelInitialized(Channel channel) {
-                    channel.addChannelListener(new Listener3());
-                }
-            });
-        }
-    });
-
-```
-
-### `IoServiceEventListener`
-
-This listener provides low-level events regarding connection establishment (by the client) or acceptance (by the server). The listener is registered
-on the `IoServiceFactory` via the `FactoryManager`-s (i.e., `SshClient/Server#setIoServiceEventListener`). Unlike other listeners defined in this
-section, it is **not cumulative** - i.e., one can `setIoServiceEventListener` but not `addIoServiceEventListener` - thus **replacing** any previously
-registered listener.
-
-### `SessionListener`
-
-Informs about session related events. One can modify the session - although the modification effect depends on the session's **state**. E.g., if one
-changes the ciphers *after* the key exchange (KEX) phase, then they will take effect only if the keys are re-negotiated. It is important to read the
-documentation very carefully and understand at which stage each listener method is invoked and what are the repercussions of changes at that stage.
-In this context, it is worth mentioning that one can attach to sessions **arbitrary attributes** that can be retrieved by the user's code later on:
-
-
-```java
-
-    public static final AttributeKey<String> STR_KEY = new AttributeKey<>();
-    public static final AttributeKey<Long> LONG_KEY = new AttributeKey<>();
-
-    sshClient/Server.addSessionListener(new SessionListener() {
-        @Override
-        public void sessionCreated(Session session) {
-            session.setAttribute(STR_KEY, "Some string value");
-            session.setAttribute(LONG_KEY, 3777347L);
-            // ...etc...
-        }
-
-        @Override
-        public void sessionClosed(Session session) {
-            String str = session.getAttribute(STR_KEY);
-            Long l = session.getAttribute(LONG_KEY);
-            // ... do something with the retrieved attributes ...
-        }
-    });
-```
-
-### `ChannelListener`
-
-
-Informs about channel related events - as with sessions, once can influence the channel to some extent, depending on the channel's **state**.
-The ability to influence channels is much more limited than sessions. In this context, it is worth mentioning that one can attach to channels
-**arbitrary attributes** that can be retrieved by the user's code later on - same was as it is done for sessions.
-
-
-### `UnknownChannelReferenceHandler`
-
-
-Invoked whenever a message intended for an unknown channel is received. By default, the code **ignores** the vast majority of such messages
-and logs them at DEBUG level. For a select few types of messages the code generates an `SSH_CHANNEL_MSG_FAILURE` packet that is sent to the
-peer session - see `DefaultUnknownChannelReferenceHandler` implementation. The user may register handlers at any level - client/server, session
-and/or connection service - the one registered "closest" to connection service will be used.
-
-
-### `SignalListener`
-
-Informs about signal requests as described in [RFC 4254 - section 6.9](https://tools.ietf.org/html/rfc4254#section-6.9), break requests
-(sent as SIGINT) as described in [RFC 4335](https://tools.ietf.org/html/rfc4335) and "window-change" (sent as SIGWINCH) requests as described
-in [RFC 4254 - section 6.7](https://tools.ietf.org/html/rfc4254#section-6.7)
-
-
-### `SftpEventListener`
-
-Provides information about major SFTP protocol events. The provided `File/DirectoryHandle` to the various callbacks an also be used to
-store user-defined attributes via its `AttributeStore` implementation. The listener is registered at the `SftpSubsystemFactory`:
-
-
-```java
-    public class MySfpEventListener implements SftpEventListener {
-        private static final AttributeKey<SomeType> MY_SPECIAL_KEY = new Attribute<SomeType>();
-
-        ...
-        @Override
-        public void opening(ServerSession session, String remoteHandle, Handle localHandle) throws IOException {
-            localHandle.setAttribute(MY_SPECIAL_KEY, instanceOfSomeType);
-        }
-
-        @Override
-        public void writing(
-                ServerSession session, String remoteHandle, FileHandle localHandle,
-                long offset, byte[] data, int dataOffset, int dataLen)
-                    throws IOException {
-            SomeType myData = localHandle.getAttribute(MY_SPECIAL_KEY);
-            ...do something based on my data...
-        }
-    }
-
-
-    SftpSubsystemFactory factory = new SftpSubsystemFactory();
-    factory.addSftpEventListener(new MySftpEventListener());
-    sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(factory));
-
-```
-
-**Note:** the attached attributed are automatically removed once handle has been closed - regardless of
-whether the close attempt was successful or not. In other words, after `SftpEventListener#closed` has been
-called, all attributes associated with the handle are cleared.
-
-### `PortForwardingEventListener`
-
-Informs and allows tracking of port forwarding events as described in [RFC 4254 - section 7](https://tools.ietf.org/html/rfc4254#section-7)
-as well as the (simple) [SOCKS](https://en.wikipedia.org/wiki/SOCKS) protocol (versions 4, 5). In this context, one can create a
-`PortForwardingTracker` that can be used in a `try-with-resource` block so that the set up forwarding is automatically torn down when
-the tracker is `close()`-d:
-
-
-```java
-
-    try (ClientSession session = client.connect(user, host, port).verify(...timeout...).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth().verify(...timeout...);
-
-        try (PortForwardingTracker tracker = session.createLocal/RemotePortForwardingTracker(...)) {
-            ...do something that requires the tunnel...
-        }
-
-        // Tunnel is torn down when code reaches this point
-    }
-```
-
-
-### `ScpTransferEventListener`
-
-Inform about SCP related events. `ScpTransferEventListener`(s) can be registered on *both* client and server side:
-
-
-```java
-
-    // Server side
-    ScpCommandFactory factory = new ScpCommandFactory(...with/out delegate..);
-    factory.addEventListener(new MyServerSideScpTransferEventListener());
-    sshd.setCommandFactory(factory);
-
-    // Client side
-    try (ClientSession session = client.connect(user, host, port).verify(...timeout...).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth().verify(...timeout...);
-
-        ScpClient scp = session.createScpClient(new MyClientSideScpTransferEventListener());
-        ...scp.upload/download...
-    }
-```
-
-### Reserved messages
-
-The implementation can be used to intercept and process the [SSH_MSG_IGNORE](https://tools.ietf.org/html/rfc4253#section-11.2),
-[SSH_MSG_DEBUG](https://tools.ietf.org/html/rfc4253#section-11.3) and [SSH_MSG_UNIMPLEMENTED](https://tools.ietf.org/html/rfc4253#section-11.4)
-messages. The handler can be registered on either side - server or client, as well as on the session. A special
-[patch](https://issues.apache.org/jira/browse/SSHD-699) has been introduced that automatically ignores such messages
-if they are malformed - i.e., they never reach the handler.
-
-#### SSH message stream "stuffing" and keys re-exchange
-
-[RFC 4253 - section 9](https://tools.ietf.org/html/rfc4253#section-9) recommends re-exchanging keys every once in a while
-based on the amount of traffic and the selected cipher - the matter is further clarified in [RFC 4251 - section 9.3.2](https://tools.ietf.org/html/rfc4251#section-9.3.2).
-These recommendations are mirrored in the code via the `FactoryManager` related `REKEY_TIME_LIMIT`, `REKEY_PACKETS_LIMIT`
-and `REKEY_BLOCKS_LIMIT` configuration properties that can be used to configure said behavior - please be sure to read
-the relevant _Javadoc_ as well as the aforementioned RFC section(s) when manipulating them. This behavior can also be
-controlled programmatically by overriding the `AbstractSession#isRekeyRequired()` method.
-
-As an added security mechanism [RFC 4251 - section 9.3.1](https://tools.ietf.org/html/rfc4251#section-9.3.1) recommends adding
-"spurious" [SSH_MSG_IGNORE](https://tools.ietf.org/html/rfc4253#section-11.2) messages. This functionality is mirrored in the
-`FactoryManager` related `IGNORE_MESSAGE_FREQUENCY`, `IGNORE_MESSAGE_VARIANCE` and `IGNORE_MESSAGE_SIZE`
-configuration properties that can be used to configure said behavior - please be sure to read the relevant _Javadoc_ as well
-as the aforementioned RFC section when manipulating them. This behavior can also be controlled programmatically by overriding
-the `AbstractSession#resolveIgnoreBufferDataLength()` method.
-
-#### `ReservedSessionMessagesHandler`
-
-Can be used to handle the following cases:
-
-* [SSH_MSG_IGNORE](https://tools.ietf.org/html/rfc4253#section-11.2)
-* [SSH_MSG_DEBUG](https://tools.ietf.org/html/rfc4253#section-11.3)
-* [SSH_MSG_UNIMPLEMENTED](https://tools.ietf.org/html/rfc4253#section-11.4)
-* Any other unrecognized message received in the session.
-
-**Note:** The `handleUnimplementedMessage` method serves both for handling `SSH_MSG_UNIMPLEMENTED` and any other unrecognized
-message received in the session as well.
-
-
-```java
-
-    class MyClientSideReservedSessionMessagesHandler implements ReservedSessionMessagesHandler {
-        @Override
-        public boolean handleUnimplementedMessage(Session session, int cmd, Buffer buffer) throws Exception {
-            switch(cmd) {
-                case MY_SPECIAL_CMD1:
-                    ....
-                    return true;
-                case MY_SPECIAL_CMD2:
-                    ....
-                    return true;
-                default:
-                    return false;    // send SSH_MSG_UNIMPLEMENTED reply if necessary
-            }
-        }
-    }
-
-    // client side
-    SshClient client = SshClient.setupDefaultClient();
-    // This is the default for ALL sessions unless specifically overridden
-    client.setReservedSessionMessagesHandler(new MyClientSideReservedSessionMessagesHandler());
-    // Adding it via a session listener
-    client.setSessionListener(new SessionListener() {
-            @Override
-            public void sessionCreated(Session session) {
-                // Overrides the one set at the client level.
-                if (isSomeSessionOfInterest(session)) {
-                    session.setReservedSessionMessagesHandler(new MyClientSessionReservedSessionMessagesHandler(session));
-                }
-            }
-    });
-
-    try (ClientSession session = client.connect(user, host, port).verify(...timeout...).getSession()) {
-        // setting it explicitly
-        session.setReservedSessionMessagesHandler(new MyOtherClientSessionReservedSessionMessagesHandler(session));
-        session.addPasswordIdentity(password);
-        session.auth().verify(...timeout...);
-
-        ...use the session...
-    }
-
-
-    // server side
-    SshServer server = SshServer.setupDefaultServer();
-    // This is the default for ALL sessions unless specifically overridden
-    server.setReservedSessionMessagesHandler(new MyServerSideReservedSessionMessagesHandler());
-    // Adding it via a session listener
-    server.setSessionListener(new SessionListener() {
-            @Override
-            public void sessionCreated(Session session) {
-                // Overrides the one set at the server level.
-                if (isSomeSessionOfInterest(session)) {
-                    session.setReservedSessionMessagesHandler(new MyServerSessionReservedSessionMessagesHandler(session));
-                }
-            }
-    });
-
-```
-
-**NOTE:** Unlike "regular" event listeners, the handler is not cumulative - i.e., setting it overrides the previous instance
-rather than being accumulated. However, one can use the `EventListenerUtils` and create a cumulative listener - see how
-`SessionListener` or `ChannelListener` proxies were implemented.
-
-
-### `RequestHandler`(s)
-
-The code supports both [global](https://tools.ietf.org/html/rfc4254#section-4) and [channel-specific](https://tools.ietf.org/html/rfc4254#section-5.4)
-requests via the registration of `RequestHandler`(s). The global handlers are derived from `ConnectionServiceRequestHandler`(s) whereas the channel-specific
-ones are derived from `ChannelRequestHandler`(s). In order to add a handler one need only register the correct implementation and handle the request when
-it is detected. For global request handlers this is done by registering them on the server:
-
-```java
-
-    // NOTE: the following code can be employed on BOTH client and server - the example is for the server
-    SshServer server = SshServer.setUpDefaultServer();
-    List<RequestHandler<ConnectionService>> oldGlobals = server.getGlobalRequestHandlers();
-    // Create a copy in case current one is null/empty/un-modifiable
-    List<RequestHandler<ConnectionService>> newGlobals = new ArrayList<>();
-    if (GenericUtils.size(oldGlobals) > 0) {
-        newGlobals.addAll(oldGLobals);
-    }
-    newGlobals.add(new MyGlobalRequestHandler());
-    server.setGlobalRequestHandlers(newGlobals);
-
-```
-
-For channel-specific requests, one uses the channel's `add/removeRequestHandler` method to manage its handlers. The way
-request handlers are invoked when a global/channel-specific request is received  is as follows:
-
-* All currently registered handlers' `process` method is invoked with the request type string parameter (among others).
-The implementation should examine the request parameters and decide whether it is able to process it.
-
-
-* If the handler returns `Result.Unsupported` then the next registered handler is invoked.
-In other words, processing stops at the **first** handler that returned a valid response. Thus the importance of
-the `List<RequestHandler<...>>` that defines the **order** in which the handlers are invoked. **Note**: while
-it is possible to register multiple handlers for the same request and rely on their order, it is highly recommended
-to avoid this situation as it makes debugging the code and diagnosing problems much more difficult.
-
-
-* If no handler reported a valid result value then a failure message is sent back to the peer. Otherwise, the returned
-result is translated into the appropriate success/failure response (if the sender asked for a response). In this context,
-the handler may choose to build and send the response within its own code, in which case it should return the
-`Result.Replied` value indicating that it has done so.
-
-
-```java
-
-    public class MySpecialChannelRequestHandler implements ChannelRequestHandler {
-        ...
-
-        @Override
-        public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
-            if (!"my-special-request".equals(request)) {
-               return Result.Unsupported;   // Not mine - maybe someone else can handle it
-            }
-
-            ...handle the request - can read more parameters from the message buffer...
-
-            return Result.ReplySuccess/Failure/Replied; // signal processing result
-        }
-    }
-```
-
-
-#### Default registered handlers
-
-* `exit-signal`, `exit-status` - As described in [RFC4254 section 6.10](https://tools.ietf.org/html/rfc4254#section-6.10)
-
-
-* `*@putty.projects.tartarus.org` - As described in [Appendix F: SSH-2 names specified for PuTTY](http://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixF.html)
-
-
-* `hostkeys-prove-00@openssh.com`, `hostkeys-00@openssh.com` - As described in [OpenSSH protocol - section 2.5](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL)
-
-
-* `tcpip-forward`, `cancel-tcpip-forward` - As described in [RFC4254 section 7](https://tools.ietf.org/html/rfc4254#section-7)
-
-
-* `keepalive@*` - Used by many implementations (including this one) to "ping" the peer and make sure the connection is still alive.
-In this context, the SSHD code allows the user to configure both the frequency and content of the heartbeat request (including whether
-to send this request at all) via the `ClientFactoryManager`-s `HEARTBEAT_INTERVAL`, `HEARTBEAT_REQUEST` and `DEFAULT_KEEP_ALIVE_HEARTBEAT_STRING`
-configuration properties.
-
-
-* `no-more-sessions@*` - As described in [OpenSSH protocol section 2.2](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL).
-In this context, the code consults the `ServerFactoryManagder.MAX_CONCURRENT_SESSIONS` server-side configuration property in order to
-decide whether to accept a successfully authenticated session.
-
-
-# Extension modules
-
-There are several extension modules available - specifically, the _sshd-contrib_ module contains some of them. **Note:** the
-module contains experimental code that may find its way some time in the future to a standard artifact. It is also subject to
-changes and/or deletion without any prior announcement. Therefore, any code that relies on it should also store a copy of the
-sources in case the classes it used it are modified or deleted.
-
-## Command line clients
-
-The _apache-sshd.zip_ distribution provides `Windows/Linux` scripts that use the MINA SSHD code base to implement the common
-_ssh, scp, sftp_ commands. The clients accept most useful switches from the original commands they mimic, where the `-o Option=Value`
-arguments can be used to configure the client/server in addition to the system properties mechanism. For more details, consult
-the _main_ methods code in the respective `SshClientMain`, `SftpCommandMain` and `ScpClientMain` classes. The code also includes
-`SshKeyScanMain` that is a simple implementation for [ssh-keyscan(1)](https://www.freebsd.org/cgi/man.cgi?query=ssh-keyscan&sektion=1).
-
-The distribution also includes also an _sshd_ script that can be used to launch a server instance - see `SshServerMain#main`
-for activation command line arguments and options.
-
-In order to use this CLI code as part of another project, one needs to include the _sshd-cli_ module:
-
-```xml
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-cli</artifactId>
-        <version>...same version as the core...</version>
-    </dependency>
-```
-
-### Command line clients
-
-* **SftpCommandMain** - by default uses an internal `SftpClientFactory`. This can be overridden as follows:
-
-1. Provide a `-o SftpClientFactory=XXX` command line argument where the option specifies the fully-qualified name of
-the class that implements this interface.
-
-2. Add a `META-INF\services\org.apache.sshd.client.subsystem.sftp.SftpClientFactory` file containing the fully-qualified name of
-the class that implements this interface. **Note:** if more than one such instance is detected an exception is thrown.
-
-**Note:** The specified class(es) must be public and contain a public no-args constructor.
-
-### Command line SSH daemon
-
-* **Port** - by default the SSH server sets up to list on port 8000 in order to avoid conflicts with any running SSH O/S daemon.
-This can be modified by providing a `-p NNNN` or `-o Port=NNNN` command line option.
-
-* **Subsystem(s)** - the server automatically detects subsystems using the
-[Java ServiceLoader mechanism](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
-
-This can be overwritten as follows (in this order):
-
-1. Provide a `org.apache.sshd.server.subsystem.SubsystemFactory` system property containing comma-separated fully-qualified names of classes implementing
-this interface. The implementations must be public and have a public no-args constructor for instantiating them. The order of the provided subsystems will
-be according to their order in the specified list.
-
-2. Provide a `-o Subsystem=xxx,yyy` command line argument where value is a comma-separated list of the **name**(s) of the auto-detected factories via
-the `ServiceLoader` mechanism. The special value `none` may be used to indicate that no subsystem is to be configured. **Note:** no specific order is
-provided when subsystems are auto-detected and/or filtered.
-
-* **Shell** - unless otherwise instructed, the default SSH server uses an internal shell (see `InteractiveProcessShellFactory`). The shell can be overridden
-or disabled by specifying a `-o ShellFactory=XXX` option where the value can either be `none` to specify that no shell is to be used, or the fully-qualified
-name of a class that implements the `ShellFactory` interface. The implementation must be public and have a public no-args constructor for instantiating it.
-
-## GIT support
-
-The _sshd-git_ artifact contains both client and server-side command factories for issuing and handling some _git_ commands. The code is based
-on [JGit](https://github.com/eclipse/jgit) and iteracts with it smoothly.
-
-### Client-side
-
-This module provides SSHD-based replacements for the SSH and SFTP transports used by the JGIT client - see `GitSshdSessionFactory` - it
-can be used as a drop-in replacement for the [JSCH](http://www.jcraft.com/jsch/) based built-in session factory provided by _jgit_. In
-this context, it is worth noting that the `GitSshdSessionFactory` has been tailored so as to provide flexible control over which `SshClient`
-instance to use, and even which `ClientSession`. The default instance allocates a **new** client every time a new `GitSshdSession` is
-created - which is started and stopped as necessary. However, this can be pretty wasteful, so if one intends to issue several commands
-that access GIT repositories via SSH, one should maintain a **single** client instance and re-use it:
-
-
-```java
-
-    SshClient client = ...create and setup the client...
-    try {
-        client.start();
-
-        GitSshdSessionFactory sshdFactory = new GitSshdSessionFactory(client);  // re-use the same client for all SSH sessions
-        org.eclipse.jgit.transport.SshSessionFactory.setInstance(sshdFactory);  // replace the JSCH-based factory
-
-        ... issue GIT commands that access remote repositories via SSH ....
-
-    } finally {
-        client.stop();
-    }
-
-```
-
-### Server-side
-
-See `GitPackCommandFactory` and `GitPgmCommandFactory` - in order for the various commands to function correctly, they require a `GitLocationResolver`
-that is invoked in order to allow the user to decide which is the correct GIT repository root location for a given command. The resolver is provided
-with all the relevant details - including the command and server session through which the command was received:
-
-
-```java
-
-    GitLocationResolver resolver = (cmd, session, fs) -> ...consult some code - perhaps based on the authenticated username...
-    sshd.setCommandFactory(new GitPackCommandFactory().withGitLocationResolver(resolver));
-
-```
-
- These command factories also accept a delegate to which non-_git_ commands are routed:
-
-
-```java
-
-    sshd.setCommandFactory(new GitPackCommandFactory()
-        .withDelegate(new MyCommandFactory())
-        .withGitLocationResolver(resolver));
-
-    // Here is how it looks if SCP is also requested
-    sshd.setCommandFactory(new GitPackCommandFactory()
-        .withDelegate(new ScpCommandFactory()
-            .withDelegate(new MyCommandFactory()))
-        .withGitLocationResolver(resolver));
-
-    // or
-    sshd.setCommandFactory(new ScpCommandFactory()
-        .withDelegate(new GitPackCommandFactory()
-            .withDelegate(new MyCommandFactory())
-            .withGitLocationResolver(resolver)));
-
-    // or any other combination ...
-
-```
-
-as with all other built-in commands, the factories allow the user to provide an `ExecutorService` in order to control the spawned threads
-for servicing the commands. If none provided, an internal single-threaded "pool" is created ad-hoc and destroyed once the command execution
-is completed (regardless of whether successful or not):
-
-
-```java
-
-    sshd.setCommandFactory(new GitPackCommandFactory(resolver)
-        .withDelegate(new MyCommandFactory())
-        .withExecutorService(myService)
-        .withShutdownOnExit(false));
-
-```
-
-
-## LDAP adaptors
-
-The _sshd-ldap_ artifact contains an [LdapPasswordAuthenticator](https://issues.apache.org/jira/browse/SSHD-607) and
-an [LdapPublicKeyAuthenticator](https://issues.apache.org/jira/browse/SSHD-608) that have been written along the same
-lines as the [openssh-ldap-publickey](https://github.com/AndriiGrytsenko/openssh-ldap-publickey) project. The authenticators
-can be easily configured to match most LDAP schemes, or alternatively serve as base classes for code that extends them
-and adds proprietary logic.
-
-## PROXY / SSLH protocol hooks
-
-The code contains [support for "wrapper" protocols](https://issues.apache.org/jira/browse/SSHD-656) such
-as [PROXY](http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt) or [sslh](http://www.rutschle.net/tech/sslh.shtml).
-The idea is that one can register either a `ClientProxyConnector` or `ServerProxyAcceptor` and intercept
-the 1st packet being sent/received (respectively) **before** it reaches the SSHD code. This gives the programmer
-the capability to write a front-end that routes outgoing/incoming packets:
-
-* `SshClient/ClientSesssion#setClientProxyConnector` - sets a proxy that intercepts the 1st packet before being sent to the server
-
-* `SshServer/ServerSession#setServerProxyAcceptor` - sets a proxy that intercept the 1st incoming packet before being processed by the server
-
-## Configuration/data files parsing support
-
-Most of the configuration data files parsing support resides in the _sshd-common_ artfiact:
-
-```xml
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-common</artifactId>
-        <version>...same version as the rest of the artifacts...</version>
-    </dependency>
-```
-
-The code contains support for parsing the [_authorized_keys_](http://man.openbsd.org/sshd.8#AUTHORIZED_KEYS_FILE_FORMAT),
-[_known\_hosts_](http://www.manpagez.com/man/8/sshd/), [_ssh\_config_, _sshd\_config_](https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5),
-and [_~/config_](http://www.gsp.com/cgi-bin/man.cgi?topic=ssh_config) files. The code resides in the _sshd-common_ artifact - specifically
-the `KeyUtils#getPublicKeyEntryDecoder`, `AuthorizedKeyEntry#readAuthorizedKeys`, `KnownHostEntry#readKnownHostEntries`
-and `HostConfigEntry#readHostConfigEntries`.
-
-### PEM/OpenSSH
-
-The common code contains built-in support for parsing PEM and/or _OpenSSH_ formatted key files and using them for authentication purposes.
-As mentioned previously, it can leverage _Bouncycastle_ if available, but can do most of the work without it as well. For _ed25519_ support,
-one must provide the _eddsa_ artifact dependency.
-
-### [PUTTY](https://www.putty.org/)
-
-The code contains built-in support for parsing PUTTY key files (usually _.ppk_) and using them same as SSH ones as key-pair
-providers for autentication purposes. The PUTTY key file(s) readers are contained in the `org.apache.sshd.common.config.keys.loader.putty`
-package (specifically `PuttyKeyUtils#DEFAULT_INSTANCE KeyPairResourceParser`) of the _sshd-putty_ artifact. **Note:** the artifact should
-be included as an extra dependency:
-
-```xml
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-putty</artifactId>
-        <version>...same version as the rest of the artifacts...</version>
-    </dependency>
-```
-
-### [OpenPGP](https://www.openpgp.org/)
-
-The code contains the _sshd-openpgp_ module that enables using _OpenPGP_ private key files as identity providers.
-
-```xml
-    <dependency>
-        <groupId>org.apache.sshd</groupId>
-        <artifactId>sshd-openpgp</artifactId>
-        <version>...same version as the rest of the artifacts...</version>
-    </dependency>
-```
-
-The [support](https://issues.apache.org/jira/browse/SSHD-757) for it is currently still in its infancy, and therefore
-this feature should be considered **experimental** for the time being. However, within its limitations it supports
-
-* RSA keys
-* DSA keys
-* ECDSA keys
-
-(*) For now `ed25519` keys are not supported by this module.
-
-The code reads **all** the available key pairs in the key file without any distinction between encryption, decryption,
-authentication or signature ones.
-
-This code relies on the [jpgpgj](https://github.com/justinludwig/jpgpj) support module
-
-```xml
-    <dependency>
-        <groupId>org.c02e.jpgpj</groupId>
-        <artifactId>jpgpj</artifactId>
-        <version>0.5</version>
-    </dependency>
-```
-
-(which in turn automatically uses _Bouncycastle_ - so if one does not want _Bouncycastle_ one cannot use this module).
-
-#### Using OpenPGP authorized keys entries
-
-In order to be able to read `authorized_keys` files that may contain _OpenPGP_ keys references, one needs to register
-the relevant `PublicKeyEntryDataResolver`-s. This is done by calling `PGPPublicKeyEntryDataResolver#registerDefaultKeyEntryDataResolvers`
-once during the _main_ code setup. This will enable the code to safely read authorized keys entries having the format
-specified in the [OpenSSH PGP configuration](https://www.red-bean.com/~nemo/openssh-gpg/):
-
-```
-    pgp-sign-dss 87C36E60187451050A4F26B134824FC95C781A18 with-comment
-    pgp-sign-rsa 87C36E60187451050A4F26B134824FC95C781A18
-```
-
-Where the key data following the key type specification is the fingerprint value of the referenced key. In order to
-use a "mixed mode" file (i.e., one that has both SSH and _OpenPGP_ keys) one needs to replace the default `AuthorizedKeysAuthenticator`
-instance with one that is derived from it and overrides the `createDelegateAuthenticator` method in a manner similar
-as shown below:
-
-```java
-// Using PGPAuthorizedEntriesTracker
-public class MyAuthorizedKeysAuthenticatorWithBothPGPAndSsh extends AuthorizedKeysAuthenticator {
-    ... constructor(s) ...
-
-    @Override
-    protected PublickeyAuthenticator createDelegateAuthenticator(
-            String username, ServerSession session, Path path,
-            Collection<AuthorizedKeyEntry> entries, PublicKeyEntryResolver fallbackResolver)
-                throws IOException, GeneralSecurityException {
-        PGPAuthorizedEntriesTracker tracker = ... obtain an instance ...
-        // Note: need to catch the PGPException and transform it into either an IOException or a GeneralSecurityException
-        Collection<PublicKey> keys = tracker.resolveAuthorizedEntries(session, entries, fallbackResolver);
-        if (GenericUtils.isEmpty(keys)) {
-            return RejectAllPublickeyAuthenticator.INSTANCE;
-        } else {
-            return new KeySetPublickeyAuthenticator(id, keys);
-        }
-    }
-}
-
-// Using PGPPublicRingWatcher
-public class MyAuthorizedKeysAuthenticatorWithBothPGPAndSsh extends AuthorizedKeysAuthenticator {
-    ... constructor(s) ...
-
-    @Override
-    protected PublickeyAuthenticator createDelegateAuthenticator(
-            String username, ServerSession session, Path path,
-            Collection<AuthorizedKeyEntry> entries, PublicKeyEntryResolver fallbackResolver)
-                throws IOException, GeneralSecurityException {
-        PGPPublicRingWatcher watcher = ... obtain an instance ...
-        // Note: need to catch the PGPException and transform it into either an IOException or a GeneralSecurityException
-        Collection<PublicKey> keys = watcher.resolveAuthorizedEntries(session, entries, fallbackResolver);
-        if (GenericUtils.isEmpty(keys)) {
-            return RejectAllPublickeyAuthenticator.INSTANCE;
-        } else {
-            return new KeySetPublickeyAuthenticator(id, keys);
-        }
-    }
-}
-
-```
-
-**Note:** seems that currently, this capability is limited to v1.x key rings (see [jpgpj - issue 21](https://github.com/justinludwig/jpgpj/issues/21))
-
-## Useful extra components in _sshd-contrib_
-
-* `InteractivePasswordIdentityProvider` - helps implement a `PasswordIdentityProvider` by delegating calls
-to `UserInteraction#getUpdatedPassword`. The way to use it would be as follows:
-
-
-```java
-try (ClientSession session = client.connect(login, host, port).await().getSession()) {
-     session.setUserInteraction(...);     // this can also be set at the client level
-     PasswordIdentityProvider passwordIdentityProvider =
-          InteractivePasswordIdentityProvider.providerOf(session, "My prompt");
-     session.setPasswordIdentityProvider(passwordIdentityProvider);
-     session.auth.verify(...timeout...);
-     ... continue with the authenticated session ...
-}
-```
-
-or
-
-
-```java
-UserInteraction ui = ....;
-try (ClientSession session = client.connect(login, host, port).await().getSession()) {
-    PasswordIdentityProvider passwordIdentityProvider =
-         InteractivePasswordIdentityProvider.providerOf(session, ui, "My prompt");
-    session.setPasswordIdentityProvider(passwordIdentityProvider);
-    session.auth.verify(...timeout...);
-     ... continue with the authenticated session ...
-}
-```
-
-
-**Note:** `UserInteraction#isInteractionAllowed` is consulted prior to invoking `getUpdatedPassword` - if it
-returns _false_ then password retrieval method is not invoked, and it is assumed that no more passwords are available
-
-
-* `SimpleAccessControlScpEventListener` - Provides a simple access control by making a distinction between
-methods that upload data and ones that download it via SCP. In order to use it, simply extend it and override
-its `isFileUpload/DownloadAllowed` methods
+## [Security providers setup](./docs/security-providers.md)
 
+## [Commands infrastructure](./docs/commands.md)
 
-* `SimpleAccessControlSftpEventListener` - Provides a simple access control by making a distinction between
-methods that provide SFTP file information - including reading data - and those that modify it
+## [SCP](./docs/scp.md)
 
+## [SFTP](./docs/sftp.md)
 
-* `ProxyProtocolAcceptor` - A working prototype to support the PROXY protocol as described in
-[HAProxy Documentation](http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
+## [Port forwarding](./docs/port-forwarding.md)
 
+## [Internal support classes](./docs/internals.md)
 
-* `ThrottlingPacketWriter` - An example of a way to overcome big window sizes when sending data - as
-described in [SSHD-754](https://issues.apache.org/jira/browse/SSHD-754) and [SSHD-768](https://issues.apache.org/jira/browse/SSHD-768)
+## [Event listeners](./docs/event-listeners.md)
 
-* `AndroidOpenSSLSecurityProviderRegistrar` - A security registrar that uses the [AndroidOpenSSL](https://github.com/guardianproject/openssl-android)
-security provider
+## [Command line clients](./docs/cli.md)
 
-# Builtin components
+## [GIT support](./docs/git.md)
 
-Below is the list of builtin components:
+## [Configuration/data files parsing support](./docs/files-parsing.md)
 
-* **Ciphers**: aes128cbc, aes128ctr, aes192cbc, aes192ctr, aes256cbc, aes256ctr, arcfour128, arcfour256, blowfishcbc, tripledescbc
-* **Digests**: md5, sha1, sha224, sha384, sha512
-* **Macs**: hmacmd5, hmacmd596, hmacsha1, hmacsha196, hmacsha256, hmacsha512
-* **Key exchange**: dhg1, dhg14, dhgex, dhgex256, ecdhp256, ecdhp384, ecdhp521
-* **Compressions**: none, zlib, zlib@openssh.com
-* **Signatures/Keys**: ssh-dss, ssh-rsa, nistp256, nistp384, nistp521, ed25519 (requires `eddsa` optional module)
+## [Extension modules](./docs/extensions.md)
diff --git a/docs/cli.md b/docs/cli.md
new file mode 100644
index 0000000..b0d6b6b
--- /dev/null
+++ b/docs/cli.md
@@ -0,0 +1,54 @@
+## Command line clients
+
+The _apache-sshd.zip_ distribution provides `Windows/Linux` scripts that use the MINA SSHD code base to implement the common
+_ssh, scp, sftp_ commands. The clients accept most useful switches from the original commands they mimic, where the `-o Option=Value`
+arguments can be used to configure the client/server in addition to the system properties mechanism. For more details, consult
+the _main_ methods code in the respective `SshClientMain`, `SftpCommandMain` and `ScpClientMain` classes. The code also includes
+`SshKeyScanMain` that is a simple implementation for [ssh-keyscan(1)](https://www.freebsd.org/cgi/man.cgi?query=ssh-keyscan&sektion=1).
+
+The distribution also includes also an _sshd_ script that can be used to launch a server instance - see `SshServerMain#main`
+for activation command line arguments and options.
+
+In order to use this CLI code as part of another project, one needs to include the _sshd-cli_ module:
+
+```xml
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-cli</artifactId>
+        <version>...same version as the core...</version>
+    </dependency>
+```
+
+### Command line clients
+
+* **SftpCommandMain** - by default uses an internal `SftpClientFactory`. This can be overridden as follows:
+
+1. Provide a `-o SftpClientFactory=XXX` command line argument where the option specifies the fully-qualified name of
+the class that implements this interface.
+
+2. Add a `META-INF\services\org.apache.sshd.client.subsystem.sftp.SftpClientFactory` file containing the fully-qualified name of
+the class that implements this interface. **Note:** if more than one such instance is detected an exception is thrown.
+
+**Note:** The specified class(es) must be public and contain a public no-args constructor.
+
+### Command line SSH daemon
+
+* **Port** - by default the SSH server sets up to list on port 8000 in order to avoid conflicts with any running SSH O/S daemon.
+This can be modified by providing a `-p NNNN` or `-o Port=NNNN` command line option.
+
+* **Subsystem(s)** - the server automatically detects subsystems using the
+[Java ServiceLoader mechanism](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
+
+This can be overwritten as follows (in this order):
+
+1. Provide a `org.apache.sshd.server.subsystem.SubsystemFactory` system property containing comma-separated fully-qualified names of classes implementing
+this interface. The implementations must be public and have a public no-args constructor for instantiating them. The order of the provided subsystems will
+be according to their order in the specified list.
+
+2. Provide a `-o Subsystem=xxx,yyy` command line argument where value is a comma-separated list of the **name**(s) of the auto-detected factories via
+the `ServiceLoader` mechanism. The special value `none` may be used to indicate that no subsystem is to be configured. **Note:** no specific order is
+provided when subsystems are auto-detected and/or filtered.
+
+* **Shell** - unless otherwise instructed, the default SSH server uses an internal shell (see `InteractiveProcessShellFactory`). The shell can be overridden
+or disabled by specifying a `-o ShellFactory=XXX` option where the value can either be `none` to specify that no shell is to be used, or the fully-qualified
+name of a class that implements the `ShellFactory` interface. The implementation must be public and have a public no-args constructor for instantiating it.
diff --git a/docs/client-setup.md b/docs/client-setup.md
new file mode 100644
index 0000000..a640153
--- /dev/null
+++ b/docs/client-setup.md
@@ -0,0 +1,155 @@
+# Set up an SSH client in 5 minutes
+
+
+SSHD is designed to easily allow setting up and using an SSH client in a few simple steps. The client needs to be configured
+and then started before it can be used to connect to an SSH server. There are a few simple steps for creating a client
+instance - for more details refer to the `SshClient` class.
+
+## Creating an instance of the `SshClient` class
+
+This is simply done by calling
+
+```java
+
+    SshClient client = SshClient.setupDefaultClient();
+
+```
+
+The call will create an instance with a default configuration suitable for most use cases - including ciphers,
+compression, MACs, key exchanges, signatures, etc... If your code requires some special configuration, one can
+look at the code for `setupDefaultClient` and `checkConfig` as a reference for available options and configure
+the SSH client the way you need.
+
+## Set up client side security
+
+The SSH client contains some security related configuration that one needs to consider
+
+### `ServerKeyVerifier`
+
+`client.setServerKeyVerifier(...);` sets up the server key verifier. As part of the SSH connection initialization
+protocol, the server proves its "identity" by presenting a public key. The client can examine the key (e.g., present
+it to the user via some UI) and decide whether to trust the server and continue with the connection setup. By default
+the client is initialized with an `AcceptAllServerKeyVerifier` that simply logs a warning that an un-verified server
+key was accepted. There are other out-of-the-box verifiers available in the code:
+
+* `RejectAllServerKeyVerifier` - rejects all server key - usually used in tests or as a fallback verifier if none
+of it predecesors validated the server key
+
+
+* `RequiredServerKeyVerifier` - accepts only **one** specific server key (similar to certificate pinning for SSL)
+
+
+* `KnownHostsServerKeyVerifier` - uses the [known_hosts](https://en.wikibooks.org/wiki/OpenSSH/Client_Configuration_Files#Public_Keys_from_other_Hosts_.E2.80.93_.7E.2F.ssh.2Fknown_hosts)
+file to validate the server key. One can use this class + some existing code to **update** the file when new servers are detected and their keys are accepted.
+
+
+Of course, one can implement the verifier in whatever other manner is suitable for the specific code needs.
+
+### ClientIdentityLoader/KeyPairProvider
+
+One can set up the public/private keys to be used in case a password-less authentication is needed. By default, the client is configured to automatically
+detect and use the identity files residing in the user's *~/.ssh* folder (e.g., *id_rsa*, *id_ecdsa*) and present them as part of the authentication process.
+**Note:** if the identity files are encrypted via a password, one must configure a `FilePasswordProvider` so that the code can decrypt them before using
+and presenting them to the server as part of the authentication process. Reading key files in PEM format (including encrypted ones) is supported by default
+for the standard keys and formats. Using additional non-standard special features requires that the [Bouncy Castle](https://www.bouncycastle.org/) supporting
+artifacts be available in the code's classpath.
+
+#### Providing passwords for encrypted key files
+
+The `FilePasswordProvider` is required for all private key files that are encrypted and being loaded (not just the "identity" ones). If the user
+knows ahead of time that the file being currently decoded is not encrypted, a *null* provider may be used (if the file turns out to be encrypted
+though an exception will be thrown in this case).
+
+The `FilePasswordProvider`has support for a **retry mechanism** via its `handleDecodeAttemptResult`. When the code detects an encrypted private key,
+it will start a loop where it prompts for the password, attempts to decode the key using the provided password and then informs the provider of
+the outcome - success or failure. If failure is signaled, then the provider can decide whether to retry using a new password, abort (with exception)
+or ignore. If the provider chooses to ignore the failure, then the code will make a best effort to proceed without the (undecoded) key.
+
+The invoked methods are provided with a `NamedResource` that provides an indication of the key source "name" that is being attempted. This name
+can be used in order to prompt the user interactively and provide a useful "hint" as to the password that needs to be provided. Furthermore, the
+vast majority of the provided `NamedResource`-s also implement `IoResource` - which means that the code can find out what type of resource
+is being attempted - e.g., a file [Path](https://docs.oracle.com/javase/8/docs/api/index.html?java/nio/file/Path.html),
+a [URL](https://docs.oracle.com/javase/8/docs/api/java/net/URL.html), a [URI](https://docs.oracle.com/javase/8/docs/api/java/net/URI.html),
+etc. - and modify it's behavior accordingly.
+
+#### OpenSSH file format support
+
+The code supports [OpenSSH](http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?rev=1.1&content-type=text/x-cvsweb-markup)
+formatted files without any specific extra artifacts (although for reading _ed25519_ keys one needs to add the _EdDSA_ support artifacts). For
+**encrypted** files only the the `bcrypt` key derivation function (KDF) is [currently supported](https://issues.apache.org/jira/browse/SSHD-708).
+In this context, the maximum allowed number of rounds has been set to ~255 in order to protect the decryption process from
+malformed or malicious data. However, since the protocol allows for 2^31 values, it is possible to modify the default by
+calling `BCryptKdfOptions#setMaxAllowedRounds()` **programmatically** at any time - please note that
+
+* The setting is **global** - i.e., affects all decryption attempts from then on and not just for the current SSH session or thread.
+
+* The setting value is never allowed to be non-positive - any attempt to set such a value programmatically
+throws an exception.
+
+The usual _OpenSSH_ default seems to be 16, but users can ask for more (or less) by generating an encrypted key via
+[`ssh-keygen -a NNN`](http://man7.org/linux/man-pages/man1/ssh-keygen.1.html). However, this comes at a cost:
+
+>> -a rounds
+>>
+>>    When saving a private key this option specifies the number of
+>>    KDF (key derivation function) rounds used.  Higher numbers
+>>    result in slower passphrase verification
+
+Various discussions on the net seem to indicate that 64 is the value at which many computers start to slow down noticeably, so
+our default limit seems quite suitable (and beyond) for most cases we are likely to encounter "in the wild".
+
+### UserInteraction
+
+This interface is required for full support of `keyboard-interactive` authentication protocol as described in [RFC 4256](https://www.ietf.org/rfc/rfc4256.txt).
+The client can handle a simple password request from the server, but if more complex challenge-response interaction is required, then this interface must be
+provided - including support for `SSH_MSG_USERAUTH_PASSWD_CHANGEREQ` as described in [RFC 4252 section 8](https://www.ietf.org/rfc/rfc4252.txt).
+
+While RFC-4256 support is the primary purpose of this interface, it can also be used to retrieve the server's welcome banner as described
+in [RFC 4252 section 5.4](https://www.ietf.org/rfc/rfc4252.txt) as well as its initial identification string as described
+in [RFC 4253 section 4.2](https://tools.ietf.org/html/rfc4253#section-4.2).
+
+## Using the `SshClient` to connect to a server
+
+Once the `SshClient` instance is properly configured it needs to be `start()`-ed in order to connect to a server.
+**Note:** one can use a single `SshClient` instance to connnect to multiple servers as well as modifying the default
+configuration (ciphers, MACs, keys, etc.) on a per-session manner (see more in the *Advanced usage* section).
+Furthermore, one can change almost any configured `SshClient` parameter - although its influence on currently established
+sessions depends on the actual changed configuration. Here is how a typical usage would look like
+
+```java
+
+    SshClient client = SshClient.setupDefaultClient();
+    // override any default configuration...
+    client.setSomeConfiguration(...);
+    client.setOtherConfiguration(...);
+    client.start();
+
+        // using the client for multiple sessions...
+        try (ClientSession session = client.connect(user, host, port)
+                    .verify(...timeout...)
+                    .getSession()) {
+            session.addPasswordIdentity(...password..); // for password-based authentication
+            // or
+            session.addPublicKeyIdentity(...key-pair...); // for password-less authentication
+            // Note: can add BOTH password AND public key identities - depends on the client/server security setup
+
+            session.auth().verify(...timeout...);
+            // start using the session to run commands, do SCP/SFTP, create local/remote port forwarding, etc...
+        }
+
+        // NOTE: this is just an example - one can open multiple concurrent sessions using the same client.
+        //      No need to close the previous session before establishing a new one
+        try (ClientSession anotherSession = client.connect(otherUser, otherHost, port)
+                    .verify(...timeout...)
+                    .getSession()) {
+            anotherSession.addPasswordIdentity(...password..); // for password-based authentication
+            anotherSession.addPublicKeyIdentity(...key-pair...); // for password-less authentication
+            anotherSession.auth().verify(...timeout...);
+            // start using the session to run commands, do SCP/SFTP, create local/remote port forwarding, etc...
+        }
+
+    // exiting in an orderly fashion once the code no longer needs to establish SSH session
+    // NOTE: this can/should be done when the application exits.
+    client.stop();
+
+```
diff --git a/docs/commands.md b/docs/commands.md
new file mode 100644
index 0000000..f981aa6
--- /dev/null
+++ b/docs/commands.md
@@ -0,0 +1,174 @@
+# Commands infrastucture
+
+## `FileSystemFactory` usage
+
+This interface is used to provide "file"-related services/commands - e.g., SCP and SFTP - although it can be used for remote command execution
+as well (see the section about commands and the `Aware` interfaces). The default implementation is a `NativeFileSystemFactory`
+that simply exposes the [FileSystems.getDefault()](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystems.html#getDefault)
+result. However, for "sandboxed" implementations one can use the `VirtualFileSystemFactory`. This implementation provides a way for
+deciding what is the logged-in user's file system view and then use a `RootedFileSystemProvider` in order to provide a "sandboxed"
+file system where the logged-in user can access only the files under the specified root and no others.
+
+```java
+
+    SshServer sshd = SshServer.setupDefaultServer();
+    sshd.setFileSystemFactory(new VirtualFileSystemFactory() {
+        @Override
+        protected Path computeRootDir(Session session) throws IOException  {
+            String username = session.getUsername(); // or any other session related parameter
+            Path path = resolveUserHome(username);
+            return path;
+        }
+    });
+
+```
+
+The usage of a `FileSystemFactory` is not limited though to the server only - the `ScpClient` implementation also uses
+it in order to retrieve the *local* path for upload/download-ing files/folders. This means that the client side can also
+be tailored to present different views for different clients
+
+## `ExecutorService`-s
+
+The framework requires from time to time spawning some threads in order to function correctly - e.g., commands, SFTP subsystem,
+port forwarding (among others) require such support. By default, the framework will allocate an [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
+for each specific purpose and then shut it down when the module has completed its work - e.g., session was closed. Note that
+SSHD uses the `CloseableExecutorService` interface instead of the usual `ExecutorService` in order to provide graceful shutdown.
+Users may provide their own `CloseableExecutorService`(s) instead of the internally auto-allocated ones - e.g., in order to
+control the max. spawned threads, stack size, track threads, etc... but they can leverage the `SshThreadPoolExecutor` implementation
+which should cover most use cases.
+
+Users who want to provide their own `ExecutorService` and not use `SshThreadPoolExecutor` should wrap it as a `NoCloseExecutor`
+and take care of shutting it down when SSHD is done with (provided, of course, that the user's own code does not need it to
+remain active afterwards...).
+
+```java
+
+    /*
+     * An example user-provided executor service for SFTP - there are other such locations.
+     * By default, the SftpSubsystem implementation creates a single-threaded executor
+     * for each session, uses it to spawn the SFTP command handler and shuts
+     * it down when the command is destroyed
+     */
+    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
+        .withExecutorService(new NoCloseExecutor(mySuperDuperExecutorService))
+        .build();
+    SshServer sshd = SshServer.setupDefaultServer();
+    sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(factory));
+
+```
+
+If a single `CloseableExecutorService` is shared between several services, it needs to be wrapped with the
+`ThreadUtils.noClose(executor)` method.
+
+```java
+    CloseableExecutorService sharedService = ...obtain/create an instance...;
+
+    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
+        .withExecutorService(ThreadUtils.noClose(sharedService))
+        .build();
+
+   ChannelAgentForwarding forward = new ChannelAgentForwarding(ThreadUtils.noClose(sharedService));
+```
+
+**Note:** Do not share the instance returned by `ThreadUtils.noClose` between services as it interferes with
+the graceful closing mechanism. Use a new wrapper instance for each service.
+
+## Remote command execution
+
+All command execution - be it shell or single command - boils down to a `Command` instance being created, initialized and then
+started. In this context, it is **crucial** to notice that the command's `start()` method implementation **must spawn a new thread** - even
+for the simplest or most trivial command. Any attempt to communicate via the established session will most likely **fail** since
+the packets processing thread may be blocked by this call. **Note:** one might get away with executing some command in the
+context of the thread that called the `start()` method, but it is **extremely dangerous** and should not be attempted.
+
+The command execution code can communicate with the peer client via the input/output/error streams that are provided as
+part of the command initialization process. Once the command is done, it should call the `ExitCallback#onExit` method to indicate
+that it has finished. The framework will then take care of propagating the exit code, closing the session and (eventually) `destroy()`-ing
+the command. **Note**: the command may not assume that it is done until its `destroy()` method is called - i.e., it should not
+release or null-ify any of its internal state even if `onExit()` was called.
+
+Upon calling the `onExit` method the code sends an [SSH_MSG_CHANNEL_EOF](https://tools.ietf.org/html/rfc4254#section-5.3) message,
+and the provided result status code is sent as an `exit-status` message as described in [RFC4254 - section 6.10](https://tools.ietf.org/html/rfc4254#section-6.10).
+The provided message is simply logged at DEBUG level.
+
+```java
+
+    // A simple command implementation example
+    class MyCommand implements Command, Runnable {
+        private InputStream in;
+        private OutputStream out, err;
+        private ExitCallback callback;
+
+        public MyCommand() {
+            super();
+        }
+
+        @Override
+        public void setInputStream(InputStream in) {
+            this.in = in;
+        }
+
+        @Override
+        public void setOutputStream(OutputStream out) {
+            this.out = out;
+        }
+
+        @Override
+        public void setErrorStream(OutputStream err) {
+            this.err = err;
+        }
+
+        @Override
+        public void setExitCallback(ExitCallback callback) {
+            this.callback = callback;
+        }
+
+        @Override
+        public void start(Environment env) throws IOException {
+            spawnHandlerThread(this);
+        }
+
+        @Override
+        public void run() {
+            while(true) {
+                try {
+                    String cmd = readCommand(in);
+                    if ("exit".equals(cmd)) {
+                        break;
+                    }
+
+                    handleCommand(cmd, out);
+                } catch (Exception e) {
+                    writeError(err, e);
+                    callback.onExit(-1, e.getMessage());
+                    return;
+            }
+
+            callback.onExit(0);
+        }
+    }
+```
+
+### `Aware` interfaces
+
+Once created, the `Command` instance is checked to see if it implements one of the `Aware` interfaces that enables
+injecting some dynamic data before the command is `start()`-ed.
+
+* `SessionAware` - Injects the `Session` instance through which the command request was received.
+
+* `ChannelSessionAware` - Injects the `ChannelSession` instance through which the command request was received.
+
+* `FileSystemAware` - Injects the result of consulting the `FileSystemFactory` as to the [FileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html)
+associated with this command.
+
+
+### Data stream(s) sizing consideration
+
+Some commands may send/receive large amounts of data over their STDIN/STDOUT/STDERR streams. Since (by default) the sending mechanism in SSHD is
+**asynchronous** it may cause _Out of memory_ errors due to one side (client/server) generating `SSH_MSG_CHANNEL_DATA` or `SSH_MSG_CHANNEL_EXTENDED_DATA`
+at a much higher rate than the other side can consume. This leads to a build-up of a packets backlog that eventually consumes all available memory
+(as described in [SSHD-754](https://issues.apache.org/jira/browse/SSHD-754) and [SSHD-768](https://issues.apache.org/jira/browse/SSHD-768)). As of
+version 1.7 one can register a `ChannelStreamPacketWriterResolver` at the client/server/session/channel level that can enable the user to replace
+the raw channel with some throttling mechanism that will be used for stream packets. Such an (experimental) example is the `ThrottlingPacketWriter`
+available in the `sshd-contrib` module. **Note:** if the `ChannelStreamPacketWriterResolver` returns a wrapper instance instead of a `Channel` then
+it will be **closed** automatically when the stream using it is closed.
diff --git a/docs/dependencies.md b/docs/dependencies.md
new file mode 100644
index 0000000..618f943
--- /dev/null
+++ b/docs/dependencies.md
@@ -0,0 +1,112 @@
+# Optional dependencies
+
+## [Bouncy Castle](https://www.bouncycastle.org/)
+
+
+Required mainly for writing keys to PEM files or for special keys/ciphers/etc. that are not part of the standard
+[Java Cryptography Extension](https://en.wikipedia.org/wiki/Java_Cryptography_Extension). See
+[Java Cryptography Architecture (JCA) Reference Guide](https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html)
+for key classes and explanations as to how _Bouncy Castle_ is plugged in (other security providers).
+
+**Caveat**: If _Bouncy Castle_ modules are registered, then the code will use its implementation of the ciphers,
+keys, signatures, etc. rather than the default JCE provided in the JVM.
+
+ **Note:**
+
+ - The security provider can also be registered for keys/ciphers/etc. that are already supported by the standard JCE as a **replacement** for them.
+
+
+ - The _BouncyCastle_ code can also be used to load keys from PEM files instead or in parallel with the built-in code that
+already parses the standard PEM formats for the default JCE supported key types.
+
+
+- One can use the `BouncyCastleKeyPairResourceParser` to load standard PEM files instead of the core one - either directly
+or via `SecurityUtils#setKeyPairResourceParser` for **global** usage - even without registering or enabling the provider.
+
+
+ - The required _Maven_ module(s) are defined as `optional` so must be added as an **explicit** dependency in order to be included in the classpath:
+
+
+```xml
+
+    <dependency>
+        <groupId>org.bouncycastle</groupId>
+        <artifactId>bcpg-jdk15on</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>org.bouncycastle</groupId>
+        <artifactId>bcpkix-jdk15on</artifactId>
+    </dependency>
+
+```
+
+## NIO2 default socket factory replacements
+
+Optional dependency to enable choosing between NIO asynchronous sockets (the default - for improved performance), and "legacy" sockets.
+**Note:** the required Maven module(s) are defined as `optional` so must be added as an **explicit** dependency in order to be included
+in the classpath.
+
+### [MINA core](https://mina.apache.org/mina-project/)
+
+```xml
+
+    <dependency>
+        <groupId>org.apache.mina</groupId>
+        <artifactId>mina-core</artifactId>
+            <!-- see SSHD POM for latest tested known version of MINA core -->
+        <version>2.0.17</version>
+    </dependency>
+
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-mina</artifactId>
+        <version>...same as sshd-core...</version>
+    </dependency>
+
+```
+
+### [Netty](https://netty.io/)
+
+Another a NIO client server framework option that can be used as a replacement for the default NIO asynchronous sockets core
+implementation. This is also an **optional** dependency and must be add explicitly via the `sshd-netty` artifact.
+
+```xml
+
+    <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-transport</artifactId>
+        <version>...Netty version...</version>
+    </dependency>
+    <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-handler</artifactId>
+        <version>...Netty version...</version>
+    </dependency>
+
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-netty</artifactId>
+        <version>...same as sshd-core...</version>
+    </dependency>
+
+```
+
+## [ed25519-java](https://github.com/str4d/ed25519-java)
+
+Required for supporting [ssh-ed25519](https://tools.ietf.org/html/draft-bjh21-ssh-ed25519-02) keys
+and [ed25519-sha-512](https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02) signatures. **Note:**
+the required Maven module(s) are defined as `optional` so must be added as an **explicit** dependency in
+order to be included in the classpath:
+
+
+```xml
+
+        <!-- For ed25519 support -->
+    <dependency>
+        <groupId>net.i2p.crypto</groupId>
+        <artifactId>eddsa</artifactId>
+    </dependency>
+
+```
+
+The code contains support for reading _ed25519_ [OpenSSH formatted private keys](https://issues.apache.org/jira/browse/SSHD-703).
diff --git a/docs/event-listeners.md b/docs/event-listeners.md
new file mode 100644
index 0000000..5436763
--- /dev/null
+++ b/docs/event-listeners.md
@@ -0,0 +1,247 @@
+## Event listeners
+
+The code supports registering many types of event listeners that enable receiving notifications about important events
+as well as sometimes intervening in the way these events are handled. All listener interfaces extend `SshdEventListener`
+so they can be easily detected and distinguished from other `EventListener`(s).
+
+In general, event listeners are **cumulative** - e.g., any channel event listeners registered on the `SshClient/Server` are
+automatically added to all sessions, *in addition* to any such listeners registered on the `Session`, as well as any specific
+listeners registered on a specific `Channel` - e.g.,
+
+
+```java
+
+    // Any channel event will be signalled to ALL the registered listeners
+    sshClient/Server.addChannelListener(new Listener1());
+    sshClient/Server.addSessionListener(new SessionListener() {
+        @Override
+        public void sessionCreated(Session session) {
+            session.addChannelListener(new Listener2());
+            session.addChannelListener(new ChannelListener() {
+                @Override
+                public void channelInitialized(Channel channel) {
+                    channel.addChannelListener(new Listener3());
+                }
+            });
+        }
+    });
+
+```
+
+### `IoServiceEventListener`
+
+This listener provides low-level events regarding connection establishment (by the client) or acceptance (by the server). The listener is registered
+on the `IoServiceFactory` via the `FactoryManager`-s (i.e., `SshClient/Server#setIoServiceEventListener`). Unlike other listeners defined in this
+section, it is **not cumulative** - i.e., one can `setIoServiceEventListener` but not `addIoServiceEventListener` - thus **replacing** any previously
+registered listener.
+
+### `SessionListener`
+
+Informs about session related events. One can modify the session - although the modification effect depends on the session's **state**. E.g., if one
+changes the ciphers *after* the key exchange (KEX) phase, then they will take effect only if the keys are re-negotiated. It is important to read the
+documentation very carefully and understand at which stage each listener method is invoked and what are the repercussions of changes at that stage.
+In this context, it is worth mentioning that one can attach to sessions **arbitrary attributes** that can be retrieved by the user's code later on:
+
+
+```java
+
+    public static final AttributeKey<String> STR_KEY = new AttributeKey<>();
+    public static final AttributeKey<Long> LONG_KEY = new AttributeKey<>();
+
+    sshClient/Server.addSessionListener(new SessionListener() {
+        @Override
+        public void sessionCreated(Session session) {
+            session.setAttribute(STR_KEY, "Some string value");
+            session.setAttribute(LONG_KEY, 3777347L);
+            // ...etc...
+        }
+
+        @Override
+        public void sessionClosed(Session session) {
+            String str = session.getAttribute(STR_KEY);
+            Long l = session.getAttribute(LONG_KEY);
+            // ... do something with the retrieved attributes ...
+        }
+    });
+```
+
+### `ChannelListener`
+
+
+Informs about channel related events - as with sessions, once can influence the channel to some extent, depending on the channel's **state**.
+The ability to influence channels is much more limited than sessions. In this context, it is worth mentioning that one can attach to channels
+**arbitrary attributes** that can be retrieved by the user's code later on - same was as it is done for sessions.
+
+
+### `UnknownChannelReferenceHandler`
+
+
+Invoked whenever a message intended for an unknown channel is received. By default, the code **ignores** the vast majority of such messages
+and logs them at DEBUG level. For a select few types of messages the code generates an `SSH_CHANNEL_MSG_FAILURE` packet that is sent to the
+peer session - see `DefaultUnknownChannelReferenceHandler` implementation. The user may register handlers at any level - client/server, session
+and/or connection service - the one registered "closest" to connection service will be used.
+
+### `ReservedSessionMessagesHandler`
+
+Can be used to handle the following cases:
+
+* [SSH_MSG_IGNORE](https://tools.ietf.org/html/rfc4253#section-11.2)
+* [SSH_MSG_DEBUG](https://tools.ietf.org/html/rfc4253#section-11.3)
+* [SSH_MSG_UNIMPLEMENTED](https://tools.ietf.org/html/rfc4253#section-11.4)
+* Any other unrecognized message received in the session.
+
+**Note:** The `handleUnimplementedMessage` method serves both for handling `SSH_MSG_UNIMPLEMENTED` and any other unrecognized
+message received in the session as well.
+
+
+```java
+
+    class MyClientSideReservedSessionMessagesHandler implements ReservedSessionMessagesHandler {
+        @Override
+        public boolean handleUnimplementedMessage(Session session, int cmd, Buffer buffer) throws Exception {
+            switch(cmd) {
+                case MY_SPECIAL_CMD1:
+                    ....
+                    return true;
+                case MY_SPECIAL_CMD2:
+                    ....
+                    return true;
+                default:
+                    return false;    // send SSH_MSG_UNIMPLEMENTED reply if necessary
+            }
+        }
+    }
+
+    // client side
+    SshClient client = SshClient.setupDefaultClient();
+    // This is the default for ALL sessions unless specifically overridden
+    client.setReservedSessionMessagesHandler(new MyClientSideReservedSessionMessagesHandler());
+    // Adding it via a session listener
+    client.setSessionListener(new SessionListener() {
+            @Override
+            public void sessionCreated(Session session) {
+                // Overrides the one set at the client level.
+                if (isSomeSessionOfInterest(session)) {
+                    session.setReservedSessionMessagesHandler(new MyClientSessionReservedSessionMessagesHandler(session));
+                }
+            }
+    });
+
+    try (ClientSession session = client.connect(user, host, port).verify(...timeout...).getSession()) {
+        // setting it explicitly
+        session.setReservedSessionMessagesHandler(new MyOtherClientSessionReservedSessionMessagesHandler(session));
+        session.addPasswordIdentity(password);
+        session.auth().verify(...timeout...);
+
+        ...use the session...
+    }
+
+
+    // server side
+    SshServer server = SshServer.setupDefaultServer();
+    // This is the default for ALL sessions unless specifically overridden
+    server.setReservedSessionMessagesHandler(new MyServerSideReservedSessionMessagesHandler());
+    // Adding it via a session listener
+    server.setSessionListener(new SessionListener() {
+            @Override
+            public void sessionCreated(Session session) {
+                // Overrides the one set at the server level.
+                if (isSomeSessionOfInterest(session)) {
+                    session.setReservedSessionMessagesHandler(new MyServerSessionReservedSessionMessagesHandler(session));
+                }
+            }
+    });
+
+```
+
+**NOTE:** Unlike "regular" event listeners, the handler is not cumulative - i.e., setting it overrides the previous instance
+rather than being accumulated. However, one can use the `EventListenerUtils` and create a cumulative listener - see how
+`SessionListener` or `ChannelListener` proxies were implemented.
+
+### `SignalListener`
+
+Informs about signal requests as described in [RFC 4254 - section 6.9](https://tools.ietf.org/html/rfc4254#section-6.9), break requests
+(sent as SIGINT) as described in [RFC 4335](https://tools.ietf.org/html/rfc4335) and "window-change" (sent as SIGWINCH) requests as described
+in [RFC 4254 - section 6.7](https://tools.ietf.org/html/rfc4254#section-6.7)
+
+
+### `SftpEventListener`
+
+Provides information about major SFTP protocol events. The provided `File/DirectoryHandle` to the various callbacks an also be used to
+store user-defined attributes via its `AttributeStore` implementation. The listener is registered at the `SftpSubsystemFactory`:
+
+
+```java
+    public class MySfpEventListener implements SftpEventListener {
+        private static final AttributeKey<SomeType> MY_SPECIAL_KEY = new Attribute<SomeType>();
+
+        ...
+        @Override
+        public void opening(ServerSession session, String remoteHandle, Handle localHandle) throws IOException {
+            localHandle.setAttribute(MY_SPECIAL_KEY, instanceOfSomeType);
+        }
+
+        @Override
+        public void writing(
+                ServerSession session, String remoteHandle, FileHandle localHandle,
+                long offset, byte[] data, int dataOffset, int dataLen)
+                    throws IOException {
+            SomeType myData = localHandle.getAttribute(MY_SPECIAL_KEY);
+            ...do something based on my data...
+        }
+    }
+
+
+    SftpSubsystemFactory factory = new SftpSubsystemFactory();
+    factory.addSftpEventListener(new MySftpEventListener());
+    sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(factory));
+
+```
+
+**Note:** the attached attributed are automatically removed once handle has been closed - regardless of
+whether the close attempt was successful or not. In other words, after `SftpEventListener#closed` has been
+called, all attributes associated with the handle are cleared.
+
+### `PortForwardingEventListener`
+
+Informs and allows tracking of port forwarding events as described in [RFC 4254 - section 7](https://tools.ietf.org/html/rfc4254#section-7)
+as well as the (simple) [SOCKS](https://en.wikipedia.org/wiki/SOCKS) protocol (versions 4, 5). In this context, one can create a
+`PortForwardingTracker` that can be used in a `try-with-resource` block so that the set up forwarding is automatically torn down when
+the tracker is `close()`-d:
+
+
+```java
+
+    try (ClientSession session = client.connect(user, host, port).verify(...timeout...).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth().verify(...timeout...);
+
+        try (PortForwardingTracker tracker = session.createLocal/RemotePortForwardingTracker(...)) {
+            ...do something that requires the tunnel...
+        }
+
+        // Tunnel is torn down when code reaches this point
+    }
+```
+
+### `ScpTransferEventListener`
+
+Inform about SCP related events. `ScpTransferEventListener`(s) can be registered on *both* client and server side:
+
+
+```java
+
+    // Server side
+    ScpCommandFactory factory = new ScpCommandFactory(...with/out delegate..);
+    factory.addEventListener(new MyServerSideScpTransferEventListener());
+    sshd.setCommandFactory(factory);
+
+    // Client side
+    try (ClientSession session = client.connect(user, host, port).verify(...timeout...).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth().verify(...timeout...);
+
+        ScpClient scp = session.createScpClient(new MyClientSideScpTransferEventListener());
+        ...scp.upload/download...
+    }
+```
diff --git a/docs/extensions.md b/docs/extensions.md
new file mode 100644
index 0000000..d2f5eb1
--- /dev/null
+++ b/docs/extensions.md
@@ -0,0 +1,68 @@
+# Extension modules
+
+There are several extension modules available - specifically, the _sshd-contrib_ module contains some of them. **Note:** the
+module contains experimental code that may find its way some time in the future to a standard artifact. It is also subject to
+changes and/or deletion without any prior announcement. Therefore, any code that relies on it should also store a copy of the
+sources in case the classes it used it are modified or deleted.
+
+## LDAP adaptors
+
+The _sshd-ldap_ artifact contains an [LdapPasswordAuthenticator](https://issues.apache.org/jira/browse/SSHD-607) and
+an [LdapPublicKeyAuthenticator](https://issues.apache.org/jira/browse/SSHD-608) that have been written along the same
+lines as the [openssh-ldap-publickey](https://github.com/AndriiGrytsenko/openssh-ldap-publickey) project. The authenticators
+can be easily configured to match most LDAP schemes, or alternatively serve as base classes for code that extends them
+and adds proprietary logic.
+
+## Useful extra components in _sshd-contrib_
+
+* `InteractivePasswordIdentityProvider` - helps implement a `PasswordIdentityProvider` by delegating calls
+to `UserInteraction#getUpdatedPassword`. The way to use it would be as follows:
+
+
+```java
+try (ClientSession session = client.connect(login, host, port).await().getSession()) {
+     session.setUserInteraction(...);     // this can also be set at the client level
+     PasswordIdentityProvider passwordIdentityProvider =
+          InteractivePasswordIdentityProvider.providerOf(session, "My prompt");
+     session.setPasswordIdentityProvider(passwordIdentityProvider);
+     session.auth.verify(...timeout...);
+     ... continue with the authenticated session ...
+}
+```
+
+or
+
+
+```java
+UserInteraction ui = ....;
+try (ClientSession session = client.connect(login, host, port).await().getSession()) {
+    PasswordIdentityProvider passwordIdentityProvider =
+         InteractivePasswordIdentityProvider.providerOf(session, ui, "My prompt");
+    session.setPasswordIdentityProvider(passwordIdentityProvider);
+    session.auth.verify(...timeout...);
+     ... continue with the authenticated session ...
+}
+```
+
+**Note:** `UserInteraction#isInteractionAllowed` is consulted prior to invoking `getUpdatedPassword` - if it
+returns _false_ then password retrieval method is not invoked, and it is assumed that no more passwords are available
+
+
+* `SimpleAccessControlScpEventListener` - Provides a simple access control by making a distinction between
+methods that upload data and ones that download it via SCP. In order to use it, simply extend it and override
+its `isFileUpload/DownloadAllowed` methods
+
+
+* `SimpleAccessControlSftpEventListener` - Provides a simple access control by making a distinction between
+methods that provide SFTP file information - including reading data - and those that modify it
+
+
+* `ProxyProtocolAcceptor` - A working prototype to support the PROXY protocol as described in
+[HAProxy Documentation](http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
+
+
+* `ThrottlingPacketWriter` - An example of a way to overcome big window sizes when sending data - as
+described in [SSHD-754](https://issues.apache.org/jira/browse/SSHD-754) and [SSHD-768](https://issues.apache.org/jira/browse/SSHD-768)
+
+* `AndroidOpenSSLSecurityProviderRegistrar` - A security registrar that uses the [AndroidOpenSSL](https://github.com/guardianproject/openssl-android)
+security provider
diff --git a/docs/files-parsing.md b/docs/files-parsing.md
new file mode 100644
index 0000000..66fba20
--- /dev/null
+++ b/docs/files-parsing.md
@@ -0,0 +1,135 @@
+## Configuration/data files parsing support
+Most of the configuration data files parsing support resides in the _sshd-common_ artfiact:
+
+```xml
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-common</artifactId>
+        <version>...same version as the rest of the artifacts...</version>
+    </dependency>
+```
+
+The code contains support for parsing the [_authorized_keys_](http://man.openbsd.org/sshd.8#AUTHORIZED_KEYS_FILE_FORMAT),
+[_known\_hosts_](http://www.manpagez.com/man/8/sshd/), [_ssh\_config_, _sshd\_config_](https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5),
+and [_~/config_](http://www.gsp.com/cgi-bin/man.cgi?topic=ssh_config) files. The code resides in the _sshd-common_ artifact - specifically
+the `KeyUtils#getPublicKeyEntryDecoder`, `AuthorizedKeyEntry#readAuthorizedKeys`, `KnownHostEntry#readKnownHostEntries`
+and `HostConfigEntry#readHostConfigEntries`.
+
+### PEM/OpenSSH
+
+The common code contains built-in support for parsing PEM and/or _OpenSSH_ formatted key files and using them for authentication purposes.
+As mentioned previously, it can leverage _Bouncycastle_ if available, but can do most of the work without it as well. For _ed25519_ support,
+one must provide the _eddsa_ artifact dependency.
+
+### [PUTTY](https://www.putty.org/)
+
+The code contains built-in support for parsing PUTTY key files (usually _.ppk_) and using them same as SSH ones as key-pair
+providers for autentication purposes. The PUTTY key file(s) readers are contained in the `org.apache.sshd.common.config.keys.loader.putty`
+package (specifically `PuttyKeyUtils#DEFAULT_INSTANCE KeyPairResourceParser`) of the _sshd-putty_ artifact. **Note:** the artifact should
+be included as an extra dependency:
+
+```xml
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-putty</artifactId>
+        <version>...same version as the rest of the artifacts...</version>
+    </dependency>
+```
+
+### [OpenPGP](https://www.openpgp.org/)
+
+The code contains the _sshd-openpgp_ module that enables using _OpenPGP_ private key files as identity providers.
+
+```xml
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-openpgp</artifactId>
+        <version>...same version as the rest of the artifacts...</version>
+    </dependency>
+```
+
+The [support](https://issues.apache.org/jira/browse/SSHD-757) for it is currently still in its infancy, and therefore
+this feature should be considered **experimental** for the time being. However, within its limitations it supports
+
+* RSA keys
+* DSA keys
+* ECDSA keys
+
+(*) For now `ed25519` keys are not supported by this module.
+
+The code reads **all** the available key pairs in the key file without any distinction between encryption, decryption,
+authentication or signature ones.
+
+This code relies on the [jpgpgj](https://github.com/justinludwig/jpgpj) support module
+
+```xml
+    <dependency>
+        <groupId>org.c02e.jpgpj</groupId>
+        <artifactId>jpgpj</artifactId>
+        <version>0.5</version>
+    </dependency>
+```
+
+(which in turn automatically uses _Bouncycastle_ - so if one does not want _Bouncycastle_ one cannot use this module).
+
+#### Using OpenPGP authorized keys entries
+
+In order to be able to read `authorized_keys` files that may contain _OpenPGP_ keys references, one needs to register
+the relevant `PublicKeyEntryDataResolver`-s. This is done by calling `PGPPublicKeyEntryDataResolver#registerDefaultKeyEntryDataResolvers`
+once during the _main_ code setup. This will enable the code to safely read authorized keys entries having the format
+specified in the [OpenSSH PGP configuration](https://www.red-bean.com/~nemo/openssh-gpg/):
+
+```
+    pgp-sign-dss 87C36E60187451050A4F26B134824FC95C781A18 with-comment
+    pgp-sign-rsa 87C36E60187451050A4F26B134824FC95C781A18
+```
+
+Where the key data following the key type specification is the fingerprint value of the referenced key. In order to
+use a "mixed mode" file (i.e., one that has both SSH and _OpenPGP_ keys) one needs to replace the default `AuthorizedKeysAuthenticator`
+instance with one that is derived from it and overrides the `createDelegateAuthenticator` method in a manner similar
+as shown below:
+
+```java
+// Using PGPAuthorizedEntriesTracker
+public class MyAuthorizedKeysAuthenticatorWithBothPGPAndSsh extends AuthorizedKeysAuthenticator {
+    ... constructor(s) ...
+
+    @Override
+    protected PublickeyAuthenticator createDelegateAuthenticator(
+            String username, ServerSession session, Path path,
+            Collection<AuthorizedKeyEntry> entries, PublicKeyEntryResolver fallbackResolver)
+                throws IOException, GeneralSecurityException {
+        PGPAuthorizedEntriesTracker tracker = ... obtain an instance ...
+        // Note: need to catch the PGPException and transform it into either an IOException or a GeneralSecurityException
+        Collection<PublicKey> keys = tracker.resolveAuthorizedEntries(session, entries, fallbackResolver);
+        if (GenericUtils.isEmpty(keys)) {
+            return RejectAllPublickeyAuthenticator.INSTANCE;
+        } else {
+            return new KeySetPublickeyAuthenticator(id, keys);
+        }
+    }
+}
+
+// Using PGPPublicRingWatcher
+public class MyAuthorizedKeysAuthenticatorWithBothPGPAndSsh extends AuthorizedKeysAuthenticator {
+    ... constructor(s) ...
+
+    @Override
+    protected PublickeyAuthenticator createDelegateAuthenticator(
+            String username, ServerSession session, Path path,
+            Collection<AuthorizedKeyEntry> entries, PublicKeyEntryResolver fallbackResolver)
+                throws IOException, GeneralSecurityException {
+        PGPPublicRingWatcher watcher = ... obtain an instance ...
+        // Note: need to catch the PGPException and transform it into either an IOException or a GeneralSecurityException
+        Collection<PublicKey> keys = watcher.resolveAuthorizedEntries(session, entries, fallbackResolver);
+        if (GenericUtils.isEmpty(keys)) {
+            return RejectAllPublickeyAuthenticator.INSTANCE;
+        } else {
+            return new KeySetPublickeyAuthenticator(id, keys);
+        }
+    }
+}
+
+```
+
+**Note:** seems that currently, this capability is limited to v1.x key rings (see [jpgpj - issue 21](https://github.com/justinludwig/jpgpj/issues/21))
diff --git a/docs/git.md b/docs/git.md
new file mode 100644
index 0000000..8c9b9ef
--- /dev/null
+++ b/docs/git.md
@@ -0,0 +1,84 @@
+## GIT support
+
+The _sshd-git_ artifact contains both client and server-side command factories for issuing and handling some _git_ commands. The code is based
+on [JGit](https://github.com/eclipse/jgit) and iteracts with it smoothly.
+
+### Client-side
+
+This module provides SSHD-based replacements for the SSH and SFTP transports used by the JGIT client - see `GitSshdSessionFactory` - it
+can be used as a drop-in replacement for the [JSCH](http://www.jcraft.com/jsch/) based built-in session factory provided by _jgit_. In
+this context, it is worth noting that the `GitSshdSessionFactory` has been tailored so as to provide flexible control over which `SshClient`
+instance to use, and even which `ClientSession`. The default instance allocates a **new** client every time a new `GitSshdSession` is
+created - which is started and stopped as necessary. However, this can be pretty wasteful, so if one intends to issue several commands
+that access GIT repositories via SSH, one should maintain a **single** client instance and re-use it:
+
+
+```java
+
+    SshClient client = ...create and setup the client...
+    try {
+        client.start();
+
+        GitSshdSessionFactory sshdFactory = new GitSshdSessionFactory(client);  // re-use the same client for all SSH sessions
+        org.eclipse.jgit.transport.SshSessionFactory.setInstance(sshdFactory);  // replace the JSCH-based factory
+
+        ... issue GIT commands that access remote repositories via SSH ....
+
+    } finally {
+        client.stop();
+    }
+
+```
+
+### Server-side
+
+See `GitPackCommandFactory` and `GitPgmCommandFactory` - in order for the various commands to function correctly, they require a `GitLocationResolver`
+that is invoked in order to allow the user to decide which is the correct GIT repository root location for a given command. The resolver is provided
+with all the relevant details - including the command and server session through which the command was received:
+
+
+```java
+
+    GitLocationResolver resolver = (cmd, session, fs) -> ...consult some code - perhaps based on the authenticated username...
+    sshd.setCommandFactory(new GitPackCommandFactory().withGitLocationResolver(resolver));
+
+```
+
+ These command factories also accept a delegate to which non-_git_ commands are routed:
+
+
+```java
+
+    sshd.setCommandFactory(new GitPackCommandFactory()
+        .withDelegate(new MyCommandFactory())
+        .withGitLocationResolver(resolver));
+
+    // Here is how it looks if SCP is also requested
+    sshd.setCommandFactory(new GitPackCommandFactory()
+        .withDelegate(new ScpCommandFactory()
+            .withDelegate(new MyCommandFactory()))
+        .withGitLocationResolver(resolver));
+
+    // or
+    sshd.setCommandFactory(new ScpCommandFactory()
+        .withDelegate(new GitPackCommandFactory()
+            .withDelegate(new MyCommandFactory())
+            .withGitLocationResolver(resolver)));
+
+    // or any other combination ...
+
+```
+
+as with all other built-in commands, the factories allow the user to provide an `ExecutorService` in order to control the spawned threads
+for servicing the commands. If none provided, an internal single-threaded "pool" is created ad-hoc and destroyed once the command execution
+is completed (regardless of whether successful or not):
+
+
+```java
+
+    sshd.setCommandFactory(new GitPackCommandFactory(resolver)
+        .withDelegate(new MyCommandFactory())
+        .withExecutorService(myService)
+        .withShutdownOnExit(false));
+
+```
diff --git a/docs/internals.md b/docs/internals.md
new file mode 100644
index 0000000..05423f4
--- /dev/null
+++ b/docs/internals.md
@@ -0,0 +1,284 @@
+# Selecting an `IoServiceFactoryFactory`
+
+As part of the their initialization, both client and server code require the specification of a `IoServiceFactoryFactory`
+that is used to initialize network connections.
+
+```java
+
+    SshServer server = ...create server instance...
+    server.setIoServiceFactoryFactory(new MyIoServiceFactoryFactory());
+
+    SshClient client = ... create client instance ...
+    client.setIoServiceFactoryFactory(new MyIoServiceFactoryFactory());
+
+```
+
+If not set explicitly during the client/server setup code, then a factory is automatically detected and selected when the
+client/server is `#start()`-ed. The used `IoServiceFactoryFactory` is a **singleton** that is lazy created the 1st time
+`DefaultIoServiceFactoryFactory#create` is invoked. The selection process is as follows:
+
+* The `org.apache.sshd.common.io.IoServiceFactoryFactory` system property is examined for a factory specification. The
+specification can be either a **fully-qualified** class name or one of the `BuiltinIoServiceFactoryFactories` values.
+
+* If no specific factory is specified, then the [ServiceLoader#load](https://docs.oracle.com/javase/tutorial/ext/basics/spi.html#register-service-providers)
+mechanism is used to detect and instantiate any registered services in any `META-INF\services\org.apache.sshd.common.io.IoServiceFactoryFactory`
+location in the classpath. If **exactly one** implementation was instantiated, then it is used. If several such implementations are found then
+an exception is thrown.
+
+* Otherwise, the built-in `Nio2ServiceFactoryFactory` is used.
+
+**Note:** the default command line scripts for SSH/SCP/SFTP client/server are set up to use NIO2 as their default provider,
+unless overridden via the `-io` command line option. The `org.apache.sshd.common.io.IoServiceFactoryFactory` system property does
+not apply for the command line wrappers since they look only for the `-io` option and use it to initialize the client/server **explicitly**
+before starting the client/server. Therefore, the default selection process described in this section does not apply for them.
+
+# Advanced configuration and interaction
+
+## Properties and inheritance model
+The code's behavior is highly customizable not only via non-default implementations of interfaces but also as far as
+the **parameters** that govern its behavior - e.g., timeouts, min./max. values, allocated memory size, etc... All the
+customization related code flow implements a **hierarchical** `PropertyResolver` inheritance model where the "closest"
+entity is consulted first, and then its "owner", and so on until the required value is found. If the entire hierarchy
+yielded no specific result, then some pre-configured default is used. E.g., if a channel requires some parameter in order
+to decide how to behave, then the following configuration hierarchy is consulted:
+
+* The channel-specific configuration
+* The "owning" session configuration
+* The "owning" client/server instance configuration
+* The system properties - **Note:** any configuration value required by the code can be provided via a system property bearing
+the `org.apache.sshd.config` prefix - see `SyspropsMapWrapper` for the implementation details.
+
+
+### Using the inheritance model for fine-grained/targeted configuration
+
+As previously mentioned, this hierarchical lookup model is not limited to "simple" configuration values (strings, integers, etc.), but
+used also for **interfaces/implementations** such as cipher/MAC/compression/authentication/etc. factories - the exception being that
+the system properties are not consulted in such a case. This code behavior provides highly customizable fine-grained/targeted control
+of the code's behavior - e.g., one could impose usage of specific ciphers/authentication methods/etc. or present different public key
+"identities"/welcome banner behavior/etc., based on address, username or whatever other decision parameter is deemed relevant by the
+user's code. This can be done on __both__ sides of the connection - client or server. E.g., the client could present different keys
+based on the server's address/identity string/welcome banner, or the server could accept only specific types of authentication methods
+based on the client's address/username/etc... This can be done in conjunction with the usage of the various `EventListener`-s provided
+by the code (see below).
+
+One of the code locations where this behavior can be leveraged is when the server provides __file-based__ services (SCP, SFTP) in
+order to provide a different/limited view of the available files based on the username - see the section dealing with `FileSystemFactory`-ies.
+
+## Welcome banner configuration
+
+According to [RFC 4252 - section 5.4](https://tools.ietf.org/html/rfc4252#section-5.4) the server may send a welcome
+banner message during the authentication process. Both the message contents and the phase at which it is sent can be
+configured/customized.
+
+### Welcome banner content customization
+
+The welcome banner contents are controlled by the `ServerAuthenticationManager.WELCOME_BANNER` configuration
+key - there are several possible values for this key:
+
+* A simple string - in which case its contents are the welcome banner.
+
+
+* A file [URI](https://docs.oracle.com/javase/8/docs/api/java/net/URI.html) - or a string starting with `"file:/"` followed by the file path - see below.
+
+
+* A [URL](https://docs.oracle.com/javase/8/docs/api/java/net/URL.html) - or a string containing "://" - in which
+case the [URL#openStream()](https://docs.oracle.com/javase/8/docs/api/java/net/URL.html#openStream) method is invoked
+and its contents are read.
+
+
+* A [File](https://docs.oracle.com/javase/8/docs/api/java/io/File.html) or
+a [Path](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html) - in this case, the file's contents are __re-loaded__ every time it is required and sent as the banner contents.
+
+
+* The special value `ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE` which generates a combined "random art" of
+all the server's keys as described in `Perrig A.` and `Song D.`-s article
+[Hash Visualization: a New Technique to improve Real-World Security](http://sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf) - _International Workshop on Cryptographic Techniques and E-Commerce (CrypTEC '99)_
+
+
+* One can also override the `ServerUserAuthService#resolveWelcomeBanner` method and use whatever other content customization one sees fit.
+
+**Note:**
+
+
+1. If any of the sources yields an empty string or is missing (in the case of a resource) then no welcome banner message is sent.
+
+2. If the banner is loaded from a file or URL resource, then one can configure the [Charset](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html) used to convert the file's contents into a string via the `ServerAuthenticationManager.WELCOME_BANNER_CHARSET` configuration key (default=`UTF-8`).
+
+3. In this context, see also the `ServerAuthenticationManager.WELCOME_BANNER_LANGUAGE` configuration key - which
+provides control over the declared language tag, although most clients seem to ignore it.
+
+
+### Welcome banner sending phase
+
+According to [RFC 4252 - section 5.4](https://tools.ietf.org/html/rfc4252#section-5.4):
+
+> The SSH server may send an SSH_MSG_USERAUTH_BANNER message at any time after this authentication protocol starts and before authentication is successful.
+
+
+The code contains a `WelcomeBannerPhase` enumeration that can be used to configure via the `ServerAuthenticationManager.WELCOME_BANNER_PHASE`
+configuration key the authentication phase at which the welcome banner is sent (see also the `ServerAuthenticationManager.DEFAULT_BANNER_PHASE` value).
+In this context, note that if the `NEVER` phase is configured, no banner will be sent even if one has been configured via one of the methods mentioned previously.
+
+
+## `HostConfigEntryResolver`
+
+This interface provides the ability to intervene during the connection and authentication phases and "re-write"
+the user's original parameters. The `DefaultConfigFileHostEntryResolver` instance used to set up the default
+client instance follows the [SSH config file](https://www.digitalocean.com/community/tutorials/how-to-configure-custom-connection-options-for-your-ssh-client)
+standards, but the interface can be replaced so as to implement whatever proprietary logic is required.
+
+
+```java
+
+    SshClient client = SshClient.setupDefaultClient();
+    client.setHostConfigEntryResolver(new MyHostConfigEntryResolver());
+    client.start();
+
+    /*
+     * The resolver might decide to connect to some host2/port2 using user2 and password2
+     * (or maybe using some key instead of the password).
+     */
+    try (ClientSession session = client.connect(user1, host1, port1).verify(...timeout...).getSession()) {
+        session.addPasswordIdentity(...password1...);
+        session.auth().verify(...timeout...);
+    }
+```
+
+
+## `SshConfigFileReader`
+
+Can be used to read various standard SSH [client](http://linux.die.net/man/5/ssh_config)
+or [server](http://manpages.ubuntu.com/manpages/precise/en/man5/sshd_config.5.html) configuration files
+and initialize the client/server respectively. Including (among other things), bind address, ciphers,
+signature, MAC(s), KEX protocols, compression, welcome banner, etc..
+
+### Reserved messages
+
+The implementation can be used to intercept and process the [SSH_MSG_IGNORE](https://tools.ietf.org/html/rfc4253#section-11.2),
+[SSH_MSG_DEBUG](https://tools.ietf.org/html/rfc4253#section-11.3) and [SSH_MSG_UNIMPLEMENTED](https://tools.ietf.org/html/rfc4253#section-11.4)
+messages. The handler can be registered on either side - server or client, as well as on the session. A special
+[patch](https://issues.apache.org/jira/browse/SSHD-699) has been introduced that automatically ignores such messages
+if they are malformed - i.e., they never reach the handler.
+
+#### SSH message stream "stuffing" and keys re-exchange
+
+[RFC 4253 - section 9](https://tools.ietf.org/html/rfc4253#section-9) recommends re-exchanging keys every once in a while
+based on the amount of traffic and the selected cipher - the matter is further clarified in [RFC 4251 - section 9.3.2](https://tools.ietf.org/html/rfc4251#section-9.3.2).
+These recommendations are mirrored in the code via the `FactoryManager` related `REKEY_TIME_LIMIT`, `REKEY_PACKETS_LIMIT`
+and `REKEY_BLOCKS_LIMIT` configuration properties that can be used to configure said behavior - please be sure to read
+the relevant _Javadoc_ as well as the aforementioned RFC section(s) when manipulating them. This behavior can also be
+controlled programmatically by overriding the `AbstractSession#isRekeyRequired()` method.
+
+As an added security mechanism [RFC 4251 - section 9.3.1](https://tools.ietf.org/html/rfc4251#section-9.3.1) recommends adding
+"spurious" [SSH_MSG_IGNORE](https://tools.ietf.org/html/rfc4253#section-11.2) messages. This functionality is mirrored in the
+`FactoryManager` related `IGNORE_MESSAGE_FREQUENCY`, `IGNORE_MESSAGE_VARIANCE` and `IGNORE_MESSAGE_SIZE`
+configuration properties that can be used to configure said behavior - please be sure to read the relevant _Javadoc_ as well
+as the aforementioned RFC section when manipulating them. This behavior can also be controlled programmatically by overriding
+the `AbstractSession#resolveIgnoreBufferDataLength()` method.
+
+### `RequestHandler`(s)
+
+The code supports both [global](https://tools.ietf.org/html/rfc4254#section-4) and [channel-specific](https://tools.ietf.org/html/rfc4254#section-5.4)
+requests via the registration of `RequestHandler`(s). The global handlers are derived from `ConnectionServiceRequestHandler`(s) whereas the channel-specific
+ones are derived from `ChannelRequestHandler`(s). In order to add a handler one need only register the correct implementation and handle the request when
+it is detected. For global request handlers this is done by registering them on the server:
+
+```java
+
+    // NOTE: the following code can be employed on BOTH client and server - the example is for the server
+    SshServer server = SshServer.setUpDefaultServer();
+    List<RequestHandler<ConnectionService>> oldGlobals = server.getGlobalRequestHandlers();
+    // Create a copy in case current one is null/empty/un-modifiable
+    List<RequestHandler<ConnectionService>> newGlobals = new ArrayList<>();
+    if (GenericUtils.size(oldGlobals) > 0) {
+        newGlobals.addAll(oldGLobals);
+    }
+    newGlobals.add(new MyGlobalRequestHandler());
+    server.setGlobalRequestHandlers(newGlobals);
+
+```
+
+For channel-specific requests, one uses the channel's `add/removeRequestHandler` method to manage its handlers. The way
+request handlers are invoked when a global/channel-specific request is received  is as follows:
+
+* All currently registered handlers' `process` method is invoked with the request type string parameter (among others).
+The implementation should examine the request parameters and decide whether it is able to process it.
+
+
+* If the handler returns `Result.Unsupported` then the next registered handler is invoked.
+In other words, processing stops at the **first** handler that returned a valid response. Thus the importance of
+the `List<RequestHandler<...>>` that defines the **order** in which the handlers are invoked. **Note**: while
+it is possible to register multiple handlers for the same request and rely on their order, it is highly recommended
+to avoid this situation as it makes debugging the code and diagnosing problems much more difficult.
+
+
+* If no handler reported a valid result value then a failure message is sent back to the peer. Otherwise, the returned
+result is translated into the appropriate success/failure response (if the sender asked for a response). In this context,
+the handler may choose to build and send the response within its own code, in which case it should return the
+`Result.Replied` value indicating that it has done so.
+
+
+```java
+
+    public class MySpecialChannelRequestHandler implements ChannelRequestHandler {
+        ...
+
+        @Override
+        public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
+            if (!"my-special-request".equals(request)) {
+               return Result.Unsupported;   // Not mine - maybe someone else can handle it
+            }
+
+            ...handle the request - can read more parameters from the message buffer...
+
+            return Result.ReplySuccess/Failure/Replied; // signal processing result
+        }
+    }
+```
+
+#### Default registered handlers
+
+* `exit-signal`, `exit-status` - As described in [RFC4254 section 6.10](https://tools.ietf.org/html/rfc4254#section-6.10)
+
+
+* `*@putty.projects.tartarus.org` - As described in [Appendix F: SSH-2 names specified for PuTTY](http://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixF.html)
+
+
+* `hostkeys-prove-00@openssh.com`, `hostkeys-00@openssh.com` - As described in [OpenSSH protocol - section 2.5](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL)
+
+
+* `tcpip-forward`, `cancel-tcpip-forward` - As described in [RFC4254 section 7](https://tools.ietf.org/html/rfc4254#section-7)
+
+
+* `keepalive@*` - Used by many implementations (including this one) to "ping" the peer and make sure the connection is still alive.
+In this context, the SSHD code allows the user to configure both the frequency and content of the heartbeat request (including whether
+to send this request at all) via the `ClientFactoryManager`-s `HEARTBEAT_INTERVAL`, `HEARTBEAT_REQUEST` and `DEFAULT_KEEP_ALIVE_HEARTBEAT_STRING`
+configuration properties.
+
+
+* `no-more-sessions@*` - As described in [OpenSSH protocol section 2.2](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL).
+In this context, the code consults the `ServerFactoryManagder.MAX_CONCURRENT_SESSIONS` server-side configuration property in order to
+decide whether to accept a successfully authenticated session.
+
+## PROXY / SSLH protocol hooks
+
+The code contains [support for "wrapper" protocols](https://issues.apache.org/jira/browse/SSHD-656) such
+as [PROXY](http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt) or [sslh](http://www.rutschle.net/tech/sslh.shtml).
+The idea is that one can register either a `ClientProxyConnector` or `ServerProxyAcceptor` and intercept
+the 1st packet being sent/received (respectively) **before** it reaches the SSHD code. This gives the programmer
+the capability to write a front-end that routes outgoing/incoming packets:
+
+* `SshClient/ClientSesssion#setClientProxyConnector` - sets a proxy that intercepts the 1st packet before being sent to the server
+
+* `SshServer/ServerSession#setServerProxyAcceptor` - sets a proxy that intercept the 1st incoming packet before being processed by the server
+
+# Builtin components
+
+Below is the list of builtin components:
+
+* **Ciphers**: aes128cbc, aes128ctr, aes192cbc, aes192ctr, aes256cbc, aes256ctr, arcfour128, arcfour256, blowfishcbc, tripledescbc
+* **Digests**: md5, sha1, sha224, sha384, sha512
+* **Macs**: hmacmd5, hmacmd596, hmacsha1, hmacsha196, hmacsha256, hmacsha512
+* **Key exchange**: dhg1, dhg14, dhgex, dhgex256, ecdhp256, ecdhp384, ecdhp521
+* **Compressions**: none, zlib, zlib@openssh.com
+* **Signatures/Keys**: ssh-dss, ssh-rsa, nistp256, nistp384, nistp521, ed25519 (requires `eddsa` optional module)
diff --git a/docs/port-forwarding.md b/docs/port-forwarding.md
new file mode 100644
index 0000000..4291e9d
--- /dev/null
+++ b/docs/port-forwarding.md
@@ -0,0 +1,36 @@
+## Port forwarding
+
+### Standard port forwarding
+
+Port forwarding as specified in [RFC 4254 - section 7](https://tools.ietf.org/html/rfc4254#section-7) is fully
+supported by the client and server. From the client side, this capability is exposed via the `start/stopLocal/RemotePortForwarding`
+method. The key player in this capability is the configured `ForwardingFilter` that controls this feature - on **both** sides - client
+and server. By default, this capability is **disabled** - i.e., the user must provide an implementation and call the appropriate
+`setForwardingFilter` method on the client/server.
+
+The code contains 2 simple implementations - an accept-all and a reject-all one that can be used for these trivial
+policies. **Note:** setting a _null_ filter is equivalent to rejecting all such attempts.
+
+### SOCKS
+
+The code implements a [SOCKS](https://en.wikipedia.org/wiki/SOCKS) proxy for versions 4 and 5. The proxy capability is
+invoked via the `start/stopDynamicPortForwarding` methods.
+
+### Proxy agent
+
+The code provides to some extent an SSH proxy agent via the available `SshAgentFactory` implementations. As of latest version
+both [Secure Shell Authentication Agent Protocol Draft 02](https://tools.ietf.org/html/draft-ietf-secsh-agent-02) and its
+[OpenSSH](https://www.libssh.org/features/) equivalent are supported. **Note:** in order to support this feature the
+[Apache Portable Runtime Library](https://apr.apache.org/) needs to be added to the Maven dependencies:
+
+```xml
+
+    <dependency>
+        <groupId>tomcat</groupId>
+        <artifactId>tomcat-apr</artifactId>
+    </dependency>
+
+```
+
+**Note:** Since the portable runtime library uses **native** code, one needs to also make sure that the appropriate _.dll/.so_ library
+is available in the LD\_LIBRARY\_PATH.
diff --git a/docs/scp.md b/docs/scp.md
new file mode 100644
index 0000000..05ef79e
--- /dev/null
+++ b/docs/scp.md
@@ -0,0 +1,96 @@
+## SCP
+
+Both client-side and server-side SCP are supported. Starting from version 2.0, the SCP related code is located in the `sshd-scp` module, so you need
+to add this additional dependency to your maven project:
+
+```xml
+
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-sscp</artifactId>
+        <version>...same as sshd-core...</version>
+    </dependency>
+
+```
+
+### Client-side SCP
+
+In order to obtain an `ScpClient` one needs to use an `ScpClientCreator`:
+
+```java
+
+ClientSession session = ... obtain an instance ...
+ScpClientCreator creator = ... obtain an instance ...
+ScpClient client = creator.createScpClient(session);
+
+```
+
+A default `ScpClientCreator` instance is provided as part of the module - see `ScpClientCreator.instance()`
+
+#### ScpFileOpener(s)
+
+As part of the `ScpClientCreator`, the SCP module also uses a `ScpFileOpener` instance in order to access
+the local files. The default implementation simply opens an [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html)
+or [OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html) on the requested local path. However,
+the user may replace it and intercept the calls - e.g., for logging, monitoring transfer progess, wrapping/filtering the streams, etc...
+The user may attach a default opener that will be automatically attached to **all** clients created unless specifically overridden:
+
+```java
+
+/**
+ * Example of using a non-default opener for monitoring and reporting on transfer progress
+ */
+public class ScpTransferProgressMonitor extends DefaultScpFileOpener {
+    public static ScpTransferProgressMonitor MONITOR = new ScpTransferProgressMonitor();
+
+    public ScpTransferProgressMonitor() {
+        super();
+    }
+
+    @Override
+    public InputStream openRead(
+            Session session, Path file, long size, Set<PosixFilePermission> permissions, OpenOption... options)
+                throws IOException {
+        return new MyProgressReportingInputStream(super.openRead(session, file, size, permissions, options), size /* how much is expected */);
+    }
+
+    @Override
+    public OutputStream openWrite(
+            Session session, Path file, long size, Set<PosixFilePermission> permissions, OpenOption... options)
+                throws IOException {
+        return new MyProgressReportingOutputStream(super.openWrite(session, file, size, permissions, options), size /* how much is expected */);
+    }
+}
+
+ClientSession session = ... obtain an instance ...
+ScpClientCreator creator = ... obtain an instance ...
+creator.setScpFileOpener(ScpTransferProgressMonitor.INSTANCE);
+
+ScpClient client1 = creator.createScpClient(session);   // <<== automatically uses ScpTransferProgressMonitor
+ScpClient client2 = creator.createScpClient(session, new SomeOtherOpener());   // <<== uses SomeOtherOpener instead of ScpTransferProgressMonitor
+
+```
+
+**Note:** due to SCP protocol limitations one cannot change the **size** of the input/output since it is passed as part of the command
+**before** the file opener is invoked - so there are a few limitations on what one can do within this interface implementation.
+
+#### ScpTransferEventListener(s)
+
+The `ScpClientCreator` can also be used to attach a default `ScpTransferEventListener` that will be attached to
+**all** created SCP client instances through that creator - unless specifically overridden:
+
+```java
+
+ClientSession session = ... obtain an instance ...
+ScpClientCreator creator = ... obtain an instance ...
+creator.setScpTransferEventListener(new MySuperDuperListener());
+
+ScpClient client1 = creator.createScpClient(session);   // <<== automatically uses MySuperDuperListener
+ScpClient client2 = creator.createScpClient(session, new SomeOtherListener());   // <<== uses SomeOtherListener instead of MySuperDuperListener
+
+```
+
+### Server-side SCP
+
+The `ScpCommandFactory` allows users to attach an `ScpFileOpener` and/or `ScpTransferEventListener` having the same behavior as the client - i.e.,
+monitoring and intervention on the accessed local files.
diff --git a/docs/security-providers.md b/docs/security-providers.md
new file mode 100644
index 0000000..bbb3f69
--- /dev/null
+++ b/docs/security-providers.md
@@ -0,0 +1,95 @@
+## Security providers setup
+
+While the code supports _BouncyCastle_ and _EdDSA_ security providers out-of-the-box,
+it also provides a way to [add security providers](https://issues.apache.org/jira/browse/SSHD-713) via the `SecurityProviderRegistrar`
+interface implementation. In order to add support for a new security provider one needs to implement the registrar interface and make
+the code aware of it.
+
+### Default/built-in security provider registrars
+
+The code contains built-in security provider registrars for _BouncyCastle_ and _EdDSA_ (a.k.a. `ed25519`). It automatically detects
+the existence of the required artifacts (since they are optional dependencies) and executes the respective security provider registration.
+This behavior is controlled by the `org.apache.sshd.security.registrars` system property. This property contains a comma-separated list
+of **fully-qualified** class names implementing the `SecurityProviderRegistrar` interface and assumed to contain a default **public**
+no-arguments constructor. The code automatically parses the list and attempts to instantiate and invoke the registrar.
+
+**Note:**
+
+
+- The registration code automatically parses the configured registrars list and instantiates them. In this context, one can use the
+special `none` value to indicate that the code should not attempt to automatically register the default providers.
+
+- A registrar instance might be created but eventually discarded and not invoked if it is disabled, unsupported or already registered
+programmatically via `SecurityUtils#registerSecurityProvider`.
+
+
+- The registration attempt is a **one-shot** deal - i.e., once the registrars list is parsed and successfully resolved, any modifications
+to the registered security providers must be done **programatically**. One can call `SecurityUtils#isRegistrationCompleted()` to find out
+if the registration phase has already been executed.
+
+
+- The registrars are consulted in the same **order** as they were initially registered - either programmatically or via the system property
+configuration. Therefore, if two or more registrars support the same algorithm, then the earlier registered one will be used.
+
+
+- If no matching registrar was found, then the default security provider is used. If none set, the JCE defaults are invoked. The default
+security provider can be configured either via the `org.apache.sshd.security.defaultProvider` system property or by programmatically
+invoking `SecurityUtils#setDefaultProviderChoice`. **Note:** if the system property option is used, then it is assumed to contain a security
+provider's **name** (rather than its `Provider` class name...).
+
+
+- If programmatic selection of the default security provider choice is required, then the code flow must ensure that
+`SecurityUtils#setDefaultProviderChoice` is called before **any** security entity (e.g., ciphers, keys, etc...) are
+required. Theoretically, one could change the choice after ciphers have been been requested but before keys were generated
+(e.g....), but it is dangerous and may yield unpredictable behavior.
+
+
+### Implementing a new security provider registrar
+
+See `AbstractSecurityProviderRegistrar` helper class for a default implementation of most of the required functionality, as
+well as the existing implementations for _BouncyCastle_ and _EdDSA_ for examples of how to implement it. The most important
+issues to consider when adding such an implementation are:
+
+* Try using reflection API to detect the existence of the registered provider class and/or instantiate it. The main reason
+for this recommendation is that it isolates the code from a direct dependency on the provider's classes and makes class loading
+issue less likely.
+
+
+* Decide whether to use the provider's name or instance when creating security related entities such as ciphers, keys, etc...
+**Note:** the default preference is to use the provider name, thus registering via `Security.addProvider` call. In order to
+change that, either register the instance yourself or override the `isNamedProviderUsed` method. In this context, **cache**
+the generated `Provider` instance if the instance rather than the name is used. **Note:** using only the provider instance
+instead of the name is a rather new feature and has not been fully tested. It is possible though to decide and use it anyway
+as long as it can be configurably disabled.
+
+
+* The default implementation provides fine-grained control over the declared supported security entities - ciphers, signatures,
+key generators, etc... By default, it is done via consulting a system property composed of `org.apache.sshd.security.provider`,
+followed by the security provider name and the relevant security entity - e.g., `org.apache.sshd.security.provider.BC.KeyFactory`
+is assumed to contain a comma-separated list of supported `KeyFactory` algorithms.
+
+**Note:**
+
+
+* The same naming convention can be used to enable/disable the registrar - even if supported - e.g.,
+`org.apache.sshd.security.provider.BC.enabled=false` disables the _BouncyCastle_ registrar.
+
+
+* One can use `all` or `*` to specify that all entities of the specified type are supported - e.g.,
+`org.apache.sshd.security.provider.BC.MessageDigest=all`. In this context, one can override the
+`getDefaultSecurityEntitySupportValue` method if no fine-grained configuration is required per-entity type,
+
+
+* The result of an `isXxxSupported` call is/should be **cached** (see `AbstractSecurityProviderRegistrar`).
+
+
+* For ease of implementation, all support query calls are routed to the `isSecurityEntitySupported` method
+so that one can concentrate all the configuration in a single method. This is done for **convenience**
+reasons - the code will invoke the correct support query as per the type of entity it needs. E.g., if it
+needs a cipher, it will invoke `isCipherSupported` - which by default will invoke `isSecurityEntitySupported`
+with the `Cipher` class as its argument.
+
+
+* Specifically for **ciphers** the argument to the support query contains a **transformation** (e.g., `AES/CBC/NoPadding`)
+so one should take that into account when parsing the input argument to decide which cipher is referenced - see
+`SecurityProviderRegistrar.getEffectiveSecurityEntityName(Class<?>, String)` helper method
diff --git a/docs/server-setup.md b/docs/server-setup.md
new file mode 100644
index 0000000..fc25267
--- /dev/null
+++ b/docs/server-setup.md
@@ -0,0 +1,139 @@
+# Embedding an SSHD server instance in 5 minutes
+
+SSHD is designed to be easily embedded in your application as an SSH server. The embedded SSH server needs
+to be configured before it can be started. Essentially, there are a few simple steps for creating the
+server - for more details refer to the `SshServer` class.
+
+## Creating an instance of the `SshServer` class
+
+Creating an instance of `SshServer` is as simple as creating a new object
+
+```java
+
+    SshServer sshd = SshServer.setUpDefaultServer();
+
+```
+
+It will configure the server with sensible defaults for ciphers, macs, key exchange algorithm, etc...
+If different behavior is required, one should consult the code of the `setUpDefaultServer` as well as
+`checkConfig` methods as a reference for available options and configure the SSH server the way it is needed.
+
+## Configuring the server instance
+
+There are a few things that need to be configured on the server before being able to actually use it:
+
+* Port - `sshd.setPort(22);` - sets the listen port for the server instance. If not set explicitly then a
+**random** free port is selected by the O/S. In any case, once the server is `start()`-ed one can query the
+instance as to the assigned port via `sshd.getPort()`.
+
+
+In this context, the listen bind address can also be specified explicitly via `sshd.setHost(...some IP address...)`
+that causes the server to bind to a specific network address rather than **all** addresses (the default). Using
+`"0.0.0.0"` as the bind address is also tantamount to binding to all addresses.
+
+
+* `KeyPairProvider` - `sshd.setKeyPairProvider(...);` - sets the host's private keys used for key exchange with
+clients as well as representing the host's "identities". There are several choices - one can load keys from standard
+PEM files or generate them in the code.  It's usually a good idea to save generated keys, so that if the SSHD server
+is restarted, the same keys will be used to authenticate the server and avoid the warning the clients might get if
+the host keys are modified. **Note**: saving key files in PEM format requires  that the [Bouncy Castle](https://www.bouncycastle.org/)
+supporting artifacts be available in the code's classpath.
+
+
+* `ShellFactory` - That's the part one usually has to write to customize the SSHD server. The shell factory will
+be used to create a new shell each time a user logs in and wants to run an interactive shell. SSHD provides a simple
+implementation that you can use if you want. This implementation will create a process and delegate everything to it,
+so it's mostly useful to launch the OS native shell. E.g.,
+
+
+```java
+
+    sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" }));
+
+```
+
+
+There is an out-of-the-box `InteractiveProcessShellFactory` that detects the O/S and spawns the relevant shell. Note
+that the `ShellFactory` is not required. If none is configured, any request for an interactive shell will be denied to clients.
+
+
+* `CommandFactory` - The `CommandFactory` provides the ability to run a **single** direct command at a time instead
+of an interactive session (it also uses a **different** channel type than shells). It can be used **in addition** to the `ShellFactory`.
+
+
+SSHD provides a `CommandFactory` to support SCP that can be configured in the following way:
+
+
+```java
+
+    sshd.setCommandFactory(new ScpCommandFactory());
+
+```
+
+One can also use the `ScpCommandFactory` on top of one's own `CommandFactory` by placing the command factory as a **delegate**
+of the `ScpCommandFactory`. The `ScpCommandFactory` will intercept SCP commands and execute them by itself, while passing all
+other commands to the delegate `CommandFactory`
+
+
+```java
+
+    sshd.setCommandFactory(new ScpCommandFactory(myCommandFactory));
+
+```
+
+Note that using a `CommandFactory` is also **optional**. If none is configured, any direct command sent by clients will be rejected.
+
+## Server side security setup
+
+The SSHD server security layer has to be customized to suit your needs. This layer is pluggable and uses the following interfaces:
+
+* `PasswordAuthenticator` for password based authentication - [RFC 4252 section 8](https://www.ietf.org/rfc/rfc4252.txt)
+* `PublickeyAuthenticator` for key based authentication - [RFC 4252 section 7](https://www.ietf.org/rfc/rfc4252.txt)
+* `HostBasedAuthenticator` for host based authentication - [RFC 4252 section 9](https://www.ietf.org/rfc/rfc4252.txt)
+* `KeyboardInteractiveAuthenticator` for user interactive authentication - [RFC 4256](https://www.ietf.org/rfc/rfc4256.txt)
+
+
+These custom classes can be configured on the SSHD server using the respective setter methods:
+
+
+```java
+
+    sshd.setPasswordAuthenticator(new MyPasswordAuthenticator());
+    sshd.setPublickeyAuthenticator(new MyPublickeyAuthenticator());
+    sshd.setKeyboardInteractiveAuthenticator(new MyKeyboardInteractiveAuthenticator());
+    ...etc...
+
+```
+
+Several useful implementations are available that can be used as-is or extended in order to provide some custom behavior. In any
+case, the default initializations are:
+
+* `DefaultAuthorizedKeysAuthenticator` - uses the _authorized_keys_ file the same way as the SSH daemon does
+* `DefaultKeyboardInteractiveAuthenticator` - for password-based or interactive authentication. **Note:** this authenticator
+requires a `PasswordAuthenticator` to be configured since it delegates some of the functionality to it.
+
+## Configuring ciphers, macs, digest...
+
+SSH supports pluggable factories to define various configuration parts such as ciphers, digests, key exchange, etc...
+The list of supported implementations can be changed to suit one's needs, or one can also implement one's own factories.
+
+Configuring supported factories can be done with the following code:
+
+```java
+
+    sshd.setCipherFactories(Arrays.asList(BuiltinCiphers.aes256ctr, BuiltinCiphers.aes192ctr, BuiltinCiphers.aes128ctr));
+    sshd.setKeyExchangeFactories(Arrays.asList(new MyKex1(), new MyKex2(), BuiltinKeyExchange.A, ...etc...));
+
+```
+
+One can configure other security components using built-in factories the same way. It is important to remember though
+that the **order** of the factories is important as it affects the key exchange phase where the client and server decide
+what options to use out of each peer's reported preferences.
+
+## Starting the Server
+
+Once we have configured the server, one need only call `sshd.start();`. **Note**: once the server is started, all of the
+configurations (except the port) can still be *overridden* while the server is running (caveat emptor). In such cases,
+only **new** clients that connect to the server after the change will be affected - with the exception of the negotiation
+options (keys, macs, ciphers, etc...) which take effect the next time keys are re-exchanged, that can affect live sessions
+and not only new ones.
diff --git a/docs/sftp.md b/docs/sftp.md
new file mode 100644
index 0000000..6fc2a88
--- /dev/null
+++ b/docs/sftp.md
@@ -0,0 +1,423 @@
+## SFTP
+
+Both client-side and server-side SFTP are supported. Starting from version 2.0, the SFTP related code is located
+in the `sshd-sftp` artifact, so one needs to add this additional dependency to one's maven project:
+
+```xml
+
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-sftp</artifactId>
+        <version>...same as sshd-core...</version>
+    </dependency>
+
+```
+
+### Server-side SFTP
+
+On the server side, the following code needs to be added:
+
+```java
+
+    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
+        .build();
+    server.setSubsystemFactories(Collections.singletonList(factory));
+
+```
+
+### `SftpEventListener`
+
+(See above more details...) - users may register an `SftpEventListener` (or more...) in the `SftpSubsystemFactory` in
+order to monitor and even intervene in the susbsytem's functionality.
+
+### Client-side SFTP
+
+In order to obtain an `SftpClient` instance one needs to use an `SftpClientFactory`:
+
+
+```java
+
+    ClientSession session = ...obtain session...
+    SftpClientFactory factory = ...obtain factory...
+    SftpClient client = factory.createSftpClient(session);
+
+```
+
+A default client factory implementations is provided in the module - see `SftpClientFactory.instance()`
+
+
+### Using a custom `SftpClientFactory`
+
+The code creates `SftpClient`-s and `SftpFileSystem`-s using a default built-in `SftpClientFactory` instance (see
+`DefaultSftpClientFactory`). Users may choose to use a custom factory in order to provide their own
+implementations - e.g., in order to override some default behavior - e.g.:
+
+```java
+
+    SshClient client = ... setup client...
+
+    try (ClientSession session = client.connect(user, host, port).verify(timeout).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth.verify(timeout);
+
+        // User-specific factory
+        try (SftpClient sftp = MySpecialSessionSftpClientFactory.INSTANCE.createSftpClient(session)) {
+            ... instance created through SpecialSessionSftpClientFactory ...
+        }
+    }
+
+```
+
+### Version selection via `SftpVersionSelector`
+
+
+The SFTP subsystem code supports versions 3-6 (inclusive), and by default attempts to negotiate the **highest**
+possible one - on both client and server code. The user can intervene and force a specific version or a narrower
+range.
+
+
+```java
+
+    SftpVersionSelector myVersionSelector = new SftpVersionSelector() {
+        @Override
+        public int selectVersion(ClientSession session, int current, List<Integer> available) {
+            int selectedVersion = ...run some logic to decide...;
+            return selectedVersion;
+        }
+    };
+
+    try (ClientSession session = client.connect(user, host, port).verify(timeout).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth.verify(timeout);
+
+        SftpClientFactory factory = SftpClientFactory.instance();
+        try (SftpClient sftp = factory.createSftpClient(session, myVersionSelector)) {
+            ... do SFTP related stuff...
+        }
+    }
+
+```
+
+On the server side, version selection restriction is more complex - please remember that the **client** chooses
+the version, and all we can do at the server is require a **specific** version via the `SftpSubsystem#SFTP_VERSION`
+configuration key. For more advanced restrictions one needs to sub-class `SftpSubSystem` and provide a non-default
+`SftpSubsystemFactory` that uses the sub-classed code.
+
+### Using `SftpFileSystemProvider` to create an `SftpFileSystem`
+
+
+The code automatically registers the `SftpFileSystemProvider` as the handler for `sftp://` URL(s). Such URLs are
+interpreted as remote file locations and automatically exposed to the user as [Path](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html)
+objects. In effect, this allows the code to "mount" a remote directory via SFTP and treat it as if it were local using
+standard [java.nio](https://docs.oracle.com/javase/8/docs/api/java/nio/package-frame.html) calls like any "ordinary" file
+system.
+
+```java
+
+    // Direct URI
+    Path remotePath = Paths.get(new URI("sftp://user:password@host/some/remote/path"));
+    // Releasing the file-system once no longer necessary
+    try (FileSystem fs = remotePath.getFileSystem()) {
+        ... work with the remote path...
+    }
+
+    // "Mounting" a file system
+    URI uri = SftpFileSystemProvider.createFileSystemURI(host, port, username, password);
+    try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
+        Path remotePath = fs.getPath("/some/remote/path");
+        ...
+    }
+
+    // Full programmatic control
+    SshClient client = ...setup and start the SshClient instance...
+    SftpFileSystemProvider provider = new SftpFileSystemProvider(client);
+    URI uri = SftpFileSystemProvider.createFileSystemURI(host, port, username, password);
+    try (FileSystem fs = provider.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
+        Path remotePath = fs.getPath("/some/remote/path");
+    }
+
+```
+
+ The obtained `Path` instance can be used in exactly the same way as any other "regular" one:
+
+
+ ```java
+
+    try (InputStream input = Files.newInputStream(remotePath)) {
+        ...read from remote file...
+    }
+
+    try (DirectoryStream<Path> ds = Files.newDirectoryStream(remoteDir)) {
+        for (Path remoteFile : ds) {
+            if (Files.isRegularFile(remoteFile)) {
+                System.out.println("Delete " + remoteFile + " size=" + Files.size(remoteFile));
+                Files.delete(remoteFile);
+            } else if (Files.isDirectory(remoteFile)) {
+                System.out.println(remoteFile + " - directory");
+            }
+        }
+    }
+```
+
+It is highly recommended to `close()` the mounted file system once no longer necessary in order to release the
+associated SFTP session sooner rather than later - e.g., via a `try-with-resource` code block.
+
+**Caveat:** Due to URI encoding of the username/password as a basic authentication, the system currently
+does not allow colon (`:`) in either one in order to avoid parsing confusion. See [RFC 3986 - section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1):
+
+>> Use of the format "user:password" in the userinfo field is
+>> deprecated ... Applications may choose to ignore or reject such
+>> data when it is received as part of a reference...
+
+#### Configuring the `SftpFileSystemProvider`
+
+When "mounting" a new file system one can provide extra configuration parameters using either the
+environment map in the [FileSystems#newFileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystems.html#newFileSystem)
+method or via the URI query parameters. See the `SftpFileSystemProvider` for the available
+configuration keys and values.
+
+
+```java
+
+    // Using explicit parameters
+    Map<String, Object> params = new HashMap<>();
+    params.put("param1", value1);
+    params.put("param2", value2);
+    ...etc...
+
+    URI uri = SftpFileSystemProvider.createFileSystemURI(host, port, username, password);
+    try (FileSystem fs = FileSystems.newFileSystem(uri, params)) {
+        Path remotePath = fs.getPath("/some/remote/path");
+        ... work with the remote path...
+    }
+
+    // Using URI parameters
+    Path remotePath = Paths.get(new URI("sftp://user:password@host/some/remote/path?param1=value1&param2=value2..."));
+    // Releasing the file-system once no longer necessary
+    try (FileSystem fs = remotePath.getFileSystem()) {
+        ... work with the remote path...
+    }
+
+```
+
+**Note**: if **both** options are used then the URI parameters **override** the environment ones
+
+
+```java
+
+    Map<String, Object> params = new HashMap<>();
+    params.put("param1", value1);
+    params.put("param2", value2);
+
+    // The value of 'param1' is overridden in the URI
+    try (FileSystem fs = FileSystems.newFileSystem(new URI("sftp://user:password@host/some/remote/path?param1=otherValue1", params)) {
+        Path remotePath = fs.getPath("/some/remote/path");
+        ... work with the remote path...
+    }
+
+```
+
+#### Configuring the client session used to create an `SftpFileSystem`
+
+It is possible to register a `SftpFileSystemClientSessionInitializer` with the provider instead of the default one
+and thus better control the `ClientSession` used to generate the file-system instance. The default implementation
+simply connects and authenticates before creating a default `SftpFileSystem` instance. Users may wish
+to override some options or provide their own - e.g., execute a password-less authentication instead of
+the (default) password-based one:
+
+```java
+
+    SftpFileSystemProvider provider = ... obtain/create a provider ...
+    provider.setSftpFileSystemClientSessionInitializer(new SftpFileSystemClientSessionInitializer() {
+        @Override
+        public void authenticateClientSession(
+                SftpFileSystemProvider provider, SftpFileSystemInitializationContext context, ClientSession session)
+                    throws IOException {
+            /*
+             * Set up password-less login instead of password-based using the specified key
+             *
+             * Note: if SSH client and/or session already have a KeyPairProvider set up and the code
+             * knows that these keys are already registered with the remote server, then no need to
+             * add the public key identitiy - can simply call sesssion.auth().verify(context.getMaxAuthTime()).
+             */
+            KeyPair kp = ... obtain a registered key-pair...
+            session.addPublicKeyIdentity(kp);
+            return sesssion.auth().verify(context.getMaxAuthTime());
+        }
+    });
+
+```
+
+#### Tracking accessed locations via `SftpFileSystemAccessor`
+
+One can override the default `SftpFileSystemAccessor` and thus be able to track all opened files and folders
+throughout the SFTP server subsystem code. The accessor is registered/overwritten in via the `SftpSubSystemFactory`:
+
+```java
+
+    SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
+        .withFileSystemAccessor(new MySftpFileSystemAccessor())
+        .build();
+    server.setSubsystemFactories(Collections.singletonList(factory));
+
+```
+
+### SFTP sent/received names encoding
+
+By default, the SFTP client uses UTF-8 to encode/decode any referenced file/folder name. However, some servers do not properly encode such names,
+and thus the "visible" names by the client become corrupted, or even worse - cause an exception upon decoding attempt. The `SftpClient` exposes
+a `get/setNameDecodingCharset` method which enables the user to modify the charset - even while the SFTP session is in progress - e.g.:
+
+```java
+
+    try (SftpClient client = ...obtain an instance...) {
+        client.setNameDecodingCharset(Charset.forName("ISO-8859-8"));
+        for (DirEntry entry : client.readDir(...some path...)) {
+            ...handle entry assuming ISO-8859-8 encoded names...
+        }
+
+        client.setNameDecodingCharset(Charset.forName("ISO-8859-4"));
+        for (DirEntry entry : client.readDir(...some other path...)) {
+            ...handle entry assuming ISO-8859-4 encoded names...
+        }
+    }
+
+```
+
+The initial charset can be pre-configured on the client/session by using the `sftp-name-decoding-charset` property - if none specified then
+UTF-8 is used. **Note:** the value can be a charset name or a `java.nio.charset.Charset` instance - e.g.:
+
+```java
+
+    SshClient client = ... setup/obtain an instance...
+    // default for ALL SFTP clients obtained through this client
+    PropertyResolverUtils.updateProperty(client, SftpClient.NAME_DECODING_CHARSET, "ISO-8859-8");
+
+    try (ClientSession session = client.connect(...)) {
+         // default for ALL SFTP clients obtained through the session - overrides client setting
+         PropertyResolverUtils.updateProperty(session, SftpClient.NAME_DECODING_CHARSET, "ISO-8859-4");
+         session.authenticate(...);
+
+         SftpClientFactory factory = SftpClientFactory.instance();
+         try (SftpClient sftp = factory.createSftpClient(session)) {
+             for (DirEntry entry : sftp.readDir(...some path...)) {
+                 ...handle entry assuming ISO-8859-4 (inherited from the session) encoded names...
+             }
+
+             // override the inherited default from the session
+             sftp.setNameDecodingCharset(Charset.forName("ISO-8859-1"));
+
+             for (DirEntry entry : sftp.readDir(...some other path...)) {
+                 ...handle entry assuming ISO-8859-1 encoded names...
+             }
+         }
+    }
+
+```
+
+Both client and server support several of the SFTP extensions specified in various drafts:
+
+* `supported` - [DRAFT 05 - section 4.4](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-05.tx)
+* `supported2` - [DRAFT 13 section 5.4](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-10)
+* `versions` - [DRAFT 09 Section 4.6](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
+* `vendor-id` - [DRAFT 09 - section 4.4](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
+* `acl-supported` - [DRAFT 11 - section 5.4](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-11)
+* `newline` - [DRAFT 09 Section 4.3](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
+* `md5-hash`, `md5-hash-handle` - [DRAFT 09 - section 9.1.1](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
+* `check-file-handle`, `check-file-name` - [DRAFT 09 - section 9.1.2](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
+* `copy-file`, `copy-data` - [DRAFT 00 - sections 6, 7](http://tools.ietf.org/id/draft-ietf-secsh-filexfer-extensions-00.txt)
+* `space-available` - [DRAFT 09 - section 9.3](http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt)
+
+Furthermore several [OpenSSH SFTP extensions](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL) are also supported:
+
+* `fsync@openssh.com`
+* `fstatvfs@openssh.com`
+* `hardlink@openssh.com`
+* `posix-rename@openssh.com`
+* `statvfs@openssh.com`
+
+
+On the server side, the reported standard extensions are configured via the `SftpSubsystem.CLIENT_EXTENSIONS_PROP` configuration
+key, and the _OpenSSH_ ones via the `SftpSubsystem.OPENSSH_EXTENSIONS_PROP`.
+
+On the client side, all the supported extensions are classes that implement `SftpClientExtension`. These classes can be used
+to query the client whether the remote server supports the specific extension and then obtain a parser for its contents. Users
+can easily add support for more extensions in a similar manner as the existing ones by implementing an appropriate `ExtensionParser`
+and then registering it at the `ParserUtils` - see the existing ones for details how this can be achieved.
+
+
+```java
+
+    // properietary/special extension parser
+    ParserUtils.registerExtension(new MySpecialExtension());
+
+    try (ClientSession session = client.connect(username, host, port).verify(timeout).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth().verify(timeout);
+
+        SftpClientFactory factory = SftpClientFactory.instance();
+        try (SftpClient sftp = factory.createSftpClient(session)) {
+            Map<String, byte[]> extensions = sftp.getServerExtensions();
+            // Key=extension name, value=registered parser instance
+            Map<String, ?> data = ParserUtils.parse(extensions);
+            for (Map.Entry<String, ?> de : data.entrySet()) {
+                String extName = de.getKey();
+                Object extValue = de.getValue();
+                if (SftpConstants.EXT_ACL_SUPPORTED.equalsIgnoreCase(extName)) {
+                    AclCapabilities capabilities = (AclCapabilities) extValue;
+                    ...see what other information can be gleaned from it...
+                } else if (SftpConstants.EXT_VERSIONS.equalsIgnoreCase(extName)) {
+                    Versions versions = (Versions) extValue;
+                    ...see what other information can be gleaned from it...
+                } else if ("my-special-extension".equalsIgnoreCase(extName)) {
+                    MySpecialExtension special = (MySpecialExtension) extValue;
+                    ...see what other information can be gleaned from it...
+                } // ...etc....
+            }
+        }
+    }
+
+```
+
+One can skip all the conditional code if a specific known extension is required:
+
+
+```java
+
+    try (ClientSession session = client.connect(username, host, port).verify(timeout).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth().verify(timeout);
+
+        SftpClientFactory factory = SftpClientFactory.instance();
+        try (SftpClient sftp = factory.createSftpClient(session)) {
+            // Returns null if extension is not supported by remote server
+            SpaceAvailableExtension space = sftp.getExtension(SpaceAvailableExtension.class);
+            if (space != null) {
+                ...use it...
+            }
+        }
+    }
+
+```
+
+### Internal exceptions and error message handling
+
+If an exception is thrown during processing of an SFTP command, then the exception is translated into a `SSH_FXP_STATUS` message
+using a registered `SftpErrorStatusDataHandler`. The default implementation provides a short description of the failure based on the thrown
+exception type. However, users may override it when creating the `SftpSubsystemFactory` and provide their own codes and/or messages - e.g.,
+for debugging one can register a `DetailedSftpErrorStatusDataHandler` (see `sshd-contrib`) that "leaks" more information in the generated message.
+
+If the registered handler implements `ChannelSessionAware` then it will also be informed of the registered `ChannelSession` when it is
+provided to the `SftpSubsystem` itself. This can be used to register an extended data writer that can handle data sent via the STDERR
+channel. **Note:** this feature is allowed according to [SFTP version 4 - section 3.1](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-3.1):
+
+>> Packets are sent and received on stdout and stdin. Data sent on stderr by the server SHOULD be considered debug
+>> or supplemental error information, and MAY be displayed to the user.
+
+however, the current code provides no built-in support for this feature.
+
+If registering an extended data writer then one should take care of any race conditions that may occur where (extended) data
+may arrive before the handler is informed of the existence of the `ChannelSession`. For this purpose one should configure a
+reasonable buffer size by setting the `channel-session-max-extdata-bufsize` property. This way, if any data arrives before the
+extended data handler is registered it will be buffered (up to the specified max. size). **Note:** if a buffer size is configured
+but no extended data handler is registered when channel is spawning the command then an exception will occur.


[mina-sshd] 01/02: [SSHD-872] Split changes documentation into separate files according to version number

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit ab893e5ec703fe4f27d495aff3ac673aab895acc
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Tue Feb 5 11:30:22 2019 +0200

    [SSHD-872] Split changes documentation into separate files according to version number
---
 CHANGES.md                          | 188 +-----------------------------------
 CHANGES.md => docs/changes/2.2.0.md |   7 +-
 pom.xml                             |   5 +-
 3 files changed, 8 insertions(+), 192 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index e2221a6..739b760 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,191 +1,13 @@
-# Since version 2.1.0
+# [Version 2.1.0 to 2.2.0](./docs/changes/2.2.0.md)
 
-## Major code re-factoring
-
-* `AttributeStore` "read" methods moved to (new class) `AttributeRepository`.
-
-    * `AttributeKey` moved to `AttributeRepository`.
-
-    * `getAttribute` and `resolveAttribute` moved to `AttributeRepository`.
-
-    * Added `attributeKeys` enumeration method to `AttributeRepository`.
-
-    * In this context, please note that all associated session/channel/client/server attributes
-    are cleared when entity is closed. The clearing usually occurs as after all relevant registered
-    event listeners have been invoked.
-
-* `DEFAULT_PORT` moved from `SshConfigFileReader` to `SshConstants`.
-
-* Moved some session "summary" related definitions from `Session` to `SessionContext` (which `Session` extends).
-
-* Added new `sessionDisconnect` method to `SessionListener`.
-
-* `ReservedSessionMessagesHandler#handleUnimplementedMessage` has an extra `cmd` argument
-and is called both for `SSH_MSG_UNIMPLEMENTED` as well as for any other unexpected/unrecognized
-command encountered during the session message processing loop.
-
-* `AttributeRepository` optional context propagated during initial connection establishment
-
-    * `ClientSessionCreator` has extra `connect` methods with an `AttributeRepository`
-    connection context argument
-
-    * The context is also propagated to `HostConfigEntryResolver#resolveEffectiveHost` method
-
-    * `connectionEstablished` and `abortEstablishedConnection` methods of `IoServiceEventListener`
-    accept also an `AttributeRepository` connection context argument (propagated from the
-    `ClientSessionCreator#connect` invocation).
-
-* `FilePasswordProvider`
-
-    * Added an extra method (`handleDecodeAttemptResult`) that enables users to try and repeat an
-    encrypted private key decoding using a different password.
-
-    * The interface methods are also provided with a retry index that indicates the number of
-    times they have been re-invoked for the same resource (including on success).
-
-    * The available session context (if any) is also provided as an argument to the interface methods.
-
-    * The interface methods use a `NamedResource` as the resource key instead of a plain string.
-
-* `SshAgent#getIdentities` returns an `Iterable` rather than a `List`
-
-* `SftpFileSystemProvider` and its associated helper classes have been moved to
-`org.apache.sshd.client.subsystem.sftp.fs` package.
-
-* `KeyPairProvider` accepts a `SessionContext` argument in its `getKeyTypes/loadKey` methods.
-
-* `KeyIdentityProvider` accepts a `SessionContext` argument in its `loadKeys` method.
-
-* `ClientIdentityProvider` accepts a `SessionContext` argument in its `getClientIdentity` method.
-
-* `ClientIdentityLoader`
-    * Accepts a `SessionContext` argument in its `loadClientIdentity` method.
-
-    * Uses a `NamedResource` as the identity location indicator instead of a plain old string.
-
-* `ApacheSshdSftpSessionFactory#get/setPrivateKey` has been renamed to `get/setPrivateKeyLocation`.
-
-* `SshClient` and `ClientSession` use a `KeyIdentityProvider` instead of a full blown `KeyPairProvider`.
-`KeyPairProvider` is used only in the context of an `SshServer` and/or `ServerSession`.
-
-* `SshClient#loadClientIdentities` has been renamed to `preloadClientIdentities` + it returns a
-`KeyIdentityProvider` instead of a collection of strings representing paths.
-
-* The various `ClientIdentitiesWatcher`(s) use a type-safe `ClientIdentityLoaderHolder` and
-`FilePasswordProviderHolder` instead of the generic `Supplier` definition.
-
-* Removed API(s) that used string file paths to create `FileInputStream`-s - using only `java.nio.file.Path`-s
-
-* Converted most of the key-pair identity loaders (e.g., `ClientIdentityLoader`, `ClientIdentityProvider`, etc.)
-to return an `Iterable<KeyPair>` instead of single `KeyPair` instance.
-
-* Code that converts authorized keys entries into `PublicKey`-s has been renamed to `resolvePublicKeyEntries`
-and moved to `PublicKeyEntry` class.
-    * Note that the parameters **order** has also been modified
-
-* `PublicKeyEntryResolver` (and its derived classes) accept an extra `SessionContext` parameter.
-
-* All methods `ScpTransferEventListener` accept an extra `Session` parameter indicating the SSH client/server
-session context for the listener's invocation.
-    * Same applies for `ScpFileOpener` and `ScpReceiveLineHandler`
+# Planned for next version
 
-* Re-provide expected SCP byte count transfer and permissions when invoking `ScpFileOpener#openRead/openWrite`
-
-* `CipherInformation#getBlockSize` has been renamed to `getKdfSize` in order to emphasize that its value
-represents the number of bytes used to derive the cipher's secret key value and not the cipher's underlying
-block size.
-
-    * See [SSHD-873](https://issues.apache.org/jira/browse/SSHD-873) enhancement remark below
-    for the cipher block size information.
-
-* `IdentityResourceLoader` exposes `getSupportedKeyTypes()` instead of `getSupportedTypeNames()`
-
-    * This method is now also implemented by the `Identity` interface as well
-
-* `HostConfigEntryResolver#resolveEffectiveHost` accepts also an (optional) initial connection
-context and/or local peer binding address - propagated from the `ClientSessionCreator#connect` invocation.
+## Major code re-factoring
 
-* `connectionAccepted/abortAcceptedConnection` methods of `IoServiceEventListener` accept an extra
-argument - the service listen endpoint through which the connection was accepted.
+* The `ChannelSession` provides a mechanism for supporting non-standard extended data (a.k.a. STDERR data)
+in a similar manner as the "regular" data. Please read the relevant section in the main documentation page.
 
 ## Behavioral changes and enhancements
 
-* [SSHD-708](https://issues.apache.org/jira/browse/SSHD-708) - Add support for password encrypted OpenSSH private key files.
-
-* [SSHD-757](https://issues.apache.org/jira/browse/SSHD-757) - Added hooks and some initial code to allow (limited) usage
-of [OpenPGP](https://www.openpgp.org/) key files - e.g. in `authorized_keys` files or as client identities.
-
-* [SSHD-849](https://issues.apache.org/jira/browse/SSHD-849) - Data forwarding code makes sure all
-pending packets have been sent to the peer channel when closing the tunnel gracefully.
-
-* [SSHD-850](https://issues.apache.org/jira/browse/SSHD-850) - Add capability to retry a failed private key decryption.
-
-* [SSHD-857](https://issues.apache.org/jira/browse/SSHD-857) - Add session disconnect event signalling to SessionListener.
-
-    * Also calling `ReservedSessionMessagesHandler#handleUnimplementedMessage` not only for `SSH_MSG_UNIMPLEMENTED` but
-    also for any unexpected/unrecognized command encountered during the session message processing loop.
-
-* [SSHD-859](https://issues.apache.org/jira/browse/SSHD-859) - Provide client session connection context that is propagated to the SSH session.
-
-    * Also added connection context argument (propagated from the `ClientSessionCreator#connect` invocation)
-    to`connectionEstablished` and `abortEstablishedConnection` methods of `IoServiceEventListener`.
-
-* [SSHD-860](https://issues.apache.org/jira/browse/SSHD-860) - Use lazy loading of public key identities.
-
-* [SSHD-861](https://issues.apache.org/jira/browse/SSHD-861) - Fixed username/password encoding for `SftpFileSystem` URI(s).
-
-    * Also added `SftpFileSystemClientSessionInitializer` support in `SftpFileSystemProvider`
-
-* [SSHD-862](https://issues.apache.org/jira/browse/SSHD-862) - Provide session context argument (if available) when
-key loading methods are invoked.
-
-* [SSHD-864](https://issues.apache.org/jira/browse/SSHD-864) - Using a `NamedResource` instead of plain old string
-in order to provide key file(s) location information
-
-* [SSHD-865](https://issues.apache.org/jira/browse/SSHD-865) - Key identities overrides specified in the
-[ssh_config](http://www.gsp.com/cgi-bin/man.cgi?topic=ssh_config) configuration file are also lazy loaded
-
-* [SSHD-866](https://issues.apache.org/jira/browse/SSHD-866) - Counting empty challenges separately when enforcing
-max. attempts during `keyboard-interactive` authentication
-
-* [SSHD-870](https://issues.apache.org/jira/browse/SSHD-870) - Added hooks and some initial code to allow (limited) usage
-of [OpenPGP](https://www.openpgp.org/) key rings in `authorized_keys` files
-
-* [SSHD-873](https://issues.apache.org/jira/browse/SSHD-873) - `CipherInformation#getCipherBlockSize` method has been added
-for exposing the cipher's block size. **Note:** for the time being we declare a virtual block size for stream ciphers as well
-(e.g., RC4) in order to facilitate the automatic re-keying mechanism described in [RFC 4253 - section 9](https://tools.ietf.org/html/rfc4253#section-9)
- and [RFC 4344 - section 3.2](https://tools.ietf.org/html/rfc4344#section-3.2).
-
-* [SSHD-876](https://issues.apache.org/jira/browse/SSHD-876) - Looking through the resolvable class-loaders "hierarchy"
-(thread-context => anchor => system) for `sshd-version.properties` file instead of just in the thread context class loader.
-
-    * In this context, the default reported client/server SSH version string has been set to `APACHE-SSHD-...version...`.
-    Reminder: the user can override this default via configuration properties set on the client/server instance
-    (see `AbstractSession#resolveIdentificationString`, `ClientFactoryManager#CLIENT_IDENTIFICATION`, and
-    `ServerFactoryManager#SERVER_IDENTIFICATION`).
-
-* [SSHD-878](https://issues.apache.org/jira/browse/SSHD-876) - The `File/DirectoryHandle`(s) used by the SFTP subsystem
-implement `AttributeStore` interface - which means that `SftpEventListener`(s) can now attach user-defined attributes
-to the generated handle(s).
-
-* [SSHD-886](https://issues.apache.org/jira/browse/SSHD-886) - Do not send `SSH_MSG_UNIMPLEMENTED` reply if registered
-`ReservedSessionMessagesHandler` signals that it has handled the unknown packet type.
-
-* `SftpCommandMain` shows by default `get/put` command progress using the hash sign (`#`) marker. The marker
-can be enabled/disabled via the `progress` command:
-
-```
-    > progress
-
-    ... reponse is whether it is 'on' or 'off'
-
-    > progress on/off
-
-    ... set the progress marker indicator  ...
-
-```
-
-# Since version 2.2.0
-
 * [SSHD-882](https://issues.apache.org/jira/browse/SSHD-882) - Provide hooks to allow users to register a consumer
 for STDERR data sent via the `ChannelSession` - especially for the SFTP subsystem.
diff --git a/CHANGES.md b/docs/changes/2.2.0.md
similarity index 97%
copy from CHANGES.md
copy to docs/changes/2.2.0.md
index e2221a6..0cea806 100644
--- a/CHANGES.md
+++ b/docs/changes/2.2.0.md
@@ -1,4 +1,4 @@
-# Since version 2.1.0
+# Introduced in version 2.2.0
 
 ## Major code re-factoring
 
@@ -184,8 +184,3 @@ can be enabled/disabled via the `progress` command:
     ... set the progress marker indicator  ...
 
 ```
-
-# Since version 2.2.0
-
-* [SSHD-882](https://issues.apache.org/jira/browse/SSHD-882) - Provide hooks to allow users to register a consumer
-for STDERR data sent via the `ChannelSession` - especially for the SFTP subsystem.
diff --git a/pom.xml b/pom.xml
index 3282568..3e1af50 100644
--- a/pom.xml
+++ b/pom.xml
@@ -635,9 +635,8 @@
                     <configuration>
                         <consoleOutput>true</consoleOutput>
                         <excludes>
-                            <exclude>README.md</exclude>
-                            <exclude>CHANGES.md</exclude>
-                            <exclude>src/docs/**</exclude>
+                            <exclude>*.md</exclude>
+                            <exclude>docs/**</exclude>
                             <exclude>src/test/resources/**</exclude>
                             <exclude>**/stty-output-*.txt</exclude>
                             <exclude>**/target/**</exclude>