Skip to content

Commit 74a192a

Browse files
xiangyan99chlowell
andauthored
update new app service api version (Azure#23034)
* update new app service api version * update * update * Add azure ml credential * remove unused code * Update sdk/identity/azure-identity/tests/test_managed_identity.py Co-authored-by: Charles Lowell <[email protected]> * Update sdk/identity/azure-identity/tests/test_managed_identity.py Co-authored-by: Charles Lowell <[email protected]> * Update sdk/identity/azure-identity/tests/test_managed_identity.py Co-authored-by: Charles Lowell <[email protected]> * update Co-authored-by: Charles Lowell <[email protected]>
1 parent 15af9d6 commit 74a192a

17 files changed

+231
-580
lines changed

sdk/identity/azure-identity/azure/identity/_credentials/app_service.py

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,64 +33,25 @@ def _get_client_args(**kwargs):
3333
# type: (dict) -> Optional[dict]
3434
identity_config = kwargs.pop("identity_config", None) or {}
3535

36-
url = os.environ.get(EnvironmentVariables.MSI_ENDPOINT)
37-
secret = os.environ.get(EnvironmentVariables.MSI_SECRET)
36+
url = os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT)
37+
secret = os.environ.get(EnvironmentVariables.IDENTITY_HEADER)
3838
if not (url and secret):
3939
# App Service managed identity isn't available in this environment
4040
return None
4141

42-
if kwargs.get("client_id"):
43-
identity_config["clientid"] = kwargs.pop("client_id")
4442
if kwargs.get("resource_id"):
4543
identity_config["mi_res_id"] = kwargs.pop("resource_id")
4644

4745
return dict(
4846
kwargs,
49-
_content_callback=_parse_app_service_expires_on,
5047
identity_config=identity_config,
51-
base_headers={"secret": secret},
48+
base_headers={"X-IDENTITY-HEADER": secret},
5249
request_factory=functools.partial(_get_request, url),
5350
)
5451

5552

5653
def _get_request(url, scope, identity_config):
5754
# type: (str, str, dict) -> HttpRequest
5855
request = HttpRequest("GET", url)
59-
request.format_parameters(dict({"api-version": "2017-09-01", "resource": scope}, **identity_config))
56+
request.format_parameters(dict({"api-version": "2019-08-01", "resource": scope}, **identity_config))
6057
return request
61-
62-
63-
def _parse_app_service_expires_on(content):
64-
# type: (dict) -> None
65-
"""Parse an App Service MSI version 2017-09-01 expires_on value to epoch seconds.
66-
67-
This version of the API returns expires_on as a UTC datetime string rather than epoch seconds. The string's
68-
format depends on the OS. Responses on Windows include AM/PM, for example "1/16/2020 5:24:12 AM +00:00".
69-
Responses on Linux do not, for example "06/20/2019 02:57:58 +00:00".
70-
71-
:raises ValueError: ``expires_on`` didn't match an expected format
72-
"""
73-
74-
# Azure ML sets the same environment variables as App Service but returns expires_on as an integer.
75-
# That means we could have an Azure ML response here, so let's first try to parse expires_on as an int.
76-
try:
77-
content["expires_on"] = int(content["expires_on"])
78-
return
79-
except ValueError:
80-
pass
81-
82-
import calendar
83-
import time
84-
85-
expires_on = content["expires_on"]
86-
if expires_on.endswith(" +00:00"):
87-
date_string = expires_on[: -len(" +00:00")]
88-
for format_string in ("%m/%d/%Y %H:%M:%S", "%m/%d/%Y %I:%M:%S %p"): # (Linux, Windows)
89-
try:
90-
t = time.strptime(date_string, format_string)
91-
content["expires_on"] = calendar.timegm(t)
92-
return
93-
except ValueError:
94-
pass
95-
96-
raise ValueError("'{}' doesn't match the expected format".format(expires_on))
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# ------------------------------------
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
# ------------------------------------
5+
import functools
6+
import os
7+
from typing import TYPE_CHECKING
8+
9+
from azure.core.pipeline.transport import HttpRequest
10+
11+
from .._constants import EnvironmentVariables
12+
from .._internal.managed_identity_base import ManagedIdentityBase
13+
from .._internal.managed_identity_client import ManagedIdentityClient
14+
15+
if TYPE_CHECKING:
16+
from typing import Any, Optional
17+
18+
19+
class AzureMLCredential(ManagedIdentityBase):
20+
def get_client(self, **kwargs):
21+
# type: (**Any) -> Optional[ManagedIdentityClient]
22+
client_args = _get_client_args(**kwargs)
23+
if client_args:
24+
return ManagedIdentityClient(**client_args)
25+
return None
26+
27+
def get_unavailable_message(self):
28+
# type: () -> str
29+
return "Azure ML managed identity configuration not found in environment"
30+
31+
32+
def _get_client_args(**kwargs):
33+
# type: (dict) -> Optional[dict]
34+
identity_config = kwargs.pop("identity_config", None) or {}
35+
36+
url = os.environ.get(EnvironmentVariables.MSI_ENDPOINT)
37+
secret = os.environ.get(EnvironmentVariables.MSI_SECRET)
38+
if not (url and secret):
39+
# Azure ML managed identity isn't available in this environment
40+
return None
41+
42+
if kwargs.get("client_id"):
43+
identity_config["clientid"] = kwargs.pop("client_id")
44+
if kwargs.get("resource_id"):
45+
identity_config["mi_res_id"] = kwargs.pop("resource_id")
46+
47+
return dict(
48+
kwargs,
49+
identity_config=identity_config,
50+
base_headers={"secret": secret},
51+
request_factory=functools.partial(_get_request, url),
52+
)
53+
54+
55+
def _get_request(url, scope, identity_config):
56+
# type: (str, str, dict) -> HttpRequest
57+
request = HttpRequest("GET", url)
58+
request.format_parameters(dict({"api-version": "2017-09-01", "resource": scope}, **identity_config))
59+
return request

sdk/identity/azure-identity/azure/identity/_credentials/managed_identity.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,30 +45,34 @@ class ManagedIdentityCredential(object):
4545
def __init__(self, **kwargs):
4646
# type: (**Any) -> None
4747
self._credential = None # type: Optional[TokenCredential]
48-
if os.environ.get(EnvironmentVariables.MSI_ENDPOINT):
48+
if os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT):
49+
if os.environ.get(EnvironmentVariables.IDENTITY_HEADER):
50+
if os.environ.get(EnvironmentVariables.IDENTITY_SERVER_THUMBPRINT):
51+
_LOGGER.info("%s will use Service Fabric managed identity", self.__class__.__name__)
52+
from .service_fabric import ServiceFabricCredential
53+
54+
self._credential = ServiceFabricCredential(**kwargs)
55+
else:
56+
_LOGGER.info("%s will use App Service managed identity", self.__class__.__name__)
57+
from .app_service import AppServiceCredential
58+
59+
self._credential = AppServiceCredential(**kwargs)
60+
elif os.environ.get(EnvironmentVariables.IMDS_ENDPOINT):
61+
_LOGGER.info("%s will use Azure Arc managed identity", self.__class__.__name__)
62+
from .azure_arc import AzureArcCredential
63+
64+
self._credential = AzureArcCredential(**kwargs)
65+
elif os.environ.get(EnvironmentVariables.MSI_ENDPOINT):
4966
if os.environ.get(EnvironmentVariables.MSI_SECRET):
50-
_LOGGER.info("%s will use App Service managed identity", self.__class__.__name__)
51-
from .app_service import AppServiceCredential
67+
_LOGGER.info("%s will use Azure ML managed identity", self.__class__.__name__)
68+
from .azure_ml import AzureMLCredential
5269

53-
self._credential = AppServiceCredential(**kwargs)
70+
self._credential = AzureMLCredential(**kwargs)
5471
else:
5572
_LOGGER.info("%s will use Cloud Shell managed identity", self.__class__.__name__)
5673
from .cloud_shell import CloudShellCredential
5774

5875
self._credential = CloudShellCredential(**kwargs)
59-
elif os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT):
60-
if os.environ.get(EnvironmentVariables.IDENTITY_HEADER) and os.environ.get(
61-
EnvironmentVariables.IDENTITY_SERVER_THUMBPRINT
62-
):
63-
_LOGGER.info("%s will use Service Fabric managed identity", self.__class__.__name__)
64-
from .service_fabric import ServiceFabricCredential
65-
66-
self._credential = ServiceFabricCredential(**kwargs)
67-
elif os.environ.get(EnvironmentVariables.IMDS_ENDPOINT):
68-
_LOGGER.info("%s will use Azure Arc managed identity", self.__class__.__name__)
69-
from .azure_arc import AzureArcCredential
70-
71-
self._credential = AzureArcCredential(**kwargs)
7276
elif all(os.environ.get(var) for var in EnvironmentVariables.TOKEN_EXCHANGE_VARS):
7377
_LOGGER.info("%s will use token exchange", self.__class__.__name__)
7478
from .token_exchange import TokenExchangeCredential
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# ------------------------------------
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
# ------------------------------------
5+
from typing import TYPE_CHECKING
6+
7+
from .._internal.managed_identity_base import AsyncManagedIdentityBase
8+
from .._internal.managed_identity_client import AsyncManagedIdentityClient
9+
from ..._credentials.azure_ml import _get_client_args
10+
11+
if TYPE_CHECKING:
12+
from typing import Any, Optional
13+
14+
15+
class AzureMLCredential(AsyncManagedIdentityBase):
16+
def get_client(self, **kwargs: "Any") -> "Optional[AsyncManagedIdentityClient]":
17+
client_args = _get_client_args(**kwargs)
18+
if client_args:
19+
return AsyncManagedIdentityClient(**client_args)
20+
return None
21+
22+
def get_unavailable_message(self) -> str:
23+
return "Azure ML managed identity configuration not found in environment"

sdk/identity/azure-identity/azure/identity/aio/_credentials/managed_identity.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,39 @@ class ManagedIdentityCredential(AsyncContextManager):
3838
def __init__(self, **kwargs: "Any") -> None:
3939
self._credential = None # type: Optional[AsyncTokenCredential]
4040

41-
if os.environ.get(EnvironmentVariables.MSI_ENDPOINT):
42-
if os.environ.get(EnvironmentVariables.MSI_SECRET):
43-
_LOGGER.info("%s will use App Service managed identity", self.__class__.__name__)
44-
from .app_service import AppServiceCredential
41+
if os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT):
42+
if os.environ.get(EnvironmentVariables.IDENTITY_HEADER):
43+
if os.environ.get(EnvironmentVariables.IDENTITY_SERVER_THUMBPRINT):
44+
_LOGGER.info("%s will use Service Fabric managed identity", self.__class__.__name__)
45+
from .service_fabric import ServiceFabricCredential
46+
47+
self._credential = ServiceFabricCredential(**kwargs)
48+
else:
49+
_LOGGER.info("%s will use App Service managed identity", self.__class__.__name__)
50+
from .app_service import AppServiceCredential
51+
52+
self._credential = AppServiceCredential(**kwargs)
53+
elif os.environ.get(EnvironmentVariables.IMDS_ENDPOINT):
54+
_LOGGER.info("%s will use Azure Arc managed identity", self.__class__.__name__)
55+
from .azure_arc import AzureArcCredential
4556

46-
self._credential = AppServiceCredential(**kwargs)
57+
self._credential = AzureArcCredential(**kwargs)
4758
else:
4859
_LOGGER.info("%s will use Cloud Shell managed identity", self.__class__.__name__)
4960
from .cloud_shell import CloudShellCredential
5061

5162
self._credential = CloudShellCredential(**kwargs)
52-
elif os.environ.get(EnvironmentVariables.IDENTITY_ENDPOINT):
53-
if os.environ.get(EnvironmentVariables.IDENTITY_HEADER) and os.environ.get(
54-
EnvironmentVariables.IDENTITY_SERVER_THUMBPRINT
55-
):
56-
_LOGGER.info("%s will use Service Fabric managed identity", self.__class__.__name__)
57-
from .service_fabric import ServiceFabricCredential
58-
59-
self._credential = ServiceFabricCredential(**kwargs)
60-
elif os.environ.get(EnvironmentVariables.IMDS_ENDPOINT):
61-
_LOGGER.info("%s will use Azure Arc managed identity", self.__class__.__name__)
62-
from .azure_arc import AzureArcCredential
63+
elif os.environ.get(EnvironmentVariables.MSI_ENDPOINT):
64+
if os.environ.get(EnvironmentVariables.MSI_SECRET):
65+
_LOGGER.info("%s will use Azure ML managed identity", self.__class__.__name__)
66+
from .azure_ml import AzureMLCredential
6367

64-
self._credential = AzureArcCredential(**kwargs)
68+
self._credential = AzureMLCredential(**kwargs)
69+
else:
70+
_LOGGER.info("%s will use Cloud Shell managed identity", self.__class__.__name__)
71+
from .cloud_shell import CloudShellCredential
72+
73+
self._credential = CloudShellCredential(**kwargs)
6574
elif all(os.environ.get(var) for var in EnvironmentVariables.TOKEN_EXCHANGE_VARS):
6675
_LOGGER.info("%s will use token exchange", self.__class__.__name__)
6776
from .token_exchange import TokenExchangeCredential

sdk/identity/azure-identity/tests/recordings/test_app_service.test_system_assigned.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ interactions:
1313
secret:
1414
- redacted
1515
method: GET
16-
uri: https://msi-endpoint/token?api-version=2017-09-01&resource=https://management.azure.com
16+
uri: https://msi-endpoint/token?api-version=2019-08-01&resource=https://management.azure.com
1717
response:
1818
body:
19-
string: '{"access_token": "redacted", "expires_on": "05/22/2021 17:14:33 +00:00",
19+
string: '{"access_token": "redacted", "expires_on": "1646265298",
2020
"resource": "https://management.azure.com", "token_type": "Bearer", "client_id":
2121
"6d807b1c-2a6f-41a0-b428-d0e3a08382a0"}'
2222
headers:

sdk/identity/azure-identity/tests/recordings/test_app_service.test_system_assigned_tenant_id.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ interactions:
1313
secret:
1414
- redacted
1515
method: GET
16-
uri: https://msi-endpoint/token?api-version=2017-09-01&resource=https://management.azure.com
16+
uri: https://msi-endpoint/token?api-version=2019-08-01&resource=https://management.azure.com
1717
response:
1818
body:
19-
string: '{"access_token": "redacted", "expires_on": "05/22/2021 17:14:33 +00:00",
19+
string: '{"access_token": "redacted", "expires_on": "1646265298",
2020
"resource": "https://management.azure.com", "token_type": "Bearer", "client_id":
2121
"6d807b1c-2a6f-41a0-b428-d0e3a08382a0"}'
2222
headers:

sdk/identity/azure-identity/tests/recordings/test_app_service.test_user_assigned.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ interactions:
1313
secret:
1414
- redacted
1515
method: GET
16-
uri: https://msi-endpoint/token?api-version=2017-09-01&resource=https://management.azure.com&clientid=client-id
16+
uri: https://msi-endpoint/token?api-version=2019-08-01&resource=https://management.azure.com&client_id=client-id
1717
response:
1818
body:
19-
string: '{"access_token": "redacted", "expires_on": "05/22/2021 17:18:21 +00:00",
19+
string: '{"access_token": "redacted", "expires_on": "1646265298",
2020
"resource": "https://management.azure.com", "token_type": "Bearer", "client_id":
2121
"client-id"}'
2222
headers:

sdk/identity/azure-identity/tests/recordings/test_app_service.test_user_assigned_tenant_id.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ interactions:
1313
secret:
1414
- redacted
1515
method: GET
16-
uri: https://msi-endpoint/token?api-version=2017-09-01&resource=https://management.azure.com&clientid=client-id
16+
uri: https://msi-endpoint/token?api-version=2019-08-01&resource=https://management.azure.com&client_id=client-id
1717
response:
1818
body:
19-
string: '{"access_token": "redacted", "expires_on": "05/22/2021 17:18:21 +00:00",
19+
string: '{"access_token": "redacted", "expires_on": "1646265298",
2020
"resource": "https://management.azure.com", "token_type": "Bearer", "client_id":
2121
"client-id"}'
2222
headers:

sdk/identity/azure-identity/tests/recordings/test_app_service_async.test_system_assigned.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ interactions:
77
secret:
88
- redacted
99
method: GET
10-
uri: https://msi-endpoint/token?api-version=2017-09-01&resource=https://management.azure.com
10+
uri: https://msi-endpoint/token?api-version=2019-08-01&resource=https://management.azure.com
1111
response:
1212
body:
13-
string: '{"access_token": "redacted", "expires_on": "05/22/2021 17:18:20 +00:00",
13+
string: '{"access_token": "redacted", "expires_on": "1646265298",
1414
"resource": "https://management.azure.com", "token_type": "Bearer", "client_id":
1515
"6d807b1c-2a6f-41a0-b428-d0e3a08382a0"}'
1616
headers:
@@ -21,5 +21,5 @@ interactions:
2121
status:
2222
code: 200
2323
message: OK
24-
url: http://172.16.7.2:8081/msi/token?api-version=2017-09-01&resource=https://management.azure.com
24+
url: http://172.16.7.2:8081/msi/token?api-version=2019-08-01&resource=https://management.azure.com
2525
version: 1

0 commit comments

Comments
 (0)