@@ -21,15 +21,19 @@ def _scope_to_resource(scope): # This is an experimental reasonable-effort appr
21
21
return scope # There is no much else we can do here
22
22
23
23
24
- def _obtain_token (http_client , resource , client_id = None ):
24
+ def _obtain_token (http_client , resource , client_id = None , object_id = None , mi_res_id = None ):
25
25
if "IDENTITY_ENDPOINT" in os .environ and "IDENTITY_HEADER" in os .environ :
26
26
return _obtain_token_on_app_service (
27
27
http_client , os .environ ["IDENTITY_ENDPOINT" ], os .environ ["IDENTITY_HEADER" ],
28
- resource , client_id = client_id )
29
- return _obtain_token_on_azure_vm (http_client , resource , client_id = client_id )
28
+ resource , client_id = client_id , object_id = object_id , mi_res_id = mi_res_id )
29
+ return _obtain_token_on_azure_vm (
30
+ http_client ,
31
+ resource , client_id = client_id , object_id = object_id , mi_res_id = mi_res_id )
30
32
31
33
32
- def _obtain_token_on_azure_vm (http_client , resource , client_id = None ):
34
+ def _obtain_token_on_azure_vm (http_client , resource ,
35
+ client_id = None , object_id = None , mi_res_id = None ,
36
+ ):
33
37
# Based on https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
34
38
logger .debug ("Obtaining token via managed identity on Azure VM" )
35
39
params = {
@@ -38,6 +42,10 @@ def _obtain_token_on_azure_vm(http_client, resource, client_id=None):
38
42
}
39
43
if client_id :
40
44
params ["client_id" ] = client_id
45
+ if object_id :
46
+ params ["object_id" ] = object_id
47
+ if mi_res_id :
48
+ params ["mi_res_id" ] = mi_res_id
41
49
resp = http_client .get (
42
50
"http://169.254.169.254/metadata/identity/oauth2/token" ,
43
51
params = params ,
@@ -57,7 +65,9 @@ def _obtain_token_on_azure_vm(http_client, resource, client_id=None):
57
65
logger .debug ("IMDS emits unexpected payload: %s" , resp .text )
58
66
raise
59
67
60
- def _obtain_token_on_app_service (http_client , endpoint , identity_header , resource , client_id = None ):
68
+ def _obtain_token_on_app_service (http_client , endpoint , identity_header , resource ,
69
+ client_id = None , object_id = None , mi_res_id = None ,
70
+ ):
61
71
"""Obtains token for
62
72
`App Service <https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=portal%2Chttp#rest-endpoint-reference>`_
63
73
"""
@@ -71,6 +81,10 @@ def _obtain_token_on_app_service(http_client, endpoint, identity_header, resourc
71
81
}
72
82
if client_id :
73
83
params ["client_id" ] = client_id
84
+ if object_id :
85
+ params ["object_id" ] = object_id
86
+ if mi_res_id :
87
+ params ["mi_res_id" ] = mi_res_id
74
88
resp = http_client .get (
75
89
endpoint ,
76
90
params = params ,
@@ -103,7 +117,10 @@ def _obtain_token_on_app_service(http_client, endpoint, identity_header, resourc
103
117
class ManagedIdentity (object ):
104
118
_instance , _tenant = socket .getfqdn (), "managed_identity" # Placeholders
105
119
106
- def __init__ (self , http_client , client_id = None , token_cache = None ):
120
+ def __init__ (self , http_client ,
121
+ client_id = None , object_id = None , mi_res_id = None ,
122
+ token_cache = None ,
123
+ ):
107
124
"""Create a managed identity object.
108
125
109
126
:param http_client:
@@ -117,13 +134,24 @@ def __init__(self, http_client, client_id=None, token_cache=None):
117
134
:param token_cache:
118
135
Optional. It accepts a :class:`msal.TokenCache` instance to store tokens.
119
136
"""
137
+ if len (list (filter (bool , [client_id , object_id , mi_res_id ]))) > 1 :
138
+ raise ValueError ("You can use up to one of these: client_id, object_id, mi_res_id" )
120
139
self ._http_client = http_client
121
140
self ._client_id = client_id
141
+ self ._object_id = object_id
142
+ self ._mi_res_id = mi_res_id
122
143
self ._token_cache = token_cache
123
144
124
- def acquire_token (self , resource ):
145
+ def acquire_token (self , resource = None ):
146
+ if not resource :
147
+ raise ValueError (
148
+ "The resource parameter is currently required. "
149
+ "It is only declared as optional in method signature, "
150
+ "in case we want to support scope parameter in the future." )
125
151
access_token_from_cache = None
126
- client_id_in_cache = self ._client_id or "SYSTEM_ASSIGNED_MANAGED_IDENTITY"
152
+ client_id_in_cache = (
153
+ self ._client_id or self ._object_id or self ._mi_res_id
154
+ or "SYSTEM_ASSIGNED_MANAGED_IDENTITY" )
127
155
if self ._token_cache :
128
156
matches = self ._token_cache .find (
129
157
self ._token_cache .CredentialType .ACCESS_TOKEN ,
@@ -149,7 +177,13 @@ def acquire_token(self, resource):
149
177
if "refresh_on" in entry and int (entry ["refresh_on" ]) < now : # aging
150
178
break # With a fallback in hand, we break here to go refresh
151
179
return access_token_from_cache # It is still good as new
152
- result = _obtain_token (self ._http_client , resource , client_id = self ._client_id )
180
+ result = _obtain_token (
181
+ self ._http_client ,
182
+ resource ,
183
+ client_id = self ._client_id ,
184
+ object_id = self ._object_id ,
185
+ mi_res_id = self ._mi_res_id ,
186
+ )
153
187
if self ._token_cache and "access_token" in result :
154
188
self ._token_cache .add (dict (
155
189
client_id = client_id_in_cache ,
0 commit comments