Skip to content

Commit 5b3c524

Browse files
committed
ad-generic-update
1 parent 39abf17 commit 5b3c524

8 files changed

Lines changed: 1072 additions & 578 deletions

File tree

src/azure-cli/azure/cli/command_modules/role/_help.py

Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -261,65 +261,66 @@
261261
type: command
262262
short-summary: Update an application.
263263
examples:
264-
- name: update a native application with delegated permission of "access the AAD directory as the signed-in user"
265-
text: |
266-
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --required-resource-accesses @manifest.json
267-
("manifest.json" contains the following content)
268-
[{
269-
"resourceAppId": "00000002-0000-0000-c000-000000000000",
270-
"resourceAccess": [
271-
{
272-
"id": "a42657d6-7f20-40e3-b6f0-cee03008a62a",
273-
"type": "Scope"
274-
}
275-
]
276-
}]
277-
- name: declare an application role
278-
text: |
279-
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --app-roles @manifest.json
280-
("manifest.json" contains the following content)
281-
[{
282-
"allowedMemberTypes": [
283-
"User"
284-
],
285-
"description": "Approvers can mark documents as approved",
286-
"displayName": "Approver",
287-
"isEnabled": "true",
288-
"value": "approver"
289-
}]
290-
- name: update optional claims
291-
text: |
292-
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --optional-claims @manifest.json
293-
("manifest.json" contains the following content)
294-
{
295-
"idToken": [
296-
{
297-
"name": "auth_time",
298-
"essential": false
299-
}
300-
],
301-
"accessToken": [
302-
{
303-
"name": "ipaddr",
304-
"essential": false
305-
}
306-
],
307-
"saml2Token": [
308-
{
309-
"name": "upn",
310-
"essential": false
311-
},
312-
{
313-
"name": "extension_ab603c56068041afb2f6832e2a17e237_skypeId",
314-
"source": "user",
315-
"essential": false
316-
}
317-
]
318-
}
319-
- name: update an application's group membership claims to "All"
320-
text: >
321-
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --set groupMembershipClaims=All
322-
264+
- name: Update a native application with delegated permission of "access the AAD directory as the signed-in user"
265+
text: |
266+
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --required-resource-accesses @manifest.json
267+
("manifest.json" contains the following content)
268+
[{
269+
"resourceAppId": "00000002-0000-0000-c000-000000000000",
270+
"resourceAccess": [
271+
{
272+
"id": "a42657d6-7f20-40e3-b6f0-cee03008a62a",
273+
"type": "Scope"
274+
}
275+
]
276+
}]
277+
- name: Declare an application role
278+
text: |
279+
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --app-roles @manifest.json
280+
("manifest.json" contains the following content)
281+
[{
282+
"allowedMemberTypes": [
283+
"User"
284+
],
285+
"description": "Approvers can mark documents as approved",
286+
"displayName": "Approver",
287+
"isEnabled": "true",
288+
"value": "approver"
289+
}]
290+
- name: Update optional claims
291+
text: |
292+
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --optional-claims @manifest.json
293+
("manifest.json" contains the following content)
294+
{
295+
"idToken": [
296+
{
297+
"name": "auth_time",
298+
"essential": false
299+
}
300+
],
301+
"accessToken": [
302+
{
303+
"name": "ipaddr",
304+
"essential": false
305+
}
306+
],
307+
"saml2Token": [
308+
{
309+
"name": "upn",
310+
"essential": false
311+
},
312+
{
313+
"name": "extension_ab603c56068041afb2f6832e2a17e237_skypeId",
314+
"source": "user",
315+
"essential": false
316+
}
317+
]
318+
}
319+
- name: Update an application's groupMembershipClaims property to "All"
320+
text: az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --set groupMembershipClaims=All
321+
- name: Update an application's groupMembershipClaims property to "All" with JSON (Bash)
322+
text: |
323+
az ad app update --id e042ec79-34cd-498f-9d9f-123456781234 --parameters '{"groupMembershipClaims": "All"}'
323324
"""
324325

325326
helps['ad app federated-credential'] = """
@@ -627,9 +628,11 @@
627628
type: command
628629
short-summary: Update a service principal
629630
examples:
630-
- name: update a service principal (autogenerated)
631-
text: az ad sp update --id 00000000-0000-0000-0000-000000000000 --set groupMembershipClaims=All
632-
crafted: true
631+
- name: Update a service principal's appRoleAssignmentRequired property to true
632+
text: az ad sp update --id 00000000-0000-0000-0000-000000000000 --set appRoleAssignmentRequired=true
633+
- name: Update a service principal's appRoleAssignmentRequired property to true with JSON (Bash)
634+
text: >
635+
az ad sp update --id 00000000-0000-0000-0000-000000000000 --parameters '{"appRoleAssignmentRequired": true}'
633636
"""
634637

635638
helps['ad user'] = """

src/azure-cli/azure/cli/command_modules/role/_params.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ def load_arguments(self, _):
219219
c.argument('key_id', help='credential key id')
220220
c.argument('cert', action='store_true', help='a certificate based credential')
221221

222+
# Generic Update
223+
for item in ['ad app update', 'ad sp update']:
224+
with self.argument_context(item) as c:
225+
c.argument('properties_to_set', arg_group='Generic Update', options_list=['--set'], nargs='+',
226+
help='Set properties. Space-separated list of {name}={string or JSON}.')
227+
c.argument('parameters', arg_group='Generic Update', type=validate_file_or_dict, is_experimental=True,
228+
help='Parameters for update operation. ' + JSON_PROPERTY_HELP)
229+
222230
with self.argument_context('ad') as c:
223231
c.argument('display_name', help='object\'s display name or its prefix')
224232
c.argument('identifier_uri', help='graph application identifier, must be in uri format')

src/azure-cli/azure/cli/command_modules/role/commands.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,14 @@ def load_command_table(self, _):
8181
g.custom_command('create', 'create_application')
8282
g.custom_command('delete', 'delete_application')
8383
g.custom_command('list', 'list_applications', table_transformer=get_graph_object_transformer('app'))
84+
g.custom_command('update', 'update_application')
8485
g.custom_show_command('show', 'show_application')
8586
g.custom_command('permission grant', 'grant_application')
8687
g.custom_command('permission list', 'list_permissions')
8788
g.custom_command('permission add', 'add_permission')
8889
g.custom_command('permission delete', 'delete_permission')
8990
g.custom_command('permission list-grants', 'list_permission_grants')
9091
g.custom_command('permission admin-consent', 'admin_consent')
91-
g.generic_update_command('update', setter_name='patch_application', setter_type=role_custom,
92-
getter_name='show_application', getter_type=role_custom,
93-
custom_func_name='update_application', custom_func_type=role_custom)
9492
g.custom_command('credential reset', 'reset_application_credential')
9593
g.custom_command('credential list', 'list_application_credentials')
9694
g.custom_command('credential delete', 'delete_application_credential')
@@ -112,9 +110,7 @@ def load_command_table(self, _):
112110
g.custom_command('delete', 'delete_service_principal')
113111
g.custom_command('list', 'list_service_principals', table_transformer=get_graph_object_transformer('sp'))
114112
g.custom_show_command('show', 'show_service_principal')
115-
g.generic_update_command('update', getter_name='show_service_principal', getter_type=role_custom,
116-
setter_name='patch_service_principal', setter_type=role_custom,
117-
custom_func_name='update_service_principal', custom_func_type=role_custom)
113+
g.custom_command('update', 'update_service_principal')
118114

119115
with self.command_group('ad sp owner', client_factory=get_graph_client, exception_handler=graph_err_handler) as g:
120116
g.custom_command('list', 'list_service_principal_owners')

src/azure-cli/azure/cli/command_modules/role/custom.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,9 @@ def create_application(cmd, client, display_name, identifier_uris=None,
625625
if len(existing_apps) == 1:
626626
logger.warning("Found an existing application instance: (id) %s. We will patch it.",
627627
existing_apps[0][ID])
628-
body = update_application(
629-
existing_apps[0], display_name=display_name, identifier_uris=identifier_uris,
628+
update_application(
629+
client, existing_apps[0][ID],
630+
display_name=display_name, identifier_uris=identifier_uris,
630631
is_fallback_public_client=is_fallback_public_client, sign_in_audience=sign_in_audience,
631632
# keyCredentials
632633
key_value=key_value, key_type=key_type, key_usage=key_usage,
@@ -642,7 +643,6 @@ def create_application(cmd, client, display_name, identifier_uris=None,
642643
app_roles=app_roles,
643644
optional_claims=optional_claims,
644645
required_resource_accesses=required_resource_accesses)
645-
patch_application(cmd, existing_apps[0][ID], body)
646646

647647
# no need to resolve identifierUris or appId. Just use id.
648648
return client.application_get(existing_apps[0][ID])
@@ -680,7 +680,7 @@ def create_application(cmd, client, display_name, identifier_uris=None,
680680
return result
681681

682682

683-
def update_application(instance, display_name=None, identifier_uris=None, # pylint: disable=unused-argument
683+
def update_application(client, identifier, display_name=None, identifier_uris=None,
684684
is_fallback_public_client=None, sign_in_audience=None,
685685
# keyCredentials
686686
key_value=None, key_type=None, key_usage=None, start_date=None, end_date=None,
@@ -691,8 +691,11 @@ def update_application(instance, display_name=None, identifier_uris=None, # pyl
691691
# publicClient
692692
public_client_redirect_uris=None,
693693
# JSON properties
694-
app_roles=None, optional_claims=None, required_resource_accesses=None):
694+
app_roles=None, optional_claims=None, required_resource_accesses=None,
695+
# Generic update
696+
parameters=None, properties_to_set=None):
695697
body = {}
698+
_update_patch_body(body, parameters, properties_to_set)
696699

697700
key_credentials = None
698701
if key_value:
@@ -714,14 +717,8 @@ def update_application(instance, display_name=None, identifier_uris=None, # pyl
714717
# JSON properties
715718
app_roles=app_roles, optional_claims=optional_claims, required_resource_accesses=required_resource_accesses
716719
)
717-
718-
return body
719-
720-
721-
def patch_application(cmd, identifier, parameters):
722-
graph_client = _graph_client_factory(cmd.cli_ctx)
723-
object_id = _resolve_application(graph_client, identifier)
724-
return graph_client.application_update(object_id, parameters)
720+
object_id = _resolve_application(client, identifier)
721+
return client.application_update(object_id, body)
725722

726723

727724
def show_application(client, identifier):
@@ -1013,15 +1010,14 @@ def create_service_principal(cmd, identifier):
10131010
return _create_service_principal(cmd.cli_ctx, identifier)
10141011

10151012

1016-
def update_service_principal(instance): # pylint: disable=unused-argument
1013+
def update_service_principal(client, identifier,
1014+
# Generic update
1015+
parameters=None, properties_to_set=None):
10171016
# Do not PATCH back properties retrieved with GET and leave everything else to generic update.
1018-
return {}
1019-
1020-
1021-
def patch_service_principal(cmd, identifier, parameters):
1022-
graph_client = _graph_client_factory(cmd.cli_ctx)
1023-
object_id = _resolve_service_principal(graph_client, identifier)
1024-
return graph_client.service_principal_update(object_id, parameters)
1017+
body = {}
1018+
_update_patch_body(body, parameters, properties_to_set)
1019+
object_id = _resolve_service_principal(client, identifier)
1020+
return client.service_principal_update(object_id, body)
10251021

10261022

10271023
def _create_service_principal(cli_ctx, identifier, resolve_app=True):
@@ -1989,3 +1985,26 @@ def _get_member_groups(get_member_group_func, identifier, security_enabled_only)
19891985
"securityEnabledOnly": security_enabled_only
19901986
}
19911987
return get_member_group_func(identifier, body)
1988+
1989+
1990+
def _update_patch_body(body, parameters, properties_to_set):
1991+
# --parameters
1992+
if parameters:
1993+
body.update(parameters)
1994+
1995+
# --set
1996+
if properties_to_set:
1997+
for exp in properties_to_set:
1998+
try:
1999+
key, value = exp.split('=', 1)
2000+
except ValueError as ex:
2001+
from azure.cli.core.azclierror import ArgumentUsageError
2002+
raise ArgumentUsageError('Usage error: Please set properties with space-separated list of '
2003+
'{name}={string or JSON}, such as `--set displayName=myapp`') from ex
2004+
# Try parsing value as JSON
2005+
try:
2006+
value = shell_safe_json_parse(value)
2007+
except: # pylint:disable=bare-except
2008+
pass
2009+
body[key] = value
2010+
return body

0 commit comments

Comments
 (0)