Esempio n. 1
0
 def test_BadHostKeyException(self):
     got_key = RSAKey.generate(2048)
     wanted_key = RSAKey.generate(2048)
     exc = BadHostKeyException("myhost", got_key, wanted_key)
     expected = "Host key for server 'myhost' does not match: got '{}', expected '{}'"  # noqa
     assert str(exc) == expected.format(got_key.get_base64(),
                                        wanted_key.get_base64())
Esempio n. 2
0
 def test_open_connection_badhostkey_exception(self, mock_rsa, sshClient):
     got_key = pkey.PKey("sadad")
     expected_key = pkey.PKey("sadadaa")
     sshClient.return_value.connect = Mock(
         side_effect=BadHostKeyException(
             self.hostname, got_key, expected_key))
     configurator = ssh_utilities.RemoteConnection(
         self.hostname, user=self.user, passwd=self.passwd,
         priv_key_file=self.priv_key_file)
     self.assertRaises(BadHostKeyException, configurator.open_connection)
Esempio n. 3
0
    def connect(self, ssh=None):
        """Connects the ssh instance.

        If :param:`ssh` is not provided will connect `self.ssh`.
        """
        ssh = ssh if ssh else self.ssh
        ssh.load_system_host_keys()
        if self.trusted_host:
            ssh.set_missing_host_key_policy(AutoAddPolicy())
        while True:
            try:
                ssh.connect(
                    self.hostname,
                    username=self.remote_user,
                    timeout=self.timeout,
                    compress=True,
                )
                print('Connected to host {}. '.format(self.hostname))
                break
            except (socket.timeout, ConnectionRefusedError) as e:
                print('{}. {} for {}@{}. Retrying ...'.format(
                    timezone.now(), str(e), self.remote_user, self.hostname))
                time.sleep(5)
            except AuthenticationException as e:
                raise AuthenticationException('Got {} for user {}@{}'.format(
                    str(e)[0:-1], self.remote_user, self.hostname))
            except BadHostKeyException as e:
                raise BadHostKeyException(
                    'Add server to known_hosts on host {}.'
                    ' Got {}.'.format(e, self.hostname))
            except socket.gaierror:
                raise socket.gaierror(
                    'Hostname {} not known or not available'.format(
                        self.hostname))
            except ConnectionResetError as e:
                raise ConnectionResetError('{} for {}@{}'.format(
                    str(e), self.remote_user, self.hostname))
            except SSHException as e:
                raise SSHException('{} for {}@{}'.format(
                    str(e), self.remote_user, self.hostname))
Esempio n. 4
0
    def _paramiko_connect(self):
        # Find supported address families.
        addrinfo = socket.getaddrinfo(self.host, self.port)
        for family, socktype, proto, canonname, sockaddr in addrinfo:
            af = family
            addr = sockaddr
            if socktype == socket.SOCK_STREAM:
                break

        # Open a socket.
        sock = socket.socket(af, socket.SOCK_STREAM)
        try:
            sock.settimeout(self.connect_timeout or None)
        except:
            pass
        sock.connect(addr)

        # Init the paramiko protocol.
        t = paramiko.Transport(sock)
        t.banner_timeout = self.banner_timeout
        t.start_client()
        ResourceManager.register(self, t)

        # Check system host keys.
        server_key = t.get_remote_server_key()
        keytype = server_key.get_name()
        our_server_key = self._system_host_keys.get(self.host,
                                                    {}).get(keytype, None)
        if our_server_key is None:
            our_server_key = self._host_keys.get(self.host,
                                                 {}).get(keytype, None)
        if our_server_key is None:
            self._missing_host_key(server_key)
            # if the callback returns, assume the key is ok
            our_server_key = server_key
        if server_key != our_server_key:
            raise BadHostKeyException(self.host, server_key, our_server_key)

        t.set_keepalive(self.KEEPALIVE_INTERVAL)
        return t
    def test_execute_command_invokes_ssh_identity_possibly_changed_notification(
            self):
        """
        When a BadHostKeyException, THEN we send "ssh_identity_possibly_changed" notification
        """

        ssh = mock.Mock()
        ssh.execute_command.side_effect = BadHostKeyException(
            'test', mock.Mock(), mock.Mock())

        notifier = mock.Mock()

        node = Node({'healthchecks': []}, {}, ssh)
        node.set_notifier(notifier)

        try:
            node.execute_command('curl https://iwa-ait.org')
        except BadHostKeyException:
            notifier.ssh_identity_possibly_changed.assert_called_once()
            return

        self.fail('BadHostKeyException not thrown')
Esempio n. 6
0
    def connect(
        self,
        hostname,
        port=SSH_PORT,
        username=None,
        password=None,
        pkey=None,
        key_filename=None,
        timeout=None,
        allow_agent=True,
        look_for_keys=True,
        compress=False,
        sock=None,
        gss_auth=False,
        gss_kex=False,
        gss_deleg_creds=True,
        gss_host=None,
        banner_timeout=None,
        auth_timeout=None,
        gss_trust_dns=True,
    ):
        """
        Connect to an SSH server and authenticate to it.  The server's host key
        is checked against the system host keys (see `load_system_host_keys`)
        and any local host keys (`load_host_keys`).  If the server's hostname
        is not found in either set of host keys, the missing host key policy
        is used (see `set_missing_host_key_policy`).  The default policy is
        to reject the key and raise an `.SSHException`.

        Authentication is attempted in the following order of priority:

            - The ``pkey`` or ``key_filename`` passed in (if any)

              - ``key_filename`` may contain OpenSSH public certificate paths
                as well as regular private-key paths; when files ending in
                ``-cert.pub`` are found, they are assumed to match a private
                key, and both components will be loaded. (The private key
                itself does *not* need to be listed in ``key_filename`` for
                this to occur - *just* the certificate.)

            - Any key we can find through an SSH agent
            - Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in
              ``~/.ssh/``

              - When OpenSSH-style public certificates exist that match an
                existing such private key (so e.g. one has ``id_rsa`` and
                ``id_rsa-cert.pub``) the certificate will be loaded alongside
                the private key and used for authentication.

            - Plain username/password auth, if a password was given

        If a private key requires a password to unlock it, and a password is
        passed in, that password will be used to attempt to unlock the key.

        :param str hostname: the server to connect to
        :param int port: the server port to connect to
        :param str username:
            the username to authenticate as (defaults to the current local
            username)
        :param str password:
            a password to use for authentication or for unlocking a private key
        :param .PKey pkey: an optional private key to use for authentication
        :param str key_filename:
            the filename, or list of filenames, of optional private key(s)
            and/or certs to try for authentication
        :param float timeout:
            an optional timeout (in seconds) for the TCP connect
        :param bool allow_agent:
            set to False to disable connecting to the SSH agent
        :param bool look_for_keys:
            set to False to disable searching for discoverable private key
            files in ``~/.ssh/``
        :param bool compress: set to True to turn on compression
        :param socket sock:
            an open socket or socket-like object (such as a `.Channel`) to use
            for communication to the target host
        :param bool gss_auth:
            ``True`` if you want to use GSS-API authentication
        :param bool gss_kex:
            Perform GSS-API Key Exchange and user authentication
        :param bool gss_deleg_creds: Delegate GSS-API client credentials or not
        :param str gss_host:
            The targets name in the kerberos database. default: hostname
        :param bool gss_trust_dns:
            Indicates whether or not the DNS is trusted to securely
            canonicalize the name of the host being connected to (default
            ``True``).
        :param float banner_timeout: an optional timeout (in seconds) to wait
            for the SSH banner to be presented.
        :param float auth_timeout: an optional timeout (in seconds) to wait for
            an authentication response.

        :raises:
            `.BadHostKeyException` -- if the server's host key could not be
            verified
        :raises: `.AuthenticationException` -- if authentication failed
        :raises:
            `.SSHException` -- if there was any other error connecting or
            establishing an SSH session
        :raises socket.error: if a socket error occurred while connecting

        .. versionchanged:: 1.15
            Added the ``banner_timeout``, ``gss_auth``, ``gss_kex``,
            ``gss_deleg_creds`` and ``gss_host`` arguments.
        .. versionchanged:: 2.3
            Added the ``gss_trust_dns`` argument.
        """
        if not sock:
            errors = {}
            # Try multiple possible address families (e.g. IPv4 vs IPv6)
            to_try = list(self._families_and_addresses(hostname, port))
            for af, addr in to_try:
                try:
                    sock = socket.socket(af, socket.SOCK_STREAM)
                    if timeout is not None:
                        try:
                            sock.settimeout(timeout)
                        except:
                            pass
                    retry_on_signal(lambda: sock.connect(addr))
                    # Break out of the loop on success
                    break
                except socket.error as e:
                    # Raise anything that isn't a straight up connection error
                    # (such as a resolution error)
                    if e.errno not in (ECONNREFUSED, EHOSTUNREACH):
                        raise
                    # Capture anything else so we know how the run looks once
                    # iteration is complete. Retain info about which attempt
                    # this was.
                    errors[addr] = e

            # Make sure we explode usefully if no address family attempts
            # succeeded. We've no way of knowing which error is the "right"
            # one, so we construct a hybrid exception containing all the real
            # ones, of a subclass that client code should still be watching for
            # (socket.error)
            if len(errors) == len(to_try):
                raise NoValidConnectionsError(errors)

        t = self._transport = Transport(sock,
                                        gss_kex=gss_kex,
                                        gss_deleg_creds=gss_deleg_creds)
        t.use_compression(compress=compress)
        t.set_gss_host(
            # t.hostname may be None, but GSS-API requires a target name.
            # Therefore use hostname as fallback.
            gss_host=gss_host or hostname,
            trust_dns=gss_trust_dns,
            gssapi_requested=gss_auth or gss_kex,
        )
        if self._log_channel is not None:
            t.set_log_channel(self._log_channel)
        if banner_timeout is not None:
            t.banner_timeout = banner_timeout
        if auth_timeout is not None:
            t.auth_timeout = auth_timeout

        if port == SSH_PORT:
            server_hostkey_name = hostname
        else:
            server_hostkey_name = "[%s]:%d" % (hostname, port)
        our_server_keys = None

        our_server_keys = self._system_host_keys.get(server_hostkey_name)
        if our_server_keys is None:
            our_server_keys = self._host_keys.get(server_hostkey_name)
        if our_server_keys is not None:
            keytype = our_server_keys.keys()[0]
            sec_opts = t.get_security_options()
            other_types = [x for x in sec_opts.key_types if x != keytype]
            sec_opts.key_types = [keytype] + other_types

        t.start_client(timeout=timeout)

        # If GSS-API Key Exchange is performed we are not required to check the
        # host key, because the host is authenticated via GSS-API / SSPI as
        # well as our client.
        if not self._transport.gss_kex_used:
            server_key = t.get_remote_server_key()
            if our_server_keys is None:
                # will raise exception if the key is rejected
                self._policy.missing_host_key(self, server_hostkey_name,
                                              server_key)
            else:
                our_key = our_server_keys.get(server_key.get_name())
                if our_key != server_key:
                    if our_key is None:
                        our_key = list(our_server_keys.values())[0]
                    raise BadHostKeyException(hostname, server_key, our_key)

        if username is None:
            username = getpass.getuser()

        if key_filename is None:
            key_filenames = []
        elif isinstance(key_filename, string_types):
            key_filenames = [key_filename]
        else:
            key_filenames = key_filename

        self._auth(
            username,
            password,
            pkey,
            key_filenames,
            allow_agent,
            look_for_keys,
            gss_auth,
            gss_kex,
            gss_deleg_creds,
            t.gss_host,
        )
Esempio n. 7
0
    def connect(self,
                hostname,
                port=SSH_PORT,
                username=None,
                password=None,
                pkey=None,
                key_filename=None,
                timeout=None,
                allow_agent=True,
                look_for_keys=True,
                compress=False,
                sock=None,
                gss_auth=False,
                gss_kex=False,
                gss_deleg_creds=True,
                gss_host=None,
                banner_timeout=None):
        """
        Connect to an SSH server and authenticate to it.  The server's host key
        is checked against the system host keys (see `load_system_host_keys`)
        and any local host keys (`load_host_keys`).  If the server's hostname
        is not found in either set of host keys, the missing host key policy
        is used (see `set_missing_host_key_policy`).  The default policy is
        to reject the key and raise an `.SSHException`.

        Authentication is attempted in the following order of priority:

            - The ``pkey`` or ``key_filename`` passed in (if any)
            - Any key we can find through an SSH agent
            - Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in
              ``~/.ssh/``
            - Plain username/password auth, if a password was given

        If a private key requires a password to unlock it, and a password is
        passed in, that password will be used to attempt to unlock the key.

        :param str hostname: the server to connect to
        :param int port: the server port to connect to
        :param str username:
            the username to authenticate as (defaults to the current local
            username)
        :param str password:
            a password to use for authentication or for unlocking a private key
        :param .PKey pkey: an optional private key to use for authentication
        :param str key_filename:
            the filename, or list of filenames, of optional private key(s) to
            try for authentication
        :param float timeout: an optional timeout (in seconds) for the TCP connect
        :param bool allow_agent: set to False to disable connecting to the SSH agent
        :param bool look_for_keys:
            set to False to disable searching for discoverable private key
            files in ``~/.ssh/``
        :param bool compress: set to True to turn on compression
        :param socket sock:
            an open socket or socket-like object (such as a `.Channel`) to use
            for communication to the target host
        :param bool gss_auth: ``True`` if you want to use GSS-API authentication
        :param bool gss_kex: Perform GSS-API Key Exchange and user authentication
        :param bool gss_deleg_creds: Delegate GSS-API client credentials or not
        :param str gss_host: The targets name in the kerberos database. default: hostname
        :param float banner_timeout: an optional timeout (in seconds) to wait
            for the SSH banner to be presented.

        :raises BadHostKeyException: if the server's host key could not be
            verified
        :raises AuthenticationException: if authentication failed
        :raises SSHException: if there was any other error connecting or
            establishing an SSH session
        :raises socket.error: if a socket error occurred while connecting

        .. versionchanged:: 1.15
            Added the ``banner_timeout``, ``gss_auth``, ``gss_kex``,
            ``gss_deleg_creds`` and ``gss_host`` arguments.
        """
        if not sock:
            for (family, socktype, proto, canonname,
                 sockaddr) in socket.getaddrinfo(hostname, port,
                                                 socket.AF_UNSPEC,
                                                 socket.SOCK_STREAM):
                if socktype == socket.SOCK_STREAM:
                    af = family
                    addr = sockaddr
                    break
            else:
                # some OS like AIX don't indicate SOCK_STREAM support, so just guess. :(
                af, _, _, _, addr = socket.getaddrinfo(hostname, port,
                                                       socket.AF_UNSPEC,
                                                       socket.SOCK_STREAM)
            sock = socket.socket(af, socket.SOCK_STREAM)
            if timeout is not None:
                try:
                    sock.settimeout(timeout)
                except:
                    pass
            retry_on_signal(lambda: sock.connect(addr))

        t = self._transport = Transport(sock,
                                        gss_kex=gss_kex,
                                        gss_deleg_creds=gss_deleg_creds)
        t.use_compression(compress=compress)
        if gss_kex and gss_host is None:
            t.set_gss_host(hostname)
        elif gss_kex and gss_host is not None:
            t.set_gss_host(gss_host)
        else:
            pass
        if self._log_channel is not None:
            t.set_log_channel(self._log_channel)
        if banner_timeout is not None:
            t.banner_timeout = banner_timeout
        t.start_client()
        ResourceManager.register(self, t)

        server_key = t.get_remote_server_key()
        keytype = server_key.get_name()

        if port == SSH_PORT:
            server_hostkey_name = hostname
        else:
            server_hostkey_name = "[%s]:%d" % (hostname, port)

        # If GSS-API Key Exchange is performed we are not required to check the
        # host key, because the host is authenticated via GSS-API / SSPI as
        # well as our client.
        if not self._transport.use_gss_kex:
            our_server_key = self._system_host_keys.get(
                server_hostkey_name, {}).get(keytype, None)
            if our_server_key is None:
                our_server_key = self._host_keys.get(server_hostkey_name,
                                                     {}).get(keytype, None)
            if our_server_key is None:
                # will raise exception if the key is rejected; let that fall out
                self._policy.missing_host_key(self, server_hostkey_name,
                                              server_key)
                # if the callback returns, assume the key is ok
                our_server_key = server_key

            if server_key != our_server_key:
                raise BadHostKeyException(hostname, server_key, our_server_key)

        if username is None:
            username = getpass.getuser()

        if key_filename is None:
            key_filenames = []
        elif isinstance(key_filename, string_types):
            key_filenames = [key_filename]
        else:
            key_filenames = key_filename
        if gss_host is None:
            gss_host = hostname
        self._auth(username, password, pkey, key_filenames, allow_agent,
                   look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host)
Esempio n. 8
0
    def connect(
        self,
        hostname,
        port=SSH_PORT,
        username=None,
        password=None,
        pkey=None,
        key_filename=None,
        timeout=None,
        allow_agent=True,
        look_for_keys=True,
        compress=False,
        sock=None,
        gss_auth=False,
        gss_kex=False,
        gss_deleg_creds=True,
        gss_host=None,
        banner_timeout=None,
        auth_timeout=None,
        gss_trust_dns=True,
        passphrase=None,
    ):
        """
        Connect to an SSH server and authenticate to it.  The server's host key
        is checked against the system host keys (see `load_system_host_keys`)
        and any local host keys (`load_host_keys`).  If the server's hostname
        is not found in either set of host keys, the missing host key policy
        is used (see `set_missing_host_key_policy`).  The default policy is
        to reject the key and raise an `.SSHException`.

        Authentication is attempted in the following order of priority:

            - The ``pkey`` or ``key_filename`` passed in (if any)

              - ``key_filename`` may contain OpenSSH public certificate paths
                as well as regular private-key paths; when files ending in
                ``-cert.pub`` are found, they are assumed to match a private
                key, and both components will be loaded. (The private key
                itself does *not* need to be listed in ``key_filename`` for
                this to occur - *just* the certificate.)

            - Any key we can find through an SSH agent
            - Any "id_rsa", "id_dsa", "id_ecdsa", or "id_ed25519" key
              discoverable in ``~/.ssh/``

              - When OpenSSH-style public certificates exist that match an
                existing such private key (so e.g. one has ``id_rsa`` and
                ``id_rsa-cert.pub``) the certificate will be loaded alongside
                the private key and used for authentication.

            - Plain username/password auth, if a password was given

        If a private key requires a password to unlock it, and a password is
        passed in, that password will be used to attempt to unlock the key.

        :param str hostname: the server to connect to
        :param int port: the server port to connect to
        :param str username:
            the username to authenticate as (defaults to the current local
            username)
        :param str password:
            Used for password authentication; is also used for private key
            decryption if ``passphrase`` is not given.
        :param str passphrase:
            Used for decrypting private keys.
        :param .PKey pkey: an optional private key to use for authentication
        :param str key_filename:
            the filename, or list of filenames, of optional private key(s)
            and/or certs to try for authentication
        :param float timeout:
            an optional timeout (in seconds) for the TCP connect
        :param bool allow_agent:
            set to False to disable connecting to the SSH agent
        :param bool look_for_keys:
            set to False to disable searching for discoverable private key
            files in ``~/.ssh/``
        :param bool compress: set to True to turn on compression
        :param socket sock:
            an open socket or socket-like object (such as a `.Channel`) to use
            for communication to the target host
        :param bool gss_auth:
            ``True`` if you want to use GSS-API authentication
        :param bool gss_kex:
            Perform GSS-API Key Exchange and user authentication
        :param bool gss_deleg_creds: Delegate GSS-API client credentials or not
        :param str gss_host:
            The targets name in the kerberos database. default: hostname
        :param bool gss_trust_dns:
            Indicates whether or not the DNS is trusted to securely
            canonicalize the name of the host being connected to (default
            ``True``).
        :param float banner_timeout: an optional timeout (in seconds) to wait
            for the SSH banner to be presented.
        :param float auth_timeout: an optional timeout (in seconds) to wait for
            an authentication response.

        :raises:
            `.BadHostKeyException` -- if the server's host key could not be
            verified
        :raises: `.AuthenticationException` -- if authentication failed
        :raises:
            `.SSHException` -- if there was any other error connecting or
            establishing an SSH session
        :raises socket.error: if a socket error occurred while connecting

        .. versionchanged:: 1.15
            Added the ``banner_timeout``, ``gss_auth``, ``gss_kex``,
            ``gss_deleg_creds`` and ``gss_host`` arguments.
        .. versionchanged:: 2.3
            Added the ``gss_trust_dns`` argument.
        .. versionchanged:: 2.4
            Added the ``passphrase`` argument.
        """
        if not sock:
            sock = retry_on_signal(lambda: socket.create_connection(
                (hostname, port), timeout))

        t = self._transport = Transport(sock,
                                        gss_kex=gss_kex,
                                        gss_deleg_creds=gss_deleg_creds)
        t.use_compression(compress=compress)
        t.set_gss_host(
            # t.hostname may be None, but GSS-API requires a target name.
            # Therefore use hostname as fallback.
            gss_host=gss_host or hostname,
            trust_dns=gss_trust_dns,
            gssapi_requested=gss_auth or gss_kex,
        )
        if self._log_channel is not None:
            t.set_log_channel(self._log_channel)
        if banner_timeout is not None:
            t.banner_timeout = banner_timeout
        if auth_timeout is not None:
            t.auth_timeout = auth_timeout

        if port == SSH_PORT:
            server_hostkey_name = hostname
        else:
            server_hostkey_name = "[{}]:{}".format(hostname, port)
        our_server_keys = None

        our_server_keys = self._system_host_keys.get(server_hostkey_name)
        if our_server_keys is None:
            our_server_keys = self._host_keys.get(server_hostkey_name)
        if our_server_keys is not None:
            keytype = our_server_keys.keys()[0]
            sec_opts = t.get_security_options()
            other_types = [x for x in sec_opts.key_types if x != keytype]
            sec_opts.key_types = [keytype] + other_types

        t.start_client(timeout=timeout)

        # If GSS-API Key Exchange is performed we are not required to check the
        # host key, because the host is authenticated via GSS-API / SSPI as
        # well as our client.
        if not self._transport.gss_kex_used:
            server_key = t.get_remote_server_key()
            if our_server_keys is None:
                # will raise exception if the key is rejected
                self._policy.missing_host_key(self, server_hostkey_name,
                                              server_key)
            else:
                our_key = our_server_keys.get(server_key.get_name())
                if our_key != server_key:
                    if our_key is None:
                        our_key = list(our_server_keys.values())[0]
                    raise BadHostKeyException(hostname, server_key, our_key)

        if username is None:
            username = getpass.getuser()

        if key_filename is None:
            key_filenames = []
        elif isinstance(key_filename, string_types):
            key_filenames = [key_filename]
        else:
            key_filenames = key_filename

        self._auth(
            username,
            password,
            pkey,
            key_filenames,
            allow_agent,
            look_for_keys,
            gss_auth,
            gss_kex,
            gss_deleg_creds,
            t.gss_host,
            passphrase,
        )
Esempio n. 9
0
    def connect(self,
                hostname,
                port=SSH_PORT,
                username=None,
                password=None,
                pkey=None,
                key_filename=None,
                timeout=None,
                allow_agent=True,
                look_for_keys=True):
        """
        Connect to an SSH server and authenticate to it.  The server's host key
        is checked against the system host keys (see L{load_system_host_keys})
        and any local host keys (L{load_host_keys}).  If the server's hostname
        is not found in either set of host keys, the missing host key policy
        is used (see L{set_missing_host_key_policy}).  The default policy is
        to reject the key and raise an L{SSHException}.

        Authentication is attempted in the following order of priority:

            - The C{pkey} or C{key_filename} passed in (if any)
            - Any key we can find through an SSH agent
            - Any "id_rsa" or "id_dsa" key discoverable in C{~/.ssh/}
            - Plain username/password auth, if a password was given

        If a private key requires a password to unlock it, and a password is
        passed in, that password will be used to attempt to unlock the key.

        @param hostname: the server to connect to
        @type hostname: str
        @param port: the server port to connect to
        @type port: int
        @param username: the username to authenticate as (defaults to the
            current local username)
        @type username: str
        @param password: a password to use for authentication or for unlocking
            a private key
        @type password: str
        @param pkey: an optional private key to use for authentication
        @type pkey: L{PKey}
        @param key_filename: the filename, or list of filenames, of optional
            private key(s) to try for authentication
        @type key_filename: str or list(str)
        @param timeout: an optional timeout (in seconds) for the TCP connect
        @type timeout: float
        @param allow_agent: set to False to disable connecting to the SSH agent
        @type allow_agent: bool
        @param look_for_keys: set to False to disable searching for discoverable
            private key files in C{~/.ssh/}
        @type look_for_keys: bool

        @raise BadHostKeyException: if the server's host key could not be
            verified
        @raise AuthenticationException: if authentication failed
        @raise SSHException: if there was any other error connecting or
            establishing an SSH session
        @raise socket.error: if a socket error occurred while connecting
        """
        for (family, socktype, proto, canonname,
             sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC,
                                             socket.SOCK_STREAM):
            if socktype == socket.SOCK_STREAM:
                af = family
                addr = sockaddr
                break
        else:
            raise SSHException('No suitable address family for %s' % hostname)
        sock = socket.socket(af, socket.SOCK_STREAM)
        if timeout is not None:
            try:
                sock.settimeout(timeout)
            except:
                pass
        sock.connect(addr)
        t = self._transport = Transport(sock)

        if self._log_channel is not None:
            t.set_log_channel(self._log_channel)
        t.start_client()
        ResourceManager.register(self, t)

        server_key = t.get_remote_server_key()
        keytype = server_key.get_name()

        if port == SSH_PORT:
            server_hostkey_name = hostname
        else:
            server_hostkey_name = "[%s]:%d" % (hostname, port)
        our_server_key = self._system_host_keys.get(server_hostkey_name,
                                                    {}).get(keytype, None)
        if our_server_key is None:
            our_server_key = self._host_keys.get(server_hostkey_name,
                                                 {}).get(keytype, None)
        if our_server_key is None:
            # will raise exception if the key is rejected; let that fall out
            self._policy.missing_host_key(self, server_hostkey_name,
                                          server_key)
            # if the callback returns, assume the key is ok
            our_server_key = server_key

        if server_key != our_server_key:
            raise BadHostKeyException(hostname, server_key, our_server_key)

        if username is None:
            username = getpass.getuser()

        if key_filename is None:
            key_filenames = []
        elif isinstance(key_filename, (str, unicode)):
            key_filenames = [key_filename]
        else:
            key_filenames = key_filename
        self._auth(username, password, pkey, key_filenames, allow_agent,
                   look_for_keys)
class DecoratorConnectHostTestCase(TestCase):
    def setUp(self):
        self.host_ssh = HostSSH(
            address='fake_address',
            username='******',
            password='******'
        )
        self.fake_func = MagicMock(
            return_value={
                'stdout': 'fake_stdout',
                'stdin': 'fake_stdin',
                'stderr': 'fake_stderr',
                'exception': '',
            }
        )
        self.decorated = connect_host(self.fake_func)

    @patch.object(HostSSH, 'connect')
    def test_call_connect_when_not_error(self, connect_mock):
        output = self.decorated(self.host_ssh)

        self.assertTrue(connect_mock.called)
        self.assertTrue(self.fake_func.called)
        self.assertEqual(output['stdout'], 'fake_stdout')
        self.assertEqual(output['exception'], '')

    @patch.object(HostSSH, 'connect',
                  side_effect=BadHostKeyException(
                      'fake_hostname', MagicMock(), MagicMock()
                  ))
    def test_call_connect_bad_host_exeption(self, connect_mock):
        output = self.decorated(self.host_ssh)

        self.assertTrue(connect_mock.called)
        self.assertFalse(self.fake_func.called)
        self.assertEqual(output['stdout'], '')
        self.assertIn(
            "fake_hostname",
            output['exception']
        )

    @patch.object(HostSSH, 'connect',
                  side_effect=SSHException(
                      'fake err msg'
                  ))
    def test_call_connect_ssh_exeption(self, connect_mock):
        output = self.decorated(self.host_ssh)

        self.assertTrue(connect_mock.called)
        self.assertFalse(self.fake_func.called)
        self.assertEqual(output['stdout'], '')
        self.assertEqual(
            "fake err msg",
            output['exception']
        )

    @patch.object(HostSSH, 'connect',
                  side_effect=AuthenticationException(
                      'fake err msg'
                  ))
    def test_call_connect_auth_exeption(self, connect_mock):
        output = self.decorated(self.host_ssh)

        self.assertTrue(connect_mock.called)
        self.assertFalse(self.fake_func.called)
        self.assertEqual(output['stdout'], '')
        self.assertEqual(
            "fake err msg",
            output['exception']
        )

    @patch.object(HostSSH, 'connect',
                  side_effect=socker_err(
                      'fake err msg'
                  ))
    def test_call_connect_socket_exeption(self, connect_mock):
        output = self.decorated(self.host_ssh)

        self.assertTrue(connect_mock.called)
        self.assertFalse(self.fake_func.called)
        self.assertEqual(output['stdout'], '')
        self.assertEqual(
            "fake err msg",
            output['exception']
        )
Esempio n. 11
0
import pickle

import pytest

from paramiko import RSAKey
from paramiko.ssh_exception import (
    BadAuthenticationType,
    PartialAuthentication,
    ChannelException,
    BadHostKeyException,
    ProxyCommandFailure,
)


@pytest.mark.parametrize(['exc'], [
    (BadAuthenticationType("Bad authentication type", ["ok", "also-ok"]), ),
    (PartialAuthentication(["ok", "also-ok"]), ),
    (BadHostKeyException("myhost", RSAKey.generate(2048),
                         RSAKey.generate(2048)), ),
    (ProxyCommandFailure("nc servername 22", 1), ),
    (ChannelException(17, "whatever"), ),
])
def test_ssh_exception_strings(exc):
    assert isinstance(str(exc), str)
    assert isinstance(repr(exc), str)
    if type(exc) != BadHostKeyException:
        ne = pickle.loads(pickle.dumps(exc))
        assert type(ne) == type(exc)
Esempio n. 12
0
    def connect(self,
                hostname,
                port=22,
                username=None,
                password=None,
                pkey=None,
                key_filename=None,
                timeout=None):
        """
        Connect to an SSH server and authenticate to it.  The server's host key
        is checked against the system host keys (see L{load_system_host_keys})
        and any local host keys (L{load_host_keys}).  If the server's hostname
        is not found in either set of host keys, the missing host key policy
        is used (see L{set_missing_host_key_policy}).  The default policy is
        to reject the key and raise an L{SSHException}.
        
        Authentication is attempted in the following order of priority:
        
            - The C{pkey} or C{key_filename} passed in (if any)
            - Any key we can find through an SSH agent
            - Any "id_rsa" or "id_dsa" key discoverable in C{~/.ssh/}
            - Plain username/password auth, if a password was given
        
        If a private key requires a password to unlock it, and a password is
        passed in, that password will be used to attempt to unlock the key.

        @param hostname: the server to connect to
        @type hostname: str
        @param port: the server port to connect to
        @type port: int
        @param username: the username to authenticate as (defaults to the
            current local username)
        @type username: str
        @param password: a password to use for authentication or for unlocking
            a private key
        @type password: str
        @param pkey: an optional private key to use for authentication
        @type pkey: L{PKey}
        @param key_filename: the filename of an optional private key to use
            for authentication
        @type key_filename: str
        @param timeout: an optional timeout (in seconds) for the TCP connect
        @type timeout: float
        
        @raise BadHostKeyException: if the server's host key could not be
            verified
        @raise AuthenticationException: if authentication failed
        @raise SSHException: if there was any other error connecting or
            establishing an SSH session
        """
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        if timeout is not None:
            try:
                sock.settimeout(timeout)
            except:
                pass

        sock.connect((hostname, port))
        t = self._transport = Transport(sock)

        if self._log_channel is not None:
            t.set_log_channel(self._log_channel)
        t.start_client()
        ResourceManager.register(self, t)

        server_key = t.get_remote_server_key()
        keytype = server_key.get_name()

        our_server_key = self._system_host_keys.get(hostname,
                                                    {}).get(keytype, None)
        if our_server_key is None:
            our_server_key = self._host_keys.get(hostname,
                                                 {}).get(keytype, None)
        if our_server_key is None:
            # will raise exception if the key is rejected; let that fall out
            self._policy.missing_host_key(self, hostname, server_key)
            # if the callback returns, assume the key is ok
            our_server_key = server_key

        if server_key != our_server_key:
            raise BadHostKeyException(hostname, server_key, our_server_key)

        if username is None:
            username = getpass.getuser()
        self._auth(username, password, pkey, key_filename)
Esempio n. 13
0
    def connect(self,
                hostname,
                port=SSH_PORT,
                username=None,
                password=None,
                pkey=None,
                key_filename=None,
                timeout=None,
                allow_agent=True,
                look_for_keys=True,
                compress=False,
                sock=None,
                gss_auth=False,
                gss_kex=False,
                gss_deleg_creds=True,
                gss_host=None,
                banner_timeout=None,
                check_key=False):
        """
        Connect to an SSH server and authenticate to it.  The server's host key
        is checked against the system host keys (see `load_system_host_keys`)
        and any local host keys (`load_host_keys`).  If the server's hostname
        is not found in either set of host keys, the missing host key policy
        is used (see `set_missing_host_key_policy`).  The default policy is
        to reject the key and raise an `.SSHException`.

        Authentication is attempted in the following order of priority:

            - The ``pkey`` or ``key_filename`` passed in (if any)
            - Any key we can find through an SSH agent
            - Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in
              ``~/.ssh/``
            - Plain username/password auth, if a password was given

        If a private key requires a password to unlock it, and a password is
        passed in, that password will be used to attempt to unlock the key.

        :param str hostname: the server to connect to
        :param int port: the server port to connect to
        :param str username:
            the username to authenticate as (defaults to the current local
            username)
        :param str password:
            a password to use for authentication or for unlocking a private key
        :param .PKey pkey: an optional private key to use for authentication
        :param str key_filename:
            the filename, or list of filenames, of optional private key(s) to
            try for authentication
        :param float timeout:
            an optional timeout (in seconds) for the TCP connect
        :param bool allow_agent:
            set to False to disable connecting to the SSH agent
        :param bool look_for_keys:
            set to False to disable searching for discoverable private key
            files in ``~/.ssh/``
        :param bool compress: set to True to turn on compression
        :param socket sock:
            an open socket or socket-like object (such as a `.Channel`) to use
            for communication to the target host
        :param bool gss_auth:
            ``True`` if you want to use GSS-API authentication
        :param bool gss_kex:
            Perform GSS-API Key Exchange and user authentication
        :param bool gss_deleg_creds: Delegate GSS-API client credentials or not
        :param str gss_host:
            The targets name in the kerberos database. default: hostname
        :param float banner_timeout: an optional timeout (in seconds) to wait
            for the SSH banner to be presented.
        :param bool check_key:
            set to True to perform server-based pubkey checking.
            This option mimics openssh behavior and could fix auth issues for
            some SSH server implementations.

        :raises BadHostKeyException: if the server's host key could not be
            verified
        :raises AuthenticationException: if authentication failed
        :raises SSHException: if there was any other error connecting or
            establishing an SSH session
        :raises socket.error: if a socket error occurred while connecting

        .. versionchanged:: 1.15
            Added the ``banner_timeout``, ``gss_auth``, ``gss_kex``,
            ``gss_deleg_creds`` and ``gss_host`` arguments.
        """
        if not sock:
            errors = {}
            # Try multiple possible address families (e.g. IPv4 vs IPv6)
            to_try = list(self._families_and_addresses(hostname, port))
            for af, addr in to_try:
                try:
                    sock = socket.socket(af, socket.SOCK_STREAM)
                    if timeout is not None:
                        try:
                            sock.settimeout(timeout)
                        except:
                            pass
                    retry_on_signal(lambda: sock.connect(addr))
                    # Break out of the loop on success
                    break
                except socket.error as e:
                    # Raise anything that isn't a straight up connection error
                    # (such as a resolution error)
                    if e.errno not in (ECONNREFUSED, EHOSTUNREACH):
                        raise
                    # Capture anything else so we know how the run looks once
                    # iteration is complete. Retain info about which attempt
                    # this was.
                    errors[addr] = e

            # Make sure we explode usefully if no address family attempts
            # succeeded. We've no way of knowing which error is the "right"
            # one, so we construct a hybrid exception containing all the real
            # ones, of a subclass that client code should still be watching for
            # (socket.error)
            if len(errors) == len(to_try):
                raise NoValidConnectionsError(errors)

        t = self._transport = Transport(sock,
                                        gss_kex=gss_kex,
                                        gss_deleg_creds=gss_deleg_creds)
        t.use_compression(compress=compress)
        if gss_kex and gss_host is None:
            t.set_gss_host(hostname)
        elif gss_kex and gss_host is not None:
            t.set_gss_host(gss_host)
        else:
            pass
        if self._log_channel is not None:
            t.set_log_channel(self._log_channel)
        if banner_timeout is not None:
            t.banner_timeout = banner_timeout
        t.start_client()
        ResourceManager.register(self, t)

        server_key = t.get_remote_server_key()
        keytype = server_key.get_name()

        if port == SSH_PORT:
            server_hostkey_name = hostname
        else:
            server_hostkey_name = "[%s]:%d" % (hostname, port)

        # If GSS-API Key Exchange is performed we are not required to check the
        # host key, because the host is authenticated via GSS-API / SSPI as
        # well as our client.
        if not self._transport.use_gss_kex:
            our_server_key = self._system_host_keys.get(
                server_hostkey_name, {}).get(keytype, None)
            if our_server_key is None:
                our_server_key = self._host_keys.get(server_hostkey_name,
                                                     {}).get(keytype, None)
            if our_server_key is None:
                # will raise exception if the key is rejected; let that fall out
                self._policy.missing_host_key(self, server_hostkey_name,
                                              server_key)
                # if the callback returns, assume the key is ok
                our_server_key = server_key

            if server_key != our_server_key:
                raise BadHostKeyException(hostname, server_key, our_server_key)

        if username is None:
            username = getpass.getuser()

        if key_filename is None:
            key_filenames = []
        elif isinstance(key_filename, string_types):
            key_filenames = [key_filename]
        else:
            key_filenames = key_filename
        if gss_host is None:
            gss_host = hostname
        self._auth(username, password, pkey, key_filenames, allow_agent,
                   look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host,
                   check_key)