Hello community, here is the log from the commit of package azure-cli-role for openSUSE:Factory checked in at 2018-10-15 10:47:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/azure-cli-role (Old) and /work/SRC/openSUSE:Factory/.azure-cli-role.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "azure-cli-role" Mon Oct 15 10:47:04 2018 rev:4 rq:641213 version:2.1.4 Changes: -------- --- /work/SRC/openSUSE:Factory/azure-cli-role/azure-cli-role.changes 2018-05-13 16:03:09.862492425 +0200 +++ /work/SRC/openSUSE:Factory/.azure-cli-role.new/azure-cli-role.changes 2018-10-15 10:47:05.375156242 +0200 @@ -1,0 +2,9 @@ +Wed Sep 19 09:12:47 UTC 2018 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- New upstream release + + Version 2.1.4 + + For detailed information about changes see the + HISTORY.txt file provided with this package +- Update Requires from setup.py + +------------------------------------------------------------------- Old: ---- azure-cli-role-2.0.22.tar.gz New: ---- azure-cli-role-2.1.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ azure-cli-role.spec ++++++ --- /var/tmp/diff_new_pack.h3JeT7/_old 2018-10-15 10:47:07.131154367 +0200 +++ /var/tmp/diff_new_pack.h3JeT7/_new 2018-10-15 10:47:07.131154367 +0200 @@ -12,12 +12,12 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: azure-cli-role -Version: 2.0.22 +Version: 2.1.4 Release: 0 Summary: Microsoft Azure CLI 'role' Command Module for Role-Based Access Control (RBAC) License: MIT @@ -35,9 +35,9 @@ Requires: azure-cli-core Requires: azure-cli-nspkg Requires: python3-azure-graphrbac >= 0.40.0 -Requires: python3-azure-keyvault >= 0.3.7 -Requires: python3-azure-mgmt-authorization >= 0.40.0 -Requires: python3-azure-mgmt-monitor >= 0.5.0 +Requires: python3-azure-keyvault >= 1.1.0 +Requires: python3-azure-mgmt-authorization >= 0.50.0 +Requires: python3-azure-mgmt-monitor >= 0.5.2 Requires: python3-azure-nspkg Requires: python3-pytz Conflicts: azure-cli < 2.0.0 ++++++ azure-cli-role-2.0.22.tar.gz -> azure-cli-role-2.1.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/HISTORY.rst new/azure-cli-role-2.1.4/HISTORY.rst --- old/azure-cli-role-2.0.22/HISTORY.rst 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/HISTORY.rst 2018-08-23 01:07:57.000000000 +0200 @@ -2,10 +2,55 @@ Release History =============== +2.1.4 +++++++ +* Minor fixes. -2.0.22 + +2.1.3 +++++++ +* role assignment: fix a recent regression that principalName is missing + +2.1.2 +++++++ +* support for stack profile 2017-03-09-profile + +2.1.1 ++++++ +* `ad app update`: Fixes issue where generic update parameters would not work correctly. + +2.1.0 ++++++ +* BREAKING CHANGE: 'show' commands log error message and fail with exit code of 3 upon a missing resource. + +2.0.27 +++++++ +* Minor fixes. + +2.0.26 ++++++ +* Minor fixes. +2.0.25 +++++++ +* ad: remove stack traces from graph exceptions before surface to users +* ad sp create: do not throw if CLI can't resolve app id + +2.0.25 +++++++ +* Minor fixes. + +2.0.24 +++++++ +* ad app update: add generic update support + +2.0.23 +++++++ +* BREAKING CHANGE: remove deprecated `az ad sp reset-credentials` +* Minor fixes. + +2.0.22 +++++++ * `sdist` is now compatible with wheel 0.31.0 2.0.21 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/PKG-INFO new/azure-cli-role-2.1.4/PKG-INFO --- old/azure-cli-role-2.0.22/PKG-INFO 2018-04-06 19:33:56.000000000 +0200 +++ new/azure-cli-role-2.1.4/PKG-INFO 2018-08-23 01:09:56.000000000 +0200 @@ -1,12 +1,11 @@ Metadata-Version: 1.1 Name: azure-cli-role -Version: 2.0.22 +Version: 2.1.4 Summary: Microsoft Azure Command-Line Tools Role Command Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation Author-email: azpy...@microsoft.com License: MIT -Description-Content-Type: UNKNOWN Description: Microsoft Azure CLI 'role' Command Module for Role-Based Access Control (RBAC) ============================================================================== @@ -20,10 +19,55 @@ Release History =============== + 2.1.4 + ++++++ + * Minor fixes. - 2.0.22 + + 2.1.3 + ++++++ + * role assignment: fix a recent regression that principalName is missing + + 2.1.2 + ++++++ + * support for stack profile 2017-03-09-profile + + 2.1.1 + +++++ + * `ad app update`: Fixes issue where generic update parameters would not work correctly. + + 2.1.0 + +++++ + * BREAKING CHANGE: 'show' commands log error message and fail with exit code of 3 upon a missing resource. + + 2.0.27 + ++++++ + * Minor fixes. + + 2.0.26 ++++++ + * Minor fixes. + 2.0.25 + ++++++ + * ad: remove stack traces from graph exceptions before surface to users + * ad sp create: do not throw if CLI can't resolve app id + + 2.0.25 + ++++++ + * Minor fixes. + + 2.0.24 + ++++++ + * ad app update: add generic update support + + 2.0.23 + ++++++ + * BREAKING CHANGE: remove deprecated `az ad sp reset-credentials` + * Minor fixes. + + 2.0.22 + ++++++ * `sdist` is now compatible with wheel 0.31.0 2.0.21 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure/cli/command_modules/role/__init__.py new/azure-cli-role-2.1.4/azure/cli/command_modules/role/__init__.py --- old/azure-cli-role-2.0.22/azure/cli/command_modules/role/__init__.py 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure/cli/command_modules/role/__init__.py 2018-08-23 01:07:57.000000000 +0200 @@ -4,6 +4,7 @@ # -------------------------------------------------------------------------------------------- from azure.cli.core import AzCommandsLoader +from azure.cli.core.profiles import ResourceType import azure.cli.command_modules.role._help # pylint: disable=unused-import @@ -13,7 +14,10 @@ def __init__(self, cli_ctx=None): from azure.cli.core.commands import CliCommandType role_custom = CliCommandType(operations_tmpl='azure.cli.command_modules.role.custom#{}') - super(RoleCommandsLoader, self).__init__(cli_ctx=cli_ctx, custom_command_type=role_custom) + super(RoleCommandsLoader, self).__init__(cli_ctx=cli_ctx, + resource_type=ResourceType.MGMT_AUTHORIZATION, + operation_group='role_assignments', + custom_command_type=role_custom) def load_command_table(self, args): from azure.cli.command_modules.role.commands import load_command_table diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure/cli/command_modules/role/_client_factory.py new/azure-cli-role-2.1.4/azure/cli/command_modules/role/_client_factory.py --- old/azure-cli-role-2.0.22/azure/cli/command_modules/role/_client_factory.py 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure/cli/command_modules/role/_client_factory.py 2018-08-23 01:07:57.000000000 +0200 @@ -6,14 +6,14 @@ def _auth_client_factory(cli_ctx, scope=None): import re + from azure.cli.core.profiles import ResourceType from azure.cli.core.commands.client_factory import get_mgmt_service_client - from azure.mgmt.authorization import AuthorizationManagementClient subscription_id = None if scope: matched = re.match('/subscriptions/(?P<subscription>[^/]*)/', scope) if matched: subscription_id = matched.groupdict()['subscription'] - return get_mgmt_service_client(cli_ctx, AuthorizationManagementClient, subscription_id=subscription_id) + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_AUTHORIZATION, subscription_id=subscription_id) def _graph_client_factory(cli_ctx, **_): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure/cli/command_modules/role/_help.py new/azure-cli-role-2.1.4/azure/cli/command_modules/role/_help.py --- old/azure-cli-role-2.0.22/azure/cli/command_modules/role/_help.py 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure/cli/command_modules/role/_help.py 2018-08-23 01:07:57.000000000 +0200 @@ -1,3 +1,4 @@ +# coding=utf-8 # -------------------------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. @@ -72,11 +73,6 @@ short-summary: delete a service principal's credential. """ -helps['ad sp reset-credentials'] = """ - type: command - short-summary: (Deprecated, use "az ad sp credential reset") -""" - helps['ad sp credential reset'] = """ type: command short-summary: Reset a service principal credential. @@ -117,14 +113,14 @@ type: command short-summary: Get the details of a service principal. """ +helps['ad app'] = """ + type: group + short-summary: Manage applications with AAD Graph. +""" helps['ad app delete'] = """ type: command short-summary: Delete an application. """ -helps['ad app create'] = """ - type: command - short-summary: Create an application. -""" helps['ad app list'] = """ type: command short-summary: List applications. @@ -136,6 +132,24 @@ helps['ad app update'] = """ type: command short-summary: Update an application. + examples: + - name: update a native application with delegated permission of "access the AAD directory as the signed-in user" + text: | + az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --required-resource-accesses @manifest.json + ("manifest.json" contains the following content) + [{ + "resourceAppId": "00000002-0000-0000-c000-000000000000", + "resourceAccess": [ + { + "id": "a42657d6-7f20-40e3-b6f0-cee03008a62a", + "type": "Scope" + } + ] + }] + - name: update an application's group membership claims to "All" + text: > + az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --set groupMembershipClaims=All + """ helps['ad user list'] = """ type: command @@ -165,6 +179,10 @@ short-summary: List role assignments. long-summary: By default, only assignments scoped to subscription will be displayed. To view assignments scoped by resource or group, use `--all`. """ +helps['role assignment list-changelogs'] = """ + type: command + short-summary: List changelogs for role assignments. +""" helps['role definition'] = """ type: group short-summary: Manage role definitions. @@ -223,35 +241,6 @@ - name: --role-definition type: string short-summary: Description of a role as JSON, or a path to a file containing a JSON description. - examples: - - name: Create a role with read-only access to storage and network resources, and the ability to start or restart VMs. - text: | - az role definition create --role-definition '{ - "Name": "Contoso On-call", - "Description": "Perform VM actions and read storage and network information." - "Actions": [ - "Microsoft.Compute/*/read", - "Microsoft.Compute/virtualMachines/start/action", - "Microsoft.Compute/virtualMachines/restart/action", - "Microsoft.Network/*/read", - "Microsoft.Storage/*/read", - "Microsoft.Authorization/*/read", - "Microsoft.Resources/subscriptions/resourceGroups/read", - "Microsoft.Resources/subscriptions/resourceGroups/resources/read", - "Microsoft.Insights/alertRules/*", - "Microsoft.Support/*" - ], - "DataActions": [ - "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/*" - ], - "NotDataActions": [ - "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write" - ], - "AssignableScopes": ["/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"] - }' - - name: Create a role from a file containing a JSON description. - text: > - az role definition create --role-definition ad-role.json """ helps['ad'] = """ type: group @@ -261,9 +250,9 @@ type: command short-summary: Create a web application, web API or native application examples: - - name: Create a native application with delegated permission of "access the AAD directory as the signed-in user + - name: Create a native application with delegated permission of "access the AAD directory as the signed-in user" text: | - az ad app create --display-name my-native --native-app --requiredResourceAccess @manifest.json + az ad app create --display-name my-native --native-app --required-resource-accesses @manifest.json ("manifest.json" contains the following content) [{ "resourceAppId": "00000002-0000-0000-c000-000000000000", @@ -279,10 +268,18 @@ type: group short-summary: Manage Azure Active Directory groups. """ +helps['ad group create'] = """ + type: command + short-summary: Create a group in the directory. +""" helps['ad group member'] = """ type: group short-summary: Manage Azure Active Directory group members. """ +helps['ad group member check'] = """ + type: command + short-summary: Check if a member is in a group. +""" helps['ad sp'] = """ type: group short-summary: Manage Azure Active Directory service principals for automation authentication. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure/cli/command_modules/role/_params.py new/azure-cli-role-2.1.4/azure/cli/command_modules/role/_params.py --- old/azure-cli-role-2.0.22/azure/cli/command_modules/role/_params.py 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure/cli/command_modules/role/_params.py 2018-08-23 01:07:57.000000000 +0200 @@ -18,6 +18,9 @@ # pylint: disable=too-many-statements def load_arguments(self, _): + with self.argument_context('ad') as c: + c.argument('_subscription') # hide global subscription param + with self.argument_context('ad app') as c: c.argument('app_id', help='application id') c.argument('application_object_id', options_list=('--object-id',)) @@ -39,9 +42,6 @@ help="resource scopes and roles the application requires access to. Should be in manifest json format. See examples below for details") c.argument('native_app', arg_type=get_three_state_flag(), help="an application which can be installed on a user's device or computer") - with self.argument_context('ad') as c: - c.ignore('additional_properties') - with self.argument_context('ad sp') as c: c.argument('identifier', options_list=['--id'], help='service principal name, or object id') @@ -54,7 +54,7 @@ c.argument('skip_assignment', arg_type=get_three_state_flag(), help='do not create default assignment') c.argument('show_auth_for_sdk', options_list='--sdk-auth', help='output result in compatible with Azure SDK auth file', arg_type=get_three_state_flag()) - for item in ['create-for-rbac', 'reset-credentials', 'ad sp']: + for item in ['create-for-rbac', 'credential reset']: with self.argument_context('ad sp {}'.format(item)) as c: c.argument('name', name_arg_type) c.argument('cert', arg_group='Credential', validator=validate_cert) @@ -64,6 +64,11 @@ c.argument('keyvault', arg_group='Credential') c.argument('append', action='store_true', help='Append the new credential instead of overwriting.') + for item in ['delete', 'list']: + with self.argument_context('ad sp credential {}'.format(item)) as c: + c.argument('key_id', help='credential key id') + c.argument('cert', action='store_true', help='a certificate based credential') + with self.argument_context('ad') as c: c.argument('display_name', help='object\'s display name or its prefix') c.argument('identifier_uri', help='graph application identifier, must be in uri format') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure/cli/command_modules/role/commands.py new/azure-cli-role-2.1.4/azure/cli/command_modules/role/commands.py --- old/azure-cli-role-2.0.22/azure/cli/command_modules/role/commands.py 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure/cli/command_modules/role/commands.py 2018-08-23 01:07:57.000000000 +0200 @@ -9,8 +9,6 @@ from azure.cli.core.profiles import PROFILE_TYPE from azure.cli.core.commands import CliCommandType -from azure.cli.core.util import empty_on_404 - from ._client_factory import (_auth_client_factory, _graph_client_factory) @@ -25,9 +23,12 @@ ('Scope', r['scope'])]) for r in result] -def get_role_definition_op(operation_name): - return 'azure.mgmt.authorization.operations.role_definitions_operations' \ - '#RoleDefinitionsOperations.{}'.format(operation_name) +def graph_err_handler(ex): + from azure.graphrbac.models.graph_error import GraphErrorException + if isinstance(ex, GraphErrorException): + from knack.util import CLIError + raise CLIError(ex.message) + raise ex def get_role_definitions(cli_ctx, _): @@ -63,6 +64,8 @@ client_factory=get_graph_client_groups ) + role_custom = CliCommandType(operations_tmpl='azure.cli.command_modules.role.custom#{}') + with self.command_group('role definition') as g: g.custom_command('list', 'list_role_definitions', table_transformer=transform_definition_list) g.custom_command('delete', 'delete_role_definition') @@ -75,41 +78,43 @@ g.custom_command('create', 'create_role_assignment') g.custom_command('list-changelogs', 'list_role_assignment_change_logs') - with self.command_group('ad app', client_factory=get_graph_client_applications, resource_type=PROFILE_TYPE, min_api='2017-03-10') as g: + with self.command_group('ad app', client_factory=get_graph_client_applications, resource_type=PROFILE_TYPE, + exception_handler=graph_err_handler) as g: g.custom_command('create', 'create_application') g.custom_command('delete', 'delete_application') g.custom_command('list', 'list_apps') - g.custom_command('show', 'show_application', exception_handler=empty_on_404) - g.custom_command('update', 'update_application') + g.custom_show_command('show', 'show_application') + g.generic_update_command('update', setter_name='patch_application', setter_type=role_custom, + getter_name='show_application', getter_type=role_custom, + custom_func_name='update_application', custom_func_type=role_custom) - with self.command_group('ad sp', resource_type=PROFILE_TYPE, min_api='2017-03-10') as g: + with self.command_group('ad sp', resource_type=PROFILE_TYPE, exception_handler=graph_err_handler) as g: g.custom_command('create', 'create_service_principal') g.custom_command('delete', 'delete_service_principal') g.custom_command('list', 'list_sps', client_factory=get_graph_client_service_principals) - g.custom_command('show', 'show_service_principal', client_factory=get_graph_client_service_principals, exception_handler=empty_on_404) + g.custom_show_command('show', 'show_service_principal', client_factory=get_graph_client_service_principals) # RBAC related - with self.command_group('ad sp') as g: + with self.command_group('ad sp', exception_handler=graph_err_handler) as g: g.custom_command('create-for-rbac', 'create_service_principal_for_rbac') - g.custom_command('reset-credentials', 'reset_service_principal_credential', deprecate_info='ad sp credential reset') g.custom_command('credential reset', 'reset_service_principal_credential') g.custom_command('credential list', 'list_service_principal_credentials') g.custom_command('credential delete', 'delete_service_principal_credential') - with self.command_group('ad user', role_users_sdk) as g: + with self.command_group('ad user', role_users_sdk, exception_handler=graph_err_handler) as g: g.command('delete', 'delete') - g.command('show', 'get', exception_handler=empty_on_404) + g.show_command('show', 'get') g.custom_command('list', 'list_users', client_factory=get_graph_client_users) g.custom_command('create', 'create_user', client_factory=get_graph_client_users, doc_string_source='azure.graphrbac.models#UserCreateParameters') - with self.command_group('ad group', role_group_sdk) as g: + with self.command_group('ad group', role_group_sdk, exception_handler=graph_err_handler) as g: g.custom_command('create', 'create_group', client_factory=get_graph_client_groups) g.command('delete', 'delete') - g.command('show', 'get', exception_handler=empty_on_404) + g.show_command('show', 'get') g.command('get-member-groups', 'get_member_groups') g.custom_command('list', 'list_groups', client_factory=get_graph_client_groups) - with self.command_group('ad group member', role_group_sdk) as g: + with self.command_group('ad group member', role_group_sdk, exception_handler=graph_err_handler) as g: g.command('list', 'get_group_members') g.command('add', 'add_member') g.command('remove', 'remove_member') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure/cli/command_modules/role/custom.py new/azure-cli-role-2.1.4/azure/cli/command_modules/role/custom.py --- old/azure-cli-role-2.0.22/azure/cli/command_modules/role/custom.py 2018-04-06 19:33:13.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure/cli/command_modules/role/custom.py 2018-08-23 01:07:57.000000000 +0200 @@ -16,13 +16,12 @@ from knack.log import get_logger from knack.util import CLIError, todict +from msrest.serialization import TZ_UTC from msrestazure.azure_exceptions import CloudError from azure.graphrbac.models.graph_error import GraphErrorException from azure.cli.core.util import get_file_json, shell_safe_json_parse -from azure.mgmt.authorization.models import RoleAssignmentCreateParameters, Permission, RoleDefinition - from azure.graphrbac.models import (ApplicationCreateParameters, ApplicationUpdateParameters, PasswordCredential, KeyCredential, UserCreateParameters, PasswordProfile, ServicePrincipalCreateParameters, RequiredResourceAccess, @@ -46,20 +45,47 @@ def create_role_definition(cmd, role_definition): - return _create_update_role_definition(cmd.cli_ctx, role_definition, for_update=False) + return _create_update_role_definition(cmd, role_definition, for_update=False) def update_role_definition(cmd, role_definition): - return _create_update_role_definition(cmd.cli_ctx, role_definition, for_update=True) + return _create_update_role_definition(cmd, role_definition, for_update=True) + + +def _get_role_property(obj, property_name): + if isinstance(obj, dict): + if 'properties' in obj: + return obj['properties'][property_name] + return obj[property_name] + + if hasattr(obj, 'properties'): + return getattr(obj.properties, property_name) + return getattr(obj, property_name) + + +def _set_role_property(obj, property_name, property_value): + if isinstance(obj, dict): + if 'properties' in obj: + obj['properties'][property_name] = property_value + else: + obj[property_name] = property_value + else: + if hasattr(obj, 'properties'): + setattr(obj.properties, property_name, property_value) + else: + setattr(obj, property_name, property_value) -def _create_update_role_definition(cli_ctx, role_definition, for_update): - definitions_client = _auth_client_factory(cli_ctx).role_definitions +def _create_update_role_definition(cmd, role_definition, for_update): + from azure.cli.core.profiles import ResourceType, get_sdk, get_api_version + definitions_client = _auth_client_factory(cmd.cli_ctx).role_definitions if os.path.exists(role_definition): role_definition = get_file_json(role_definition) else: role_definition = shell_safe_json_parse(role_definition) + if not isinstance(role_definition, dict): + raise CLIError('Invalid role defintion. A valid dictionary JSON representation is expected.') # to workaround service defects, ensure property names are camel case names = [p for p in role_definition if p[:1].isupper()] for n in names: @@ -78,7 +104,7 @@ raise CLIError('Please provide the unique logic name of an existing role') role_definition['name'] = matched[0].name # ensure correct logical name and guid name. For update we accept both - role_name = matched[0].role_name + role_name = _get_role_property(matched[0], 'role_name') role_id = matched[0].name else: role_id = _gen_guid() @@ -86,20 +112,39 @@ if not for_update and 'assignableScopes' not in role_definition: raise CLIError("please provide 'assignableScopes'") + Permission, RoleDefinition, RoleDefinitionProperties = get_sdk(cmd.cli_ctx, ResourceType.MGMT_AUTHORIZATION, + 'Permission', 'RoleDefinition', + 'RoleDefinitionProperties', mod='models', + operation_group='role_definitions') + + version = getattr(get_api_version(cmd.cli_ctx, ResourceType.MGMT_AUTHORIZATION), 'role_definitions') + if version == '2015-07-01': + permission = Permission(actions=role_definition.get('actions', None), + not_actions=role_definition.get('notActions', None)) + + properties = RoleDefinitionProperties(role_name=role_name, + description=role_definition.get('description', None), + type=_CUSTOM_RULE, + assignable_scopes=role_definition['assignableScopes'], + permissions=[permission]) + definition = RoleDefinition(name=role_id, properties=properties) + return definitions_client.create_or_update(role_definition_id=role_id, + scope=properties.assignable_scopes[0], + properties=properties) + permission = Permission(actions=role_definition.get('actions', None), not_actions=role_definition.get('notActions', None), data_actions=role_definition.get('dataActions', None), not_data_actions=role_definition.get('notDataActions', None)) - role_definition = RoleDefinition(role_name=role_name, - description=role_definition.get('description', None), - role_type=_CUSTOM_RULE, - assignable_scopes=role_definition['assignableScopes'], - permissions=[permission]) - + definition = RoleDefinition(role_name=role_name, + description=role_definition.get('description', None), + role_type=_CUSTOM_RULE, + assignable_scopes=role_definition['assignableScopes'], + permissions=[permission]) return definitions_client.create_or_update(role_definition_id=role_id, - scope=role_definition.assignable_scopes[0], - role_definition=role_definition) + scope=definition.assignable_scopes[0], + role_definition=definition) def delete_role_definition(cmd, name, resource_group_name=None, scope=None, @@ -115,9 +160,9 @@ def _search_role_definitions(definitions_client, name, scope, custom_role_only=False): roles = list(definitions_client.list(scope)) if name: - roles = [r for r in roles if r.name == name or r.role_name == name] + roles = [r for r in roles if r.name == name or _get_role_property(r, 'role_name') == name] if custom_role_only: - roles = [r for r in roles if r.role_type == _CUSTOM_RULE] + roles = [r for r in roles if _get_role_property(r, 'role_type') == _CUSTOM_RULE] return roles @@ -131,18 +176,31 @@ def _create_role_assignment(cli_ctx, role, assignee, resource_group_name=None, scope=None, resolve_assignee=True): + from azure.cli.core.profiles import ResourceType, get_sdk, get_api_version factory = _auth_client_factory(cli_ctx, scope) assignments_client = factory.role_assignments definitions_client = factory.role_definitions + RoleAssignmentCreateParameters, RoleAssignmentProperties = get_sdk(cli_ctx, ResourceType.MGMT_AUTHORIZATION, + 'RoleAssignmentCreateParameters', + 'RoleAssignmentProperties', mod='models', + operation_group='role_assignments') scope = _build_role_scope(resource_group_name, scope, assignments_client.config.subscription_id) role_id = _resolve_role_id(role, scope, definitions_client) object_id = _resolve_object_id(cli_ctx, assignee) if resolve_assignee else assignee - parameters = RoleAssignmentCreateParameters(role_definition_id=role_id, principal_id=object_id) + version = getattr(get_api_version(cli_ctx, ResourceType.MGMT_AUTHORIZATION), 'role_assignments') assignment_name = _gen_guid() custom_headers = None + + if version == '2015-07-01': + properties = RoleAssignmentProperties(role_definition_id=role_id, principal_id=object_id) + return assignments_client.create(scope=scope, role_assignment_name=assignment_name, + properties=properties, + custom_headers=custom_headers) + + parameters = RoleAssignmentCreateParameters(role_definition_id=role_id, principal_id=object_id) return assignments_client.create(scope=scope, role_assignment_name=assignment_name, parameters=parameters, custom_headers=custom_headers) @@ -153,7 +211,7 @@ show_all=False, include_groups=False, include_classic_administrators=False): ''' :param include_groups: include extra assignments to the groups of which the user is a - member(transitively). Supported only for a user principal. + member(transitively). ''' graph_client = _graph_client_factory(cmd.cli_ctx) factory = _auth_client_factory(cmd.cli_ctx, scope) @@ -184,13 +242,17 @@ # 2. fill in role names role_defs = list(definitions_client.list( scope=scope or ('/subscriptions/' + definitions_client.config.subscription_id))) - role_dics = {i.id: i.role_name for i in role_defs} + role_dics = {i.id: _get_role_property(i, 'role_name') for i in role_defs} for i in results: - if role_dics.get(i['roleDefinitionId']): - i['roleDefinitionName'] = role_dics[i['roleDefinitionId']] + if not i.get('roleDefinitionName'): + if role_dics.get(_get_role_property(i, 'roleDefinitionId')): + _set_role_property(i, 'roleDefinitionName', role_dics[_get_role_property(i, 'roleDefinitionId')]) + else: + i['roleDefinitionName'] = None # the role definition might have been deleted # fill in principal names - principal_ids = set(i['principalId'] for i in results if i['principalId']) + principal_ids = set(_get_role_property(i, 'principalId') for i in results if _get_role_property(i, 'principalId')) + if principal_ids: try: principals = _get_object_stubs(graph_client, principal_ids) @@ -198,12 +260,15 @@ for i in [r for r in results if not r.get('principalName')]: i['principalName'] = '' - if principal_dics.get(i['principalId']): - i['principalName'] = principal_dics[i['principalId']] + if principal_dics.get(_get_role_property(i, 'principalId')): + _set_role_property(i, 'principalName', principal_dics[_get_role_property(i, 'principalId')]) except (CloudError, GraphErrorException) as ex: # failure on resolving principal due to graph permission should not fail the whole thing logger.info("Failed to resolve graph object information per error '%s'", ex) + for r in results: + if not r.get('additionalProperties'): # remove the useless "additionalProperties" + r.pop('additionalProperties', None) return results @@ -255,7 +320,7 @@ # pylint: disable=too-many-nested-blocks, too-many-statements result = [] start_events, end_events, offline_events, client = _get_assignment_events(cmd.cli_ctx, start_time, end_time) - role_defs = {d.id: [d.role_name, d.id.split('/')[-1]] for d in list_role_definitions(cmd)} + role_defs = {d.id: [_get_role_property(d, 'role_name'), d.id.split('/')[-1]] for d in list_role_definitions(cmd)} for op_id in start_events: e = end_events.get(op_id, None) @@ -341,7 +406,7 @@ def _backfill_assignments_for_co_admins(cli_ctx, auth_client, assignee=None): co_admins = auth_client.classic_administrators.list() # known swagger bug on api-version handling - co_admins = [x for x in co_admins if x.email_address] + co_admins = [x for x in co_admins if _get_role_property(x, 'email_address')] graph_client = _graph_client_factory(cli_ctx) if assignee: # apply assignee filter if applicable if _is_guid(assignee): @@ -352,26 +417,27 @@ assignee = _get_displayable_name(result[0]).lower() except ValueError: pass - co_admins = [x for x in co_admins if assignee == x.email_address.lower()] + co_admins = [x for x in co_admins if assignee == _get_role_property(x, 'email_address').lower()] if not co_admins: return [] result, users = [], [] for i in range(0, len(co_admins), 10): # graph allows up to 10 query filters, so split into chunks here - upn_queries = ["userPrincipalName eq '{}'".format(x.email_address) for x in co_admins[i:i + 10]] + upn_queries = ["userPrincipalName eq '{}'".format(_get_role_property(x, 'email_address')) + for x in co_admins[i:i + 10]] temp = list(list_users(graph_client.users, query_filter=' or '.join(upn_queries))) users += temp upns = {u.user_principal_name: u.object_id for u in users} for admin in co_admins: na_text = 'NA(classic admins)' - email = admin.email_address + email = _get_role_property(admin, 'email_address') result.append({ 'id': na_text, 'name': na_text, 'principalId': upns.get(email), 'principalName': email, - 'roleDefinitionName': admin.role, + 'roleDefinitionName': _get_role_property(admin, 'role'), 'roleDefinitionId': 'NA(classic admin role)', 'scope': '/subscriptions/' + auth_client.config.subscription_id }) @@ -433,13 +499,13 @@ if assignments: assignments = [a for a in assignments if ( not scope or - include_inherited and re.match(a.scope, scope, re.I) or - a.scope.lower() == scope.lower() + include_inherited and re.match(_get_role_property(a, 'scope'), scope, re.I) or + _get_role_property(a, 'scope').lower() == scope.lower() )] if role: role_id = _resolve_role_id(role, scope, definitions_client) - assignments = [i for i in assignments if i.role_definition_id == role_id] + assignments = [i for i in assignments if _get_role_property(i, 'role_definition_id') == role_id] return assignments @@ -603,12 +669,11 @@ return result -def update_application(client, identifier, display_name=None, homepage=None, +def update_application(instance, display_name=None, homepage=None, # pylint: disable=unused-argument identifier_uris=None, password=None, reply_urls=None, key_value=None, key_type=None, key_usage=None, start_date=None, end_date=None, available_to_other_tenants=None, oauth2_allow_implicit_flow=None, required_resource_accesses=None): - object_id = _resolve_application(client, identifier) - + from azure.cli.core.commands.arm import make_camel_case, make_snake_case password_creds, key_creds, required_accesses = None, None, None if any([key_value, key_type, key_usage, start_date, end_date]): password_creds, key_creds = _build_application_creds(password, key_value, key_type, @@ -617,16 +682,31 @@ if required_resource_accesses: required_accesses = _build_application_accesses(required_resource_accesses) - app_patch_param = ApplicationUpdateParameters(display_name=display_name, - homepage=homepage, - identifier_uris=identifier_uris, - reply_urls=reply_urls, - key_credentials=key_creds, - password_credentials=password_creds, - available_to_other_tenants=available_to_other_tenants, - required_resource_access=required_accesses, - oauth2_allow_implicit_flow=oauth2_allow_implicit_flow) - return client.patch(object_id, app_patch_param) + # Workaround until https://github.com/Azure/azure-rest-api-specs/issues/3437 is fixed + def _get_property(name): + try: + return getattr(instance, make_snake_case(name)) + except AttributeError: + return instance.additional_properties.get(make_camel_case(name), None) + + app_patch_param = ApplicationUpdateParameters( + display_name=display_name or _get_property('display_name'), + homepage=homepage or _get_property('homepage'), + identifier_uris=identifier_uris or _get_property('identifier_uris'), + reply_urls=reply_urls or _get_property('reply_urls'), + key_credentials=key_creds or _get_property('key_credentials'), + password_credentials=password_creds or _get_property('password_credentials'), + available_to_other_tenants=available_to_other_tenants or _get_property('available_to_other_tenants'), + required_resource_access=required_accesses or _get_property('required_resource_access'), + oauth2_allow_implicit_flow=oauth2_allow_implicit_flow or _get_property('oauth2_allow_implicit_flow')) + + return app_patch_param + + +def patch_application(cmd, identifier, parameters): + graph_client = _graph_client_factory(cmd.cli_ctx) + object_id = _resolve_application(graph_client.applications, identifier) + return graph_client.applications.patch(object_id, parameters) def _build_application_accesses(required_resource_accesses): @@ -699,7 +779,7 @@ def _create_service_principal(cli_ctx, identifier, resolve_app=True): client = _graph_client_factory(cli_ctx) - + app_id = identifier if resolve_app: if _is_guid(identifier): result = list(client.applications.list(filter="appId eq '{}'".format(identifier))) @@ -707,11 +787,12 @@ result = list(client.applications.list( filter="identifierUris/any(s:s eq '{}')".format(identifier))) - if not result: # assume we get an object id - result = [client.applications.get(identifier)] - app_id = result[0].app_id - else: - app_id = identifier + try: + if not result: # assume we get an object id + result = [client.applications.get(identifier)] + app_id = result[0].app_id + except GraphErrorException: + pass # fallback to appid (maybe from an external tenant?) return client.service_principals.create(ServicePrincipalCreateParameters(app_id, True)) @@ -884,7 +965,6 @@ scopes=None, role='Contributor', show_auth_for_sdk=None, skip_assignment=False, keyvault=None): import time - import pytz graph_client = _graph_client_factory(cmd.cli_ctx) role_client = _auth_client_factory(cmd.cli_ctx).role_assignments @@ -904,7 +984,7 @@ if aad_sps: raise CLIError("'{}' already exists.".format(name)) - app_start_date = datetime.datetime.now(pytz.utc) + app_start_date = datetime.datetime.now(TZ_UTC) app_end_date = app_start_date + relativedelta(years=years or 1) app_display_name = app_display_name or ('azure-cli-' + @@ -995,12 +1075,14 @@ def _get_keyvault_client(cli_ctx): from azure.cli.core._profile import Profile - from azure.keyvault import KeyVaultClient, KeyVaultAuthentication + from azure.cli.core.profiles import get_api_version, ResourceType + from azure.keyvault import KeyVaultAuthentication, KeyVaultClient + version = str(get_api_version(cli_ctx, ResourceType.DATA_KEYVAULT)) def _get_token(server, resource, scope): # pylint: disable=unused-argument return Profile(cli_ctx=cli_ctx).get_login_credentials(resource)[0]._token_retriever() # pylint: disable=protected-access - return KeyVaultClient(KeyVaultAuthentication(_get_token)) + return KeyVaultClient(KeyVaultAuthentication(_get_token), api_version=version) def _create_self_signed_cert(start_date, end_date): # pylint: disable=too-many-locals @@ -1146,7 +1228,6 @@ def reset_service_principal_credential(cmd, name, password=None, create_cert=False, cert=None, years=None, keyvault=None, append=False): - import pytz client = _graph_client_factory(cmd.cli_ctx) # pylint: disable=no-member @@ -1164,7 +1245,7 @@ 'app id guid, or app id uri') app = show_application(client.applications, aad_sps[0].app_id) - app_start_date = datetime.datetime.now(pytz.utc) + app_start_date = datetime.datetime.now(TZ_UTC) app_end_date = app_start_date + relativedelta(years=years or 1) # build a new password/cert credential and patch it diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure_cli_role.egg-info/PKG-INFO new/azure-cli-role-2.1.4/azure_cli_role.egg-info/PKG-INFO --- old/azure-cli-role-2.0.22/azure_cli_role.egg-info/PKG-INFO 2018-04-06 19:33:56.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure_cli_role.egg-info/PKG-INFO 2018-08-23 01:09:56.000000000 +0200 @@ -1,12 +1,11 @@ Metadata-Version: 1.1 Name: azure-cli-role -Version: 2.0.22 +Version: 2.1.4 Summary: Microsoft Azure Command-Line Tools Role Command Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation Author-email: azpy...@microsoft.com License: MIT -Description-Content-Type: UNKNOWN Description: Microsoft Azure CLI 'role' Command Module for Role-Based Access Control (RBAC) ============================================================================== @@ -20,10 +19,55 @@ Release History =============== + 2.1.4 + ++++++ + * Minor fixes. - 2.0.22 + + 2.1.3 + ++++++ + * role assignment: fix a recent regression that principalName is missing + + 2.1.2 + ++++++ + * support for stack profile 2017-03-09-profile + + 2.1.1 + +++++ + * `ad app update`: Fixes issue where generic update parameters would not work correctly. + + 2.1.0 + +++++ + * BREAKING CHANGE: 'show' commands log error message and fail with exit code of 3 upon a missing resource. + + 2.0.27 + ++++++ + * Minor fixes. + + 2.0.26 ++++++ + * Minor fixes. + 2.0.25 + ++++++ + * ad: remove stack traces from graph exceptions before surface to users + * ad sp create: do not throw if CLI can't resolve app id + + 2.0.25 + ++++++ + * Minor fixes. + + 2.0.24 + ++++++ + * ad app update: add generic update support + + 2.0.23 + ++++++ + * BREAKING CHANGE: remove deprecated `az ad sp reset-credentials` + * Minor fixes. + + 2.0.22 + ++++++ * `sdist` is now compatible with wheel 0.31.0 2.0.21 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/azure_cli_role.egg-info/requires.txt new/azure-cli-role-2.1.4/azure_cli_role.egg-info/requires.txt --- old/azure-cli-role-2.0.22/azure_cli_role.egg-info/requires.txt 2018-04-06 19:33:56.000000000 +0200 +++ new/azure-cli-role-2.1.4/azure_cli_role.egg-info/requires.txt 2018-08-23 01:09:56.000000000 +0200 @@ -1,6 +1,6 @@ azure-cli-core -azure-mgmt-authorization==0.40.0 -azure-mgmt-monitor==0.5.0 +azure-mgmt-authorization==0.50.0 +azure-mgmt-monitor==0.5.2 azure-graphrbac==0.40.0 -azure-keyvault==0.3.7 +azure-keyvault==1.1.0 pytz diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-role-2.0.22/setup.py new/azure-cli-role-2.1.4/setup.py --- old/azure-cli-role-2.0.22/setup.py 2018-04-06 19:33:14.000000000 +0200 +++ new/azure-cli-role-2.1.4/setup.py 2018-08-23 01:07:57.000000000 +0200 @@ -14,7 +14,8 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") cmdclass = {} -VERSION = "2.0.22" +VERSION = "2.1.4" + CLASSIFIERS = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', @@ -31,10 +32,10 @@ DEPENDENCIES = [ 'azure-cli-core', - 'azure-mgmt-authorization==0.40.0', - 'azure-mgmt-monitor==0.5.0', + 'azure-mgmt-authorization==0.50.0', + 'azure-mgmt-monitor==0.5.2', 'azure-graphrbac==0.40.0', - 'azure-keyvault==0.3.7', + 'azure-keyvault==1.1.0', 'pytz' ]