Example #1
0
def get_ssh_client(hostname, username, password):
    try:
        ssh_client = paramiko.SSHClient()

        if settings.ALLOW_SSH_UNKNOWN_HOSTS:
            # If true, this will permit connection to unknown SSH servers
            ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        # Will establish a connection to specified SSH server on port 22
        ssh_client.connect(
            hostname=hostname,
            username=username,
            password=password,
        )

        return ssh_client
    except AuthenticationException:
        print('Authentication failed, please verify your credentials: %s')
        raise AuthenticationException('AuthenticationException: %s')
    except SSHException as sshException:
        print('Unable to establish SSH connection: %s' % sshException)
        raise AuthenticationException('Unable to establish SSH connection: %s' % sshException)
    except BadHostKeyException as badHostKeyException:
        print('Unable to verify server\'s host key: %s' % badHostKeyException)
        raise AuthenticationException('Unable to verify server\'s host key: %s' % badHostKeyException)
 def connect_remote(self):
     # open connection to remote host
     try:
         self.client = SSHClient()
         self.client.load_system_host_keys()
         self.client.set_missing_host_key_policy(AutoAddPolicy())
         self.client.connect(self.host,
                             port=22,
                             username=self.user,
                             password=self.password,
                             look_for_keys=False,
                             timeout=10)
         self.scp = SCPClient(self.client.get_transport())
         sftp = SFTPClient.from_transport(self.client.get_transport())
         try:
             sftp.stat(self.remote_path)
         except FileNotFoundError:
             raise AuthenticationException("Remote path does not exist")
         try:
             sftp.stat(self.index_path)
         except FileNotFoundError:
             raise AuthenticationException("Index path does not exist")
         return self.client
     except AuthenticationException as error:
         logger.info(
             'Authentication failed: did you enter the correct username and password?'
         )
         logger.error(error)
         self.scp = None
         return error
    def wait_for_response(self, event):
        max_ts = None
        if self.transport.auth_timeout is not None:
            max_ts = time.time() + self.transport.auth_timeout
        while True:
            event.wait(0.1)
            if not self.transport.is_active():
                e = self.transport.get_exception()
                if (e is None) or issubclass(e.__class__, EOFError):
                    e = AuthenticationException('Authentication failed.')
                raise e
            if event.is_set():
                break
            if max_ts is not None and max_ts <= time.time():
                raise AuthenticationException('Authentication timeout.')

        if not self.is_authenticated():
            e = self.transport.get_exception()
            if e is None:
                e = AuthenticationException('Authentication failed.')
            # this is horrible.  Python Exception isn't yet descended from
            # object, so type(e) won't work. :(
            if issubclass(e.__class__, PartialAuthentication):
                return e.allowed_types
            raise e
        return []
Example #4
0
 def open(self):
     '''Initialize shell connection'''
     self.logger.info('Opening SSH connection')
     try:
         ## Extract user/password from protocol and return the following:
         ##   fabric.Connection(host=self.endpoint, user=user, connect_timeout=self.connectTimeout, connect_kwargs)
         self.client = externalProtocolLibrary.connection(
             self.runtime, self.protocol, self.endpoint,
             self.connectTimeout)
         ## Send something through stdin to verify we have a connection...
         ## TODO: consider making this more useful by validating something
         ## like user, an environmental setting, shell type/version, etc
         self.run('hostname', timeout=3)
         self.connected = True
     except NoValidConnectionsError as e:
         raise NoValidConnectionsError(e.errors)
     except socket.timeout:
         raise socket.timeout(str(sys.exc_info()[1]))
     except AuthenticationException:
         raise AuthenticationException(str(sys.exc_info()[1]))
     except:
         stacktrace = traceback.format_exception(sys.exc_info()[0],
                                                 sys.exc_info()[1],
                                                 sys.exc_info()[2])
         self.logger.error('Failure in SSH open: {stacktrace!r}',
                           stacktrace=stacktrace)
         exceptionOnly = traceback.format_exception_only(
             sys.exc_info()[0],
             sys.exc_info()[1])
         raise EnvironmentError(exceptionOnly)
     if not self.connected:
         self.client.close()
         raise EnvironmentError('No connection established')
     return
Example #5
0
    def _paramiko_auth_agent(self, username, password=None):
        keys = paramiko.Agent().get_keys()
        if not keys:
            raise AuthenticationException('auth agent found no keys')

        saved_exception = AuthenticationException(
            'Failed to authenticate with given username')

        for key in keys:
            try:
                fp = hexlify(key.get_fingerprint())
                self._dbg(1, 'Trying SSH agent key %s' % fp)
                self.client.auth_publickey(username, key)
                return
            except SSHException, e:
                saved_exception = e
Example #6
0
def undeploy_docker_image(node, node_data, project_id, r):
    ssh_user = node_data['ssh_username']
    ssh_password = node_data['ssh_password']
    node_ip = node_data['ip']
    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        ssh_client.connect(node_ip, username=ssh_user, password=ssh_password)
    except AuthenticationException:
        r.hset(node, 'ssh_access', False)
        ssh_client.close()
        logger.error('An error occurred connecting to: ' + node)
        raise AuthenticationException('An error occurred connecting to: ' +
                                      node)

    try:
        project_docker_image = os.path.join(settings.DOCKER_REPO,
                                            project_id[0:13])
        command = 'sudo docker rmi -f ' + project_docker_image
        ssh_client.exec_command(command)
        ssh_client.close()
    except SSHException:
        ssh_client.close()
        logger.error('An error occurred creating the Docker image in: ' + node)
        raise SSHException('An error occurred creating the Docker image in: ' +
                           node)
Example #7
0
    def auth_interactive(self, transport):
        """
        try keyboard interactive authentication type
        """
        self.logger.debug('try keyboard interactive authentication type')
        password = self.password

        def handler(title, instructions, fields):
            if len(fields) > 1:
                raise SSHException('Fallback authentication failed')
            if len(fields) == 0:
                return []
            return [password]

        my_event = threading.Event()
        transport.auth_handler = paramiko.AuthHandler(transport)
        transport.auth_handler.auth_interactive(self.username, handler,
                                                my_event, "")
        my_event.wait(120)
        if not my_event.is_set():
            self.logger.warn('Authenticate timeout')
        if not transport.is_authenticated():
            error = transport.get_exception()
            if error is None:
                error = AuthenticationException('Authentication failed')
            raise error
Example #8
0
 def test_open_connection_authentication_exception_multiple_retries(
         self, mock_rsa, sshClient):
     sshClient.return_value.connect = Mock(
         side_effect=AuthenticationException())
     configurator = ssh_utilities.RemoteConnection(
         self.hostname, user=self.user, passwd=self.passwd,
         priv_key_file=self.priv_key_file)
     self.assertRaises(exception.AuthenticationError,
         configurator.open_connection)
Example #9
0
    def test_authentication_failure(self, mck_log, mck_paramiko):
        """
        Check that ssh authentication errors are handled.
        """
        connect_mck = mock.Mock(side_effect=AuthenticationException('error'))
        mck_paramiko.SSHClient().connect = connect_mck
        ssh_client = self.collector._ssh_client('127.0.0.1')

        self.assertIsNone(ssh_client)
        self.assertTrue(mck_log.error.called)
Example #10
0
    def _google_authenticator_client_mimic_handler(title, instructions,
                                                   prompt_list):
        answers = []
        for i in range(len(prompt_list)):
            prompt, show_input = prompt_list[i]
            if prompt.strip() == TWO_FACTOR_AUTH_PROMPT:
                answers.append('12345')
            else:
                raise AuthenticationException('More prompts than expected.')

        return answers
 def wait_for_response(self, event):
     while True:
         event.wait(0.1)
         if not self.transport.is_active():
             e = self.transport.get_exception()
             if e is None:
                 e = AuthenticationException('Authentication failed.')
             raise e
         if event.isSet():
             break
     if not self.is_authenticated():
         e = self.transport.get_exception()
         if e is None:
             e = AuthenticationException('Authentication failed.')
         # this is horrible.  python Exception isn't yet descended from
         # object, so type(e) won't work. :(
         if issubclass(e.__class__, PartialAuthentication):
             return e.allowed_types
         raise e
     return []
 def _finalize_pubkey_algorithm(self, key_type):
     # Short-circuit for non-RSA keys
     if "rsa" not in key_type:
         return key_type
     self._log(
         DEBUG,
         "Finalizing pubkey algorithm for key of type {!r}".format(
             key_type),
     )
     # Only consider RSA algos from our list, lest we agree on another!
     my_algos = [x for x in self.transport.preferred_pubkeys if "rsa" in x]
     self._log(DEBUG, "Our pubkey algorithm list: {}".format(my_algos))
     # Short-circuit negatively if user disabled all RSA algos (heh)
     if not my_algos:
         raise SSHException(
             "An RSA key was specified, but no RSA pubkey algorithms are configured!"  # noqa
         )
     # Check for server-sig-algs if supported & sent
     server_algo_str = u(
         self.transport.server_extensions.get("server-sig-algs", b("")))
     pubkey_algo = None
     if server_algo_str:
         server_algos = server_algo_str.split(",")
         self._log(DEBUG,
                   "Server-side algorithm list: {}".format(server_algos))
         # Only use algos from our list that the server likes, in our own
         # preference order. (NOTE: purposefully using same style as in
         # Transport...expect to refactor later)
         agreement = list(filter(server_algos.__contains__, my_algos))
         if agreement:
             pubkey_algo = agreement[0]
             self._log(
                 DEBUG,
                 "Agreed upon {!r} pubkey algorithm".format(pubkey_algo),
             )
         else:
             self._log(DEBUG, "No common pubkey algorithms exist! Dying.")
             # TODO: MAY want to use IncompatiblePeer again here but that's
             # technically for initial key exchange, not pubkey auth.
             err = "Unable to agree on a pubkey algorithm for signing a {!r} key!"  # noqa
             raise AuthenticationException(err.format(key_type))
     else:
         # Fallback: first one in our (possibly tweaked by caller) list
         pubkey_algo = my_algos[0]
         msg = "Server did not send a server-sig-algs list; defaulting to our first preferred algo ({!r})"  # noqa
         self._log(DEBUG, msg.format(pubkey_algo))
         self._log(
             DEBUG,
             "NOTE: you may use the 'disabled_algorithms' SSHClient/Transport init kwarg to disable that or other algorithms if your server does not support them!",  # noqa
         )
     self.transport._agreed_pubkey_algorithm = pubkey_algo
     return pubkey_algo
Example #13
0
 def run(self):
     try:
         (r, addr) = self.get_connection()
         # Found that r should be either a socket from the socket library or None
         self.__inr = r
         self.__addr = addr # This should be an IP address as a string? or None
         self._agent.connect()
         if not isinstance(self._agent, int) and (self._agent._conn is None or not hasattr(self._agent._conn, 'fileno')):
             raise AuthenticationException("Unable to connect to SSH agent")
         self._communicate()
     except:
         #XXX Not sure what to do here ... raise or pass ?
         raise
Example #14
0
 def test_connection_connect_auth_failure(self, mocked_ssh_close):
     ckey = self._create_credentials_with_key(port=self.ssh_server.port)
     dc = self._create_device_connection(credentials=ckey)
     auth_failed = AuthenticationException('Authentication failed.')
     with mock.patch(
         'paramiko.SSHClient.connect', side_effect=auth_failed
     ) as mocked_connect:
         dc.connect()
     self.assertEqual(mocked_connect.call_count, 2)
     self.assertFalse(dc.is_working)
     mocked_ssh_close.assert_called_once()
     if sys.version_info[0:2] > (3, 7):
         self.assertNotIn('disabled_algorithms', mocked_connect.mock_calls[0].kwargs)
         self.assertIn('disabled_algorithms', mocked_connect.mock_calls[1].kwargs)
Example #15
0
    def wait_for_response(self, event):
        max_ts = None
        if self.transport.auth_timeout is not None:
            max_ts = time.time() + self.transport.auth_timeout
        while True:
            event.wait(0.1)
            if not self.transport.is_active():
                e = self.transport.get_exception()
                if e is None or isinstance(e, EOFError):
                    e = AuthenticationException('Authentication failed.')
                raise e
            if event.is_set():
                break
            if max_ts is not None and max_ts <= time.time():
                raise AuthenticationException('Authentication timeout.')

        if not self.is_authenticated():
            e = self.transport.get_exception()
            if e is None:
                e = AuthenticationException('Authentication failed.')
            if isinstance(e, PartialAuthentication):
                return e.allowed_types
            raise e
        return []
Example #16
0
def delete_docker_image(r, project_id):
    nodes = r.keys('*_node:*')
    already_deleted = list()
    for node in nodes:
        node_data = r.hgetall(node)
        node_ip = node_data['ip']
        if node_ip not in already_deleted:
            if node_data['ssh_access']:
                already_deleted.append(node_ip)
                # threading.Thread(target=undeploy_docker_image, args=(node, node_data, project_id, r,)).start()
                undeploy_docker_image(node, node_data, project_id, r)
            else:
                logger.error('An error occurred connecting to: ' + node)
                raise AuthenticationException(
                    'An error occurred connecting to: ' + node)
Example #17
0
    def open_sftp_connection(self):
        host = self.host
        port = self.port
        user = self.user
        password = self.password
        ssh_priv_key = self.ssh_priv_key
        ssh_priv_key_pass = self.ssh_priv_key_pass

        # delete files
        try:
            print(
                "Connecting to {0}@{1}:{2}".format(user, host, port)
            )
            ssh = paramiko.SSHClient()

            # allow connection to the new unknown host
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            # open the ssh connection
            if password:
                print("Using password")
                ssh.connect(host, username=user, port=port, password=password)
            elif ssh_priv_key:
                print("Using RSA private key")
                pkey = paramiko.RSAKey.from_private_key_file(
                    ssh_priv_key, ssh_priv_key_pass
                )
                ssh.connect(host, username=user, port=port, pkey=pkey)
            else:
                print(
                    "No password or private key provided. Can't proceed"
                )
                raise AuthenticationException

            # open the sftp session inside the ssh connection
            print("SSH Connection Successful")
            return ssh.open_sftp(), ssh

        except AuthenticationException as e:
            print("ERROR in {0}: {1}".format(e.__class__, e))
            raise AuthenticationException(
                "Couldn't connect to {0}, due to an Authentication exception.")
        except NoValidConnectionsError as e:
            print("ERROR in {0}: {1}".format(e.__class__, e))
            raise NoValidConnectionsError(
                "Couldn't connect to {0}, possible timeout or invalid hostname")
Example #18
0
    def auth_password(self, transport):
        self.logger.debug('try keyboard interactive authentication type')
        my_event = threading.Event()

        self.logger.debug('login IP:%s username:%s password:%s' %
                          (self.hostname, self.username, self.password))
        transport.auth_password(self.username, self.password, my_event)
        my_event.wait(120)
        if not my_event.is_set():
            self.logger.warn(
                'authentication timeout, ip:%s, user:%s, password:%s' %
                (self.hostname, self.username, self.password))
        if not transport.is_authenticated():
            error = transport.get_exception()
            if error in None:
                error = AuthenticationException('Authentication failed')
            raise error
Example #19
0
    def _paramiko_auth_key(self, username, keys, password):
        if password is None:
            password = ''

        saved_exception = AuthenticationException(
            'Failed to authenticate with given username and password/key')

        for pkey_class, filename in keys:
            try:
                key = pkey_class.from_private_key_file(filename, password)
                fp = hexlify(key.get_fingerprint())
                self._dbg(1, 'Trying key %s in %s' % (fp, filename))
                self.client.auth_publickey(username, key)
                return
            except SSHException, e:
                saved_exception = e
            except IOError, e:
                saved_exception = e
Example #20
0
    def open_sftp_connection(self, options):
        host = self.get_option("host", options)
        port = self.get_option("port", options)
        user = self.get_option("user", options)
        password = self.get_option("password", options)
        ssh_priv_key = self.get_option("privateKeyPath", options)
        ssh_priv_key_pass = self.get_option("privateKeyPass", options)

        # delete files
        try:
            current_app.logger.debug(
                "Connecting to {0}@{1}:{2}".format(user, host, port)
            )
            ssh = paramiko.SSHClient()

            # allow connection to the new unknown host
            ssh.set_missing_host_key_policy(paramiko.RejectPolicy())

            # open the ssh connection
            if password:
                current_app.logger.debug("Using password")
                ssh.connect(host, username=user, port=port, password=password)
            elif ssh_priv_key:
                current_app.logger.debug("Using RSA private key")
                pkey = paramiko.RSAKey.from_private_key_file(
                    ssh_priv_key, ssh_priv_key_pass
                )
                ssh.connect(host, username=user, port=port, pkey=pkey)
            else:
                current_app.logger.error(
                    "No password or private key provided. Can't proceed"
                )
                raise AuthenticationException

            # open the sftp session inside the ssh connection
            return ssh.open_sftp(), ssh

        except AuthenticationException as e:
            current_app.logger.error("ERROR in {0}: {1}".format(e.__class__, e))
            raise AuthenticationException("Couldn't connect to {0}, due to an Authentication exception.")
        except NoValidConnectionsError as e:
            current_app.logger.error("ERROR in {0}: {1}".format(e.__class__, e))
            raise NoValidConnectionsError("Couldn't connect to {0}, possible timeout or invalid hostname")
Example #21
0
 def auth_public_key(self, transport):
     self.logger.debug('try keyboard interactive authentication type')
     my_event = threading.Event()
     try:
         key = paramiko.RSAKey.from_private_key_file(self.privateKey)
     except SSHException:
         key = paramiko.DSSKey.from_private_key_file(self.privateKey)
     self.logger.debug('login IP:%s username:%s privateKey:%s' %
                       (self.hostname, self.username, self.privateKey))
     transport.auth_publickey(self.username, key, my_event)
     my_event.wait(120)
     if not my_event.is_set():
         self.logger.warn(
             'authentication timeout, ip:%s user:%s privateKey:%s' %
             (self.hostname, self.username, self.privateKey))
     if not transport.is_authenticated():
         error = transport.get_exception()
         if error is None:
             error = AuthenticationException(
                 'Authentication failed, privateKey: %s' % self.privateKey)
         raise error
    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))
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']
        )
Example #24
0
 def test_authentication_exception(self):
     self.mock_lookup_keys_manager.return_value.add_public_key = MagicMock(side_effect=AuthenticationException())
     result, message, status = self.run_add_pub_key_to_resource()
     self.assertFalse(result)
     self.assertEqual(status, 403)