class SftpAuth: def __init__(self, user, hostname, port, rsa_key, remote_dir): self.user = user self.hostname = hostname self.port = port self.rsa_key = rsa_key self.remote_dir = remote_dir logger.info(self.__repr__()) def __repr__(self): return "The sftp instance was initialized. " \ "user={}, hostname={}, port={}, rsa_key={}, remote_dir={}"\ .format(self.user, self.hostname, self.port, self.rsa_key, self.remote_dir) def set_transport(self): logger.debug("Try to initialize transport.") try: self.transport = Transport(f"{self.hostname}:{self.port}") self.transport.start_client(event=None, timeout=15) self.transport.get_remote_server_key() rsa_key = RSAKey.from_private_key_file(self.rsa_key) self.transport.auth_publickey(self.user, rsa_key) except Exception as e: logger.debug(e) print(json.dumps({ "error": { "code": 00, "message": e }, }), flush=True) raise logger.info("Transport was initialized.") def __enter__(self): self.set_transport() self.sftp = SFTPClient.from_transport(self.transport) try: logger.info("Try to make a directory") self.sftp.mkdir(self.remote_dir) except Exception as e: logger.info(e) logger.info(f"Change the current directory into {self.remote_dir}") self.sftp.chdir(self.remote_dir) return self.sftp def __exit__(self, exc_type, exc_val, exc_tb): self.transport.close() self.sftp.close()
def _get_server_keys(hostname): server_keys = [] # key_type_list = ["ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256"] # default key_type used by ssh-keysca # Supported key_type for OS # alinux ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256 # ubuntu1404 ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256 # ubuntu1604 ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256 # centos7 ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256 # centos6 ssh-rsa key_type_list = ["ssh-rsa"] for key_type in key_type_list: transport = None try: sock = socket.socket() sock.settimeout(5) sock.connect((hostname, 22)) transport = Transport(sock) transport._preferred_keys = [key_type] transport.start_client() server_keys.append(transport.get_remote_server_key()) except Exception: pass finally: if transport: transport.close() if not server_keys: logging.error("Failed retrieving server key from host '%s'", hostname) return hostname, [(server_key.get_base64(), server_key.get_name()) for server_key in server_keys]
def _on_open_port(args): host, port, socket = args try: ssh_conn = Transport(socket) if key_type is not None: new_preferred_keys = [key_type] new_preferred_keys.extend(ssh_conn._preferred_keys) ssh_conn._preferred_keys = tuple(new_preferred_keys) try: ssh_conn.start_client() key = ssh_conn.get_remote_server_key() key_md5 = md5(str(key)).hexdigest() fingerprint = ':'.join( a + b for a, b in zip(key_md5[::2], key_md5[1::2])) data_cb(host, port, True, (key.get_name(), fingerprint, b64encode(str(key)))) finally: ssh_conn.close() except (socket_error, NoValidConnectionsError): data_cb(host, port, None, None) except Exception as e: data_cb(host, port, False, 'Exception: {}: {}'.format(type(e), str(e))) finally: socket.close()
def run(self, ip, port=22, timeout=2): try: socket.setdefaulttimeout(timeout) s = socket.socket() s.connect((ip, port)) banner = s.recv(50).strip('\r\n').split(' ') try: self.data["version"] = banner[0] self.data["os"] = banner[1] except IndexError: pass s.send('{}\r\n'.format(banner[0])) self._raw_recv = s.recv(2048) s.close() self._parse_raw_data() tran = Transport((ip, port)) tran.start_client() pubkey = tran.get_remote_server_key() self.data["pubkey_name"] = pubkey.get_name() fp = pubkey.get_fingerprint() self.data["pubkey_fingerprint"] = ':'.join(map(lambda x:x.encode('hex'), fp)) except Exception as e: cprint(str(e), 'error') return None finally: tran.close() self.clear() return True
def _connect(self): host_id = self._host_cfg['host_id'] host, port = self._host_cfg[host_id, 'host'] user = self._host_cfg[host_id, 'user'] passwd = self._host_cfg[host_id, 'password'] timeout = self._host_cfg[host_id, 'timeout'] or None known_hosts = self._host_cfg[host_id, 'known_hosts'] key_type = self._host_cfg[host_id, 'key_type'] key_file = self._host_cfg[host_id, 'key_file'] key_pass = self._host_cfg[host_id, 'key_pass'] try: if key_type: key = _KEY_TYPES[key_type](filename=key_file, password=key_pass) _logger.debug('private key: %s', key.get_name()) else: key = None hostname = utils.format_knownhost(host, port) hostkeys = HostKeys(known_hosts) transport = Transport((host, port)) transport.start_client(timeout=timeout) hostkey = transport.get_remote_server_key() if not hostkeys.check(hostname, hostkey): raise SSHException('Incorrect hostkey') if key: transport.auth_publickey(user, key) else: transport.auth_password(user, passwd) client = transport.open_sftp_client() client.get_channel().settimeout(timeout) _logger.debug('client for %s created', hostname) return client except (OSError, SSHException) as ex: raise ConnectError(f'Connection to server "{host}:{port}"' f' failed: {ex.args!s}')
def run(self, ip, port=22, timeout=2): try: socket.setdefaulttimeout(timeout) s = socket.socket() s.connect((ip, port)) banner = s.recv(50).strip(b"\r\n").split(b" ") try: self.data["version"] = banner[0].decode() self.data["os"] = banner[1].decode() except IndexError: pass s.send(banner[0] + b"\r\n") self._raw_recv = s.recv(2048) s.close() self._parse_raw_data() tran = Transport((ip, port)) tran.start_client() pubkey = tran.get_remote_server_key() self.data["pubkey_name"] = pubkey.get_name() fp = pubkey.get_fingerprint() self.data["pubkey_fingerprint"] = fp.hex() except Exception as e: print(repr(e)) return None finally: tran.close() return True
def connect(username, hostname='lxplus.cern.ch', port=22): "Connect to a given host" print "Connecting to %s@%s" % (username, hostname) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((hostname, port)) except Exception as err: print '*** Connect failed: ' + str(err) sys.exit(1) transport = Transport(sock) try: transport.start_client() except paramiko.SSHException as err: print "SSH negotiation failed\n%s" % str(err) try: keys = paramiko.util.load_host_keys(\ os.path.expanduser('~/.ssh/known_hosts')) except IOError: try: keys = paramiko.util.load_host_keys(\ os.path.expanduser('~/ssh/known_hosts')) except IOError: print '*** Unable to open host keys file' keys = {} # check server's host key -- this is important. key = transport.get_remote_server_key() if not keys.has_key(hostname): print '*** WARNING: Unknown host key!' elif not keys[hostname].has_key(key.get_name()): print '*** WARNING: Unknown host key!' elif keys[hostname][key.get_name()] != key: print '*** WARNING: Host key has changed!!!' sys.exit(1) else: pass # get username if username == '': default_username = getpass.getuser() username = raw_input('Username [%s]: ' % default_username) if len(username) == 0: username = default_username agent_auth(transport, username) if not transport.is_authenticated(): manual_auth(transport, username, hostname) if not transport.is_authenticated(): print '*** Authentication failed. :(' transport.close() sys.exit(1) return transport, sock
def connect(username, hostname='lxplus.cern.ch', port=22): "Connect to a given host" print "Connecting to %s@%s" % (username, hostname) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((hostname, port)) except Exception as err: print '*** Connect failed: ' + str(err) sys.exit(1) transport = Transport(sock) try: transport.start_client() except paramiko.SSHException as err: print "SSH negotiation failed\n%s" % str(err) try: keys = paramiko.util.load_host_keys(\ os.path.expanduser('~/.ssh/known_hosts')) except IOError: try: keys = paramiko.util.load_host_keys(\ os.path.expanduser('~/ssh/known_hosts')) except IOError: print '*** Unable to open host keys file' keys = {} # check server's host key -- this is important. key = transport.get_remote_server_key() if not keys.has_key(hostname): print '*** WARNING: Unknown host key!' elif not keys[hostname].has_key(key.get_name()): print '*** WARNING: Unknown host key!' elif keys[hostname][key.get_name()] != key: print '*** WARNING: Host key has changed!!!' sys.exit(1) else: pass # get username if username == '': default_username = getpass.getuser() username = raw_input('Username [%s]: ' % default_username) if len(username) == 0: username = default_username agent_auth(transport, username) if not transport.is_authenticated(): manual_auth(transport, username, hostname) if not transport.is_authenticated(): print '*** Authentication failed. :(' transport.close() sys.exit(1) return transport, sock
def _get_transport(hostname: str, username: str, path_to_private_key: str): global _transport, _transport_lock with _transport_lock: if _transport is None: key = RSAKey.from_private_key_file(path_to_private_key) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((hostname, 22)) # noinspection PyTypeChecker _transport = Transport(sock) _transport.connect(None, username=username, password='', pkey=key) _validate_key(hostname, _transport.get_remote_server_key()) if not _transport.is_authenticated(): raise SSHAuthenticationError( 'Couldn\'t authenticate the ssh transport') return _transport
def run(self, ip, port=22, timeout=2): try: socket.setdefaulttimeout(timeout) s = socket.socket() s.connect((ip, port)) banner = s.recv(50).strip('\r\n').split(' ') try: self.data.version = banner[0] self.data.os = banner[1] except IndexError: pass s.send('{}\r\n'.format(banner[0])) self._raw_recv = s.recv(2048) s.close() self._parse_raw_data() # use paramiko to get hostkey because of lazyless... tran = Transport((ip, port)) tran.start_client() pubkey = tran.get_remote_server_key() self.data.pubkey_name = pubkey.get_name() fp = pubkey.get_fingerprint() self.data.pubkey_fingerprint = ':'.join( map(lambda x: x.encode('hex'), fp)) ServicesInfo.add(ip, port, 'ssh', self.data) except Exception as e: cprint(str(e), 'error') return None finally: tran.close() self.clear() return True
def run(self, ip, port=22, timeout=2): try: socket.setdefaulttimeout(timeout) s = socket.socket() s.connect((ip, port)) banner = s.recv(50).strip('\r\n').split(' ') try: self.data.version = banner[0] self.data.os = banner[1] except IndexError: pass s.send('{}\r\n'.format(banner[0])) self._raw_recv = s.recv(2048) s.close() self._parse_raw_data() # use paramiko to get hostkey because of lazyless... tran = Transport((ip, port)) tran.start_client() pubkey = tran.get_remote_server_key() self.data.pubkey_name = pubkey.get_name() fp = pubkey.get_fingerprint() self.data.pubkey_fingerprint = ':'.join(map(lambda x:x.encode('hex'), fp)) ServicesInfo.add(ip, port, 'ssh', self.data) except Exception as e: cprint(str(e), 'error') return None finally: tran.close() self.clear() return True
def do_ssh_paramiko_connect_to(sock, host, port, username, password, proxy_command, remote_xpra, socket_dir, display_as_args, target): from paramiko import SSHException, Transport, Agent, RSAKey, PasswordRequiredException from paramiko.hostkeys import HostKeys transport = Transport(sock) transport.use_compression(False) log("SSH transport %s", transport) try: transport.start_client() except SSHException as e: log("start_client()", exc_info=True) raise InitException("SSH negotiation failed: %s" % e) host_key = transport.get_remote_server_key() assert host_key, "no remote server key" log("remote_server_key=%s", keymd5(host_key)) if VERIFY_HOSTKEY: host_keys = HostKeys() host_keys_filename = None KNOWN_HOSTS = get_ssh_known_hosts_files() for known_hosts in KNOWN_HOSTS: host_keys.clear() try: path = os.path.expanduser(known_hosts) if os.path.exists(path): host_keys.load(path) log("HostKeys.load(%s) successful", path) host_keys_filename = path break except IOError: log("HostKeys.load(%s)", known_hosts, exc_info=True) log("host keys=%s", host_keys) keys = host_keys.lookup(host) known_host_key = (keys or {}).get(host_key.get_name()) def keyname(): return host_key.get_name().replace("ssh-", "") if host_key==known_host_key: assert host_key log("%s host key '%s' OK for host '%s'", keyname(), keymd5(host_key), host) else: if known_host_key: log.warn("Warning: SSH server key mismatch") qinfo = [ "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!", "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!", "Someone could be eavesdropping on you right now (man-in-the-middle attack)!", "It is also possible that a host key has just been changed.", "The fingerprint for the %s key sent by the remote host is" % keyname(), keymd5(host_key), ] if VERIFY_STRICT: log.warn("Host key verification failed.") #TODO: show alert with no option to accept key qinfo += [ "Please contact your system administrator.", "Add correct host key in %s to get rid of this message.", "Offending %s key in %s" % (keyname(), host_keys_filename), "ECDSA host key for %s has changed and you have requested strict checking." % keyname(), ] sys.stderr.write(os.linesep.join(qinfo)) transport.close() raise InitExit(EXIT_SSH_KEY_FAILURE, "SSH Host key has changed") if not confirm_key(qinfo): transport.close() raise InitExit(EXIT_SSH_KEY_FAILURE, "SSH Host key has changed") else: assert (not keys) or (host_key.get_name() not in keys) if not keys: log.warn("Warning: unknown SSH host") else: log.warn("Warning: unknown %s SSH host key", keyname()) qinfo = [ "The authenticity of host '%s' can't be established." % (host,), "%s key fingerprint is" % keyname(), keymd5(host_key), ] if not confirm_key(qinfo): transport.close() raise InitExit(EXIT_SSH_KEY_FAILURE, "Unknown SSH host '%s'" % host) if ADD_KEY: try: if not host_keys_filename: #the first one is the default, #ie: ~/.ssh/known_hosts on posix host_keys_filename = os.path.expanduser(KNOWN_HOSTS[0]) log("adding %s key for host '%s' to '%s'", keyname(), host, host_keys_filename) if not os.path.exists(host_keys_filename): keys_dir = os.path.dirname(host_keys_filename) if not os.path.exists(keys_dir): log("creating keys directory '%s'", keys_dir) os.mkdir(keys_dir, 0o700) elif not os.path.isdir(keys_dir): log.warn("Warning: '%s' is not a directory") log.warn(" key not saved") if os.path.exists(keys_dir) and os.path.isdir(keys_dir): log("creating known host file '%s'", host_keys_filename) with umask_context(0o133): with open(host_keys_filename, 'a+'): pass host_keys.add(host, host_key.get_name(), host_key) host_keys.save(host_keys_filename) except OSError as e: log("failed to add key to '%s'", host_keys_filename) log.error("Error adding key to '%s'", host_keys_filename) log.error(" %s", e) except Exception as e: log.error("cannot add key", exc_info=True) def auth_agent(): agent = Agent() agent_keys = agent.get_keys() log("agent keys: %s", agent_keys) if agent_keys: for agent_key in agent_keys: log("trying ssh-agent key '%s'", keymd5(agent_key)) try: transport.auth_publickey(username, agent_key) if transport.is_authenticated(): log("authenticated using agent and key '%s'", keymd5(agent_key)) break except SSHException: log("agent key '%s' rejected", keymd5(agent_key), exc_info=True) if not transport.is_authenticated(): log.info("agent authentication failed, tried %i key%s", len(agent_keys), engs(agent_keys)) def auth_publickey(): log("trying public key authentication") for keyfile in ("id_rsa", "id_dsa"): keyfile_path = osexpand(os.path.join("~/", ".ssh", keyfile)) if not os.path.exists(keyfile_path): log("no keyfile at '%s'", keyfile_path) continue key = None try: key = RSAKey.from_private_key_file(keyfile_path) except PasswordRequiredException: log("%s keyfile requires a passphrase", keyfile_path) passphrase = input_pass("please enter the passphrase for %s:" % (keyfile_path,)) if passphrase: try: key = RSAKey.from_private_key_file(keyfile_path, passphrase) except SSHException as e: log("from_private_key_file", exc_info=True) log.info("cannot load key from file '%s':", keyfile_path) log.info(" %s", e) if key: log("auth_publickey using %s: %s", keyfile_path, keymd5(key)) try: transport.auth_publickey(username, key) except SSHException as e: log("key '%s' rejected", keyfile_path, exc_info=True) log.info("SSH authentication using key '%s' failed:", keyfile_path) log.info(" %s", e) else: if transport.is_authenticated(): break def auth_none(): log("trying none authentication") try: transport.auth_none(username) except SSHException as e: log("auth_none()", exc_info=True) def auth_password(): log("trying password authentication") try: transport.auth_password(username, password) except SSHException as e: log("auth_password(..)", exc_info=True) log.info("SSH password authentication failed: %s", e) banner = transport.get_banner() if banner: log.info("SSH server banner:") for x in banner.splitlines(): log.info(" %s", x) log("starting authentication") if not transport.is_authenticated() and NONE_AUTH: auth_none() if not transport.is_authenticated() and PASSWORD_AUTH and password: auth_password() if not transport.is_authenticated() and AGENT_AUTH: auth_agent() if not transport.is_authenticated() and KEY_AUTH: auth_publickey() if not transport.is_authenticated() and PASSWORD_AUTH and not password: for _ in range(1+PASSWORD_RETRY): password = input_pass("please enter the SSH password for %s@%s" % (username, host)) if not password: break auth_password() if transport.is_authenticated(): break if not transport.is_authenticated(): transport.close() raise InitException("SSH Authentication failed") assert len(remote_xpra)>0 log("will try to run xpra from: %s", remote_xpra) for xpra_cmd in remote_xpra: try: chan = transport.open_session(window_size=None, max_packet_size=0, timeout=60) chan.set_name("find %s" % xpra_cmd) except SSHException as e: log("open_session", exc_info=True) raise InitException("failed to open SSH session: %s" % e) cmd = "which %s" % xpra_cmd log("exec_command('%s')", cmd) chan.exec_command(cmd) #poll until the command terminates: start = monotonic_time() while not chan.exit_status_ready(): if monotonic_time()-start>10: chan.close() raise InitException("SSH test command '%s' timed out" % cmd) log("exit status is not ready yet, sleeping") time.sleep(0.01) r = chan.recv_exit_status() log("exec_command('%s')=%s", cmd, r) chan.close() if r!=0: continue cmd = xpra_cmd + " " + " ".join(shellquote(x) for x in proxy_command) if socket_dir: cmd += " \"--socket-dir=%s\"" % socket_dir if display_as_args: cmd += " " cmd += " ".join(shellquote(x) for x in display_as_args) log("cmd(%s, %s)=%s", proxy_command, display_as_args, cmd) #see https://github.com/paramiko/paramiko/issues/175 #WINDOW_SIZE = 2097152 log("trying to open SSH session, window-size=%i, timeout=%i", WINDOW_SIZE, TIMEOUT) try: chan = transport.open_session(window_size=WINDOW_SIZE, max_packet_size=0, timeout=TIMEOUT) chan.set_name("run-xpra") except SSHException as e: log("open_session", exc_info=True) raise InitException("failed to open SSH session: %s" % e) else: log("channel exec_command(%s)" % cmd) chan.exec_command(cmd) info = { "host" : host, "port" : port, } conn = SSHSocketConnection(chan, sock, target, info) conn.timeout = SOCKET_TIMEOUT conn.start_stderr_reader() child = None conn.process = (child, "ssh", cmd) return conn raise Exception("all SSH remote proxy commands have failed")
class MikoTransport(Transport): def __init__( self, host: str, port: int = -1, auth_username: str = "", auth_private_key: str = "", auth_password: str = "", auth_strict_key: bool = True, timeout_socket: int = 5, timeout_transport: int = 5, timeout_exit: bool = True, ssh_config_file: str = "", ssh_known_hosts_file: str = "", ) -> None: """ MikoTransport Object Inherit from Transport ABC MikoTransport <- Transport (ABC) Args: host: host ip/name to connect to port: port to connect to auth_username: username for authentication auth_private_key: path to private key for authentication auth_password: password for authentication auth_strict_key: True/False to enforce strict key checking (default is True) timeout_socket: timeout for establishing socket in seconds timeout_transport: timeout for ssh transport in seconds timeout_exit: True/False close transport if timeout encountered ssh_config_file: string to path for ssh config file ssh_known_hosts_file: string to path for ssh known hosts file Returns: N/A # noqa: DAR202 Raises: N/A """ cfg_port, cfg_user, cfg_private_key = self._process_ssh_config(host, ssh_config_file) if port == -1: port = cfg_port or 22 super().__init__( host, port, timeout_socket, timeout_transport, timeout_exit, ) self.auth_username: str = auth_username or cfg_user self.auth_private_key: str = auth_private_key or cfg_private_key self.auth_password: str = auth_password self.auth_strict_key: bool = auth_strict_key self.ssh_known_hosts_file: str = ssh_known_hosts_file self.session: ParamikoTransport self.channel: Channel self.socket = Socket(host=self.host, port=self.port, timeout=self.timeout_socket) @staticmethod def _process_ssh_config(host: str, ssh_config_file: str) -> Tuple[Optional[int], str, str]: """ Method to parse ssh config file In the future this may move to be a 'helper' function as it should be very similar between paramiko and and ssh2-python... for now it can be a static method as there may be varying supported args between the two transport drivers. Args: host: host to lookup in ssh config file ssh_config_file: string path to ssh config file; passed down from `Scrape`, or the `NetworkDriver` or subclasses of it, in most cases. Returns: Tuple: port to use for ssh, username to use for ssh, identity file (private key) to use for ssh auth Raises: N/A """ ssh = SSHConfig(ssh_config_file) host_config = ssh.lookup(host) return host_config.port, host_config.user or "", host_config.identity_file or "" def open(self) -> None: """ Parent method to open session, authenticate and acquire shell Args: N/A Returns: N/A # noqa: DAR202 Raises: Exception: if socket handshake fails ScrapliAuthenticationFailed: if all authentication means fail """ if not self.socket.socket_isalive(): self.socket.socket_open() try: self.session = ParamikoTransport(self.socket.sock) self.session.start_client() except Exception as exc: LOG.critical(f"Failed to complete handshake with host {self.host}; Exception: {exc}") raise exc if self.auth_strict_key: LOG.debug(f"Attempting to validate {self.host} public key") self._verify_key() self._authenticate() if not self._isauthenticated(): msg = f"Authentication to host {self.host} failed" LOG.critical(msg) raise ScrapliAuthenticationFailed(msg) self._open_channel() def _verify_key(self) -> None: """ Verify target host public key, raise exception if invalid/unknown Args: N/A Returns: N/A # noqa: DAR202 Raises: KeyVerificationFailed: if host is not in known hosts KeyVerificationFailed: if host is in known hosts but public key does not match """ known_hosts = SSHKnownHosts(self.ssh_known_hosts_file) if self.host not in known_hosts.hosts.keys(): raise KeyVerificationFailed(f"{self.host} not in known_hosts!") remote_server_key = self.session.get_remote_server_key() remote_public_key = remote_server_key.get_base64() if known_hosts.hosts[self.host]["public_key"] != remote_public_key: raise KeyVerificationFailed( f"{self.host} in known_hosts but public key does not match!" ) def _authenticate(self) -> None: """ Parent method to try all means of authentication Args: N/A Returns: N/A # noqa: DAR202 Raises: ScrapliAuthenticationFailed: if authentication fails """ if self.auth_private_key: self._authenticate_public_key() if self._isauthenticated(): LOG.debug(f"Authenticated to host {self.host} with public key auth") return if not self.auth_password or not self.auth_username: msg = ( f"Failed to authenticate to host {self.host} with private key " f"`{self.auth_private_key}`. Unable to continue authentication, " "missing username, password, or both." ) LOG.critical(msg) raise ScrapliAuthenticationFailed(msg) self._authenticate_password() if self._isauthenticated(): LOG.debug(f"Authenticated to host {self.host} with password") def _authenticate_public_key(self) -> None: """ Attempt to authenticate with public key authentication Args: N/A Returns: N/A # noqa: DAR202 Raises: N/A """ try: paramiko_key = RSAKey(filename=self.auth_private_key) self.session.auth_publickey(self.auth_username, paramiko_key) except AuthenticationException as exc: LOG.critical( f"Public key authentication with host {self.host} failed. Exception: {exc}." ) except Exception as exc: # pylint: disable=W0703 LOG.critical( "Unknown error occurred during public key authentication with host " f"{self.host}; Exception: {exc}" ) def _authenticate_password(self) -> None: """ Attempt to authenticate with password authentication Args: N/A Returns: N/A # noqa: DAR202 Raises: Exception: if unknown (i.e. not auth failed) exception occurs """ try: self.session.auth_password(self.auth_username, self.auth_password) except AuthenticationException as exc: LOG.critical( f"Password authentication with host {self.host} failed. Exception: {exc}." "\n\tNote: Paramiko automatically attempts both standard auth as well as keyboard " "interactive auth. Paramiko exception about bad auth type may be misleading!" ) except Exception as exc: LOG.critical( "Unknown error occurred during password authentication with host " f"{self.host}; Exception: {exc}" ) raise exc def _isauthenticated(self) -> bool: """ Check if session is authenticated Args: N/A Returns: bool: True if authenticated, else False Raises: N/A """ authenticated: bool = self.session.is_authenticated() return authenticated def _open_channel(self) -> None: """ Open channel, acquire pty, request interactive shell Args: N/A Returns: N/A # noqa: DAR202 Raises: N/A """ self.channel = self.session.open_session() self.set_timeout(self.timeout_transport) self.channel.get_pty() self.channel.invoke_shell() LOG.debug(f"Channel to host {self.host} opened") def close(self) -> None: """ Close session and socket Args: N/A Returns: N/A # noqa: DAR202 Raises: N/A """ self.channel.close() LOG.debug(f"Channel to host {self.host} closed") self.socket.socket_close() def isalive(self) -> bool: """ Check if socket is alive and session is authenticated Args: N/A Returns: bool: True if socket is alive and session authenticated, else False Raises: N/A """ if self.socket.socket_isalive() and self.session.is_alive() and self._isauthenticated(): return True return False def read(self) -> bytes: """ Read data from the channel Args: N/A Returns: bytes: bytes output as read from channel Raises: N/A """ channel_read: bytes = self.channel.recv(65535) return channel_read def write(self, channel_input: str) -> None: """ Write data to the channel Args: channel_input: string to send to channel Returns: N/A # noqa: DAR202 Raises: N/A """ self.channel.send(channel_input) # type: ignore def set_timeout(self, timeout: int) -> None: """ Set session timeout Args: timeout: timeout in seconds Returns: N/A # noqa: DAR202 Raises: N/A """ self.channel.settimeout(timeout)