i'm trying to get user data from AAD using Microsoft Graph API Python SDK.
App registration that i have in company tenant has the followiing API permissions:
I'm using the following piece of code to get user's details from AAD:
from azure.common.credentials import ServicePrincipalCredentials
from azure.graphrbac import GraphRbacManagementClient
credentials = ServicePrincipalCredentials(
client_id="appClientId",
secret="appClientSecret",
resource="https://graph.windows.net",
tenant = 'companyTenant'
)
tenant_id = 'companyTenantId'
graphrbac_client = GraphRbacManagementClient(
credentials,
tenant_id
)
user = graphrbac_client.users.get("myUserObjectId")
And get "azure.graphrbac.models.graph_error_py3.GraphErrorException: Insufficient privileges to complete the operation."
I'm using Python 3.10.5 and my app service should be able to get data of any user from AAD.
What am i doing wrong here?
Looks like the resource are trying to reach out is incorrect , https://graph.windows.net is used when you want to connect to AAD graph , please check the docs for more info - https://learn.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-operations-overview.
Could you please try by using the resource = graph.microsoft.com .
graph.microsoft.com is correct endpoint for graph .
please see the doc - https://learn.microsoft.com/en-us/graph/use-the-api
Hope this helps
Thanks
I tried to reproduce the same in my environment and got below results:
I created one Azure AD application and granted API permissions like below:
When I ran the same code as you, I got same error as below:
from azure.common.credentials import ServicePrincipalCredentials
from azure.graphrbac import GraphRbacManagementClient
credentials = ServicePrincipalCredentials(
client_id="appClientId",
secret="appClientSecret",
resource="https://graph.windows.net",
tenant = 'companyTenantId'
)
tenant_id = 'companyTenantId'
graphrbac_client = GraphRbacManagementClient(
credentials,
tenant_id
)
user = graphrbac_client.users.get("myUserObjectId")
Response:
I agree with Vicky kumar that graph.windows.net is deprecated and you need to change/migrate to https://graph.microsoft.com.
But the libraries that you are using won't support this resource that results error as below:
Your current library azure.graphrbac only supports resource as graph.windows.net that needs AAD graph permissions:
To resolve the error, you can make use of below code by installing urllib3 library beforehand:
import urllib3
uri = "https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token"
payload= {
'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'login.microsoftonline.com',
'client_id': '3de439c4-570d-4534-bxxb-e3axxx5d', #Your AppID
'scope': 'https://graph.microsoft.com/.default',
'client_secret': 'T2Y8Q~wYQxxxxxxxxxxOODUtFxajo', #Your client secret
'grant_type': 'client_credentials'
}
http = urllib3.PoolManager()
response = http.request('POST', uri, payload)
my_dict = eval(response.data)
token = f"{my_dict['token_type']} {my_dict['access_token']}"
#print(token)
uri5 = 'https://graph.microsoft.com/v1.0/users/myUserID'
payload5 = {'Authorization':token,'Host':'graph.microsoft.com','ConsistencyLevel':'eventual'}
https = urllib3.PoolManager()
response5 = http.request('GET', uri5, headers=payload5)
print(response5.data)
When I ran the above code, I got the user details successfully as below:
Okay, so it came out that the issue was that i was using wrong SDK, the one that i've used was working with the AAD graph but i need Microsoft.Graph (if the permission that i've granted to the app registration would be of the AAD Graph type - then it would work, but since AAD Graph cannot be assigned anymore to the app registration since it is deprecated i've assigned Microsoft.Graph permission).
So the fix was to use another SDK from MS (that is currenty in preview) and it worked for me, here is the code:
from azure.identity import ClientSecretCredential
from msgraph.core import GraphClient
credential = ClientSecretCredential(tenant_id='tenantId',client_secret='appRegClientId',client_id='appRegClientSecret')
client = GraphClient(credential=credential)
result = client.get('/users') # gets all users
# result = client.get('/users/userObjectId') # gets a certain user by it's objectId
# result = client.get('/users/email') # gets a certain user by it's email address
print(result.json())
Related
We are working on our dev environment around Azure ML and Python.
As part of this, we are using azure-identity (DefaultAzureCredential) for authorization. This is going to either match a CLI credential or a "VSCode-logged-in" credential.
We would programatically like to know which user (identified by email address or ID) is currently present. How would we do this?
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
token = credential.get_token("https://management.azure.com/", scopes=["user.read"])
current_user_id = ???
Update 1
As suggested by #xyan I can deconstruct the token to retrieve information about user accounts:
import json
import base64
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
token = credential.get_token("https://management.azure.com/", scopes=["user.read"])
base64_meta_data = token.token.split(".")[1].encode("utf-8") + b'=='
json_bytes = base64.decodebytes(base64_meta_data)
json_string = json_bytes.decode("utf-8")
json_dict = json.loads(json_string)
current_user_id = json_dict["upn"]
print(f"{current_user_id=}")
This works for user accounts, but not for service principals. In that case, it fails retrieving the token:
DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
EnvironmentCredential: Authentication failed: ClientApplication.acquire_token_silent_with_error() got multiple values for argument 'scopes'
What would be a proper scope that could retrieve upn/oid for various types of clients?
You can try parse the token to get the client id, tenant id information.
Sample code:
https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/azure/identity/_internal/decorators.py#L38.
(I work in the Azure SDK team in Microsoft)
I need to programmatically connect to onedrive and download some files. I am using the following code which works fine. However, when another user of my Tenant tries it, he gets a message that he must use MFA. Could this be because I am a user administrator and he is not? or is this an issue with the permissions of the application I have registered? MFA cannot be touched.
import logging
import requests
import json
import msal
import requests
CLIENT_ID = ''
TENANT_ID = ''
AUTHORITY_URL = 'https://login.microsoftonline.com/{}'.format(TENANT_ID)
RESOURCE_URL = 'https://graph.microsoft.com/'
API_VERSION = 'v1.0'
USERNAME = '' #Office365 user's account username
PASSWORD = ''
SCOPES = ['Sites.ReadWrite.All','Files.ReadWrite.All'] # Add other scopes/permissions as needed.
#Creating a public client app, Aquire a access token for the user and set the header for API calls
cognos_to_onedrive = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY_URL)
token = cognos_to_onedrive.acquire_token_by_username_password(USERNAME,PASSWORD,SCOPES)
headers = {'Authorization': 'Bearer {}'.format(token['access_token'])}
r = requests.get('https://graph.microsoft.com/v1.0/me/drives/{drive_id}/root:/DropFileOut', headers=headers).json()
print(r)
So, somehow the MFA was disabled for my ID. The solution would be to add the user to the MFA Policy exceptions, in this case.
import os
import requests
import base64
from xero.auth import OAuth2Credentials
from xero import Xero
from xero.constants import XeroScopes
my_scope = [XeroScopes.OFFLINE_ACCESS, XeroScopes.ACCOUNTING_CONTACTS, XeroScopes.ACCOUNTING_SETTINGS, XeroScopes.ACCOUNTING_TRANSACTIONS_READ,
XeroScopes.ACCOUNTING_TRANSACTIONS, XeroScopes.ACCOUNTING_CONTACTS_READ, XeroScopes.ACCOUNTING_SETTINGS_READ, ]
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
REFRESH_TOKEN_PATH = os.path.join(CURRENT_PATH, "config", "refresh_token2.txt")
CLIENT_ID = 'xxxxx'
CLIENT_SECRET = 'xxxxxx'
CALLBACK_URI = 'https://xero.com/'
TENANT_ID = 'xxxxx'
credentials = OAuth2Credentials(CLIENT_ID, CLIENT_SECRET, token=TOKEN,
callback_uri=CALLBACK_URI, tenant_id=TENANT_ID, scope=my_scope)
XERO = Xero(credentials)
invoices = XERO.invoices.all()
print invoices
accounts = XERO.accounts.all()
print accounts
While getting all accounts from xero or get_attachment_data in xero facing oauth_problem error in return, using new token every time.
Very late to the party, but https://github.com/freakboy3742/pyxero/issues/160 includes several reports of KeyError: 'oauth_problem' and seems to suggest that it is indicative of an underlying permissions issue - is that how you resolved it with Xero Support?
The original poster's issue was resolved by ensuring the accounting.settings scope was included on the authorization link and so also included in the access token.
You can check the access token by decoding it eg using code or by pasting into jwt.io to see what scopes are included in the token.
I am currently attempting to authenticate to Azure using the azure-mgmt-support MicrosoftSupport client and am receiving the following error:
AdalError: Get Token request returned http error: 400 and server response: {"error":"unauthorized_client","error_description":"AADSTS700016: Application with identifier 'xxx' was not found in the directory 'management.core.windows.net'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
I have double checked and am definitely using the correct client_id and tenant_id. What am I missing here? My code below:
from azure.mgmt.support import MicrosoftSupport
from msrestazure.azure_active_directory import ServicePrincipalCredentials
sub_id = 'xxx'
sp_creds = ServicePrincipalCredentials(client_id='xxx', secret='xxx')
SupportClient = MicrosoftSupport(sp_creds, sub_id)
After a short walk and another look at the documentation, and I spotted my error - I was missing the tenant_id from the ServicePrincipalCredentials object. It's not obvious from the SDK specification or error message that this is what was missing as the only required variables are client_id and secret, however when I looked at this example in the documentation I realised it was missing (pasting code below for posterity, in case docs page changes).
import os
from azure.mgmt.resource import SubscriptionClient
from azure.common.credentials import ServicePrincipalCredentials
# Retrieve the IDs and secret to use with ServicePrincipalCredentials
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]
tenant_id = os.environ["AZURE_TENANT_ID"]
client_id = os.environ["AZURE_CLIENT_ID"]
client_secret = os.environ["AZURE_CLIENT_SECRET"]
credential = ServicePrincipalCredentials(tenant=tenant_id, client_id=client_id, secret=client_secret)
subscription_client = SubscriptionClient(credential)
subscription = next(subscription_client.subscriptions.list())
print(subscription.subscription_id)
Trying to write a Python code where I would like to access my calendar and retrieve my schedule.
Not able to get through the authentication phase.
Seen and tested many examples, but all require running a local server where I browse locally and need to click a button and then enter my credentials.
Aiming to perform all of this inside my Python code.
You can achieve this one of two ways:
Using Resource Owner Password Credential flow - This allows you to pass the username and password to Azure AD. Gotcha's here are if there's any extra thing on the auth flow (consent, MFA, password reset) you'll just get a failure.
Using Client Credentials flow - This one requires admin consent. Also, you have to be really careful about this one as this client will have access to ALL info about all users. This should only be used with secure clients, not clients that other users have access to.
Here's a code snippet that showcases both of these:
import adal
import requests
tenant = "contoso.com"
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
username = "foo#contoso.com"
password = "mypassword"
authority = "https://login.microsoftonline.com/" + tenant
RESOURCE = "https://graph.microsoft.com"
context = adal.AuthenticationContext(authority)
# Use this for Client Credentials
#token = context.acquire_token_with_client_credentials(
# RESOURCE,
# client_id,
# client_secret
# )
# Use this for Resource Owner Password Credentials (ROPC)
token = context.acquire_token_with_username_password(RESOURCE, username, password, client_id);
graph_api_endpoint = 'https://graph.microsoft.com/v1.0{0}'
# /me only works with ROPC, for Client Credentials you'll need /<UsersObjectId/
request_url = graph_api_endpoint.format('/me')
headers = {
'User-Agent' : 'python_tutorial/1.0',
'Authorization' : 'Bearer {0}'.format(token["accessToken"]),
'Accept' : 'application/json',
'Content-Type' : 'application/json'
}
response = requests.get(url = request_url, headers = headers)
print (response.content)
Will try the above...
What I did to solve this was using this example - https://developer.microsoft.com/en-us/graph/docs/authorization/app_only
The problem was asking for the right permissions for the app in Azure.