@@ -18,6 +18,22 @@ class APIMUserCreationError(Exception):
1818 pass
1919
2020
21+ class APIMUserNotFoundError (Exception ):
22+ pass
23+
24+
25+ class APIMSubscriptionAlreadyExistsError (Exception ):
26+ pass
27+
28+
29+ class APIMSubscriptionCreationError (Exception ):
30+ pass
31+
32+
33+ class APIMSubscriptionNotFoundError (Exception ):
34+ pass
35+
36+
2137class ApimSubscriptionsManager :
2238 _tenant_id : str = None
2339 _client_id : str = None
@@ -84,16 +100,61 @@ def _get_api_token(self):
84100 self ._api_token_expiry = token_expires_on
85101 return self ._api_token
86102
103+ def _get_auth_headers (self ) -> Dict [str , str ]:
104+ """
105+ Return auth headers required for interacting with APIM
106+
107+ :return: Auth headers
108+ """
109+ headers = {
110+ "Authorization" : f"Bearer { self ._get_api_token ()} " ,
111+ "Content-Type" : "application/json" ,
112+ }
113+ return headers
114+
87115 def create_user_on_apim (self , user_id : str , email : str , first_name : str , last_name : str ,
88116 group_name : str = None ) -> Dict [str , Any ]:
89117 """
118+ Create a user on APIM
90119
91- :param user_id:
92- :param email:
93- :param first_name:
94- :param last_name:
95- :param group_name:
96- :return:
120+ :param user_id: Unique identifier for the user
121+ :param email: Email address of the user
122+ :param first_name: First name of the user
123+ :param last_name: Last name of the user
124+ :param group_name: Name of the group to which the user should be added
125+ :return: Details of the user created on APIM
126+
127+ Examples:
128+ >>> print(create_user_on_apim("123-unique-id-for-subscription-123", "test.user@spatialdays.com", "test", "user"))
129+ {
130+ "id":"<redacted>",
131+ "type":"Microsoft.ApiManagement/service/users",
132+ "name":"123-unique-id-for-subscription-123",
133+ "properties":{
134+ "firstName":"test",
135+ "lastName":"user",
136+ "email":"test.user@spatialdays.com",
137+ "state":"active",
138+ "registrationDate":"2023-06-01T09:33:15.997Z",
139+ "note":"None",
140+ "groups":[
141+ {
142+ "id":"<redacted>",
143+ "name":"Developers",
144+ "description":"Developers is a built-in group. Its membership is managed by the system. Signed-in users fall into this group.",
145+ "builtIn":true,
146+ "type":"system",
147+ "externalId":"None"
148+ }
149+ ],
150+ "identities":[
151+ {
152+ "provider":"Basic",
153+ "id":"test.user@spatialdays.com"
154+ }
155+ ]
156+ }
157+ }
97158 """
98159
99160 if not user_id :
@@ -109,10 +170,7 @@ def create_user_on_apim(self, user_id: str, email: str, first_name: str, last_na
109170 f"{ self ._apim_rg_name } /providers/Microsoft.ApiManagement/service/{ self ._apim_name } /users/{ user_id } "
110171 f"?api-version=2022-08-01" )
111172
112- headers = {
113- "Authorization" : f"Bearer { self ._get_api_token ()} " ,
114- "Content-Type" : "application/json" ,
115- }
173+ headers = self ._get_auth_headers ()
116174
117175 body = json .dumps ({
118176 "properties" : {
@@ -127,7 +185,8 @@ def create_user_on_apim(self, user_id: str, email: str, first_name: str, last_na
127185 if response .status_code == 200 :
128186 logging .error (f"User with id { user_id } already exists" )
129187 raise APIMUserAlreadyExistsError (
130- f"User with id { user_id } already exists. Status code: { response .status_code } , Response: { response .text } " )
188+ f"User with id { user_id } already exists. Status code: { response .status_code } , \
189+ Response: { response .text } " )
131190 elif response .status_code == 201 :
132191 logging .debug (f"User with id { user_id } created successfully" )
133192 if group_name :
@@ -148,3 +207,224 @@ def create_user_on_apim(self, user_id: str, email: str, first_name: str, last_na
148207 else :
149208 raise APIMUserCreationError (
150209 f"Failed to create user. Status code: { response .status_code } , Response: { response .text } " )
210+
211+ def get_user_from_apim (self , user_id : str ) -> Dict [str , Any ]:
212+ """
213+ Gets the user details from APIM
214+
215+ :param user_id: The unique identifier for the user
216+ :return: Details of the user from APIM
217+
218+ Examples:
219+ >>> print(get_user_from_apim("123-unique-id-for-subscription-123"))
220+ {
221+ 'id': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/users/123-unique-id-for-subscription-123',
222+ 'type': 'Microsoft.ApiManagement/service/users',
223+ 'name': '123-unique-id-for-subscription-123',
224+ 'properties': {
225+ 'firstName': 'test',
226+ 'lastName': 'user',
227+ 'email': 'test.user@spatialdays.com',
228+ 'state': 'active',
229+ 'registrationDate': '2023-06-01T09:33:15.997Z',
230+ 'note': None,
231+ 'identities': [{
232+ 'provider': 'Basic',
233+ 'id': 'test.user@spatialdays.com'
234+ }]
235+ }
236+ }
237+ """
238+ url = (f"https://management.azure.com/subscriptions/{ self ._apim_subscription_id } /resourceGroups/"
239+ f"{ self ._apim_rg_name } /providers/Microsoft.ApiManagement/service/{ self ._apim_name } /users/"
240+ f"{ user_id } ?api-version=2022-08-01" )
241+
242+ headers = self ._get_auth_headers ()
243+
244+ response = requests .get (url , headers = headers )
245+
246+ if response .status_code == 200 :
247+ return response .json ()
248+ else :
249+ raise APIMUserNotFoundError (
250+ f"User with id { user_id } not found. Status code: { response .status_code } , Response: { response .text } " )
251+
252+ def delete_user_from_apim (self , user_id : str ) -> str :
253+ """
254+ Deletes a user from APIM
255+
256+ :param user_id: The unique identifier of the user to be deleted
257+ :return: The unique identifier of the user deleted
258+ Examples:
259+ >>> print(delete_user_from_apim("123-unique-id-for-subscription-123"))
260+ 123-unique-id-for-subscription-123
261+ """
262+
263+ url = (f"https://management.azure.com/subscriptions/{ self ._apim_subscription_id } /resourceGroups/"
264+ f"{ self ._apim_rg_name } /providers/Microsoft.ApiManagement/service/{ self ._apim_name } /users/{ user_id } "
265+ f"?api-version=2022-08-01" )
266+
267+ headers = self ._get_auth_headers ()
268+
269+ response = requests .delete (url , headers = headers )
270+
271+ if response .status_code == 200 :
272+ return user_id
273+ elif response .status_code == 204 :
274+ raise APIMUserNotFoundError (
275+ f"User with id { user_id } not found or couldn't be deleted. Status code: { response .status_code } , Response: { response .text } " )
276+ else :
277+ raise APIMUserNotFoundError (
278+ f"User with id { user_id } not found or couldn't be deleted. Status code: { response .status_code } , Response: { response .text } " )
279+
280+ def make_subscription_for_user_on_all_apis (self , user_id : str ) -> Dict [str , Any ]:
281+ """
282+ Makes a subscription for a user on all APIs
283+
284+ :param user_id: The unique identifier of the user
285+ :return: Details of the subscription created
286+
287+ Examples:
288+ >>> print(make_subscription_for_user_on_all_apis("123-unique-id-for-subscription-123"))
289+ {
290+ 'id': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/subscriptions/123-unique-id-for-subscription-123',
291+ 'type': 'Microsoft.ApiManagement/service/subscriptions',
292+ 'name': '123-unique-id-for-subscription-123',
293+ 'properties': {
294+ 'ownerId': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/users/123-unique-id-for-subscription-123',
295+ 'user': {
296+ 'id': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/users/123-unique-id-for-subscription-123',
297+ 'firstName': 'test',
298+ 'lastName': 'user',
299+ 'email': 'test.user@spatialdays.com',
300+ 'state': 'active',
301+ 'registrationDate': '2023-06-01T09:33:15.997Z',
302+ 'note': None,
303+ 'groups': [],
304+ 'identities': []
305+ },
306+ 'scope': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/apis',
307+ 'displayName': '123-unique-id-for-subscription-123',
308+ 'state': 'active',
309+ 'createdDate': '2023-06-01T09:37:51.0432183Z',
310+ 'startDate': '2023-06-01T00:00:00Z',
311+ 'expirationDate': None,
312+ 'endDate': None,
313+ 'notificationDate': None,
314+ 'primaryKey': '<redacted>',
315+ 'secondaryKey': '<redacted>',
316+ 'stateComment': None,
317+ 'allowTracing': False
318+ }
319+ }
320+ """
321+ url = (f"https://management.azure.com/subscriptions/{ self ._apim_subscription_id } /resourceGroups/"
322+ f"{ self ._apim_rg_name } /providers/Microsoft.ApiManagement/service/{ self ._apim_name } "
323+ f"/subscriptions/{ user_id } "
324+ f"?api-version=2022-08-01" )
325+
326+ headers = {
327+ "Authorization" : f"Bearer { self ._get_api_token ()} " ,
328+ "Content-Type" : "application/json" ,
329+ }
330+
331+ body = json .dumps ({
332+ "properties" : {
333+ "scope" : "/apis" ,
334+ "displayName" : user_id ,
335+ "state" : "active" ,
336+ "ownerId" : f"/users/{ user_id } " ,
337+ }
338+ })
339+
340+ response = requests .put (url , headers = headers , data = body )
341+
342+ if response .status_code == 201 :
343+ return response .json ()
344+ elif response .status_code == 200 :
345+ raise APIMSubscriptionAlreadyExistsError (
346+ f"Subscription for user with id { user_id } already exists. Status code: { response .status_code } ,"
347+ f" Response: { response .text } " )
348+ else :
349+ raise APIMSubscriptionCreationError (
350+ f"Failed to create subscription. Status code: { response .status_code } , Response: { response .text } " )
351+
352+ def get_subscription_for_user (self , user_id : str ) -> Dict [str , Any ]:
353+ """
354+ Retrieves a subscription for a user from the API Management (APIM) service.
355+
356+ :param user_id: The unique identifier of the user for whom the subscription is to be retrieved.
357+ :return: dictionary containing the details of the user's subscription. This includes the subscription ID, type,
358+ name, associated properties such as owner ID, scope, display name, state, creation date, start date, expiration date,
359+ end date, notification date, state comment and whether tracing is allowed.
360+ Examples:
361+ >>> print(get_subscription_for_user("123-unique-id-for-subscription-123"))
362+ {
363+ 'id': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/subscriptions/123-unique-id-for-subscription-123',
364+ 'type': 'Microsoft.ApiManagement/service/subscriptions',
365+ 'name': '123-unique-id-for-subscription-123',
366+ 'properties': {
367+ 'ownerId': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/users/123-unique-id-for-subscription-123',
368+ 'scope': '/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.ApiManagement/service/<redacted>/apis',
369+ 'displayName': '123-unique-id-for-subscription-123',
370+ 'state': 'active',
371+ 'createdDate': '2023-06-01T09:37:51.043Z',
372+ 'startDate': '2023-06-01T00:00:00Z',
373+ 'expirationDate': None,
374+ 'endDate': None,
375+ 'notificationDate': None,
376+ 'stateComment': None,
377+ 'allowTracing': False
378+ }
379+ }
380+ """
381+
382+ url = (f"https://management.azure.com/subscriptions/{ self ._apim_subscription_id } /resourceGroups/"
383+ f"{ self ._apim_rg_name } /providers/Microsoft.ApiManagement/service/{ self ._apim_name } "
384+ f"/subscriptions/{ user_id } "
385+ f"?api-version=2022-08-01" )
386+
387+ headers = self ._get_auth_headers ()
388+
389+ response = requests .get (url , headers = headers )
390+
391+ if response .status_code == 200 :
392+ return response .json ()
393+ else :
394+ raise APIMSubscriptionNotFoundError (
395+ f"Subscription for user with id { user_id } not found. Status code: { response .status_code } ,"
396+ f" Response: { response .text } " )
397+
398+ def get_subscription_secrets_for_user (self , user_id : str ) -> Dict [str , str ]:
399+ """
400+ Retrieves the primary and secondary keys for a user's subscription from the API Management (APIM) service.
401+
402+ Args:
403+ user_id (str): The unique identifier of the user for whom the subscription keys are to be retrieved.
404+
405+ Returns:
406+ dict: A dictionary containing the primary and secondary keys for the user's subscription.
407+
408+ Examples:
409+ >>> print(get_subscription_secrets_for_user("123-unique-id-for-subscription-123"))
410+ {
411+ 'primaryKey': '<redacted>',
412+ 'secondaryKey': '<redacted>'
413+ }
414+ """
415+
416+ url = (f"https://management.azure.com/subscriptions/{ self ._apim_subscription_id } /resourceGroups/"
417+ f"{ self ._apim_rg_name } /providers/Microsoft.ApiManagement/service/{ self ._apim_name } /"
418+ f"subscriptions/{ user_id } /listSecrets"
419+ f"?api-version=2022-08-01" )
420+
421+ headers = self ._get_auth_headers ()
422+
423+ response = requests .post (url , headers = headers )
424+
425+ if response .status_code == 200 :
426+ return response .json ()
427+ else :
428+ raise APIMSubscriptionNotFoundError (
429+ f"Subscription for user with id { user_id } not found. Status code: { response .status_code } , "
430+ f"Response: { response .text } " )
0 commit comments