Skip to content

Commit

Permalink
Implement SecureCRT groups parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxbey committed Sep 5, 2017
1 parent d8639f1 commit 44522e2
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 85 deletions.
2 changes: 1 addition & 1 deletion termius/porting/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def take_action(self, parsed_args):
)
provider.import_hosts()

self.log.info('Skipped: %i' % len(provider.skipped_hosts))
self.log.info('Skipped hosts %i' % len(provider.skipped_hosts))
self.log.info('SecureCRT hosts has been successfully imported.')

def get_parser(self, prog_name):
Expand Down
11 changes: 8 additions & 3 deletions termius/porting/providers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def import_hosts(self):

with self.storage:
for host in hosts_to_import:
if not self.get_existed_host(host):
if not self.is_host_exists(host):
self.storage.save(host)
else:
self.skipped_hosts.append(host.label)
Expand All @@ -44,10 +44,15 @@ def assign_ssh_key_ids(self, new_ssh_key):
new_ssh_key.id = existed_key.id
return new_ssh_key

def get_existed_host(self, new_host):
def is_host_exists(self, new_host):
"""Retrieve exited host for new host."""
existed_hosts = self.storage.filter(Host, label=new_host.label)
return existed_hosts and existed_hosts[0]
for host in existed_hosts:
if host.group and new_host.group:
if host.group.label == new_host.group.label:
return True

return False

def get_existed_key(self, new_ssh_key):
"""Retrieve exited key for new key."""
Expand Down
77 changes: 44 additions & 33 deletions termius/porting/providers/securecrt/parser.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,61 @@
# -*- coding: utf-8 -*-
"""Module with SecureCRT parser."""
import collections
from os.path import expanduser


class SecureCRTConfigParser(object):
"""SecureCRT xml parser."""

meta_sessions = ['Default']

@classmethod
def parse_hosts(cls, xml):
def __init__(self, xml):
self.xml = xml
self.tree = {}

def parse_hosts(self):
"""Parse SecureCRT Sessions."""
sessions = cls.get_element_by_name(
xml.getchildren(), 'Sessions'
sessions = self.get_element_by_name(
self.xml.getchildren(), 'Sessions'
).getchildren()

parsed_hosts = []

for session in sessions:
if session.get('name') not in cls.meta_sessions:
host = cls.make_host(session)
if not host:
continue

parsed_hosts.append(host)
self.parse_sessions(sessions, self.tree)

return parsed_hosts
return self.tree

@classmethod
def parse_identity(cls, xml):
def parse_sessions(self, sessions, parent_node):
for session in sessions:
if session.get('name') not in self.meta_sessions:
if not self.is_session_group(session):
host = self.make_host(session)
if not host:
continue
parent_node[host['label']] = host
else:
parent_node[session.get('name')] = {'group': True}
self.parse_sessions(
session.getchildren(),
parent_node[session.get('name')]
)

def is_session_group(self, session):
return self.get_element_by_name(
session.getchildren(), 'Hostname'
) is None

def parse_identity(self):
"""Parse SecureCRT SSH2 raw key."""
identity = cls.get_element_by_name(
xml.getchildren(), 'SSH2'
identity = self.get_element_by_name(
self.xml.getchildren(), 'SSH2'
)
if identity is None:
return None

identity_filename = cls.get_element_by_name(
identity_filename = self.get_element_by_name(
identity.getchildren(),
'Identity Filename V2'
)

if not cls.check_attribute(identity_filename):
if not self.check_attribute(identity_filename):
return None

path = identity_filename.text.split('/')
Expand All @@ -59,33 +73,30 @@ def parse_identity(cls, xml):

return private_key_path, public_key_path

@classmethod
def make_host(cls, session):
def make_host(self, session):
"""Adapt SecureCRT Session to Termius host."""
session_attrs = session.getchildren()

hostname = cls.get_element_by_name(session_attrs, 'Hostname')
port = cls.get_element_by_name(session_attrs, '[SSH2] Port')
username = cls.get_element_by_name(session_attrs, 'Username')
hostname = self.get_element_by_name(session_attrs, 'Hostname')
port = self.get_element_by_name(session_attrs, '[SSH2] Port')
username = self.get_element_by_name(session_attrs, 'Username')

if not cls.check_attribute(hostname):
if not self.check_attribute(hostname):
return None

return {
'label': session.get('name'),
'hostname': hostname.text,
'port': port.text if cls.check_attribute(port) else '22',
'port': port.text if self.check_attribute(port) else '22',
'username': username.text
if cls.check_attribute(username) else None
if self.check_attribute(username) else None
}

@classmethod
def check_attribute(cls, attr):
def check_attribute(self, attr):
"""Check an attribute."""
return attr is not None and attr.text

@classmethod
def get_element_by_name(cls, elements, name):
def get_element_by_name(self, elements, name):
"""Get SecureCRT config block."""
for element in elements:
if element.get('name') == name:
Expand Down
104 changes: 56 additions & 48 deletions termius/porting/providers/securecrt/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,78 +19,86 @@ def __init__(self, source, *args, **kwargs):
"""Contruct new service to sync ssh config."""
super(SecureCRTPortingProvider, self).__init__(*args, **kwargs)

self.config_source = source
xml_root = ElementTree.parse(source).getroot()
self.parser = SecureCRTConfigParser(xml_root)

def export_hosts(self):
"""Skip export."""
pass

def provider_hosts(self):
"""Retrieve host instances from ssh config."""
root = ElementTree.parse(self.config_source).getroot()
self.logger.info('Got SecureCRT xml root...')
hosts = []
self.logger.info('Parse SecureCRT hosts...')
raw_hosts = SecureCRTConfigParser.parse_hosts(
root
)
self.logger.info('Parsed %i entries.' % len(raw_hosts))
identity_paths = SecureCRTConfigParser.parse_identity(root)
main_group = Group(label='SecureCRT')
result_hosts = []
tree = self.parser.parse_hosts()

group_config = SshConfig(
identity=Identity(
is_visible=False,
label='SecureCRT'
)
)
root_group = Group(label='SecureCRT')

identity_paths = self.parser.parse_identity()
if identity_paths:
self.logger.info('Found private key path: %s' % identity_paths[0])
self.logger.info('Found public key path: %s' % identity_paths[1])
try:
with open(identity_paths[0], 'r') as private_key_file:
private_key = private_key_file.read()

with open(identity_paths[1], 'r') as public_key_file:
public_key = public_key_file.read()

key = SshKey(
label='SecureCRT',
private_key=private_key,
public_key=public_key
key = self.create_key(identity_paths)
root_group.ssh_config = SshConfig(
identity=Identity(
ssh_key=key,
label='SecureCRT',
is_visible=False
)
)
group_config.identity.ssh_key = key
except IOError:
self.logger.info(
'Warning: cannot import SSH2 raw key %s' %
identity_paths[1]
)

main_group.ssh_config = group_config
self.create_entries_from_tree(tree, result_hosts, root_group)
self.logger.info('Parsed hosts %i' % len(result_hosts))
return result_hosts

for raw_host in raw_hosts:
host = Host(
label=raw_host['label'],
address=raw_host['hostname']
)
host.group = main_group
ssh_config = SshConfig(
port=raw_host['port']
)
def create_entries_from_tree(self, tree, result_hosts, parent_group=None):
for label, node in tree.iteritems():
if not isinstance(node, dict):
continue

if raw_host['username']:
identity = Identity(
username=raw_host.get('username'),
is_visible=False,
label=raw_host.get('username')
if not node.get('group', None):
result_hosts.append(
self.create_host(node, parent_group)
)
else:
group = Group(label=label, parent_group=parent_group)
self.create_entries_from_tree(node, result_hosts, group)

def create_host(self, raw_host, group):
host = Host(
label=raw_host['label'],
address=raw_host['hostname'],
group=group
)
host.ssh_config = SshConfig(
port=raw_host['port']
)

ssh_config.identity = identity
if raw_host['username']:
identity = Identity(
username=raw_host.get('username'),
is_visible=False,
label=raw_host.get('username')
)

host.ssh_config = ssh_config
host.ssh_config.identity = identity

hosts.append(host)
return host

self.logger.info('Adapted %i entries.' % len(raw_hosts))
return hosts
def create_key(self, identity_paths):
with open(identity_paths[0], 'r') as private_key_file:
private_key = private_key_file.read()

with open(identity_paths[1], 'r') as public_key_file:
public_key = public_key_file.read()

return SshKey(
label='SecureCRT',
private_key=private_key,
public_key=public_key
)

0 comments on commit 44522e2

Please sign in to comment.