Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commands related to Security permissions #582

Merged
merged 24 commits into from
May 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4fde12c
Fix python versions in Mac machines
ishitam8 Apr 12, 2019
528804e
Merge branch 'master' of https://github.com/Azure/azure-devops-cli-ex…
ishitam8 Apr 16, 2019
40b782b
Adding list and show namespace commands
ishitam8 Apr 16, 2019
99e9d5a
First draft of permissions commands
ishitam8 Apr 18, 2019
37a0975
Add and reset permission commands
ishitam8 Apr 21, 2019
707c696
Resolve permissions from json response
ishitam8 Apr 21, 2019
f5ea4f8
Adding some docs
ishitam8 Apr 22, 2019
47dcc6b
MInor
ishitam8 Apr 22, 2019
1e67ed7
Some changes in resolve permissions flow and table output
ishitam8 Apr 22, 2019
4281d4f
Update security_tokens.md
ishitam8 Apr 22, 2019
f4cc8f0
Update security_tokens.md
ishitam8 Apr 22, 2019
1569936
Remove json resolution, instead adding a switch
ishitam8 Apr 23, 2019
112d371
Refactoring the resolved json response
ishitam8 Apr 25, 2019
ace9cc1
Merge branch 'users/ishitam/securityPermissions' of https://github.co…
ishitam8 Apr 25, 2019
2ed1fec
Table format changes
ishitam8 May 2, 2019
3cd1e53
Merge with master
ishitam8 May 2, 2019
e198325
Selective output for add and reset commands
ishitam8 May 2, 2019
f814d1c
Merge branch 'master' of https://github.com/Azure/azure-devops-cli-ex…
ishitam8 May 2, 2019
1f63719
Merge branch 'master' of https://github.com/Azure/azure-devops-cli-ex…
ishitam8 May 6, 2019
812b7ec
PR comments
ishitam8 May 10, 2019
ba0a67e
Bug bash fixes and PR comments
ishitam8 May 16, 2019
72a494f
Pylint and Flake fixes
ishitam8 May 16, 2019
4d9318b
Merge branch 'master' of https://github.com/Azure/azure-devops-cli-ex…
ishitam8 May 16, 2019
3f5f5d2
Markdown styling fix
ishitam8 May 16, 2019
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
21 changes: 21 additions & 0 deletions azure-devops/azext_devops/dev/common/identities.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ def resolve_identity_as_id(identity_filter, organization):
return None


def resolve_identity_as_identity_descriptor(identity_filter, organization):
"""Takes an identity name, email, alias, or id, and returns the id.
"""
if identity_filter is None:
return identity_filter
if identity_filter.lower() == ME:
return get_current_identity(organization).descriptor
identity = resolve_identity(identity_filter, organization)
if identity is not None:
return identity.descriptor
return None


def resolve_identity_as_display_name(identity_filter, organization):
"""Takes an identity name, email, alias, or id, and returns the display name.
"""
Expand Down Expand Up @@ -116,5 +129,13 @@ def get_account_from_identity(identity):
return identity.provider_display_name


def get_identity_descriptor_from_subject_descriptor(subject_descriptor, organization):
identity_client = get_identity_client(organization)
identities = identity_client.read_identities(subject_descriptors=subject_descriptor)
snankani marked this conversation as resolved.
Show resolved Hide resolved
if identities:
return identities[0].descriptor
return subject_descriptor


ME = 'me'
_display_name_cache = get_cli_cache('identity_display_names', 3600 * 6)
5 changes: 5 additions & 0 deletions azure-devops/azext_devops/dev/common/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ def get_policy_client(organization=None):
return connection.get_client(VSTS_MODULE + 'v5_0.policy.policy_client.PolicyClient')


def get_security_client(organization=None):
connection = get_connection(organization)
return connection.get_client(VSTS_MODULE + 'v5_0.security.security_client.SecurityClient')


def get_settings_client(organization=None):
connection = get_connection(organization)
return connection.get_client(VSTS_MODULE + 'v5_0.settings.settings_client.SettingsClient')
Expand Down
77 changes: 77 additions & 0 deletions azure-devops/azext_devops/dev/team/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from __future__ import print_function
from collections import OrderedDict
from knack.util import CLIError
from azext_devops.dev.common.format import trim_for_display, date_time_to_only_date


Expand Down Expand Up @@ -166,6 +167,78 @@ def _transform_membership_row(row):
return table_row


def transform_namespaces_table_output(result):
table_output = []
for item in result:
table_output.append(_transform_namespace_row(item))
return table_output


def _transform_namespace_row(row):
table_row = OrderedDict()
table_row['Id'] = row['namespaceId']
table_row['Name'] = row['name']
return table_row


def transform_namespace_table_output(result):
table_output = []
for item in result[0]['actions']:
table_output.append(_transform_namespace_details_row(item))
return table_output


def _transform_namespace_details_row(row):
table_row = OrderedDict()
table_row['Name'] = row['name']
table_row['Permission Description'] = row['displayName']
table_row['Permission Bit'] = row['bit']
return table_row


def transform_acl_output(result):
table_output = []
for item in result:
table_output.append(_transform_acl_details_row(item))
return table_output


def _transform_acl_details_row(row):
if len(row['acesDictionary']) > 1:
raise CLIError('More than one entry found in Aces dictionary for this user/group.')
table_row = OrderedDict()
table_row['token'] = row['token']
ace = list(row['acesDictionary'].values())[0]
if row['includeExtendedInfo']:
if ace['extendedInfo']['effectiveAllow'] is not None:
table_row['Effective Allow'] = ace['extendedInfo']['effectiveAllow']
else:
table_row['Effective Allow'] = 0
if ace['extendedInfo']['effectiveDeny'] is not None:
table_row['Effective Deny'] = ace['extendedInfo']['effectiveDeny']
else:
table_row['Effective Deny'] = 0
return table_row


def transform_resolve_permission_bits(result):
table_output = []
ace_entry = list(result[0]['acesDictionary'].values())[0]
permissions = ace_entry['resolvedPermissions']
for permission in permissions:
table_output.append(_transform_resolve_bits_row(permission))
return table_output


def _transform_resolve_bits_row(row):
table_row = OrderedDict()
table_row['Name'] = row['name']
table_row['Bit'] = row['bit']
table_row['Permission Description'] = row['displayName']
table_row['Permission Value'] = row['effectivePermission']
return table_row


def transform_teams_table_output(result):
table_output = []
for item in sorted(result, key=_get_team_key):
Expand Down Expand Up @@ -265,6 +338,10 @@ def _get_extension_key(extension):
return extension['extensionName'].lower()


def _get_permission_key(permission_row):
return permission_row['displayName'].lower()


def _get_service_endpoint_key(service_endpoint_row):
return service_endpoint_row['name'].lower()

Expand Down
10 changes: 10 additions & 0 deletions azure-devops/azext_devops/dev/team/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ def load_team_help():
short-summary: Manage memberships for security groups
"""

helps['devops security permission'] = """
type: group
short-summary: Manage security permissions
"""

helps['devops security permission namespace'] = """
type: group
short-summary: Manage security namespaces
"""

helps['devops team'] = """
type: group
short-summary: Manage teams
Expand Down
24 changes: 23 additions & 1 deletion azure-devops/azext_devops/dev/team/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


from knack.arguments import enum_choice_list
from azure.cli.core.commands.parameters import get_enum_type
from azure.cli.core.commands.parameters import get_enum_type, get_three_state_flag
from azext_devops.dev.common.const import _TRUE_FALSE_SWITCH
from .const import (SERVICE_ENDPOINT_AUTHORIZATION_PERSONAL_ACCESS_TOKEN,
SERVICE_ENDPOINT_TYPE_GITHUB,
Expand Down Expand Up @@ -106,6 +106,28 @@ def load_team_arguments(self, _):
context.argument('relationship', arg_type=get_enum_type(_RELATIONSHIP_TYPES),
help='Get member of/members for this group.')

with self.argument_context('devops security permission') as context:
context.argument('namespace_id', options_list=('--namespace-id', '--id'),
help='ID of security namespace')
context.argument('token',
help='Security token.')
context.argument('subject',
help='User Email ID or Group descriptor')

with self.argument_context('devops security permission update') as context:
context.argument('merge', arg_type=get_three_state_flag(),
help='If set, the existing ACE has its allow and deny merged with \
the incoming ACE\'s allow and deny. If unset, the existing ACE is displaced.')
context.argument('allow_bit', type=int,
ishitam8 marked this conversation as resolved.
Show resolved Hide resolved
help='Allow bit or addition of bits. Required if --deny-bit is missing.')
context.argument('deny_bit', type=int,
help='Deny bit or addition of bits. Required if --allow-bit is missing.')

with self.argument_context('devops security permission reset') as context:
context.argument('permission_bit', type=int,
help='Permission bit or addition of permission bits which needs to be reset\
for given user/group and token.')

with self.argument_context('devops extension') as context:
context.argument('include_built_in', arg_type=get_enum_type(_TRUE_FALSE_SWITCH),
help='Include built in extensions.')
Expand Down
20 changes: 20 additions & 0 deletions azure-devops/azext_devops/dev/team/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
transform_group_table_output,
transform_memberships_table_output,
transform_membership_table_output,
transform_namespaces_table_output,
transform_namespace_table_output,
transform_acl_output,
transform_resolve_permission_bits,
transform_team_table_output,
transform_teams_table_output,
transform_team_members_table_output,
Expand Down Expand Up @@ -74,6 +78,10 @@
exception_handler=azure_devops_exception_handler
)

security_permissionOps = CliCommandType(
operations_tmpl='azext_devops.dev.team.security_permission#{}',
exception_handler=azure_devops_exception_handler
)

wikiOps = CliCommandType(
operations_tmpl='azext_devops.dev.team.wiki#{}',
Expand Down Expand Up @@ -143,6 +151,18 @@ def load_team_commands(self, _):
g.command('add', 'add_membership', table_transformer=transform_membership_table_output)
g.command('remove', 'remove_membership', confirmation='Are you sure you want to delete this relationship?')

with self.command_group('devops security permission', command_type=security_permissionOps) as g:
g.command('list', 'list_tokens', table_transformer=transform_acl_output)
g.command('update', 'update_permissions', table_transformer=transform_resolve_permission_bits)
g.command('reset-all', 'reset_all_permissions',
confirmation='Are you sure you want to reset all explicit permissions for this user/group and token?')
g.command('reset', 'reset_permissions', table_transformer=transform_resolve_permission_bits)
g.command('show', 'show_permissions', table_transformer=transform_resolve_permission_bits)

with self.command_group('devops security permission namespace', command_type=security_permissionOps) as g:
g.command('list', 'list_namespaces', table_transformer=transform_namespaces_table_output)
g.command('show', 'show_namespace', table_transformer=transform_namespace_table_output)

with self.command_group('devops wiki', command_type=wikiOps) as g:
g.command('create', 'create_wiki', table_transformer=transform_wiki_table_output)
g.command('list', 'list_wiki', table_transformer=transform_wikis_table_output)
Expand Down
Loading