Reputation: 65
I want to be able to search for users across multiple tenants, and therefore my thoughts were to create a python script that runs on HTTP triggered Azure functions. This python script can authenticate to Microsoft Graph API for different tenants via service principals and then search for a user and return the data. is this a good idea or is there a better way of doing this?
Upvotes: 0
Views: 1106
Reputation: 15906
Let's discuss on the achievement.
I find that one multi-tenant
azure ad application is enough for querying users in different tenant through graph api. For example, there're 2 tenants, I created a multi-tenant application in azure ad app registration, after that I generated the client secret and add api permission of User.Read.All
.
Now I have an app with its client id and secret in 'tenant_a'. Next, visit https://login.microsoftonline.com/{tenant_b}/adminconsent?client_id={client-id}
in the browser, after sign in with the admin account in tenant_b, it will appear a 'permission' window to make consent the application have permission in tenant_b, after the consent, you will the the app created in tenant_a appears in the list of Enterprise applications
in tenant_b.
Now we need to generate access token for different tenant to call graph api. It's necessary to generate access token for each tenant, because I tried to use common
to replace the domain in the request(https://login.microsoftonline.com/common/oauth2/v2.0/token
), it can generate access token successfully, but the token can't used in the api to query user information. The query user api needs user principal name as the input parameter. For example, I have a user which account is 'bob@tenant_b.onmicrosoft.com', use the account as the parameter is ok to get response, but if I use 'bob' as the parameter, it will return 'Resource xxx does not exist...'.
I'm not an expert in python, I only found a sample and tested successfully with it. Here's my code, it will execute loop query until the user be found. And if you wanna a function, you may create a http trigger base on it.
import sys
import json
import logging
import requests
import msal
config = json.load(open(sys.argv[1]))
authorityName = ["<tenant_a>.onmicrosoft.com","<tenant_b>.onmicrosoft.com"]
username = "userone@<tenant_a>.onmicrosoft.com"
for domainName in authorityName:
# Create a preferably long-lived app instance which maintains a token cache.
print("==============:"+config["authority"]+domainName)
app = msal.ConfidentialClientApplication(
"<client_id>", authority="https://login.microsoftonline.com/"+domainName,
client_credential="<client_secret>",
)
# The pattern to acquire a token looks like this.
result = None
# Firstly, looks up a token from cache
# Since we are looking for token for the current app, NOT for an end user,
# notice we give account parameter as None.
result = app.acquire_token_silent(["https://graph.microsoft.com/.default"], account=None)
if not result:
result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
if "access_token" in result:
print("access token===:"+result['access_token'])
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
"https://graph.microsoft.com/v1.0/users/"+username,
headers={'Authorization': 'Bearer ' + result['access_token']}, ).json()
if "error" in graph_data:
print("error===="+json.dumps(graph_data, indent=2))
else:
print(json.dumps(graph_data, indent=2))
break
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id"))
Upvotes: 1