Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 96 additions & 2 deletions keepercommander/commands/enterprise.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ def register_command_info(aliases, command_info):
SUPPORTED_USER_COLUMNS = ['name', 'status', 'transfer_status', 'node', 'team_count', 'teams', 'role_count',
'roles', 'alias', '2fa_enabled']
SUPPORTED_TEAM_COLUMNS = ['restricts', 'node', 'user_count', 'users', 'queued_user_count', 'queued_users', 'role_count', 'roles']
SUPPORTED_ROLE_COLUMNS = ['visible_below', 'default_role', 'admin', 'node', 'user_count', 'users', 'team_count', 'teams']
SUPPORTED_ROLE_COLUMNS = ['visible_below', 'default_role', 'admin', 'node', 'user_count', 'users', 'team_count', 'teams',
'enforcement_count', 'enforcements', 'managed_node_count', 'managed_nodes', 'managed_nodes_permissions']

enterprise_data_parser = argparse.ArgumentParser(prog='enterprise-down',
description='Download & decrypt enterprise data.')
Expand Down Expand Up @@ -662,7 +663,15 @@ def tree_node(node):
else:
columns = set()
if kwargs.get('columns'):
columns.update((x.strip() for x in kwargs.get('columns').split(',')))
raw_columns = kwargs.get('columns')
# Handle role(...) or roles(...) syntax by stripping the prefix and suffix
for prefix in ['roles(', 'role(', 'teams(', 'team(', 'users(', 'user(', 'nodes(', 'node(']:
if raw_columns.startswith(prefix):
raw_columns = raw_columns[len(prefix):]
if raw_columns.endswith(')'):
raw_columns = raw_columns[:-1]
break
columns.update((x.strip() for x in raw_columns.split(',')))
pattern = (kwargs.get('pattern') or '').lower()
if show_nodes:
supported_columns = SUPPORTED_NODE_COLUMNS
Expand Down Expand Up @@ -928,9 +937,54 @@ def tree_node(node):

displayed_columns = [x for x in supported_columns if x in columns]

role_enforcements = {} # type: Dict[int, dict]
if 'role_enforcements' in params.enterprise:
for re_entry in params.enterprise['role_enforcements']:
role_id = re_entry.get('role_id')
if role_id:
role_enforcements[role_id] = re_entry.get('enforcements', {})

role_managed_nodes = {} # type: Dict[int, List[dict]]
if 'managed_nodes' in params.enterprise:
node_names = {x['node_id']: x['data'].get('displayname') or params.enterprise['enterprise_name']
for x in params.enterprise['nodes']}
for mn in params.enterprise['managed_nodes']:
role_id = mn['role_id']
if role_id not in role_managed_nodes:
role_managed_nodes[role_id] = []
node_id = mn['managed_node_id']
role_managed_nodes[role_id].append({
'node_id': node_id,
'node_name': node_names.get(node_id, str(node_id)),
'cascade': mn.get('cascade_node_management', False)
})

role_privileges = {} # type: Dict[int, Dict[int, List[str]]]
is_msp = EnterpriseCommand.is_msp(params)
supported_privileges = {x[1].lower(): x[2] for x in constants.ROLE_PRIVILEGES}
if 'role_privileges' in params.enterprise:
for rp in params.enterprise['role_privileges']:
privilege = rp['privilege'].lower()
if privilege not in supported_privileges:
continue
if supported_privileges[privilege] == constants.PrivilegeScope.Hidden:
continue
if supported_privileges[privilege] == constants.PrivilegeScope.MSP and not is_msp:
continue
role_id = rp['role_id']
node_id = rp['managed_node_id']
if role_id not in role_privileges:
role_privileges[role_id] = {}
if node_id not in role_privileges[role_id]:
role_privileges[role_id][node_id] = []
role_privileges[role_id][node_id].append(privilege)

rows = []
for r in roles.values():
row = [r['id'], r['name']]
role_id = r['id']
managed_nodes_list = role_managed_nodes.get(role_id, [])

for column in displayed_columns:
if column == 'visible_below':
row.append(r['visible_below'])
Expand All @@ -949,6 +1003,46 @@ def tree_node(node):
elif column == 'teams':
team_names = [teams[team_uid]['name'] for team_uid in r['teams'] if team_uid in teams]
row.append(team_names)
elif column == 'enforcement_count':
enforcements = role_enforcements.get(role_id, {})
row.append(len(enforcements))
elif column == 'enforcements':
enforcements = role_enforcements.get(role_id, {})
row.append(list(enforcements.keys()))
elif column == 'managed_node_count':
row.append(len(managed_nodes_list))
elif column == 'managed_nodes':
managed_node_info = []
for mn in managed_nodes_list:
node_name = mn.get('node_name', '')
managed_node_info.append(node_name)
row.append(managed_node_info)
elif column == 'managed_nodes_permissions':
privileges_for_role = role_privileges.get(role_id, {})
is_json = kwargs.get('format') == 'json'
permissions_info = []

for mn in managed_nodes_list:
node_id = mn.get('node_id')
node_name = mn.get('node_name', '')
cascade = mn.get('cascade', False)
privs = privileges_for_role.get(node_id, [])

if is_json:
permissions_info.append({
'node_name': node_name,
'node_id': node_id,
'cascade': cascade,
'privileges': privs
})
else:
if privs:
permissions_info.append(f"{node_name} (cascade: {cascade}):")
for priv in privs:
permissions_info.append(f" {priv}")
else:
permissions_info.append(f"{node_name} (cascade: {cascade}): none")
row.append(permissions_info)
if pattern:
if not any(1 for x in row if x and str(x).lower().find(pattern) >= 0):
continue
Expand Down
7 changes: 7 additions & 0 deletions keepercommander/commands/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -2398,6 +2398,13 @@ def execute(self, params, **kwargs):
urls = {} # type: Dict[str, str]
for record_name in record_names:
record_uid = OneTimeShareCommand.resolve_record(params, record_name)

record = api.get_record(params, record_uid)
if record and hasattr(record, 'record_type'):
pam_record_types = {'pamDatabase', 'pamDirectory', 'pamMachine', 'pamUser', 'pamRemoteBrowser'}
if record.record_type in pam_record_types:
raise CommandError('one-time-share', 'One-Time Shares are currently not available for PAM records.')

record_key = params.record_cache[record_uid]['record_key_unencrypted']

client_key = utils.generate_aes_key()
Expand Down