Class OpenSshConfigFile

  • All Implemented Interfaces:
    SshConfigStore

    public class OpenSshConfigFile
    extends java.lang.Object
    implements SshConfigStore
    Fairly complete configuration parser for the openssh ~/.ssh/config file.

    Both JSch 0.1.54 and Apache MINA sshd 2.1.0 have parsers for this, but both are buggy. Therefore we implement our own parser to read an openssh configuration file.

    Limitations compared to the full openssh 7.5 parser:

    • This parser does not handle Match or Include keywords.
    • This parser does not do host name canonicalization.

    Note that openssh's readconf.c is a validating parser; this parser does not validate entries.

    This config does %-substitutions for the following tokens:

    • %% - single %
    • %C - short-hand for %l%h%p%r.
    • %d - home directory path
    • %h - remote host name
    • %L - local host name without domain
    • %l - FQDN of the local host
    • %n - host name as specified in lookup(String, int, String)
    • %p - port number; if not given in lookup(String, int, String) replaced only if set in the config
    • %r - remote user name; if not given in lookup(String, int, String) replaced only if set in the config
    • %u - local user name

    %i is not handled; Java has no concept of a "user ID". %T is always replaced by NONE.

    See Also:
    man ssh-config
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private java.io.File configFile
      The .ssh/config file we read and monitor for updates.
      private java.io.File home
      The user's home directory, as key files may be relative to here.
      private java.time.Instant lastModified
      Modification time of configFile when it was last loaded.
      private java.lang.String localUserName
      User name of the user on the host OS.
      private OpenSshConfigFile.State state
      State read from the config file, plus the cache.
    • Constructor Summary

      Constructors 
      Constructor Description
      OpenSshConfigFile​(java.io.File home, java.io.File config, java.lang.String localUserName)
      Creates a new OpenSshConfigFile that will read the config from file config use the given file home as "home" directory.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static boolean flag​(java.lang.String value)
      Converts a ssh config flag value (yes/true/on - no/false/off) into an boolean.
      java.lang.String getLocalUserName()
      Retrieves the local user name as given in the constructor.
      OpenSshConfigFile.HostEntry lookup​(java.lang.String hostName, int port, java.lang.String userName)
      Locate the configuration for a specific host request.
      private OpenSshConfigFile.HostEntry lookup​(java.lang.String hostName, int port, java.lang.String userName, boolean fillDefaults)  
      OpenSshConfigFile.HostEntry lookupDefault​(java.lang.String hostName, int port, java.lang.String userName)
      Locate the configuration for a specific host request and if the configuration has no values for SshConstants.HOST_NAME, SshConstants.PORT, SshConstants.USER, or SshConstants.CONNECTION_ATTEMPTS, fill those values with defaults from the arguments: ssh config key value from argument HostName hostName Port port > 0 ? port : 22 User userName ConnectionAttempts 1
      private java.util.List<OpenSshConfigFile.HostEntry> parse​(java.io.BufferedReader reader)  
      private static java.util.List<java.lang.String> parseList​(java.lang.String argument)
      Splits the argument into a list of whitespace-separated elements.
      private static int parseToken​(java.lang.String argument, int from, int to, java.util.List<java.lang.String> result)
      Parses a token up to the next whitespace not inside a string quoted by single or double quotes.
      private static boolean patternMatchesHost​(java.lang.String pattern, java.lang.String name)  
      static int positive​(java.lang.String value)
      Converts a positive value into an int.
      private OpenSshConfigFile.State refresh()  
      private static java.lang.String stripWhitespace​(java.lang.String value)  
      static int timeSpec​(java.lang.String value)
      Converts an OpenSSH time value into a number of seconds.
      private java.lang.String toCacheKey​(java.lang.String hostName, int port, java.lang.String userName)  
      private static java.io.File toFile​(java.lang.String path, java.io.File home)  
      java.lang.String toString()
      protected java.lang.String validate​(java.lang.String key, java.lang.String value)
      Hook to perform validation on a single value, or to sanitize it.
      protected java.util.List<java.lang.String> validate​(java.lang.String key, java.util.List<java.lang.String> value)
      Hook to perform validation on values, or to sanitize them.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
    • Field Detail

      • home

        private final java.io.File home
        The user's home directory, as key files may be relative to here.
      • configFile

        private final java.io.File configFile
        The .ssh/config file we read and monitor for updates.
      • localUserName

        private final java.lang.String localUserName
        User name of the user on the host OS.
      • lastModified

        private java.time.Instant lastModified
        Modification time of configFile when it was last loaded.
    • Constructor Detail

      • OpenSshConfigFile

        public OpenSshConfigFile​(@NonNull
                                 java.io.File home,
                                 @NonNull
                                 java.io.File config,
                                 @NonNull
                                 java.lang.String localUserName)
        Creates a new OpenSshConfigFile that will read the config from file config use the given file home as "home" directory.
        Parameters:
        home - user's home directory for the purpose of ~ replacement
        config - file to load.
        localUserName - user name of the current user on the local host OS
    • Method Detail

      • lookup

        @NonNull
        public OpenSshConfigFile.HostEntry lookup​(@NonNull
                                                  java.lang.String hostName,
                                                  int port,
                                                  java.lang.String userName)
        Locate the configuration for a specific host request.
        Specified by:
        lookup in interface SshConfigStore
        Parameters:
        hostName - the name the user has supplied to the SSH tool. This may be a real host name, or it may just be a "Host" block in the configuration file.
        port - the user supplied; <= 0 if none
        userName - the user supplied, may be null or empty if none given
        Returns:
        the configuration for the requested name.
      • toCacheKey

        @NonNull
        private java.lang.String toCacheKey​(@NonNull
                                            java.lang.String hostName,
                                            int port,
                                            java.lang.String userName)
      • parse

        private java.util.List<OpenSshConfigFile.HostEntry> parse​(java.io.BufferedReader reader)
                                                           throws java.io.IOException
        Throws:
        java.io.IOException
      • parseList

        private static java.util.List<java.lang.String> parseList​(java.lang.String argument)
        Splits the argument into a list of whitespace-separated elements. Elements containing whitespace must be quoted and will be de-quoted. Backslash-escapes are handled for quotes and blanks.
        Parameters:
        argument - argument part of the configuration line as read from the config file
        Returns:
        a List of elements, possibly empty and possibly containing empty elements, but not containing null
      • parseToken

        private static int parseToken​(java.lang.String argument,
                                      int from,
                                      int to,
                                      java.util.List<java.lang.String> result)
        Parses a token up to the next whitespace not inside a string quoted by single or double quotes. Inside a string, quotes can be escaped by backslash characters. Outside of a string, "\ " can be used to include a space in a token; inside a string "\ " is taken literally as '\' followed by ' '.
        Parameters:
        argument - to parse the token out of
        from - index at the beginning of the token
        to - index one after the last character to look at
        result - a list collecting tokens to which the parsed token is added
        Returns:
        the index after the token
      • validate

        protected java.lang.String validate​(java.lang.String key,
                                            java.lang.String value)
        Hook to perform validation on a single value, or to sanitize it. If this throws an (unchecked) exception, parsing of the file is abandoned.
        Parameters:
        key - of the entry
        value - as read from the config file
        Returns:
        the validated and possibly sanitized value
      • validate

        protected java.util.List<java.lang.String> validate​(java.lang.String key,
                                                            java.util.List<java.lang.String> value)
        Hook to perform validation on values, or to sanitize them. If this throws an (unchecked) exception, parsing of the file is abandoned.
        Parameters:
        key - of the entry
        value - list of arguments as read from the config file
        Returns:
        a List of values, possibly empty and possibly containing empty elements, but not containing null
      • patternMatchesHost

        private static boolean patternMatchesHost​(java.lang.String pattern,
                                                  java.lang.String name)
      • stripWhitespace

        private static java.lang.String stripWhitespace​(java.lang.String value)
      • toFile

        private static java.io.File toFile​(java.lang.String path,
                                           java.io.File home)
      • positive

        public static int positive​(java.lang.String value)
        Converts a positive value into an int.
        Parameters:
        value - to convert
        Returns:
        the value, or -1 if it wasn't a positive integral value
      • flag

        public static boolean flag​(java.lang.String value)
        Converts a ssh config flag value (yes/true/on - no/false/off) into an boolean.
        Parameters:
        value - to convert
        Returns:
        true if value is "yes", "on", or "true"; false otherwise
      • timeSpec

        public static int timeSpec​(java.lang.String value)
        Converts an OpenSSH time value into a number of seconds. The format is defined by OpenSSH as a sequence of (positive) integers with suffixes for seconds, minutes, hours, days, and weeks.
        Parameters:
        value - to convert
        Returns:
        the parsed value as a number of seconds, or -1 if the value is not a valid OpenSSH time value
        See Also:
        OpenBSD man 5 sshd_config, section TIME FORMATS
      • getLocalUserName

        public java.lang.String getLocalUserName()
        Retrieves the local user name as given in the constructor.
        Returns:
        the user name
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object