You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mina.apache.org by "hubick (via GitHub)" <gi...@apache.org> on 2023/06/14 04:28:00 UTC

[GitHub] [mina-sshd] hubick opened a new issue, #391: Allow KnownHostsServerKeyVerifier to read from a resource URL

hubick opened a new issue, #391:
URL: https://github.com/apache/mina-sshd/issues/391

   ### Description
   
   Hi,
   
   Currently all `KnownHostsServerKeyVerifier` constructors accept a `java.nio.file.Path` argument to the `known_hosts` file. I would like to request the addition of an additional constructor which accepts a `java.net.URL` argument, as returned by `java.lang.Class.getResource(String)`, and potentially points to a `known_hosts` file which exists as a resource inside a jar file.
   
   ### Motivation
   
   I have a Java application which uses SSH to connect to a number of internal servers within our organization. I am replacing the invocation of the system provided Open SSH with mina-sshd bundled with the application, allowing it to run out-of-the-box on platforms like Windows (developer workstations), or within vanilla container environments that would not normally come with SSH installed (ex: a Tomcat container).
   
   However, OpenSSH still makes for a quick and user friendly tool for building and maintaining a file of known_hosts for our internal servers, a file which can easily be dropped/updated into the project as a resource file. This file is obviously intended to be read-only in this environment.
   
   ### Alternatives considered
   
   I contemplated implementing my own `ServerKeyVerifier`, but `KnownHostsServerKeyVerifier` already has all the logic for reading this format file, iterating through the list, and matching results, etc. I ended up extending `KnownHostsServerKeyVerifier` with my own subclass that accepts a URL, and when it's supplied a `known_hosts` file that's within a jar, calls `KnownHostEntry.readKnownHostEntries(URL)`, does `AuthorizedKeyEntry.resolvePublicKey(null, null)` on each result, and builds it's own static list of `HostEntryPair` values, where it then overrides `checkReloadRequired` to always return `false`, and overrides `reloadKnownHosts` to return it's static list. This hack obviously required some digging to code, and represents a fragile maintenance burden I'd rather not bear long-term.
   
   ### Additional context
   
   Interestingly, I didn't encounter this problem loading the private keys as resources from a jar file, as `KeyPairResourceLoader.loadKeyPairs(SessionContext, URL, FilePasswordProvider)` exists. And it's worth noting you do have `KnownHostEntry.readKnownHostEntries(URL)` already, just not extending that URL functionality to `KnownHostsServerKeyVerifier`.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@mina.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@mina.apache.org
For additional commands, e-mail: dev-help@mina.apache.org


[GitHub] [mina-sshd] hubick commented on issue #391: Allow KnownHostsServerKeyVerifier to read from a resource URL

Posted by "hubick (via GitHub)" <gi...@apache.org>.
hubick commented on issue #391:
URL: https://github.com/apache/mina-sshd/issues/391#issuecomment-1590448048

   ```
       /**
        * Extend KnownHostsServerKeyVerifier to handle the known_hosts file existing as
        * a resource within a jar file.
        */
       protected static class StaticKnownHostsKeyVerifier extends KnownHostsServerKeyVerifier
       {
           protected final List<KnownHostsServerKeyVerifier.HostEntryPair> knownHosts;
   
           public StaticKnownHostsKeyVerifier(final ServerKeyVerifier delegate, final URL knownHostsURL)
                   throws IOException, URISyntaxException
           {
               super(delegate, getWatchedPath(knownHostsURL));
               knownHosts = getPath().endsWith(".jar") ? readKnownHosts(knownHostsURL) : Collections.emptyList();
               return;
           }
   
           /**
            * If known_hosts is inside a jar file, Paths.get() will throw a
            * java.nio.file.FileSystemNotFoundException if fed the resource URI directly,
            * but we need to give the parent class some Path to watch, so in that case,
            * this method will just return the Path to the jar file itself.
            */
           protected static final Path getWatchedPath(final URL knownHostsURL) throws URISyntaxException
           {
               /*
                * In a URL to a jar resource, everything up to the '!' is the path to the jar
                * itself, and everything after the '!' is the path *within* the jar to the
                * resource (known_hosts) file.
                */
               if (knownHostsURL.getPath().indexOf('!') >= 0)
               {
                   final String uri = knownHostsURL.toURI().toString();
                   return Paths.get(uri.substring(0, uri.indexOf('!')));
               }
               return Paths.get(knownHostsURL.toURI()); // URL isn't inside a jar, so just return the actual path.
           }
   
           protected static final List<KnownHostsServerKeyVerifier.HostEntryPair> readKnownHosts(final URL knownHostsURL)
                   throws IOException
           {
               return KnownHostEntry.readKnownHostEntries(knownHostsURL)
                       .stream()
                       .map(knownHost -> {
                           try
                           {
                               return new KnownHostsServerKeyVerifier.HostEntryPair(knownHost,
                                       knownHost.getKeyEntry().resolvePublicKey(null, null));
                           } catch (Exception e)
                           {
                               return null;
                           }
                       })
                       .filter(Objects::nonNull)
                       .collect(Collectors.toList());
           }
   
           @Override
           public boolean checkReloadRequired() throws IOException
           {
               if (getPath().endsWith(".jar"))
                   return false;
               return super.checkReloadRequired();
           }
   
           protected List<KnownHostsServerKeyVerifier.HostEntryPair> reloadKnownHosts(final ClientSession session,
                   final Path file)
                   throws IOException, GeneralSecurityException
           {
               if (getPath().endsWith(".jar"))
                   return knownHosts;
               return super.reloadKnownHosts(session, file);
           }
   
       } // StaticKnownHostsKeyVerifier
   
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@mina.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@mina.apache.org
For additional commands, e-mail: dev-help@mina.apache.org