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 2018/11/18 04:54:58 UTC

[03/12] mina-sshd git commit: [SSHD-862] Propagate available session context to code that deals with loading private keys

[SSHD-862] Propagate available session context to code that deals with loading private keys


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/2b013cca
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/2b013cca
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/2b013cca

Branch: refs/heads/master
Commit: 2b013cca86bede945a6da0fd20e6afaab6aca22a
Parents: 20be0e9
Author: Lyor Goldstein <lg...@apache.org>
Authored: Wed Nov 14 08:37:11 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 06:54:47 2018 +0200

----------------------------------------------------------------------
 CHANGES.md                                      |  43 +--
 .../sshd/cli/client/SshClientCliSupport.java    |   2 +-
 .../sshd/cli/server/SshServerCliSupport.java    |   2 +-
 .../sshd/client/config/keys/ClientIdentity.java |  39 +--
 .../config/keys/ClientIdentityFileWatcher.java  |   3 +-
 .../config/keys/ClientIdentityLoader.java       |  13 +-
 .../config/keys/FilePasswordProvider.java       |  14 +-
 .../sshd/common/config/keys/IdentityUtils.java  |  12 +-
 .../config/keys/PrivateKeyEntryDecoder.java     |  33 ++-
 .../config/keys/PrivateKeyEntryResolver.java    |  13 +-
 .../loader/AbstractKeyPairResourceParser.java   |  38 ++-
 .../keys/loader/KeyPairResourceLoader.java      |  67 +++--
 .../keys/loader/KeyPairResourceParser.java      |   7 +-
 .../OpenSSHDSSPrivateKeyEntryDecoder.java       |   6 +-
 .../OpenSSHECDSAPrivateKeyEntryDecoder.java     |   6 +-
 .../openssh/OpenSSHKeyPairResourceParser.java   |  32 ++-
 .../openssh/OpenSSHRSAPrivateKeyDecoder.java    |   6 +-
 .../pem/AbstractPEMResourceKeyPairParser.java   |  16 +-
 .../loader/pem/DSSPEMResourceKeyPairParser.java |   6 +-
 .../pem/ECDSAPEMResourceKeyPairParser.java      |   6 +-
 .../keys/loader/pem/PEMResourceParserUtils.java |   7 +-
 .../pem/PKCS8PEMResourceKeyPairParser.java      |  18 +-
 .../loader/pem/RSAPEMResourceKeyPairParser.java |   6 +-
 .../AbstractResourceKeyPairProvider.java        |  11 +-
 .../ClassLoadableResourceKeyPairProvider.java   |   4 +-
 .../common/keyprovider/FileKeyPairProvider.java |   7 +-
 .../common/keyprovider/KeyIdentityProvider.java |  41 +--
 .../common/keyprovider/KeyPairProvider.java     |  12 +-
 .../keyprovider/MultiKeyIdentityIterator.java   |  10 +-
 .../sshd/common/session/SessionContext.java     |   4 +-
 .../apache/sshd/common/util/ValidateUtils.java  |  12 +
 .../common/util/security/SecurityUtils.java     |  18 +-
 .../BouncyCastleKeyPairResourceParser.java      |  23 +-
 .../OpenSSHEd25519PrivateKeyEntryDecoder.java   |   6 +-
 .../AbstractGeneratorHostKeyProvider.java       |   2 +-
 .../BuiltinClientIdentitiesWatcherTest.java     |   9 +-
 .../keys/ClientIdentityFileWatcherTest.java     |   4 +-
 .../OpenSSHKeyPairResourceParserTest.java       |   2 +-
 .../pem/PKCS8PEMResourceKeyPairParserTest.java  |   2 +-
 .../common/keyprovider/KeyPairProviderTest.java |  12 +-
 .../MultiKeyIdentityProviderTest.java           |   4 +-
 .../common/util/security/SecurityUtilsTest.java |  13 +-
 .../PEMGeneratorHostKeyProviderTest.java        |  22 +-
 .../SimpleGeneratorHostKeyProviderTest.java     |  23 +-
 .../sshd/util/test/CommonTestSupportUtils.java  |  18 +-
 .../java/org/apache/sshd/client/SshClient.java  |  23 +-
 .../auth/pubkey/UserAuthPublicKeyIterator.java  |  11 +-
 .../sshd/client/session/ClientSession.java      |  15 -
 .../org/apache/sshd/common/session/Session.java |   2 -
 .../common/session/helpers/AbstractSession.java |  49 +++-
 .../sshd/server/config/keys/ServerIdentity.java |   6 +-
 .../server/session/AbstractServerSession.java   |   8 +-
 .../hosts/HostConfigEntryResolverTest.java      |  10 +-
 .../sshd/common/auth/AuthenticationTest.java    | 278 ++++++++++++++-----
 .../common/auth/SinglePublicKeyAuthTest.java    |   4 +-
 .../super-secret-passphrase-RSA-AES-128-key     |  30 ++
 .../super-secret-passphrase-RSA-AES-128-key.pub |   1 +
 .../openpgp/PGPKeyPairResourceParser.java       |  19 +-
 .../openpgp/PGPKeyPairResourceParserTest.java   |   7 +-
 .../loader/putty/AbstractPuttyKeyDecoder.java   |  23 +-
 .../keys/loader/putty/PuttyKeyUtilsTest.java    |  18 +-
 .../sftp/ApacheSshdSftpSessionFactory.java      |   2 +-
 62 files changed, 770 insertions(+), 390 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/CHANGES.md
----------------------------------------------------------------------
diff --git a/CHANGES.md b/CHANGES.md
index 57d53f6..9cc1cd4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,19 +2,19 @@
 
 ## Major code re-factoring
 
-* `AttributeStore` "read" methods moved to (new class) `AttributeRepository`
+* `AttributeStore` "read" methods moved to (new class) `AttributeRepository`.
 
-    * `AttributeKey` moved to `AttributeRepository`
+    * `AttributeKey` moved to `AttributeRepository`.
 
-    * `getAttribute` and `resolveAttribute` moved to `AttributeRepository`
+    * `getAttribute` and `resolveAttribute` moved to `AttributeRepository`.
 
     * Added `attributeKeys` enumeration method to `AttributeRepository`.
 
-* `DEFAULT_PORT` moved from `SshConfigFileReader` to `SshConstants`
+* `DEFAULT_PORT` moved from `SshConfigFileReader` to `SshConstants`.
 
-* Moved some session "summary" related definitions from `Session` to `SessionContext` (which `Session` extends)
+* Moved some session "summary" related definitions from `Session` to `SessionContext` (which `Session` extends).
 
-* Added new `sessionDisconnect` method to `SessionListener`
+* 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
@@ -35,44 +35,45 @@ accept also an `AttributeRepository` connection context argument (propagated fro
     * 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.
+
 * `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
+`org.apache.sshd.client.subsystem.sftp.fs` package.
+
+* `KeyPairProvider` accepts a `SessionContext` argument in its `getKeyTypes/loadKey` methods.
 
-* `KeyPairProvider` accepts a `SessionContext` argument in its `getKeyTypes/loadKey` methods
+* `KeyIdentityProvider` accepts a `SessionContext` argument in its `loadKeys` method.
 
-* `KeyIdentityProvider` accepts a `SessionContext` argument in its `loadKeys` method
+* `ClientIdentityProvider` accepts a `SessionContext` argument in its `getClientIdentity` method.
 
-* `ClientIdentityProvider` accepts a `SessionContext` argument in its `getClientIdentity` method
+* `ClientIdentityLoader` accepts a `SessionContext` argument in its `loadClientIdentity` method.
 
-* `ApacheSshdSftpSessionFactory#get/setPrivateKey` has been renamed to `get/setPrivateKeyLocation`
+* `ApacheSshdSftpSessionFactory#get/setPrivateKey` has been renamed to `get/setPrivateKeyLocation`.
 
 ## Behavioral changes and enhancements
 
 * [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-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
+* [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
+* [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) - `UserAuthPublicKeyIterator` uses lazy loading of public key
-identities both from agent and client session
-
-    * Also using lazy identity `KeyPair`(s) loading in `ClientIdentitiesWatcher`
+* [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)
+* [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 when
-key loading methods are invoked
+* [SSHD-862](https://issues.apache.org/jira/browse/SSHD-862) - Provide session context argument (if available) when
+key loading methods are invoked.

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
index 2978524..9286324 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
@@ -346,7 +346,7 @@ public abstract class SshClientCliSupport extends CliSupport {
     public static FileKeyPairProvider setupSessionIdentities(ClientFactoryManager client, Collection<? extends Path> identities,
             BufferedReader stdin, PrintStream stdout, PrintStream stderr)
                 throws Throwable {
-        client.setFilePasswordProvider((file, index) -> {
+        client.setFilePasswordProvider((session, file, index) -> {
             stdout.print("Enter password for private key file=" + file + ": ");
             return stdin.readLine();
         });

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
index eac5b7e..f716553 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
@@ -116,7 +116,7 @@ public abstract class SshServerCliSupport extends CliSupport {
             for (String keyFilePath : keyFiles) {
                 Path path = Paths.get(keyFilePath);
                 try (InputStream inputStream = Files.newInputStream(path)) {
-                    KeyPair kp = SecurityUtils.loadKeyPairIdentity(keyFilePath, inputStream, null);
+                    KeyPair kp = SecurityUtils.loadKeyPairIdentity(null, keyFilePath, inputStream, null);
                     pairs.add(kp);
                 } catch (Exception e) {
                     stderr.append("Failed (").append(e.getClass().getSimpleName()).append(')')

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentity.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentity.java b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentity.java
index 13f5c34..c92cfc0 100644
--- a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentity.java
+++ b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentity.java
@@ -38,6 +38,7 @@ import org.apache.sshd.common.config.keys.IdentityUtils;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PublicKeyEntry;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.FileInfoExtractor;
@@ -101,7 +102,7 @@ public final class ClientIdentity {
      *                      supported internally
      * @param provider      A {@link FilePasswordProvider} - may be {@code null}
      *                      if the loaded keys are <U>guaranteed</U> not to be encrypted. The argument
-     *                      to {@link FilePasswordProvider#getPassword(String, int)} is the path of the
+     *                      to {@code FilePasswordProvider#getPassword} is the path of the
      *                      file whose key is to be loaded
      * @param options       The {@link LinkOption}s to apply when checking
      *                      for existence
@@ -114,7 +115,7 @@ public final class ClientIdentity {
      */
     public static KeyPairProvider loadDefaultKeyPairProvider(
             boolean strict, boolean supportedOnly, FilePasswordProvider provider, LinkOption... options)
-            throws IOException, GeneralSecurityException {
+                throws IOException, GeneralSecurityException {
         return loadDefaultKeyPairProvider(PublicKeyEntry.getDefaultKeysFolderPath(), strict, supportedOnly, provider, options);
     }
 
@@ -126,7 +127,7 @@ public final class ClientIdentity {
      *                      supported internally
      * @param provider      A {@link FilePasswordProvider} - may be {@code null}
      *                      if the loaded keys are <U>guaranteed</U> not to be encrypted. The argument
-     *                      to {@link FilePasswordProvider#getPassword(String, int)} is the path of the
+     *                      to {@code FilePasswordProvider#getPassword} is the path of the
      *                      file whose key is to be loaded
      * @param options       The {@link LinkOption}s to apply when checking
      *                      for existence
@@ -139,7 +140,7 @@ public final class ClientIdentity {
      */
     public static KeyPairProvider loadDefaultKeyPairProvider(
             Path dir, boolean strict, boolean supportedOnly, FilePasswordProvider provider, LinkOption... options)
-            throws IOException, GeneralSecurityException {
+                throws IOException, GeneralSecurityException {
         Map<String, KeyPair> ids = loadDefaultIdentities(dir, strict, provider, options);
         return IdentityUtils.createKeyPairProvider(ids, supportedOnly);
     }
@@ -149,7 +150,7 @@ public final class ClientIdentity {
      *                 access rights are excluded from consideration
      * @param provider A {@link FilePasswordProvider} - may be {@code null}
      *                 if the loaded keys are <U>guaranteed</U> not to be encrypted. The argument
-     *                 to {@link FilePasswordProvider#getPassword(String, int)} is the path of the
+     *                 to {@code FilePasswordProvider#getPassword} is the path of the
      *                 file whose key is to be loaded
      * @param options  The {@link LinkOption}s to apply when checking
      *                 for existence
@@ -160,8 +161,9 @@ public final class ClientIdentity {
      * @see PublicKeyEntry#getDefaultKeysFolderPath()
      * @see #loadDefaultIdentities(Path, boolean, FilePasswordProvider, LinkOption...)
      */
-    public static Map<String, KeyPair> loadDefaultIdentities(boolean strict, FilePasswordProvider provider, LinkOption... options)
-            throws IOException, GeneralSecurityException {
+    public static Map<String, KeyPair> loadDefaultIdentities(
+            boolean strict, FilePasswordProvider provider, LinkOption... options)
+                throws IOException, GeneralSecurityException {
         return loadDefaultIdentities(PublicKeyEntry.getDefaultKeysFolderPath(), strict, provider, options);
     }
 
@@ -171,7 +173,7 @@ public final class ClientIdentity {
      *                 access rights are excluded from consideration
      * @param provider A {@link FilePasswordProvider} - may be {@code null}
      *                 if the loaded keys are <U>guaranteed</U> not to be encrypted. The argument
-     *                 to {@link FilePasswordProvider#getPassword(String, int)} is the path of the
+     *                 to {@code FilePasswordProvider#getPassword} is the path of the
      *                 file whose key is to be loaded
      * @param options  The {@link LinkOption}s to apply when checking
      *                 for existence
@@ -182,14 +184,17 @@ public final class ClientIdentity {
      * @see #loadIdentities(Path, boolean, Collection, Function, FilePasswordProvider, LinkOption...)
      * @see BuiltinIdentities
      */
-    public static Map<String, KeyPair> loadDefaultIdentities(Path dir, boolean strict, FilePasswordProvider provider, LinkOption... options)
-            throws IOException, GeneralSecurityException {
-        return loadIdentities(dir, strict, BuiltinIdentities.NAMES, ID_GENERATOR, provider, options);
+    public static Map<String, KeyPair> loadDefaultIdentities(
+            Path dir, boolean strict, FilePasswordProvider provider, LinkOption... options)
+                throws IOException, GeneralSecurityException {
+        return loadIdentities(null, dir, strict, BuiltinIdentities.NAMES, ID_GENERATOR, provider, options);
     }
 
     /**
      * Scans a folder and loads all available identity files
      *
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param dir         The {@link Path} of the folder to scan - ignored if not exists
      * @param strict      If {@code true} then files that do not have the required
      *                    access rights are excluded from consideration
@@ -198,7 +203,7 @@ public final class ClientIdentity {
      *                    holding the specified type
      * @param provider    A {@link FilePasswordProvider} - may be {@code null}
      *                    if the loaded keys are <U>guaranteed</U> not to be encrypted. The argument
-     *                    to {@link FilePasswordProvider#getPassword(String, int)} is the path of the
+     *                    to {@code FilePasswordProvider#getPassword} is the path of the
      *                    file whose key is to be loaded
      * @param options     The {@link LinkOption}s to apply when checking
      *                    for existence
@@ -210,10 +215,12 @@ public final class ClientIdentity {
      * @see IdentityUtils#loadIdentities(Map, FilePasswordProvider, java.nio.file.OpenOption...)
      */
     public static Map<String, KeyPair> loadIdentities(
-            Path dir, boolean strict, Collection<String> types, Function<String, String> idGenerator, FilePasswordProvider provider, LinkOption... options)
+            SessionContext session, Path dir, boolean strict,
+            Collection<String> types, Function<? super String, String> idGenerator,
+            FilePasswordProvider provider, LinkOption... options)
             throws IOException, GeneralSecurityException {
         Map<String, Path> paths = scanIdentitiesFolder(dir, strict, types, idGenerator, options);
-        return IdentityUtils.loadIdentities(paths, provider, IoUtils.EMPTY_OPEN_OPTIONS);
+        return IdentityUtils.loadIdentities(session, paths, provider, IoUtils.EMPTY_OPEN_OPTIONS);
     }
 
     /**
@@ -233,8 +240,8 @@ public final class ClientIdentity {
      * @see KeyUtils#validateStrictKeyFilePermissions(Path, LinkOption...)
      */
     public static Map<String, Path> scanIdentitiesFolder(
-            Path dir, boolean strict, Collection<String> types, Function<String, String> idGenerator, LinkOption... options)
-            throws IOException {
+            Path dir, boolean strict, Collection<String> types, Function<? super String, String> idGenerator, LinkOption... options)
+                throws IOException {
         if (GenericUtils.isEmpty(types)) {
             return Collections.emptyMap();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
index 411ae1b..e2e1b82 100644
--- a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
+++ b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
@@ -123,8 +123,7 @@ public class ClientIdentityFileWatcher extends ModifiableFileWatcher implements
         String location = path.toString();
         ClientIdentityLoader idLoader = Objects.requireNonNull(getClientIdentityLoader(), "No client identity loader");
         if (idLoader.isValidLocation(location)) {
-            KeyPair kp = idLoader.loadClientIdentity(
-                location, Objects.requireNonNull(getFilePasswordProvider(), "No file password provider"));
+            KeyPair kp = idLoader.loadClientIdentity(session, location, getFilePasswordProvider());
             if (log.isTraceEnabled()) {
                 PublicKey key = (kp == null) ? null : kp.getPublic();
                 if (key != null) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
index 8b3a295..542697a 100644
--- a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
+++ b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
@@ -28,6 +28,7 @@ import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
@@ -51,10 +52,12 @@ public interface ClientIdentityLoader {
         }
 
         @Override
-        public KeyPair loadClientIdentity(String location, FilePasswordProvider provider) throws IOException, GeneralSecurityException {
+        public KeyPair loadClientIdentity(
+                SessionContext session, String location, FilePasswordProvider provider)
+                    throws IOException, GeneralSecurityException {
             Path path = toPath(location);
             try (InputStream inputStream = Files.newInputStream(path, IoUtils.EMPTY_OPEN_OPTIONS)) {
-                return SecurityUtils.loadKeyPairIdentity(path.toString(), inputStream, provider);
+                return SecurityUtils.loadKeyPairIdentity(session, path.toString(), inputStream, provider);
             }
         }
 
@@ -81,6 +84,8 @@ public interface ClientIdentityLoader {
     boolean isValidLocation(String location) throws IOException;
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool).
      * @param location The identity key-pair location - the actual meaning (file, URL, etc.)
      * depends on the implementation.
      * @param provider The {@link FilePasswordProvider} to consult if the location contains
@@ -91,5 +96,7 @@ public interface ClientIdentityLoader {
      * @throws GeneralSecurityException If failed to convert the contents into
      * a valid identity
      */
-    KeyPair loadClientIdentity(String location, FilePasswordProvider provider) throws IOException, GeneralSecurityException;
+    KeyPair loadClientIdentity(
+        SessionContext session, String location, FilePasswordProvider provider)
+            throws IOException, GeneralSecurityException;
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
index 54e8465..365de50 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
@@ -22,6 +22,8 @@ package org.apache.sshd.common.config.keys;
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 
+import org.apache.sshd.common.session.SessionContext;
+
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
@@ -39,9 +41,11 @@ public interface FilePasswordProvider {
     /**
      * An &quot;empty&quot; provider that returns {@code null} - i.e., unprotected key file
      */
-    FilePasswordProvider EMPTY = (resourceKey, retryIndex) -> null;
+    FilePasswordProvider EMPTY = (session, resourceKey, retryIndex) -> null;
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param resourceKey The resource key representing the <U>private</U> file
      * @param retryIndex The zero-based index of the invocation for the specific
      * resource (in case invoked several times for the same resource)
@@ -49,13 +53,15 @@ public interface FilePasswordProvider {
      * @throws IOException if cannot resolve password
      * @see #handleDecodeAttemptResult(String, int, String, Exception)
      */
-    String getPassword(String resourceKey, int retryIndex) throws IOException;
+    String getPassword(SessionContext session, String resourceKey, int retryIndex) throws IOException;
 
     /**
      * Invoked to inform the password provide about the decoding result. <b>Note:</b>
      * any exception thrown from this method (including if called to inform about
      * success) will be propagated instead of the original (if any was reported)
      *
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param resourceKey The resource key representing the <U>private</U> file
      * @param retryIndex The zero-based index of the invocation for the specific
      * resource (in case invoked several times for the same resource). If success
@@ -68,12 +74,12 @@ public interface FilePasswordProvider {
      * @throws GeneralSecurityException If not attempting to resolve a new password
      */
     default ResourceDecodeResult handleDecodeAttemptResult(
-            String resourceKey, int retryIndex, String password, Exception err)
+            SessionContext session, String resourceKey, int retryIndex, String password, Exception err)
                 throws IOException, GeneralSecurityException {
         return ResourceDecodeResult.TERMINATE;
     }
 
     static FilePasswordProvider of(String password) {
-        return (r, index) -> password;
+        return (session, resource, index) -> password;
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
index 9cf3859..6d9ab44 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
@@ -33,6 +33,7 @@ import java.util.TreeMap;
 
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.keyprovider.MappedKeyPairProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
@@ -123,11 +124,13 @@ public final class IdentityUtils {
     }
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param paths    A {@link Map} of the identities where key=identity type (case
      *                 <U>insensitive</U>), value=the {@link Path} of file with the identity key
      * @param provider A {@link FilePasswordProvider} - may be {@code null}
      *                 if the loaded keys are <U>guaranteed</U> not to be encrypted. The argument
-     *                 to {@link FilePasswordProvider#getPassword(String, int)} is the path of the
+     *                 to {@code FilePasswordProvider#getPassword} is the path of the
      *                 file whose key is to be loaded
      * @param options  The {@link OpenOption}s to use when reading the key data
      * @return A {@link Map} of the identities where key=identity type (case
@@ -136,8 +139,9 @@ public final class IdentityUtils {
      * @throws GeneralSecurityException If failed to load the keys
      * @see SecurityUtils#loadKeyPairIdentity(String, InputStream, FilePasswordProvider)
      */
-    public static Map<String, KeyPair> loadIdentities(Map<String, ? extends Path> paths, FilePasswordProvider provider, OpenOption... options)
-            throws IOException, GeneralSecurityException {
+    public static Map<String, KeyPair> loadIdentities(
+            SessionContext session, Map<String, ? extends Path> paths, FilePasswordProvider provider, OpenOption... options)
+                throws IOException, GeneralSecurityException {
         if (GenericUtils.isEmpty(paths)) {
             return Collections.emptyMap();
         }
@@ -148,7 +152,7 @@ public final class IdentityUtils {
             String type = pe.getKey();
             Path path = pe.getValue();
             try (InputStream inputStream = Files.newInputStream(path, options)) {
-                KeyPair kp = SecurityUtils.loadKeyPairIdentity(path.toString(), inputStream, provider);
+                KeyPair kp = SecurityUtils.loadKeyPairIdentity(session, path.toString(), inputStream, provider);
                 KeyPair prev = ids.put(type, kp);
                 ValidateUtils.checkTrue(prev == null, "Multiple keys for type=%s", type);
             }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
index 8dc6113..12f6800 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
@@ -32,6 +32,7 @@ import java.util.Collection;
 import java.util.Objects;
 
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceLoader;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.NumberUtils;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -45,17 +46,19 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
             extends KeyEntryResolver<PUB, PRV>, PrivateKeyEntryResolver {
 
     @Override
-    default PrivateKey resolve(String keyType, byte[] keyData) throws IOException, GeneralSecurityException {
+    default PrivateKey resolve(SessionContext session, String keyType, byte[] keyData) throws IOException, GeneralSecurityException {
         ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type provided");
         Collection<String> supported = getSupportedTypeNames();
         if ((GenericUtils.size(supported) > 0) && supported.contains(keyType)) {
-            return decodePrivateKey(FilePasswordProvider.EMPTY, keyData);
+            return decodePrivateKey(session, FilePasswordProvider.EMPTY, keyData);
         }
 
         throw new InvalidKeySpecException("resolve(" + keyType + ") not in listed supported types: " + supported);
     }
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param passwordProvider The {@link FilePasswordProvider} to use
      * in case the data is encrypted - may be {@code null} if no encrypted
      * data is expected
@@ -65,24 +68,27 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
      * @throws IOException              If failed to decode the key
      * @throws GeneralSecurityException If failed to generate the key
      */
-    default PRV decodePrivateKey(FilePasswordProvider passwordProvider, byte... keyData)
-            throws IOException, GeneralSecurityException {
-        return decodePrivateKey(passwordProvider, keyData, 0, NumberUtils.length(keyData));
+    default PRV decodePrivateKey(
+            SessionContext session, FilePasswordProvider passwordProvider, byte... keyData)
+                throws IOException, GeneralSecurityException {
+        return decodePrivateKey(session, passwordProvider, keyData, 0, NumberUtils.length(keyData));
     }
 
-    default PRV decodePrivateKey(FilePasswordProvider passwordProvider, byte[] keyData, int offset, int length)
-            throws IOException, GeneralSecurityException {
+    default PRV decodePrivateKey(
+            SessionContext session, FilePasswordProvider passwordProvider, byte[] keyData, int offset, int length)
+                throws IOException, GeneralSecurityException {
         if (length <= 0) {
             return null;
         }
 
         try (InputStream stream = new ByteArrayInputStream(keyData, offset, length)) {
-            return decodePrivateKey(passwordProvider, stream);
+            return decodePrivateKey(session, passwordProvider, stream);
         }
     }
 
-    default PRV decodePrivateKey(FilePasswordProvider passwordProvider, InputStream keyData)
-            throws IOException, GeneralSecurityException {
+    default PRV decodePrivateKey(
+            SessionContext session, FilePasswordProvider passwordProvider, InputStream keyData)
+                throws IOException, GeneralSecurityException {
         // the actual data is preceded by a string that repeats the key type
         String type = KeyEntryResolver.decodeString(keyData, KeyPairResourceLoader.MAX_KEY_TYPE_NAME_LENGTH);
         if (GenericUtils.isEmpty(type)) {
@@ -94,10 +100,12 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
             throw new InvalidKeySpecException("Reported key type (" + type + ") not in supported list: " + supported);
         }
 
-        return decodePrivateKey(type, passwordProvider, keyData);
+        return decodePrivateKey(session, type, passwordProvider, keyData);
     }
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param keyType The reported / encode key type
      * @param passwordProvider The {@link FilePasswordProvider} to use
      * in case the data is encrypted - may be {@code null} if no encrypted
@@ -108,7 +116,8 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
      * @throws IOException              If failed to read from the data stream
      * @throws GeneralSecurityException If failed to generate the key
      */
-    PRV decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
+    PRV decodePrivateKey(
+        SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException;
 
     /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryResolver.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryResolver.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryResolver.java
index 1e4c91e..581bef7 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryResolver.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryResolver.java
@@ -24,6 +24,8 @@ import java.security.GeneralSecurityException;
 import java.security.PrivateKey;
 import java.security.spec.InvalidKeySpecException;
 
+import org.apache.sshd.common.session.SessionContext;
+
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
@@ -34,7 +36,8 @@ public interface PrivateKeyEntryResolver {
      */
     PrivateKeyEntryResolver IGNORING = new PrivateKeyEntryResolver() {
         @Override
-        public PrivateKey resolve(String keyType, byte[] keyData) throws IOException, GeneralSecurityException {
+        public PrivateKey resolve(SessionContext session, String keyType, byte[] keyData)
+                throws IOException, GeneralSecurityException {
             return null;
         }
 
@@ -49,7 +52,8 @@ public interface PrivateKeyEntryResolver {
      */
     PrivateKeyEntryResolver FAILING = new PrivateKeyEntryResolver() {
         @Override
-        public PrivateKey resolve(String keyType, byte[] keyData) throws IOException, GeneralSecurityException {
+        public PrivateKey resolve(SessionContext session, String keyType, byte[] keyData)
+                throws IOException, GeneralSecurityException {
             throw new InvalidKeySpecException("Failing resolver on key type=" + keyType);
         }
 
@@ -60,11 +64,14 @@ public interface PrivateKeyEntryResolver {
     };
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param keyType The {@code OpenSSH} reported key type
      * @param keyData The {@code OpenSSH} encoded key data
      * @return The extracted {@link PrivateKey} - ignored if {@code null}
      * @throws IOException If failed to parse the key data
      * @throws GeneralSecurityException If failed to generate the key
      */
-    PrivateKey resolve(String keyType, byte[] keyData) throws IOException, GeneralSecurityException;
+    PrivateKey resolve(SessionContext session, String keyType, byte[] keyData)
+        throws IOException, GeneralSecurityException;
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractKeyPairResourceParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractKeyPairResourceParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractKeyPairResourceParser.java
index e9ad24e..0b69906 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractKeyPairResourceParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractKeyPairResourceParser.java
@@ -34,6 +34,7 @@ import java.util.Map;
 import java.util.logging.Level;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.BufferUtils;
@@ -84,8 +85,9 @@ public abstract class AbstractKeyPairResourceParser extends AbstractLoggingBean
     }
 
     @Override
-    public Collection<KeyPair> loadKeyPairs(String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
-            throws IOException, GeneralSecurityException {
+    public Collection<KeyPair> loadKeyPairs(
+            SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
+                throws IOException, GeneralSecurityException {
         Collection<KeyPair> keyPairs = Collections.emptyList();
         List<String> beginMarkers = getBeginners();
         List<List<String>> endMarkers = getEndingMarkers();
@@ -103,8 +105,8 @@ public abstract class AbstractKeyPairResourceParser extends AbstractLoggingBean
 
             int endIndex = markerPos.getKey();
             String endLine = lines.get(endIndex);
-            Collection<KeyPair> kps =
-                extractKeyPairs(resourceKey, startLine, endLine, passwordProvider, lines.subList(startIndex, endIndex));
+            Collection<KeyPair> kps = extractKeyPairs(session, resourceKey,
+                startLine, endLine, passwordProvider, lines.subList(startIndex, endIndex));
             if (GenericUtils.isNotEmpty(kps)) {
                 if (GenericUtils.isEmpty(keyPairs)) {
                     keyPairs = new LinkedList<>(kps);
@@ -124,6 +126,8 @@ public abstract class AbstractKeyPairResourceParser extends AbstractLoggingBean
      * Extracts the key pairs within a <U>single</U> delimited by markers block of lines. By
      * default cleans up the empty lines, joins them and converts them from BASE64
      *
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param resourceKey A hint as to the origin of the text lines
      * @param beginMarker The line containing the begin marker
      * @param endMarker The line containing the end marker
@@ -136,12 +140,17 @@ public abstract class AbstractKeyPairResourceParser extends AbstractLoggingBean
      * @see #extractKeyPairs(String, String, String, FilePasswordProvider, byte[])
      */
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, List<String> lines)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            List<String> lines)
                 throws IOException, GeneralSecurityException {
-        return extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, KeyPairResourceParser.extractDataBytes(lines));
+        return extractKeyPairs(session, resourceKey, beginMarker, endMarker, passwordProvider, KeyPairResourceParser.extractDataBytes(lines));
     }
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param resourceKey A hint as to the origin of the text lines
      * @param beginMarker The line containing the begin marker
      * @param endMarker The line containing the end marker
@@ -154,18 +163,23 @@ public abstract class AbstractKeyPairResourceParser extends AbstractLoggingBean
      * @see #extractKeyPairs(String, String, String, FilePasswordProvider, InputStream)
      */
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, byte[] bytes)
-                    throws IOException, GeneralSecurityException {
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            byte[] bytes)
+                throws IOException, GeneralSecurityException {
         if (log.isTraceEnabled()) {
             BufferUtils.dumpHex(getSimplifiedLogger(), Level.FINER, beginMarker, ':', 16, bytes);
         }
 
         try (InputStream bais = new ByteArrayInputStream(bytes)) {
-            return extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, bais);
+            return extractKeyPairs(session, resourceKey, beginMarker, endMarker, passwordProvider, bais);
         }
     }
 
     /**
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param resourceKey A hint as to the origin of the text lines
      * @param beginMarker The line containing the begin marker
      * @param endMarker The line containing the end marker
@@ -177,6 +191,8 @@ public abstract class AbstractKeyPairResourceParser extends AbstractLoggingBean
      * @throws GeneralSecurityException If failed to generate the keys
      */
     public abstract Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream)
-                    throws IOException, GeneralSecurityException;
+        SessionContext session, String resourceKey,
+        String beginMarker, String endMarker,
+        FilePasswordProvider passwordProvider, InputStream stream)
+            throws IOException, GeneralSecurityException;
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceLoader.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceLoader.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceLoader.java
index 00c53cf..5bf2597 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceLoader.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceLoader.java
@@ -39,6 +39,7 @@ import java.util.List;
 import java.util.Objects;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.io.IoUtils;
 
 /**
@@ -57,74 +58,95 @@ public interface KeyPairResourceLoader {
     /**
      * An empty loader that never fails but always returns an empty list
      */
-    KeyPairResourceLoader EMPTY = (resourceKey, passwordProvider, lines) -> Collections.emptyList();
+    KeyPairResourceLoader EMPTY = (session, resourceKey, passwordProvider, lines) -> Collections.emptyList();
 
+    /**
+     * Loads private key data - <B>Note:</B> any non-ASCII characters are assumed to be UTF-8 encoded
+     *
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
+     * @param path The private key file {@link Path}
+     * @param passwordProvider The {@link FilePasswordProvider} to use
+     * in case the data is encrypted - may be {@code null} if no encrypted
+     * data is expected
+     * @param options The {@link OpenOption}-s to use to access the file data
+     * @return The extracted {@link KeyPair}s - may be {@code null}/empty if none.
+     * <B>Note:</B> the resource loader may decide to skip unknown lines if
+     * more than one key pair type is encoded in it
+     * @throws IOException If failed to process the lines
+     * @throws GeneralSecurityException If failed to generate the keys from the
+     * parsed data
+     */
     default Collection<KeyPair> loadKeyPairs(
-            Path path, FilePasswordProvider passwordProvider, OpenOption... options)
+            SessionContext session, Path path, FilePasswordProvider passwordProvider, OpenOption... options)
                 throws IOException, GeneralSecurityException {
-        return loadKeyPairs(path, passwordProvider, StandardCharsets.UTF_8, options);
+        return loadKeyPairs(session, path, passwordProvider, StandardCharsets.UTF_8, options);
     }
 
     default Collection<KeyPair> loadKeyPairs(
-            Path path, FilePasswordProvider passwordProvider, Charset cs, OpenOption... options)
+            SessionContext session, Path path, FilePasswordProvider passwordProvider, Charset cs, OpenOption... options)
                 throws IOException, GeneralSecurityException {
         try (InputStream stream = Files.newInputStream(path, options)) {
-            return loadKeyPairs(path.toString(), passwordProvider, stream, cs);
+            return loadKeyPairs(session, path.toString(), passwordProvider, stream, cs);
         }
     }
 
-    default Collection<KeyPair> loadKeyPairs(URL url, FilePasswordProvider passwordProvider)
-            throws IOException, GeneralSecurityException {
-        return loadKeyPairs(url, passwordProvider, StandardCharsets.UTF_8);
+    default Collection<KeyPair> loadKeyPairs(
+            SessionContext session, URL url, FilePasswordProvider passwordProvider)
+                throws IOException, GeneralSecurityException {
+        return loadKeyPairs(session, url, passwordProvider, StandardCharsets.UTF_8);
     }
 
-    default Collection<KeyPair> loadKeyPairs(URL url, FilePasswordProvider passwordProvider, Charset cs)
-            throws IOException, GeneralSecurityException {
+    default Collection<KeyPair> loadKeyPairs(
+            SessionContext session, URL url, FilePasswordProvider passwordProvider, Charset cs)
+                throws IOException, GeneralSecurityException {
         try (InputStream stream = Objects.requireNonNull(url, "No URL").openStream()) {
-            return loadKeyPairs(url.toExternalForm(), passwordProvider, stream, cs);
+            return loadKeyPairs(session, url.toExternalForm(), passwordProvider, stream, cs);
         }
     }
 
     default Collection<KeyPair> loadKeyPairs(
-            String resourceKey, FilePasswordProvider passwordProvider, String data)
+            SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, String data)
                 throws IOException, GeneralSecurityException {
         try (Reader reader = new StringReader((data == null) ? "" : data)) {
-            return loadKeyPairs(resourceKey, passwordProvider, reader);
+            return loadKeyPairs(session, resourceKey, passwordProvider, reader);
         }
     }
 
     default Collection<KeyPair> loadKeyPairs(
-            String resourceKey, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, InputStream stream)
                 throws IOException, GeneralSecurityException {
-        return loadKeyPairs(resourceKey, passwordProvider, stream, StandardCharsets.UTF_8);
+        return loadKeyPairs(session, resourceKey, passwordProvider, stream, StandardCharsets.UTF_8);
     }
 
     default Collection<KeyPair> loadKeyPairs(
-            String resourceKey, FilePasswordProvider passwordProvider, InputStream stream, Charset cs)
+            SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, InputStream stream, Charset cs)
                 throws IOException, GeneralSecurityException {
         try (Reader reader = new InputStreamReader(
                 Objects.requireNonNull(stream, "No stream instance"), Objects.requireNonNull(cs, "No charset"))) {
-            return loadKeyPairs(resourceKey, passwordProvider, reader);
+            return loadKeyPairs(session, resourceKey, passwordProvider, reader);
         }
     }
 
     default Collection<KeyPair> loadKeyPairs(
-            String resourceKey, FilePasswordProvider passwordProvider, Reader r)
+            SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, Reader r)
                 throws IOException, GeneralSecurityException {
         try (BufferedReader br = new BufferedReader(Objects.requireNonNull(r, "No reader instance"), IoUtils.DEFAULT_COPY_SIZE)) {
-            return loadKeyPairs(resourceKey, passwordProvider, br);
+            return loadKeyPairs(session, resourceKey, passwordProvider, br);
         }
     }
 
     default Collection<KeyPair> loadKeyPairs(
-            String resourceKey, FilePasswordProvider passwordProvider, BufferedReader r)
+            SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, BufferedReader r)
                 throws IOException, GeneralSecurityException {
-        return loadKeyPairs(resourceKey, passwordProvider, IoUtils.readAllLines(r));
+        return loadKeyPairs(session, resourceKey, passwordProvider, IoUtils.readAllLines(r));
     }
 
     /**
      * Loads key pairs from the given resource text lines
      *
+     * @param session The {@link SessionContext} for invoking this load command - may
+     * be {@code null} if not invoked within a session context (e.g., offline tool or session unknown).
      * @param resourceKey A hint as to the origin of the text lines
      * @param passwordProvider The {@link FilePasswordProvider} to use
      * in case the data is encrypted - may be {@code null} if no encrypted
@@ -137,6 +159,7 @@ public interface KeyPairResourceLoader {
      * @throws GeneralSecurityException If failed to generate the keys from the
      * parsed data
      */
-    Collection<KeyPair> loadKeyPairs(String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
+    Collection<KeyPair> loadKeyPairs(
+        SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
             throws IOException, GeneralSecurityException;
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceParser.java
index f7e336a..c434f0a 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/KeyPairResourceParser.java
@@ -31,6 +31,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 
@@ -45,7 +46,7 @@ public interface KeyPairResourceParser extends KeyPairResourceLoader {
     KeyPairResourceParser EMPTY = new KeyPairResourceParser() {
         @Override
         public Collection<KeyPair> loadKeyPairs(
-                String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
+                SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
                     throws IOException, GeneralSecurityException {
             return Collections.emptyList();
         }
@@ -153,7 +154,7 @@ public interface KeyPairResourceParser extends KeyPairResourceLoader {
         return new KeyPairResourceParser() {
             @Override
             public Collection<KeyPair> loadKeyPairs(
-                    String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
+                    SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
                         throws IOException, GeneralSecurityException {
                 Collection<KeyPair> keyPairs = Collections.emptyList();
                 for (KeyPairResourceParser p : parsers) {
@@ -161,7 +162,7 @@ public interface KeyPairResourceParser extends KeyPairResourceLoader {
                         continue;
                     }
 
-                    Collection<KeyPair> kps = p.loadKeyPairs(resourceKey, passwordProvider, lines);
+                    Collection<KeyPair> kps = p.loadKeyPairs(session, resourceKey, passwordProvider, lines);
                     if (GenericUtils.isEmpty(kps)) {
                         continue;
                     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
index 6188a04..fc87175 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
@@ -41,6 +41,7 @@ import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
@@ -54,8 +55,9 @@ public class OpenSSHDSSPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDec
     }
 
     @Override
-    public DSAPrivateKey decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
-            throws IOException, GeneralSecurityException {
+    public DSAPrivateKey decodePrivateKey(
+            SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
+                throws IOException, GeneralSecurityException {
         if (!KeyPairProvider.SSH_DSS.equals(keyType)) { // just in case we were invoked directly
             throw new InvalidKeySpecException("Unexpected key type: " + keyType);
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
index 83a0fb3..dfe01f6 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
@@ -43,6 +43,7 @@ import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder;
 import org.apache.sshd.common.config.keys.impl.ECDSAPublicKeyEntryDecoder;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
@@ -56,8 +57,9 @@ public class OpenSSHECDSAPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryD
     }
 
     @Override
-    public ECPrivateKey decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
-            throws IOException, GeneralSecurityException {
+    public ECPrivateKey decodePrivateKey(
+            SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
+                throws IOException, GeneralSecurityException {
         ECCurves curve = ECCurves.fromKeyType(keyType);
         if (curve == null) {
             throw new InvalidKeySpecException("Not an EC curve name: " + keyType);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
index d531021..c82957d 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
@@ -48,6 +48,7 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
 import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder;
 import org.apache.sshd.common.config.keys.loader.AbstractKeyPairResourceParser;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.BufferUtils;
@@ -98,9 +99,12 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
 
     @Override
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            InputStream stream)
                 throws IOException, GeneralSecurityException {
-        stream = validateStreamMagicMarker(resourceKey, stream);
+        stream = validateStreamMagicMarker(session, resourceKey, stream);
 
         String cipher = KeyEntryResolver.decodeString(stream, MAX_CIPHER_NAME_LENGTH);
         if (!OpenSSHParserContext.IS_NONE_CIPHER.test(cipher)) {
@@ -135,7 +139,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
         OpenSSHParserContext context = new OpenSSHParserContext(cipher, kdfName, kdfOptions);
         boolean traceEnabled = log.isTraceEnabled();
         for (int index = 1; index <= numKeys; index++) {
-            PublicKey pubKey = readPublicKey(resourceKey, context, stream);
+            PublicKey pubKey = readPublicKey(session, resourceKey, context, stream);
             ValidateUtils.checkNotNull(pubKey, "Empty public key #%d in %s", index, resourceKey);
             if (traceEnabled) {
                 log.trace("extractKeyPairs({}) read public key #{}: {} {}",
@@ -146,13 +150,13 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
 
         byte[] privateData = KeyEntryResolver.readRLEBytes(stream, MAX_PRIVATE_KEY_DATA_SIZE);
         try (InputStream bais = new ByteArrayInputStream(privateData)) {
-            return readPrivateKeys(resourceKey, context, publicKeys, passwordProvider, bais);
+            return readPrivateKeys(session, resourceKey, context, publicKeys, passwordProvider, bais);
         }
     }
 
     protected PublicKey readPublicKey(
-            String resourceKey, OpenSSHParserContext context, InputStream stream)
-                    throws IOException, GeneralSecurityException {
+            SessionContext session, String resourceKey, OpenSSHParserContext context, InputStream stream)
+                throws IOException, GeneralSecurityException {
         byte[] keyData = KeyEntryResolver.readRLEBytes(stream, MAX_PUBLIC_KEY_DATA_SIZE);
         try (InputStream bais = new ByteArrayInputStream(keyData)) {
             String keyType = KeyEntryResolver.decodeString(bais, MAX_KEY_TYPE_NAME_LENGTH);
@@ -166,7 +170,8 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
     }
 
     protected List<KeyPair> readPrivateKeys(
-            String resourceKey, OpenSSHParserContext context, Collection<? extends PublicKey> publicKeys,
+            SessionContext session, String resourceKey,
+            OpenSSHParserContext context, Collection<? extends PublicKey> publicKeys,
             FilePasswordProvider passwordProvider, InputStream stream)
                 throws IOException, GeneralSecurityException {
         if (GenericUtils.isEmpty(publicKeys)) {
@@ -190,7 +195,8 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
                     resourceKey, keyIndex, pubType);
             }
 
-            Map.Entry<PrivateKey, String> prvData = readPrivateKey(resourceKey, context, pubType, passwordProvider, stream);
+            Map.Entry<PrivateKey, String> prvData =
+                readPrivateKey(session, resourceKey, context, pubType, passwordProvider, stream);
             PrivateKey prvKey = (prvData == null) ? null : prvData.getKey();
             ValidateUtils.checkNotNull(prvKey, "Empty private key #%d in %s", keyIndex, resourceKey);
 
@@ -210,7 +216,9 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
     }
 
     protected SimpleImmutableEntry<PrivateKey, String> readPrivateKey(
-            String resourceKey, OpenSSHParserContext context, String keyType, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey,
+            OpenSSHParserContext context, String keyType,
+            FilePasswordProvider passwordProvider, InputStream stream)
                 throws IOException, GeneralSecurityException {
         String prvType = KeyEntryResolver.decodeString(stream, MAX_KEY_TYPE_NAME_LENGTH);
         if (!Objects.equals(keyType, prvType)) {
@@ -224,7 +232,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
             throw new NoSuchAlgorithmException("Unsupported key type (" + prvType + ") in " + resourceKey);
         }
 
-        PrivateKey prvKey = decoder.decodePrivateKey(prvType, passwordProvider, stream);
+        PrivateKey prvKey = decoder.decodePrivateKey(session, prvType, passwordProvider, stream);
         if (prvKey == null) {
             throw new InvalidKeyException("Cannot parse key type (" + prvType + ") in " + resourceKey);
         }
@@ -233,7 +241,9 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
         return new SimpleImmutableEntry<>(prvKey, comment);
     }
 
-    protected <S extends InputStream> S validateStreamMagicMarker(String resourceKey, S stream) throws IOException {
+    protected <S extends InputStream> S validateStreamMagicMarker(
+            SessionContext session, String resourceKey, S stream)
+                throws IOException {
         byte[] actual = new byte[AUTH_MAGIC_BYTES.length];
         IoUtils.readFully(stream, actual);
         if (!Arrays.equals(AUTH_MAGIC_BYTES, actual)) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
index 72e003f..b77257d 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
@@ -41,6 +41,7 @@ import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
@@ -55,8 +56,9 @@ public class OpenSSHRSAPrivateKeyDecoder extends AbstractPrivateKeyEntryDecoder<
     }
 
     @Override
-    public RSAPrivateKey decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
-            throws IOException, GeneralSecurityException {
+    public RSAPrivateKey decodePrivateKey(
+            SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
+                throws IOException, GeneralSecurityException {
         if (!KeyPairProvider.SSH_RSA.equals(keyType)) { // just in case we were invoked directly
             throw new InvalidKeySpecException("Unexpected key type: " + keyType);
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java
index 6ac9e2f..a324339 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java
@@ -39,6 +39,7 @@ import org.apache.sshd.common.config.keys.loader.AbstractKeyPairResourceParser;
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
 import org.apache.sshd.common.config.keys.loader.PrivateKeyEncryptionContext;
 import org.apache.sshd.common.config.keys.loader.PrivateKeyObfuscator;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.BufferUtils;
@@ -73,7 +74,10 @@ public abstract class AbstractPEMResourceKeyPairParser
 
     @Override
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, List<String> lines)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            List<String> lines)
                 throws IOException, GeneralSecurityException {
         if (GenericUtils.isEmpty(lines)) {
             return Collections.emptyList();
@@ -133,7 +137,7 @@ public abstract class AbstractPEMResourceKeyPairParser
             }
 
             for (int retryIndex = 0;; retryIndex++) {
-                String password = passwordProvider.getPassword(resourceKey, retryIndex);
+                String password = passwordProvider.getPassword(session, resourceKey, retryIndex);
                 Collection<KeyPair> keys;
                 try {
                     if (GenericUtils.isEmpty(password)) {
@@ -146,11 +150,11 @@ public abstract class AbstractPEMResourceKeyPairParser
                     byte[] encryptedData = KeyPairResourceParser.extractDataBytes(dataLines);
                     byte[] decodedData = applyPrivateKeyCipher(encryptedData, encContext, false);
                     try (InputStream bais = new ByteArrayInputStream(decodedData)) {
-                        keys = extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, bais);
+                        keys = extractKeyPairs(session, resourceKey, beginMarker, endMarker, passwordProvider, bais);
                     }
                 } catch (IOException | GeneralSecurityException | RuntimeException e) {
                     ResourceDecodeResult result =
-                        passwordProvider.handleDecodeAttemptResult(resourceKey, retryIndex, password, e);
+                        passwordProvider.handleDecodeAttemptResult(session, resourceKey, retryIndex, password, e);
                     if (result == null) {
                         result = ResourceDecodeResult.TERMINATE;
                     }
@@ -166,12 +170,12 @@ public abstract class AbstractPEMResourceKeyPairParser
                     }
                 }
 
-                passwordProvider.handleDecodeAttemptResult(resourceKey, retryIndex, password, null);
+                passwordProvider.handleDecodeAttemptResult(session, resourceKey, retryIndex, password, null);
                 return keys;
             }
         }
 
-        return super.extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, dataLines);
+        return super.extractKeyPairs(session, resourceKey, beginMarker, endMarker, passwordProvider, dataLines);
     }
 
     protected byte[] applyPrivateKeyCipher(

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java
index c68a815..39c84a6 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java
@@ -36,6 +36,7 @@ import java.util.List;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
 import org.apache.sshd.common.util.io.der.ASN1Object;
 import org.apache.sshd.common.util.io.der.ASN1Type;
@@ -68,7 +69,10 @@ public class DSSPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairParse
 
     @Override
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            InputStream stream)
                 throws IOException, GeneralSecurityException {
         KeyPair kp = decodeDSSKeyPair(SecurityUtils.getKeyFactory(KeyUtils.DSS_ALGORITHM), stream, false);
         return Collections.singletonList(kp);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
index 768c30f..19c15e2 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
@@ -41,6 +41,7 @@ import java.util.Map;
 import org.apache.sshd.common.cipher.ECCurves;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
 import org.apache.sshd.common.util.io.der.ASN1Object;
 import org.apache.sshd.common.util.io.der.ASN1Type;
@@ -72,7 +73,10 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
 
     @Override
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            InputStream stream)
                 throws IOException, GeneralSecurityException {
         Map.Entry<ECPublicKeySpec, ECPrivateKeySpec> spec = decodeECPrivateKeySpec(stream, false);
         if (!SecurityUtils.isECCSupported()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java
index b6749da..d3aba1e 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java
@@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 
@@ -43,11 +44,11 @@ public final class PEMResourceParserUtils {
     public static final KeyPairResourceParser PROXY = new KeyPairResourceParser() {
         @Override
         public Collection<KeyPair> loadKeyPairs(
-                String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
-                        throws IOException, GeneralSecurityException {
+                SessionContext session, String resourceKey, FilePasswordProvider passwordProvider, List<String> lines)
+                    throws IOException, GeneralSecurityException {
             @SuppressWarnings("synthetic-access")
             KeyPairResourceParser proxy = PROXY_HOLDER.get();
-            return (proxy == null) ? Collections.<KeyPair>emptyList() : proxy.loadKeyPairs(resourceKey, passwordProvider, lines);
+            return (proxy == null) ? Collections.emptyList() : proxy.loadKeyPairs(session, resourceKey, passwordProvider, lines);
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
index 1967719..90f033b 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
@@ -35,6 +35,7 @@ import java.util.List;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.IoUtils;
@@ -65,27 +66,28 @@ public class PKCS8PEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
 
     @Override
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            InputStream stream)
                 throws IOException, GeneralSecurityException {
         // Save the data before getting the algorithm OID since we will need it
         byte[] encBytes = IoUtils.toByteArray(stream);
         List<Integer> oidAlgorithm = getPKCS8AlgorithmIdentifier(encBytes);
-        PrivateKey prvKey = decodePEMPrivateKeyPKCS8(oidAlgorithm, encBytes, passwordProvider);
+        PrivateKey prvKey = decodePEMPrivateKeyPKCS8(oidAlgorithm, encBytes);
         PublicKey pubKey = ValidateUtils.checkNotNull(KeyUtils.recoverPublicKey(prvKey),
                 "Failed to recover public key of OID=%s", oidAlgorithm);
         KeyPair kp = new KeyPair(pubKey, prvKey);
         return Collections.singletonList(kp);
     }
 
-    public static PrivateKey decodePEMPrivateKeyPKCS8(
-            List<Integer> oidAlgorithm, byte[] keyBytes, FilePasswordProvider passwordProvider)
-                throws GeneralSecurityException {
+    public static PrivateKey decodePEMPrivateKeyPKCS8(List<Integer> oidAlgorithm, byte[] keyBytes)
+            throws GeneralSecurityException {
         ValidateUtils.checkNotNullAndNotEmpty(oidAlgorithm, "No PKCS8 algorithm OID");
-        return decodePEMPrivateKeyPKCS8(GenericUtils.join(oidAlgorithm, '.'), keyBytes, passwordProvider);
+        return decodePEMPrivateKeyPKCS8(GenericUtils.join(oidAlgorithm, '.'), keyBytes);
     }
 
-    public static PrivateKey decodePEMPrivateKeyPKCS8(
-            String oid, byte[] keyBytes, FilePasswordProvider passwordProvider)
+    public static PrivateKey decodePEMPrivateKeyPKCS8(String oid, byte[] keyBytes)
                 throws GeneralSecurityException {
         KeyPairPEMResourceParser parser =
             PEMResourceParserUtils.getPEMResourceParserByOid(

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java
index 988c210..8badd63 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java
@@ -37,6 +37,7 @@ import java.util.List;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
 import org.apache.sshd.common.util.io.der.ASN1Object;
 import org.apache.sshd.common.util.io.der.ASN1Type;
@@ -69,7 +70,10 @@ public class RSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairParse
 
     @Override
     public Collection<KeyPair> extractKeyPairs(
-            String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream)
+            SessionContext session, String resourceKey,
+            String beginMarker, String endMarker,
+            FilePasswordProvider passwordProvider,
+            InputStream stream)
                 throws IOException, GeneralSecurityException {
         KeyPair kp = decodeRSAKeyPair(SecurityUtils.getKeyFactory(KeyUtils.RSA_ALGORITHM), stream, false);
         return Collections.singletonList(kp);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
index 194daf5..7fbee1b 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
@@ -166,16 +166,17 @@ public abstract class AbstractResourceKeyPairProvider<R> extends AbstractKeyPair
 
     protected KeyPair doLoadKey(SessionContext session, String resourceKey, R resource, FilePasswordProvider provider)
             throws IOException, GeneralSecurityException {
-        try (InputStream inputStream = openKeyPairResource(resourceKey, resource)) {
+        try (InputStream inputStream = openKeyPairResource(session, resourceKey, resource)) {
             return doLoadKey(session, resourceKey, inputStream, provider);
         }
     }
 
-    protected abstract InputStream openKeyPairResource(String resourceKey, R resource) throws IOException;
+    protected abstract InputStream openKeyPairResource(SessionContext session, String resourceKey, R resource) throws IOException;
 
-    protected KeyPair doLoadKey(SessionContext session, String resourceKey, InputStream inputStream, FilePasswordProvider provider)
-            throws IOException, GeneralSecurityException {
-        return SecurityUtils.loadKeyPairIdentity(resourceKey, inputStream, provider);
+    protected KeyPair doLoadKey(
+            SessionContext session, String resourceKey, InputStream inputStream, FilePasswordProvider provider)
+                throws IOException, GeneralSecurityException {
+        return SecurityUtils.loadKeyPairIdentity(session, resourceKey, inputStream, provider);
     }
 
     protected class KeyPairIterator implements Iterator<KeyPair> {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2b013cca/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java
index 3132abd..54b4e30 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java
@@ -90,7 +90,9 @@ public class ClassLoadableResourceKeyPairProvider extends AbstractResourceKeyPai
     }
 
     @Override
-    protected InputStream openKeyPairResource(String resourceKey, String resource) throws IOException {
+    protected InputStream openKeyPairResource(
+            SessionContext session, String resourceKey, String resource)
+                throws IOException {
         ClassLoader cl = resolveClassLoader();
         if (cl == null) {
             throw new StreamCorruptedException("No resource loader for " + resource);