Here is the code that I am using to interactive with Office 365:
from O365 import Account
credentials = ('...', '...')
account = Account(credentials)
if account.authenticate(scopes=['basic', 'message_all']):
print('Authenticated!')
After I run the python file, I get a URL, and I click the URL:
AADSTS50194: Application '...'(test) is not configured as a multi-tenant application. Usage of the /common endpoint is not supported for such applications created after '10/15/2018'. Use a tenant-specific endpoint or configure the application to be multi-tenant.
I set "Accounts in this organizational directory only" because I only want the people in my company can access the app.
I also set this (as you can see, I have set the redirect URL ):
Am I missing something here?
Here is my new code:
from O365 import Account
credentials = ('..', '..')
# the default protocol will be Microsoft Graph
account = Account(credentials, auth_flow_type='credentials', tenant_id='..')
if account.authenticate():
print('Authenticated!')
storage = account.storage()
print(storage)
my_drive = storage.get_default_drive() # or get_drive('drive-id')
print(my_drive)
root_folder = my_drive.get_root_folder()
attachments_folder = my_drive.get_special_folder('attachments')
It can get "Authenticated!", but I get the following error:
Client Error: 403 Client Error: Forbidden for url: https://graph.microsoft.com/v1.0/drive/root | Error Message: Either scp or roles claim need to be present in the token.
{"error":{"code":"InvalidAuthenticationToken","message":"Access token is empty.","innerError":{"date":"2022-04-07T01:24:20","request-id":"be71cdcf-6f69-4d6f-b344-588d0b693253","client-request-id":"be71cdcf-6f69-4d6f-b344-588d0b693253"}}}
Thanks
You need to find your tenant Id (it will be listed on the application registration)
and then pass that in eg
from O365 import Account
credentials = ('my_client_id', 'my_client_secret')
# the default protocol will be Microsoft Graph
account = Account(credentials, auth_flow_type='credentials', tenant_id='my-tenant-id')
if account.authenticate():
print('Authenticated!')
Related
I enabled the google drive api, created a service account, added the service account email to the folder and successfully generated the .json credentials
But when I try to print the contents of the temp2 folder I get "no files found"
I'm attempting to do it this way
import logging
from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
creds = Credentials.from_service_account_file('bayfiles-779393795f34.json', scopes=['https://www.googleapis.com/auth/drive'])
service = build('drive', 'v3', credentials=creds)
query = "mimeType='application/vnd.google-apps.folder' or mimeType='application/vnd.google-apps.document' or mimeType='application/vnd.google-apps.spreadsheet' or mimeType='application/vnd.google-apps.presentation' and trashed = false and parents in '16x7o7CNCscM-lFqnKaXwUf1Bv-OTQK0W'"
results = service.files().list(q=query).execute()
items = results.get("files", [])
if not items:
logger.debug("No files found")
else:
# Print file names
for item in items:
logger.debug(f'The service account has access to the file "{item["name"]}" with ID "{item["id"]}"')
The strange thing is that the number of requests appears to me in the API page of my project
but through the code it is returned to me as if there were no files inside the temp2 folder, but it's wrong.
I tested locally, with my user account and your filter and your code works well. But as I said, strangely.
In fact, only the presentation not trashed in the mentioned folder are returned + all the other file mentioned in the OR clauses. Again, add parenthesis like that to narrow only to the current mentioned folder
query = "(mimeType='application/vnd.google-apps.folder' or mimeType='application/vnd.google-apps.document' or mimeType='application/vnd.google-apps.spreadsheet' or mimeType='application/vnd.google-apps.presentation') and trashed = false and parents in '16x7o7CNCscM-lFqnKaXwUf1Bv-OTQK0W'"
Are you sure about the Folder ID?
Let me show you how to avoid a service account key file (which is a bad practice).
You have to scope correctly your user credential. Use that CLI command for that
gcloud auth application-default login \
--scopes="https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/drive"
Keep in mind that is now your user account that will be used, and YOUR email must be granted on the Google Drive folder
If you want to use the service account identity instead of your own user email, you can use impersonation
gcloud auth application-default login \
--scopes="https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/drive" \
--impersonate-service-account="<service account email>"
You must have the role "project owner" or "service account token creator" to be able to impersonate a service account. But like that, you don't need a secret and sensitive file (JSON)
Update your code. You will see 2 changes
import logging
#from google.oauth2.service_account import Credentials -- No longer need it
import google.auth #Required for getting the default authentication
from googleapiclient.discovery import build
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
#creds = Credentials.from_service_account_file('bayfiles-779393795f34.json', scopes=['https://www.googleapis.com/auth/drive'])
# Prefer the default credential instead. Like that it works locally and in the cloud the same way
# Scopes are optional locally, but required in the cloud runtime environment
credentials, project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/drive"])
# With your user credential you also have to notify explicitly the quota project. It's optional for cloud runtime environment
service = build('drive', 'v3', credentials=credentials,client_options={"quota_project_id":project_id})
query = "mimeType='application/vnd.google-apps.folder' or mimeType='application/vnd.google-apps.document' or mimeType='application/vnd.google-apps.spreadsheet' or mimeType='application/vnd.google-apps.presentation' and trashed = false and parents in '16x7o7CNCscM-lFqnKaXwUf1Bv-OTQK0W'"
results = service.files().list(q=query).execute()
items = results.get("files", [])
if not items:
logger.debug("No files found")
else:
# Print file names
for item in items:
logger.debug(f'The service account has access to the file "{item["name"]}" with ID "{item["id"]}"')
I'm using Azure Python SDK to deploy Azure VM. I can create VM with Network Security Group without any issue via the Azure portal. However, I failed to create a Network Security Group by using API like:
async_nsg_create=network_client.network_security_groups.begin_create_or_update(
GROUP_NAME,
NSG_NAME,
nsg_parameters
)
It always complains that I "does not have authorization to perform action 'Microsoft.Network/networkSecurityGroups/write'".
However, I can create a Network Security Group via the Azure portal by clicking "create a resource" or add new source in Resource Group. I suspect I may have to create NSG via ResourceManagementClient, but I couldn't find any useful info in API doc:https://learn.microsoft.com/en-us/python/api/azure-mgmt-resource/azure.mgmt.resource.resourcemanagementclient?view=azure-python#models-api-version--2020-06-01--
I checked the solution in this issue: enter link description here, but failed at step: resource_client.providers.register('Microsoft.Compute') and it complains:"does not have authorization to perform action 'Microsoft.Compute/register/action'"
The error means your client does not have the permission to do the operations, you need to add it as an RBAC role in your resource group/subscription.
However, I can create a Network Security Group via the Azure portal by clicking "create a resource" or add new source in Resource Group.
In the portal, your are using the account logged in the portal, if you are using the code here, it uses the credentials of the service principal, it is different.
Here is a complete sample works for me, you follow the steps below.
1.Register an application with Azure AD and create a service principal.
2.Get values for signing in and create a new application secret.
3.Navigate to the resource group or the subscription -> Access control (IAM) -> Add -> add service principal of the AD App as an RBAC role e.g. Contributor, details follow this.
4.Then use the code below.
from azure.identity import ClientSecretCredential
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.network.v2020_06_01.models import NetworkSecurityGroup
from azure.mgmt.network.v2020_06_01.models import SecurityRule
tenant_id = "<tenant-id>"
client_id = "<client-id>"
client_secret = "<client-secret>"
subscription_id = "<subscription-id>"
credential = ClientSecretCredential(tenant_id, client_id, client_secret)
network_client = NetworkManagementClient(credential, subscription_id)
resource_group_name = "<group-name>"
nsg_name = "testnsg"
nsg_params = NetworkSecurityGroup(id= "testnsg", location="UK South", tags={ "name" : "testnsg" })
nsg = network_client.network_security_groups.begin_create_or_update(resource_group_name, "testnsg", parameters=nsg_params)
print(nsg.result().as_dict())
5.Check in the portal:
Update:
If you want to use the user account, you just need to use AzureCliCredential.
1.Install the Azure CLI, then login your account with az login in a local terminal, e.g. powershell.
2.After login, change the code like below and run it.
from azure.identity import ClientSecretCredential
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.network.v2020_06_01.models import NetworkSecurityGroup
from azure.mgmt.network.v2020_06_01.models import SecurityRule
subscription_id = "<subscription-id>"
credential = AzureCliCredential()
network_client = NetworkManagementClient(credential, subscription_id)
resource_group_name = "<group-name>"
nsg_name = "testnsg"
nsg_params = NetworkSecurityGroup(id= "testnsg", location="UK South", tags={ "name" : "testnsg" })
nsg = network_client.network_security_groups.begin_create_or_update(resource_group_name, "testnsg", parameters=nsg_params)
print(nsg.result().as_dict())
I have created an azure application using the Microsoft azure platform.
using the below script I make an attempt to connect to the API using the credentials given when creating the azure application.
from O365 import Account
credentials = ('azureApp_clientId', 'azureApp_clientSecret')
account = Account(credentials)
if account.authenticate(scopes=['Mail.Read']):
print('Authenticated!')
When the script runs it returns a URL to add to a browser and give consent..
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?xxxxxxxxxx
When i paste the URL into my browser it does nothing and returns a blank page..
This is my redirect URI in the azure app
What am I missing??
Docs to o365 Lib here https://pypi.org/project/O365/
Update
from O365 import Account
credentials = ('myclientID')
account = Account(credentials, auth_flow_type = 'public')
if account.authenticate(scopes = ['Mail.Read']):
print('Authenticated!')
mailbox = account.mailbox()
inbox = mailbox.inbox_folder()
for message in inbox.get_messages():
print(message)
Update
According to the configuration of the application azure (you register the application as Mobile and desktop applications), you should use the method Authenticate on behalf of a user (public) to do auth and should not provide client_secret. For more details, please refer to here and here.
For example
from O365 import Account
credentials = ('<your client_id>',)
account = Account(credentials,auth_flow_type='public')
if account.authenticate(scopes==['Mail.Read'] ):
print('Authenticated!')
mailbox = account.mailbox()
inbox = mailbox.inbox_folder()
for message in inbox.get_messages():
print(message)
#Update
My configuration
I'm trying to use python to download an excel file that is hosted in a sharepoint which is part of the Microsoft Azure platform. The sharepoint is password protected, and I have an account and a password which I can use to login in via my browser,
In order to authenticate with a python script I followed the method suggested in: Sharepoint authentication with python.
Which uses the O365 rest python client library and goes as follows:
from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.sharepoint.client_context import ClientContext
url = 'https://organization.sharepoint.com/sites/something/somepage.aspx'
username = 'userx#organization.com'
password = 'fakepass'
ctx_auth = AuthenticationContext(url)
if ctx_auth.acquire_token_for_user(username, password):
ctx = ClientContext(url, ctx_auth)
else:
print(ctx_auth.get_last_error())
But I'm getting an error message back:
An error occurred while retrieving token: AADSTS50076: Due to a configuration
change made by your administrator, or because you moved to a new location, you
must use multi-factor authentication to access ''.
I do connect to this account from multiple devices (browser), and just once I was required to use MFA to log in (SMS message). Is there a way to get around this? Note that I'm not the admin of the system.
The error message is pretty intuitive, user credentials auth is not supported when Multi-Factor Authentication (MFA) enabled.
To circumvent this error, SharePoint App-Only flow could be utilized instead (supported by Office365-REST-Python-Client library).
Setting up an app-only principal with tenant permissions section describes how to configure it, to summarize it consist of two steps:
register App principal (think of it as a "service account")
grant a permissions
Once app principal is created and consented, it could be utilized to access SharePoint resource as demonstrated below:
from office365.sharepoint.client_context import ClientContext
from office365.runtime.auth.client_credential import ClientCredential
site_url = 'https://contoso.sharepoint.com/'
app_principal = {
'client_id': '--client-id-goes-here--',
'client_secret': '--client-secret-goes-here--',
}
credentials = ClientCredential(app_principal['client_id'], app_principal['client_secret'])
ctx = ClientContext(url).with_credentials(credentials)
web = ctx.web
ctx.load(web)
ctx.execute_query()
print("Web site title: {0}".format(web.properties['Title']))
Here is an instruction on how to configure SharePoint App-Only flow:
Note: app principal registration operation(steps 1 through 5)
needs to be performed once per tenant. Although the operation for
granting permissions ( steps 6-9) could be applied either per tenant
or site collection:
permissions granted per site collection and requires a site collection administrator (in the provided instruction the permissions
are granter per site collection)
If you prefer to grant permissions on tenant level, visit tenant administration site instead, the URL must include -admin to access
the tenant administration site, for example,
https://{tenant}-admin.sharepoint.com/_layouts/15/appinv.aspx. That
operation requires a tenant administrator permissions
Steps:
Go to the appregnew.aspx page in your SharePoint Online site. For example, https://{tenant}.sharepoint.com/_layouts/15/appregnew.aspx.
On this page, click the Generate buttons next to the Client ID and Client Secret fields to generate their values.
Store the client ID and client secret securely as these credentials can be used to read or update all data in your SharePoint Online environment. You will also use them to configure the SharePoint Online connection in application.
Under Title, specify a title. For example, Python console. Under App Domain, specify localhost. Under Redirect URI, specify https://localhost.
Note: Sometimes, if you specify a actual domain, e.g. sharepoint.com domain in the App Domain and Redirect URI fields, instead of localhost, the error message An unexpected error has occurred might encounter. Check the appregnew.aspx page and make sure both fields include the proper localhost URI.
Click Create.
Go to the appinv.aspx page on the site collection. For example, https://example.sharepoint.com/_layouts/15/appinv.aspx to grant site-scoped permissions.
Specify your client ID in the App Id field and click Lookup to find your app.
To grant permissions to the app, copy the XML below to the App’s permission request XML field:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
</AppPermissionRequests>
Note: For tenant level scope, permission request XML looks as follows:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
Click Create.
On the confirmation dialog, click Trust It to grant the permissions.
I am trying to check if the user has installed my marketplace app
from oauth2client.client import SignedJwtAssertionCredentials
import json
from httplib2 import Http
from apiclient.discovery import build
fname = 'my-creds.json'
scope = [
'https://www.googleapis.com/auth/appsmarketplace.license'
]
applicationId='12345678'
customerId='mydomain.com'
json_key = json.load(open(fname))
credentials = SignedJwtAssertionCredentials(json_key['client_email'], json_key['private_key'], scope)
http_auth = credentials.authorize(Http())
appsmarket = build('appsmarket', 'v2', http=http_auth)
response = appsmarket.customerLicense().get(applicationId=applicationId, customerId=customerId).execute()
print response
I have created a service account in the same project as my app in Google console.
But I keep getting
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/appsmarket/v2/customerLicense/471879773528/ashish%40noodletools.com?alt=json returned "Not authorized to access the application ID">
Do you add service account to your domain's authorized API clients in security section?
Look at Delegating domain-wide authority to the service account here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
To delegate domain-wide authority to a service account, an administrator of the Google Apps domain must complete the following steps:
Go to your Google Apps domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
Select Show more and then Advanced settings from the list of options.
Select Manage API client access in the Authentication section.
In the Client Name field enter the service account's Client ID.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to.
Click Authorize.
Your application now has the authority to make API calls as users in your domain (to "impersonate" users). When you prepare to make authorized API calls, you specify the user to impersonate.