From 8461b8a1036012d01cbbe57acbedf3ccfe6430ca Mon Sep 17 00:00:00 2001 From: shanepeckham Date: Thu, 9 Aug 2018 11:51:13 +0100 Subject: [PATCH 1/5] Rebase az ad app permissions list grant --- .../azure/cli/command_modules/role/_help.py | 14 +++++ .../azure/cli/command_modules/role/_params.py | 7 +++ .../cli/command_modules/role/commands.py | 2 + .../azure/cli/command_modules/role/custom.py | 55 ++++++++++++++++++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py index 31a74b8d04e..0cac3fa91dc 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py @@ -175,6 +175,20 @@ type: command short-summary: remove an application owner. """ +helps['ad app permission grant'] = """ + type: command + short-summary: Grant an app OAuth2 permissions from another app + examples: + - name: Grant a native application with OAuth2 permissions from an existing AAD app with TTL of 2 years + text: az ad app permission grant --id e042ec79-34cd-498f-9d9f-1234234 --app-id a0322f79-57df-498f-9d9f-12678 --expires 2 +""" +helps['ad app permission list'] = """ + type: command + short-summary: List the app OAuth2 permissions + examples: + - name: List the OAuth2 permissions for an existing AAD app + text: az ad app permission list --id e042ec79-34cd-498f-9d9f-1234234 +""" helps['ad user list'] = """ type: command short-summary: List Azure Active Directory users. diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_params.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_params.py index 3f7b5ec308d..a9b9effc8dd 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_params.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_params.py @@ -46,6 +46,13 @@ def load_arguments(self, _): with self.argument_context('ad app owner list') as c: c.argument('identifier', options_list=['--id'], help='identifier uri, application id, or object id of the application') + with self.argument_context('ad app permission grant') as c: + c.argument('app_id', help='clientId of an existing app from which you want to grant permissions to your app') + c.argument('expires', help='Expiry date for the permissions in years, options include 1, 2 or never.') + + with self.argument_context('ad app permission list') as c: + c.argument('identifier', options_list=['--id'], help='identifier uri, application id, or object id of the associated application') + with self.argument_context('ad sp') as c: c.argument('identifier', options_list=['--id'], help='service principal name, or object id') diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/commands.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/commands.py index 8f5b3eacb55..a4728d400ff 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/commands.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/commands.py @@ -84,6 +84,8 @@ def load_command_table(self, _): g.custom_command('delete', 'delete_application') g.custom_command('list', 'list_apps') g.custom_show_command('show', 'show_application') + g.custom_command('permission grant', 'grant_application') + g.custom_command('permission list', 'list_granted_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) diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py index 7b1d8cd2b7f..21692230f11 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py @@ -669,6 +669,53 @@ def create_application(client, display_name, homepage=None, identifier_uris=None return result +def list_granted_application(cmd, identifier): + graph_client = _graph_client_factory(cmd.cli_ctx) + + # Get the Service Principal ObjectId for the client app + client_sp_object_id = _resolve_service_principal(graph_client.service_principals, appid=identifier) + + # Get the OAuth2 permissions client app + permissions = graph_client.oauth2.get( + filter="clientId eq '{}'".format(client_sp_object_id)) + + return permissions.additional_properties['value'] + + +def grant_application(cmd, identifier, app_id, expires='1'): + graph_client = _graph_client_factory(cmd.cli_ctx) + + # Get the Service Principal ObjectId for the client app + client_sp_object_id = _resolve_service_principal(graph_client.service_principals, appid=identifier) + + # Get the Service Principal ObjectId for associated app + associated_sp_object_id = _resolve_service_principal(graph_client.service_principals, appid=app_id) + + # Build payload + start_date = datetime.datetime.utcnow() + end_date = start_date + relativedelta(years=1) + + if expires == '2': + end_date = start_date + relativedelta(years=2) + elif expires.lower() == 'never': + end_date = start_date + relativedelta(years=1000) + + payload = { + "odata.type": "Microsoft.DirectoryServices.OAuth2PermissionGrant", + "clientId": client_sp_object_id, + "consentType": "AllPrincipals", + "resourceId": associated_sp_object_id, + "scope": "user_impersonation", + "startTime": start_date.isoformat(), + "expiryTime": end_date.isoformat() + } + + # Grant OAuth2 permissions + response = graph_client.oauth2.post(payload) + + return response + + 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, @@ -892,9 +939,13 @@ def delete_service_principal_credential(cmd, identifier, key_id, cert=False): key_id, identifier)) -def _resolve_service_principal(client, identifier): +def _resolve_service_principal(client, identifier=None, appid=None): # todo: confirm with graph team that a service principal name must be unique - result = list(client.list(filter="servicePrincipalNames/any(c:c eq '{}')".format(identifier))) + if identifier: + result = list(client.list(filter="servicePrincipalNames/any(c:c eq '{}')".format(identifier))) + elif appid: + result = list(client.list(filter="appId eq '{}'".format(appid))) + if result: return result[0].object_id if _is_guid(identifier): From 560c8adace967a87c38e85d30a49d777b1923adf Mon Sep 17 00:00:00 2001 From: shanepeckham Date: Thu, 9 Aug 2018 18:10:17 +0100 Subject: [PATCH 2/5] Rebased az ad app permissions list grant --- .../azure/cli/command_modules/role/_help.py | 4 ++++ .../azure/cli/command_modules/role/custom.py | 18 +++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py index 0cac3fa91dc..00732e5506f 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py @@ -175,6 +175,10 @@ type: command short-summary: remove an application owner. """ +helps['ad app permission'] = """ + type: group + short-summary: manage an application's OAuth2 permissions. +""" helps['ad app permission grant'] = """ type: command short-summary: Grant an app OAuth2 permissions from another app diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py index 21692230f11..5f4071c4270 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py @@ -673,11 +673,11 @@ def list_granted_application(cmd, identifier): graph_client = _graph_client_factory(cmd.cli_ctx) # Get the Service Principal ObjectId for the client app - client_sp_object_id = _resolve_service_principal(graph_client.service_principals, appid=identifier) + client_sp_object_id = _resolve_service_principal(graph_client.service_principals, identifier) # Get the OAuth2 permissions client app permissions = graph_client.oauth2.get( - filter="clientId eq '{}'".format(client_sp_object_id)) + filter="clientId eq '{}'".format(client_sp_object_id)) # pylint: disable=no-member return permissions.additional_properties['value'] @@ -686,10 +686,10 @@ def grant_application(cmd, identifier, app_id, expires='1'): graph_client = _graph_client_factory(cmd.cli_ctx) # Get the Service Principal ObjectId for the client app - client_sp_object_id = _resolve_service_principal(graph_client.service_principals, appid=identifier) + client_sp_object_id = _resolve_service_principal(graph_client.service_principals, identifier) # Get the Service Principal ObjectId for associated app - associated_sp_object_id = _resolve_service_principal(graph_client.service_principals, appid=app_id) + associated_sp_object_id = _resolve_service_principal(graph_client.service_principals, app_id) # Build payload start_date = datetime.datetime.utcnow() @@ -711,7 +711,7 @@ def grant_application(cmd, identifier, app_id, expires='1'): } # Grant OAuth2 permissions - response = graph_client.oauth2.post(payload) + response = graph_client.oauth2.post(payload) # pylint: disable=no-member return response @@ -939,13 +939,9 @@ def delete_service_principal_credential(cmd, identifier, key_id, cert=False): key_id, identifier)) -def _resolve_service_principal(client, identifier=None, appid=None): +def _resolve_service_principal(client, identifier): # todo: confirm with graph team that a service principal name must be unique - if identifier: - result = list(client.list(filter="servicePrincipalNames/any(c:c eq '{}')".format(identifier))) - elif appid: - result = list(client.list(filter="appId eq '{}'".format(appid))) - + result = list(client.list(filter="servicePrincipalNames/any(c:c eq '{}')".format(identifier))) if result: return result[0].object_id if _is_guid(identifier): From 9750f047cf7893bc8d28157a2f33cfdb01818cf2 Mon Sep 17 00:00:00 2001 From: Shane Peckham Date: Thu, 27 Sep 2018 15:40:25 +0100 Subject: [PATCH 3/5] Update _help.py --- .../azure-cli-role/azure/cli/command_modules/role/_help.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py index 00732e5506f..fba2652bad2 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/_help.py @@ -181,14 +181,14 @@ """ helps['ad app permission grant'] = """ type: command - short-summary: Grant an app OAuth2 permissions from another app + short-summary: Grant an app permissions from another app examples: - - name: Grant a native application with OAuth2 permissions from an existing AAD app with TTL of 2 years + - name: Grant a native application with permissions to access an existing API with TTL of 2 years text: az ad app permission grant --id e042ec79-34cd-498f-9d9f-1234234 --app-id a0322f79-57df-498f-9d9f-12678 --expires 2 """ helps['ad app permission list'] = """ type: command - short-summary: List the app OAuth2 permissions + short-summary: List the app permissions examples: - name: List the OAuth2 permissions for an existing AAD app text: az ad app permission list --id e042ec79-34cd-498f-9d9f-1234234 From 4b70f4a9782a7a6862e49a47cd0a9d4c9e1a6ff8 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Thu, 18 Oct 2018 14:20:19 -0700 Subject: [PATCH 4/5] fix a breaking change --- .../azure-cli-role/azure/cli/command_modules/role/custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py index 5f4071c4270..2102c8c00b3 100644 --- a/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py +++ b/src/command_modules/azure-cli-role/azure/cli/command_modules/role/custom.py @@ -711,7 +711,7 @@ def grant_application(cmd, identifier, app_id, expires='1'): } # Grant OAuth2 permissions - response = graph_client.oauth2.post(payload) # pylint: disable=no-member + response = graph_client.oauth2.grant(payload) # pylint: disable=no-member return response From 5b553da47cbede2b5b3ee4ac740d03737441432c Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Thu, 18 Oct 2018 14:43:50 -0700 Subject: [PATCH 5/5] version update --- src/command_modules/azure-cli-role/HISTORY.rst | 4 ++++ src/command_modules/azure-cli-role/setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/command_modules/azure-cli-role/HISTORY.rst b/src/command_modules/azure-cli-role/HISTORY.rst index 76d680dedbf..b5798763195 100644 --- a/src/command_modules/azure-cli-role/HISTORY.rst +++ b/src/command_modules/azure-cli-role/HISTORY.rst @@ -2,6 +2,10 @@ Release History =============== +2.1.9 +++++++ +* support grant permissions to AAD apps + 2.1.8 ++++++ * support add/remove/list owner on AAD Applciation and Group objects diff --git a/src/command_modules/azure-cli-role/setup.py b/src/command_modules/azure-cli-role/setup.py index cc686f9db1f..6d138f15c84 100644 --- a/src/command_modules/azure-cli-role/setup.py +++ b/src/command_modules/azure-cli-role/setup.py @@ -14,7 +14,7 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") cmdclass = {} -VERSION = "2.1.8" +VERSION = "2.1.9" CLASSIFIERS = [ 'Development Status :: 5 - Production/Stable',