Example #1
0
    def run_server(self):
        # Run server in separate process
        signal.signal(signal.SIGINT, lambda x, y: None)
        # dict to send back in queue once server is started
        new_info = {}

        creds = self.server_info.get('credentials', {}).get('ftp', {})
        username = creds.get('username', self._generate_credential())
        password = creds.get(
            'password',
            SecretString.from_plaintext(self._generate_credential()))

        # return credentials back to parent process
        new_info['credentials'] = Credentials(
            {'ftp': {
                'username': username,
                'password': password
            }})

        address = self.server_info['address']
        port = self.server_info.get('port', DEFAULT_PORT)
        address = (address, port)
        path = self.server_info.setdefault('path', '/')
        new_info['path'] = path

        # Create FTP Server
        auth = DummyAuthorizer()
        auth.add_user(username,
                      to_plaintext(password),
                      path,
                      perm='elradfmwMT')
        handler = FTPHandler
        handler.authorizer = auth
        server = FTPServer(address, handler)
        server.max_cons = 256
        server.max_cons_per_ip = 5

        # Set up logging for the FTP Server
        logfile = self.server_info.get('logfile', None)
        if logfile:
            ftp_logger = logging.getLogger('pyftpdlib')
            ftp_logger.setLevel(logging.DEBUG)
            ftp_logger.propagate = False
            ftp_handler = logging.FileHandler(logfile)
            ftp_logger.addHandler(ftp_handler)

        # Retrieve allocated port
        _, new_info['port'] = server.address

        # Send new info back to parent process
        self.queue.put(new_info)

        # Listen
        server.serve_forever()
Example #2
0
    def verify_server(self):
        ip = self.server_info.get('address', '0.0.0.0')
        port = self.server_info['port']
        username = self.server_info['credentials']['ftp']['username']
        password = to_plaintext(
            self.server_info['credentials']['ftp']['password'])

        # Connect to FTP server
        client = ftplib.FTP()
        client.connect(host=ip, port=port)
        client.login(user=username, passwd=password)
        # Get list of files from FTP server
        client.dir(lambda x: None)
        client.quit()
 def test_http_auth(self):
     with FileServer(
             protocol='http',
             subnet='127.0.0.1/32',
             custom=dict(http_auth=True),
             credentials=dict(
                 http=dict(username='******', password='******'))) as fs:
         self.assertEqual(fs['address'], '127.0.0.1')
         self.assertIn('port', fs)
         self.assertEqual(fs['path'], '/')
         self.assertEqual(fs['protocol'], 'http')
         self.assertEqual(fs['credentials']['http']['username'], 'test')
         self.assertEqual(
             to_plaintext(fs['credentials']['http']['password']), 'test123')
 def test_http_multipart_multi(self):
     with tempfile.TemporaryDirectory() as td:
         with FileServer(protocol='http', subnet='127.0.0.1/32',
                         path=td) as fs:
             url = 'http://{u}:{p}@127.0.0.1:{port}/test.txt'.format(
                 port=fs['port'],
                 u=fs['credentials']['http']['username'],
                 p=to_plaintext(fs['credentials']['http']['password']))
             orig_data = ['test123'] * 2
             data, content_type = encode_multipart_formdata(orig_data)
             r = requests.post(url,
                               data=data,
                               headers={'Content-type': content_type})
             self.assertEqual(r.status_code, 201)
             with open(os.path.join(td, 'test_1.txt'), 'rb') as f:
                 test_data = f.read().decode()
             self.assertEqual(test_data, orig_data[1])
Example #5
0
def get_username_password(device, username=None, password=None, creds=None):
    """ Gets the username and password to use to log into the device console.
    """
    if username is None or password is None:
        if hasattr(device, 'credentials') and device.credentials:
            if creds is not None:
                cred = creds[0] if isinstance(creds, list) else creds
            else:
                cred = 'default'
            username = device.credentials.get(cred, {}).get("username", "")
            password = to_plaintext(
                device.credentials.get(cred, {}).get("password", ""))
        else:
            username = device.tacacs.get("username", "")
            password = device.passwords.get("line", "")

    if not username or not password:
        raise Exception("No username or password was provided.")

    return username, password
 def test_ftp_pass_args(self):
     with tempfile.TemporaryDirectory() as td:
         with FileServer(protocol='ftp',
                         subnet='127.0.0.1',
                         credentials={
                             'ftp': {
                                 'username': '******',
                                 'password': '******'
                             }
                         },
                         path=td) as fs:
             self.assertEqual(fs['address'], '127.0.0.1')
             self.assertEqual(fs['subnet'], '127.0.0.1')
             self.assertEqual(fs['path'], td)
             self.assertEqual(fs['protocol'], 'ftp')
             self.assertIsInstance(fs['credentials']['ftp']['password'],
                                   SecretString)
             self.assertEqual(
                 to_plaintext(fs['credentials']['ftp']['password']),
                 'mypass')
Example #7
0
    def run_server(self):
        # Run server in separate process
        address = self.server_info.get('address', '0.0.0.0')
        port = self.server_info.get('port', DEFAULT_PORT)
        local_dir = self.server_info.get('path', '/')
        # use authentication by default
        http_auth = self.server_info.get('custom', {}).get('http_auth', True)

        # Setup local HTTP server
        server_address = (address, port)
        httpd = http.server.HTTPServer(server_address, HTTPRequestHandler)
        httpd.directory = local_dir
        local_port = httpd.server_port

        if http_auth:
            creds = self.server_info.get('credentials', {}).get('http', {})
            username = creds.get('username', self._generate_credential())
            password = creds.get(
                'password',
                SecretString.from_plaintext(self._generate_credential()))

            httpd.auth = base64.b64encode("{}:{}".format(
                username, to_plaintext(password)).encode()).decode()
        else:
            httpd.auth = None

        # Send new info back to parent process
        self.queue.put({
            'port': local_port,
            'path': local_dir,
            'credentials':
            Credentials({'http': {
                'username': username,
                'password': password
            }}) if http_auth else {}
        })

        # Keep process alive
        httpd.serve_forever()
Example #8
0
def get_username_password(connection):
    username = password = None
    if connection.connection_info.get('credentials'):
        try:
            username = str(
                connection.connection_info['credentials']['rest']['username'])
            password = to_plaintext(
                connection.connection_info['credentials']['rest']['password'])
        except Exception:
            pass

    if not username:
        username = connection.connection_info.get('username', \
            connection.device.tacacs.username \
            if connection.device.tacacs.username \
            else 'admin')

    if not password:
        password = connection.connection_info.get('password', \
            connection.device.passwords.tacacs \
            if connection.device.passwords.tacacs \
            else 'admin')

    return (username, password)
Example #9
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.device = kwargs.get('device')
        self.channel = None
        dev_args = self.connection_info
        if dev_args.get('protocol', '') != 'gnmi':
            msg = 'Invalid protocol {0}'.format(dev_args.get('protocol', ''))
            raise TypeError(msg)

        # Initialize ClientBuilder
        self.client_os = self.os_class_map.get(self.device.os, None)
        if self.device.os == 'iosxe':
            self.support_prefix = True
            self.json_ietf = True
        else:
            self.support_prefix = False
            self.json_ietf = False

        # ClientBuilder target is IP:Port
        target = dev_args.get('host') + ':' + str(dev_args.get('port'))
        builder = ClientBuilder(target).set_os(self.client_os)

        # Gather certificate settings
        root = dev_args.get('root_certificate')
        if not root:
            root = None
        if root and os.path.isfile(root):
            root = open(root, 'rb').read()
        chain = dev_args.get('certificate_chain')
        if not chain:
            chain = None
        if chain and os.path.isfile(chain):
            chain = open(chain, 'rb').read()
        private_key = dev_args.get('private_key', '')
        if not private_key:
            private_key = None
        if private_key and os.path.isfile(private_key):
            private_key = open(private_key, 'rb').read()
        if any((root, chain, private_key)):
            builder.set_secure(root, private_key, chain)
            builder.set_ssl_target_override(
                dev_args.get('ssl_name_override', ''))
            log.info("Connecting secure channel")
        else:
            builder._set_insecure()
            log.info("Connecting insecure channel")

        # Get/set credentials
        username = dev_args.get('username', '')
        password = dev_args.get('password', '')
        if not username or not password:
            creds = dev_args.get('credentials', '')
            if not creds:
                raise KeyError('No credentials found for testbed')
            if 'gnmi' not in creds:
                log.info('Credentials used from {0}'.format(next(iter(creds))))
            gnmi_uname_pwd = creds.get('')
            if not gnmi_uname_pwd:
                raise KeyError('No credentials found for gNMI')
            username = gnmi_uname_pwd.get('username', '')
            password = gnmi_uname_pwd.get('password', '')
            if not username or not password:
                raise KeyError('No credentials found for gNMI testbed')
            password = to_plaintext(password)
        builder.set_call_authentication(username, password)
        # builder.construct() connects grpc channel and returns client instance
        self.builder = builder
        self.gnmi = None
Example #10
0
    def connect(self):
        '''connect

        High-level api: opens the NetConf connection and exchanges
        capabilities. Since topology YAML file is parsed by BaseConnection,
        the following parameters can be specified in your YAML file.

        Parameters
        ----------

        host : `string`
            Hostname or IP address to connect to.
        port : `int`, optional
            By default port is 830, but some devices use the default SSH port
            of 22 so this may need to be specified.
        timeout : `int`, optional
            An optional keyed argument to set timeout value in seconds. By
            default this value is 30 seconds.
        username : `string`
            The username to use for SSH authentication.
        password : `string`
            The password used if using password authentication, or the
            passphrase to use for unlocking keys that require it.
        key_filename : `string`
            a filename where a the private key to be used can be found.
        allow_agent : `boolean`
            Enables querying SSH agent (if found) for keys. The default value
            is True.
        hostkey_verify : `boolean`
            Enables hostkey verification from ~/.ssh/known_hosts. The default
            value is False.
        look_for_keys : `boolean`
            Enables looking in the usual locations for ssh keys
            (e.g. ~/.ssh/id_*). The default value is True.
        ssh_config : `string`
            Enables parsing of an OpenSSH configuration file, if set to its
            path, e.g. ~/.ssh/config or to True. If the value is True,
            ncclient uses ~/.ssh/config. The default value is None.

        Raises
        ------

        Exception
            If the YAML file does not have correct connections section, or
            establishing transport to ip:port is failed, ssh authentication is
            failed, or other transport failures.

        Note
        ----

        There is no return from this method. If something goes wrong, an
        exception will be raised.


        YAML Example::

            devices:
                asr22:
                    type: 'ASR'
                    tacacs:
                        login_prompt: "login:"******"Password:"******"admin"
                    passwords:
                        tacacs: admin
                        enable: admin
                        line: admin
                    connections:
                        a:
                            protocol: telnet
                            ip: "1.2.3.4"
                            port: 2004
                        vty:
                            protocol : telnet
                            ip : "2.3.4.5"
                        netconf:
                            class: yang.connector.Netconf
                            ip : "2.3.4.5"
                            port: 830
                            username: admin
                            password: admin

        Code Example::

            >>> from pyats.topology import loader
            >>> testbed = loader.load('/users/xxx/xxx/asr22.yaml')
            >>> device = testbed.devices['asr22']
            >>> device.connect(alias='nc', via='netconf')
            >>>

        Expected Results::

            >>> device.nc.connected
            True
            >>> for iter in device.nc.server_capabilities:
            ...     print(iter)
            ...
            urn:ietf:params:xml:ns:yang:smiv2:RFC-1215?module=RFC-1215
            urn:ietf:params:xml:ns:yang:smiv2:SNMPv2-TC?module=SNMPv2-TC
            ...
            >>>
        '''

        if self.connected:
            return

        logger.debug(self.session)
        if not self.session.is_alive():
            self._session = transport.SSHSession(self._device_handler)

        # default values
        defaults = {
            'host': None,
            'port': 830,
            'timeout': 30,
            'username': None,
            'password': None,
            'key_filename': None,
            'allow_agent': False,
            'hostkey_verify': False,
            'look_for_keys': False,
            'ssh_config': None,
            }
        defaults.update(self.connection_info)

        # remove items
        disregards = ['class', 'model', 'protocol',
                      'async_mode', 'raise_mode', 'credentials']
        defaults = {k: v for k, v in defaults.items() if k not in disregards}

        # rename ip -> host, cast to str type
        if 'ip' in defaults:
            defaults['host'] = str(defaults.pop('ip'))

        # rename user -> username
        if 'user' in defaults:
            defaults['username'] = str(defaults.pop('user'))

        # check credentials
        if self.connection_info.get('credentials'):
            try:
                defaults['username'] = str(self.connection_info['credentials']['netconf']['username'])
            except Exception:
                pass
            try:
                defaults['password'] = to_plaintext(self.connection_info['credentials']['netconf']['password'])
            except Exception:
                pass

        # support sshtunnel
        if 'sshtunnel' in defaults:
            from unicon.sshutils import sshtunnel
            try:
                tunnel_port = sshtunnel.auto_tunnel_add(self.device, self.via)
                if tunnel_port:
                    defaults['host'] = self.device.connections[self.via] \
                                           .sshtunnel.tunnel_ip
                    defaults['port'] = tunnel_port
            except AttributeError as err:
                raise AttributeError("Cannot add ssh tunnel. Connection %s may "
                                     "not have ip/host or port.\n%s" % (self.via, err))
            del defaults['sshtunnel']

        defaults = {k: getattr(self, k, v) for k, v in defaults.items()}

        try:
            self.session.connect(**defaults)
            logger.info(banner('NETCONF CONNECTED'))
        except Exception:
            if self.session.transport:
                self.session.close()
            raise

        @atexit.register
        def cleanup():
            if self.session.transport:
                self.session.close()