Skip to content

Commit cac3f06

Browse files
authored
[Role] az ad/role: Azure AD Graph API to Microsoft Graph API migration (#22432)
1 parent a549b82 commit cac3f06

120 files changed

Lines changed: 85270 additions & 110100 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/azure-cli-core/azure/cli/core/util.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,9 @@ def send_raw_request(cli_ctx, method, url, headers=None, uri_parameters=None, #
978978
reason = r.reason
979979
if r.text:
980980
reason += '({})'.format(r.text)
981-
raise CLIError(reason)
981+
ex = CLIError(reason)
982+
ex.response = r
983+
raise ex
982984
if output_file:
983985
with open(output_file, 'wb') as fd:
984986
for chunk in r.iter_content(chunk_size=128):

src/azure-cli-testsdk/azure/cli/testsdk/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
from .checkers import (JMESPathCheck, JMESPathCheckExists, JMESPathCheckGreaterThan, NoneCheck, StringCheck,
1313
StringContainCheck)
1414
from .decorators import api_version_constraint
15-
from .utilities import create_random_name, AADGraphUserReplacer
15+
from .utilities import create_random_name, MSGraphUserReplacer
1616
from .patches import MOCKED_USER_NAME
1717

1818
__all__ = ['ScenarioTest', 'LiveScenarioTest', 'ResourceGroupPreparer', 'StorageAccountPreparer',
1919
'RoleBasedServicePrincipalPreparer', 'ManagedApplicationPreparer', 'CliTestError', 'JMESPathCheck',
2020
'JMESPathCheckExists', 'NoneCheck', 'live_only', 'record_only', 'StringCheck', 'StringContainCheck',
2121
'get_sha1_hash', 'KeyVaultPreparer', 'JMESPathCheckGreaterThan', 'api_version_constraint',
22-
'create_random_name', 'MOCKED_USER_NAME', 'AADGraphUserReplacer', 'LocalContextScenarioTest',
22+
'create_random_name', 'MOCKED_USER_NAME', 'MSGraphUserReplacer', 'LocalContextScenarioTest',
2323
'VirtualNetworkPreparer', 'VnetNicPreparer']
2424

2525

src/azure-cli-testsdk/azure/cli/testsdk/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
patch_progress_controller, patch_get_current_system_username)
2525
from .exceptions import CliExecutionError
2626
from .utilities import (find_recording_dir, StorageAccountKeyReplacer, GraphClientPasswordReplacer,
27-
AADAuthRequestFilter)
27+
MSGraphClientPasswordReplacer, AADAuthRequestFilter)
2828
from .reverse_dependency import get_dummy_cli
2929

3030
logger = logging.getLogger('azure.cli.testsdk')
@@ -86,7 +86,8 @@ def __init__(self, method_name, config_file=None, recording_name=None,
8686
self.name_replacer = GeneralNameReplacer()
8787
self.kwargs = {}
8888
self.test_guid_count = 0
89-
self._processors_to_reset = [StorageAccountKeyReplacer(), GraphClientPasswordReplacer()]
89+
self._processors_to_reset = [StorageAccountKeyReplacer(), GraphClientPasswordReplacer(),
90+
MSGraphClientPasswordReplacer()]
9091
default_recording_processors = [
9192
SubscriptionRecordingProcessor(MOCKED_SUBSCRIPTION_ID),
9293
AADAuthRequestFilter(),

src/azure-cli-testsdk/azure/cli/testsdk/utilities.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,8 @@ def force_progress_logging():
4848
az_logger.handlers[0].level = old_az_level
4949

5050

51-
def _py3_byte_to_str(byte_or_str):
52-
import logging
53-
logger = logging.getLogger()
54-
logger.warning(type(byte_or_str))
55-
try:
56-
return str(byte_or_str, 'utf-8') if isinstance(byte_or_str, bytes) else byte_or_str
57-
except TypeError: # python 2 doesn't allow decoding through str
58-
return str(byte_or_str)
51+
def _byte_to_str(byte_or_str):
52+
return str(byte_or_str, 'utf-8') if isinstance(byte_or_str, bytes) else byte_or_str
5953

6054

6155
class StorageAccountKeyReplacer(RecordingProcessor):
@@ -81,7 +75,7 @@ def process_request(self, request): # pylint: disable=no-self-use
8175
pass
8276
for candidate in self._candidates:
8377
if request.body:
84-
body_string = _py3_byte_to_str(request.body)
78+
body_string = _byte_to_str(request.body)
8579
request.body = body_string.replace(candidate, self.KEY_REPLACEMENT)
8680
return request
8781

@@ -99,7 +93,7 @@ def process_response(self, response):
9993
for candidate in self._candidates:
10094
if response['body']['string']:
10195
body = response['body']['string']
102-
response['body']['string'] = _py3_byte_to_str(body)
96+
response['body']['string'] = _byte_to_str(body)
10397
response['body']['string'] = response['body']['string'].replace(candidate, self.KEY_REPLACEMENT)
10498
return response
10599

@@ -127,11 +121,11 @@ def process_request(self, request): # pylint: disable=no-self-use
127121
pattern = r"[^/]+/applications$"
128122
if re.search(pattern, request.path, re.I) and request.method.lower() == 'post':
129123
self._activated = True
130-
body = _py3_byte_to_str(request.body)
124+
body = _byte_to_str(request.body)
131125
body = json.loads(body)
132126
for password_cred in body['passwordCredentials']:
133127
if password_cred['value']:
134-
body_string = _py3_byte_to_str(request.body)
128+
body_string = _byte_to_str(request.body)
135129
request.body = body_string.replace(password_cred['value'], self.PWD_REPLACEMENT)
136130

137131
except (AttributeError, KeyError):
@@ -157,18 +151,48 @@ def process_response(self, response):
157151
return response
158152

159153

160-
class AADGraphUserReplacer:
154+
class MSGraphClientPasswordReplacer(RecordingProcessor):
155+
"""Replace 'secretText' property in 'addPassword' API's response."""
156+
157+
PWD_REPLACEMENT = 'replaced-microsoft-graph-password'
158+
159+
def __init__(self):
160+
self._activated = False
161+
162+
def reset(self):
163+
self._activated = False
164+
165+
def process_request(self, request):
166+
if request.body and self.PWD_REPLACEMENT in _byte_to_str(request.body):
167+
return request
168+
if request.path.endswith('/addPassword') and request.method.lower() == 'post':
169+
self._activated = True
170+
return request
171+
172+
def process_response(self, response):
173+
if self._activated:
174+
import json
175+
176+
body = json.loads(response['body']['string'])
177+
body['secretText'] = self.PWD_REPLACEMENT
178+
179+
response['body']['string'] = json.dumps(body)
180+
self._activated = False
181+
182+
return response
183+
184+
185+
class MSGraphUserReplacer(RecordingProcessor):
161186
def __init__(self, test_user, mock_user):
162187
self.test_user = test_user
163188
self.mock_user = mock_user
164189

165190
def process_request(self, request):
166-
test_user_encoded = self.test_user.replace('@', '%40')
167-
if test_user_encoded in request.uri:
168-
request.uri = request.uri.replace(test_user_encoded, self.mock_user.replace('@', '%40'))
191+
if self.test_user in request.uri:
192+
request.uri = request.uri.replace(self.test_user, self.mock_user)
169193

170194
if request.body:
171-
body = _py3_byte_to_str(request.body)
195+
body = _byte_to_str(request.body)
172196
if self.test_user in body:
173197
request.body = body.replace(self.test_user, self.mock_user)
174198

src/azure-cli/azure/cli/command_modules/acs/tests/hybrid_2020_09_01/test_aks_commands.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
# is set with the environment varibale for sp_name. This method is compatible with
2626
# both cases.
2727
def _process_sp_name(sp_name):
28-
from azure.cli.core.util import is_guid
29-
return sp_name if is_guid(sp_name) else 'http://{}'.format(sp_name)
28+
return sp_name
3029

3130

3231
class AzureKubernetesServiceScenarioTest(ScenarioTest):
@@ -493,7 +492,7 @@ def generate_user_assigned_identity_resource_id(self, resource_group):
493492
resource_group, identity_name)).get_output_in_json()
494493
return identity.get("id")
495494

496-
495+
497496
# reset the count so in replay mode the random names will start with 0
498497
self.test_resources_count = 0
499498
# kwargs for string formatting

src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919

2020
class AKSCustomResourceGroupPreparer(ResourceGroupPreparer):
21+
"""
22+
Override to support overriding the default location in test cases using this custom preparer with specific
23+
environment variables, and a flag (preserve_default_location) to avoid being overridden by environment variables.
24+
"""
2125
def __init__(
2226
self,
2327
name_prefix="clitest.rg",
@@ -50,6 +54,11 @@ def __init__(
5054

5155

5256
class AKSCustomVirtualNetworkPreparer(VirtualNetworkPreparer):
57+
"""
58+
Override to specify custom address_prefixes to avoid conflict with aks cluster/service cidr.
59+
60+
TODO: remove this.
61+
"""
5362
def __init__(
5463
self,
5564
name_prefix="clitest.vn",
@@ -143,6 +152,10 @@ def _update_address_prefixes(self, **kwargs):
143152
class AKSCustomRoleBasedServicePrincipalPreparer(
144153
RoleBasedServicePrincipalPreparer
145154
):
155+
"""
156+
Override to keep the recording consistent with the count in the mock request in scenarios such as the
157+
check-in pipeline where the SP is pre-configured for testing and imported via environment variables.
158+
"""
146159
def __init__(
147160
self,
148161
name_prefix="clitest",
@@ -177,7 +190,7 @@ def create_resource(self, name, **kwargs):
177190
pass
178191

179192
if self.live_test or self.test_class_instance.in_recording:
180-
sp_name = name
193+
sp_name = self.result['appId']
181194
sp_password = self.result.get("password") or GraphClientPasswordReplacer.PWD_REPLACEMENT
182195
else:
183196
sp_name = MOCK_GUID

src/azure-cli/azure/cli/command_modules/acs/tests/latest/recordings/test_aks_create_default_service_without_skip_role_assignment.yaml

Lines changed: 949 additions & 1085 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)