1# --------------------------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for license information.
4# --------------------------------------------------------------------------------------------
5
6# pylint: disable=line-too-long
7
8from knack.arguments import CLIArgumentType
9from azure.graphrbac.models import ConsentType
10
11from azure.cli.core.commands.parameters import get_enum_type, get_three_state_flag, get_location_type, tags_type
12from azure.cli.core.commands.validators import validate_file_or_dict
13# from azure.cli.core.profiles import ResourceType
14
15
16from azure.cli.command_modules.role._completers import get_role_definition_name_completion_list
17from azure.cli.command_modules.role._validators import validate_group, validate_member_id, validate_cert, VARIANT_GROUP_ID_ARGS
18
19name_arg_type = CLIArgumentType(options_list=('--name', '-n'), metavar='NAME')
20
21
22# pylint: disable=too-many-statements
23def load_arguments(self, _):
24    with self.argument_context('ad') as c:
25        c.ignore('_subscription')  # hide global subscription param
26        c.argument('owner_object_id', help="owner's object id")
27        c.argument('show_mine', action='store_true', help='list entities owned by the current user')
28        c.argument('include_all', options_list='--all', action='store_true',
29                   help='list all entities, expect long delay if under a big organization')
30
31    with self.argument_context('ad app') as c:
32        c.argument('app_id', help='application id')
33        c.argument('application_object_id', options_list=('--object-id',))
34        c.argument('display_name', help='the display name of the application')
35        c.argument('homepage', help='the url where users can sign in and use your app.')
36        c.argument('identifier', options_list=['--id'], help='identifier uri, application id, or object id')
37        c.argument('identifier_uris', nargs='+', help='space-separated unique URIs that Azure AD can use for this app.')
38        c.argument('reply_urls', nargs='+', help='space-separated URIs to which Azure AD will redirect in response to an OAuth 2.0 request. The value does not need to be a physical endpoint, but must be a valid URI.')
39        c.argument('start_date', help="Date or datetime at which credentials become valid(e.g. '2017-01-01T01:00:00+00:00' or '2017-01-01'). Default value is current time")
40        c.argument('end_date', help="Date or datetime after which credentials expire(e.g. '2017-12-31T11:59:59+00:00' or '2017-12-31'). Default value is one year after current time")
41        c.argument('available_to_other_tenants', help='the application can be used from any Azure AD tenants', arg_type=get_three_state_flag())
42        c.argument('key_value', help='the value for the key credentials associated with the application')
43        # TODO: Update these with **enum_choice_list(...) when SDK supports proper enums
44        c.argument('key_type', help='the type of the key credentials associated with the application', arg_type=get_enum_type(['AsymmetricX509Cert', 'Password', 'Symmetric'], default='AsymmetricX509Cert'))
45        c.argument('key_usage', help='the usage of the key credentials associated with the application.', arg_type=get_enum_type(['Sign', 'Verify'], default='Verify'))
46        c.argument('password', help="app password, aka 'client secret'")
47        c.argument('oauth2_allow_implicit_flow', arg_type=get_three_state_flag(), help='whether to allow implicit grant flow for OAuth2')
48        c.argument('required_resource_accesses', type=validate_file_or_dict,
49                   help="resource scopes and roles the application requires access to. Should be in manifest json format. See examples below for details")
50        c.argument('app_roles', type=validate_file_or_dict,
51                   help="declare the roles you want to associate with your application. Should be in manifest json format. See examples below for details")
52        c.argument('optional_claims', type=validate_file_or_dict,
53                   help="declare the optional claims for the application. Should be in manifest json format. See examples below for details. Please reference https://docs.microsoft.com/azure/active-directory/develop/active-directory-optional-claims#optionalclaim-type for optional claim properties.")
54        c.argument('native_app', arg_type=get_three_state_flag(), help="an application which can be installed on a user's device or computer")
55        c.argument('credential_description', help="the description of the password")
56
57    with self.argument_context('ad app owner list') as c:
58        c.argument('identifier', options_list=['--id'], help='identifier uri, application id, or object id of the application')
59
60    with self.argument_context('ad app permission') as c:
61        # https://github.com/Azure/azure-rest-api-specs/blob/32e56f061668a1bf1eeca6209000fad4c09afca8/specification/graphrbac/data-plane/Microsoft.GraphRbac/stable/1.6/graphrbac.json#L2817
62        c.argument('api', help='Specify `RequiredResourceAccess.resourceAppId` - The unique identifier for the resource that the application requires access to. This should be equal to the appId declared on the target resource application.')
63        # https://github.com/Azure/azure-rest-api-specs/blob/32e56f061668a1bf1eeca6209000fad4c09afca8/specification/graphrbac/data-plane/Microsoft.GraphRbac/stable/1.6/graphrbac.json#L2833
64        c.argument('api_permissions', nargs='+', help='Specify `ResourceAccess.id` - The unique identifier for one of the OAuth2Permission or AppRole instances that the resource application exposes. Space-separated list of `<resource-access-id>=<type>`.')
65        c.argument('expires', help='Expiry date for the permissions in years. e.g. 1, 2 or "never"')
66        c.argument('scope', help='Specifies the value of the scope claim that the resource application should expect in the OAuth 2.0 access token, e.g. User.Read')
67        c.argument('consent_type', arg_type=get_enum_type(ConsentType), default=ConsentType.all_principals.value,
68                   help="Indicates if consent was provided by the administrator (on behalf of the organization) or by an individual.")
69        c.argument('principal_id', help='If --consent-type is "Principal", this argument specifies the object of the user that granted consent and applies only for that user.')
70        c.argument('show_resource_name', options_list=['--show-resource-name', '-r'],
71                   arg_type=get_three_state_flag(), help="show resource's display name")
72
73    with self.argument_context('ad app permission delete') as c:
74        # `=<type>` is not needed.
75        c.argument('api_permissions', nargs='+', help='Specify `ResourceAccess.id` - The unique identifier for one of the OAuth2Permission or AppRole instances that the resource application exposes. Space-separated list of `<resource-access-id>`.')
76
77    with self.argument_context('ad app permission list') as c:
78        c.argument('identifier', options_list=['--id'], help='identifier uri, application id, or object id of the associated application')
79
80    with self.argument_context('ad sp') as c:
81        c.argument('identifier', options_list=['--id'], help='service principal name, or object id')
82
83    with self.argument_context('ad sp create') as c:
84        c.argument('identifier', options_list=['--id'], help='identifier uri, application id, or object id of the associated application')
85
86    with self.argument_context('ad sp create-for-rbac') as c:
87        c.argument('scopes', nargs='+')
88        c.argument('role', completer=get_role_definition_name_completion_list)
89        c.argument('skip_assignment', arg_type=get_three_state_flag(),
90                   help='Skip creating the default assignment, which allows the service principal to access resources under the current subscription. '
91                        'When specified, --scopes will be ignored. You may use `az role assignment create` to create '
92                        'role assignments for this service principal later.')
93        c.argument('show_auth_for_sdk', options_list='--sdk-auth',
94                   deprecate_info=c.deprecate(target='--sdk-auth', expiration='3.0.0'),
95                   help='output result in compatible with Azure SDK auth file', arg_type=get_three_state_flag())
96
97    with self.argument_context('ad sp owner list') as c:
98        c.argument('identifier', options_list=['--id'], help='service principal name, or object id or the service principal')
99
100    for item in ['create-for-rbac', 'credential reset']:
101        with self.argument_context('ad sp {}'.format(item)) as c:
102            c.argument('name', name_arg_type)
103            c.argument('cert', arg_group='Credential', validator=validate_cert)
104            c.argument('years', type=int, default=None, arg_group='Credential')
105            c.argument('end_date', default=None, arg_group='Credential',
106                       help="Finer grain of expiry time if '--years' is insufficient, e.g. '2020-12-31T11:59:59+00:00' or '2299-12-31'")
107            c.argument('create_cert', action='store_true', arg_group='Credential')
108            c.argument('keyvault', arg_group='Credential')
109            c.argument('append', action='store_true', help='Append the new credential instead of overwriting.')
110            c.argument('credential_description', help="the description of the password", arg_group='Credential')
111
112    with self.argument_context('ad sp credential reset') as c:
113        c.argument('password', options_list=['--password', '-p'], arg_group='Credential',
114                   help="If missing, CLI will generate a strong password")
115
116    with self.argument_context('ad app credential reset') as c:
117        c.argument('name', options_list=['--id'], help='identifier uri, application id, or object id')
118        c.argument('cert', arg_group='Credential', validator=validate_cert, help='Certificate to use for credentials')
119        c.argument('password', options_list=['--password', '-p'], arg_group='Credential')
120        c.argument('years', type=int, default=None, arg_group='Credential', help='Number of years for which the credentials will be valid')
121        c.argument('create_cert', action='store_true', arg_group='Credential', help='Create a self-signed certificate to use for the credential')
122        c.argument('keyvault', arg_group='Credential', help='Name or ID of a KeyVault to use for creating or retrieving certificates.')
123        c.argument('append', action='store_true', help='Append the new credential instead of overwriting.')
124
125    for item in ['ad sp credential delete', 'ad sp credential list', 'ad app credential delete', 'ad app credential list']:
126        with self.argument_context(item) as c:
127            c.argument('key_id', help='credential key id')
128            c.argument('cert', action='store_true', help='a certificate based credential')
129
130    with self.argument_context('ad') as c:
131        c.argument('display_name', help='object\'s display name or its prefix')
132        c.argument('identifier_uri', help='graph application identifier, must be in uri format')
133        c.argument('spn', help='service principal name')
134        c.argument('upn', help='user principal name, e.g. john.doe@contoso.com')
135        c.argument('query_filter', options_list=['--filter'], help='OData filter, e.g. --filter "displayname eq \'test\' and servicePrincipalType eq \'Application\'"')
136
137    with self.argument_context('ad user') as c:
138        c.argument('mail_nickname', help='mail alias. Defaults to user principal name')
139        c.argument('force_change_password_next_login', arg_type=get_three_state_flag(), help='Require the user to change their password the next time they log in. Only valid when --password is specified')
140        c.argument('account_enabled', arg_type=get_three_state_flag(), help='enable the user account')
141        c.argument('password', help='user password')
142        c.argument('upn_or_object_id', options_list=['--id', c.deprecate(target='--upn-or-object-id', redirect='--id', hide=True)], help='The object ID or principal name of the user for which to get information')
143
144    with self.argument_context('ad user get-member-groups') as c:
145        c.argument('security_enabled_only', action='store_true',
146                   help='If true, only membership in security-enabled groups should be checked. Otherwise, membership in all groups should be checked.')
147
148    group_help_msg = "group's object id or display name(prefix also works if there is a unique match)"
149    with self.argument_context('ad group') as c:
150        for arg in VARIANT_GROUP_ID_ARGS:
151            c.argument(arg, options_list=['--group', '-g'], validator=validate_group, help=group_help_msg)
152
153    with self.argument_context('ad group create') as c:
154        c.argument('mail_nickname', help='Mail nickname')
155        c.argument('force', arg_type=get_three_state_flag(),
156                   help='always create a new group instead of updating the one with same display and mail nickname')
157        c.argument('description', help='Group description')
158
159    with self.argument_context('ad group show') as c:
160        c.extra('cmd')
161
162    member_id_help_msg = 'The object ID of the contact, group, user, or service principal'
163    with self.argument_context('ad group get-member-groups') as c:
164        c.argument('security_enabled_only', arg_type=get_three_state_flag(), default=False, required=False)
165        c.extra('cmd')
166
167    with self.argument_context('ad group member add') as c:
168        c.argument('url', options_list='--member-id', validator=validate_member_id, help=member_id_help_msg)
169
170    for item in ['member add', 'member check', 'member list', 'member remove', 'delete']:
171        with self.argument_context('ad group {}'.format(item)) as c:
172            c.extra('cmd')
173
174    with self.argument_context('ad group member') as c:
175        c.argument('member_object_id', options_list='--member-id', help=member_id_help_msg)
176
177    with self.argument_context('ad signed-in-user') as c:
178        c.argument('object_type', options_list=['--type', '-t'], help='object type filter, e.g. "application", "servicePrincipal"  "group", etc')
179
180    with self.argument_context('role') as c:
181        c.argument('scope', help='scope at which the role assignment or definition applies to, e.g., /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333, /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333/resourceGroups/myGroup, or /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333/resourceGroups/myGroup/providers/Microsoft.Compute/virtualMachines/myVM')
182        c.argument('resource_group_name', options_list=['--resource-group', '-g'], help='use it only if the role or assignment was added at the level of a resource group')
183
184    with self.argument_context('role assignment') as c:
185        c.argument('role_assignment_name', options_list=['--name', '-n'])
186        c.argument('role', help='role name or id', completer=get_role_definition_name_completion_list)
187        c.argument('show_all', options_list=['--all'], action='store_true', help='show all assignments under the current subscription')
188        c.argument('include_inherited', action='store_true', help='include assignments applied on parent scopes')
189        c.argument('can_delegate', action='store_true', help='when set, the assignee will be able to create further role assignments to the same role')
190        c.argument('assignee', help='represent a user, group, or service principal. supported format: object id, user sign-in name, or service principal name')
191        c.argument('assignee_object_id', help="Use this parameter instead of '--assignee' to bypass Graph API invocation in case of insufficient privileges. "
192                   "This parameter only works with object ids for users, groups, service principals, and "
193                   "managed identities. For managed identities use the principal id. For service principals, "
194                   "use the object id and not the app id.")
195        c.argument('ids', nargs='+', help='space-separated role assignment ids')
196        c.argument('include_classic_administrators', arg_type=get_three_state_flag(), help='list default role assignments for subscription classic administrators, aka co-admins')
197        c.argument('description', is_preview=True, min_api='2020-04-01-preview', help='Description of role assignment.')
198        c.argument('condition', is_preview=True, min_api='2020-04-01-preview', help='Condition under which the user can be granted permission.')
199        c.argument('condition_version', is_preview=True, min_api='2020-04-01-preview', help='Version of the condition syntax. If --condition is specified without --condition-version, default to 2.0.')
200
201    time_help = ('The {} of the query in the format of %Y-%m-%dT%H:%M:%SZ, e.g. 2000-12-31T12:59:59Z. Defaults to {}')
202    with self.argument_context('role assignment list-changelogs') as c:
203        c.argument('start_time', help=time_help.format('start time', '1 Hour prior to the current time'))
204        c.argument('end_time', help=time_help.format('end time', 'the current time'))
205
206    with self.argument_context('role assignment create') as c:
207        # PrincipalType = self.get_models('PrincipalType', resource_type=ResourceType.MGMT_AUTHORIZATION)
208
209        # A temporary fix for https://github.com/Azure/azure-cli/issues/11594
210        # As only 'User', 'Group' or 'ServicePrincipal' are allowed values, the REST spec contains invalid values
211        # (like MSI) which are used only internally by the service. So hide them.
212        # https://github.com/Azure/azure-rest-api-specs/blob/962013a1cf9bf5b87e3aad75a14c7dd620acda62/specification/authorization/resource-manager/Microsoft.Authorization/preview/2020-04-01-preview/authorization-RoleAssignmentsCalls.json#L508-L522
213        from enum import Enum
214
215        class PrincipalType(str, Enum):
216            user = "User"
217            group = "Group"
218            service_principal = "ServicePrincipal"
219            foreign_group = "ForeignGroup"
220
221        c.argument('assignee_principal_type', min_api='2018-09-01-preview', arg_type=get_enum_type(PrincipalType),
222                   help='use with --assignee-object-id to avoid errors caused by propagation latency in AAD Graph')
223
224    with self.argument_context('role assignment update') as c:
225        c.argument('role_assignment',
226                   help='Description of an existing role assignment as JSON, or a path to a file containing a '
227                        'JSON description.')
228
229    with self.argument_context('role assignment delete') as c:
230        c.argument('yes', options_list=['--yes', '-y'], action='store_true', help='Continue to delete all assignments under the subscription')
231
232    with self.argument_context('role definition') as c:
233        c.argument('role_definition_id', options_list=['--name', '-n'], help='the role definition name')
234        c.argument('custom_role_only', arg_type=get_three_state_flag(), help='custom roles only(vs. build-in ones)')
235        c.argument('role_definition', help="json formatted content which defines the new role.")
236        c.argument('name', arg_type=name_arg_type, completer=get_role_definition_name_completion_list, help="the role's name")
237
238    with self.argument_context('identity') as c:
239        c.argument('resource_name', arg_type=name_arg_type, id_part='name')
240
241    with self.argument_context('identity create') as c:
242        c.argument('location', get_location_type(self.cli_ctx))
243        c.argument('tags', tags_type)
244