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()
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])
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')
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()
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)
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
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()