Microsoft Sharepoint Authentication using Python - python

I am trying to upload documents to the SharePoint online.
Target url: https://companyURL.sharepoint.com/sites/A/B/Info_documents/C
My aim is to search folder C, and if X subfolder is present in folder C, I need to upload a file. To accomplish this, I have generated client_id and client_secret by navigating to http://{sharepointsite}/_layouts/15/AppRegNew.aspx. In the XML permissions, I gave the following code:
I am using https://github.com/vgrem/Office365-REST-Python-Client for this implementation. When trying to use the following code snippet to see, if I am having the access to sharepoint using client_id and client_secret, i am seeing different errors:
import json
from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.runtime.client_request import ClientRequest
from office365.runtime.utilities.request_options import RequestOptions
from office365.sharepoint.client_context import ClientContext
app_settings = {
'url': 'https://companyURL.sharepoint.com/sites/A/B/Info_documents/C',
'client_id': 'xxxxxxxx',
'client_secret': 'xxxxxx',
}
context_auth = AuthenticationContext(url=app_settings['url'])
context_auth.acquire_token_for_app(client_id=app_settings['client_id'], client_secret=app_settings['client_secret'])
ctx = ClientContext(app_settings['url'], context_auth)
web = ctx.web
ctx.load(web)
ctx.execute_query()
print("Web site title: {0}".format(web.properties['Title']))
Error:
ClientRequestException: ('-2147024891, System.UnauthorizedAccessException', 'Access denied. You do not have permission to perform this action or access this resource.', '403 Client Error: Forbidden for url: https://companyURL.sharepoint.com/sites/A/B/Info_documents/C_api/Web')
But I gave the permissions, not sure whether I am doing wrong or selected the wrong module.
Please help.
Following is the XML code i gave when generating the client_ID and client_secret:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read"/>
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web/list" Right="Write"/>
</AppPermissionRequests>

Given the description
My aim is to search folder C, and if X subfolder is present in folder
C, I need to upload a file.
and the the following link format:
https://companyURL.sharepoint.com/sites/A/B/Info_documents/C
your folder structure could be represented like this:
https://companyURL.sharepoint.com/sites/A/B/ <-this is the actual site url
|
Info_documents <-library
|
C <-folder
Since AuthenticationContext class accepts the first parameter to be site url, app_settings needs to be updated like this:
app_settings = {
'url': 'https://companyURL.sharepoint.com/sites/A/B/', //need to refer to site url
'client_id': '--client id goes here--',
'client_secret': '--client secret goes here--',
}
Now comes the turn of App principal, since the requested permissions are applicable per web (scope: http://sharepoint/content/sitecollection/web), the second step (granting permissions) needs to be accomplished per specified web:
https://companyURL.sharepoint.com/sites/A/B/_layouts/15/appinv.aspx
Example
Here is an example which demonstrates how to verify if sub folder exists under the parent folder:
context_auth = AuthenticationContext(url=app_settings['url'])
context_auth.acquire_token_for_app(client_id=app_settings['client_id'],
client_secret=app_settings['client_secret'])
ctx = ClientContext(app_settings['url'], context_auth)
folder_url = "Info_documents/C" #folder url where to find
folder_name = "X" #folder name to find
result = ctx.web.get_folder_by_server_relative_url(folder_url).folders.filter("Name eq '{0}'".format(folder_name))
ctx.load(result)
ctx.execute_query()
if len(result) > 0:
print("Folder has been found: {0}".format(result[0].properties["Name"]))

Related

403 error when trying to create a folder with Sharepoint's REST-API

So, I am trying to create a new folder in my sharepoint using POST and the Office365-REST-Python-Client.
Somehow I always get a 403 error: 403 Client Error: Forbidden for url: https://<my tenant>.sharepoint.com/_api/Web/folders')
I followed the steps in this doc: https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs to get proper auth-tokens but somehow I am missing some permissions because all get-requests are working fine.
The Permission-Request-XML was:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
Would be great if someone could tell me which are missing and how I can get these.
Ah, before I forget my code is:
url = 'https://<my tenant>.sharepoint.com'#/sites/wevest_capital/'
context_auth = AuthenticationContext(url)
context_auth.acquire_token_for_app(client_id=client_id, client_secret=client_secret)
ctx = ClientContext(url, context_auth)
folderURL = '/sites/<my Site>/Shared Documents/Test'
source_folder = ctx.web.get_folder_by_server_relative_url(folderURL)
target_folder = ctx.web.folders.add(folderURL).execute_query()
Edit: Found a "workaround": I am using a newer library with access to the new MS-Graph authentication-endpoints
I get tired of trying to solve this. UserCredential worked for me but i still prefering the access token way
from office365.runtime.auth.user_credential import UserCredential
site_url = 'https://[TENANT].sharepoint.com/sites/[site]/'
ctx = ClientContext(site_url).with_credentials(UserCredential("email", "pass"))

On accessing Files using O360 library : Client Error: 403 Client Error: Forbidden for url

I am trying to access the files in my one drive, here in python. So my code is as follow:
account = Account(credentials=credentials)
storage = account.storage() # here we get the storage instance that handles all the storage options.
# list all the drives:
drives = storage.get_drives()
# get the default drive
my_drive = storage.get_default_drive() # or get_drive('drive-id')
# get some folders:
root_folder = my_drive.get_root_folder()
attachments_folder = my_drive.get_special_folder('attachments')
# iterate over the first 25 items on the root folder
for item in root_folder.get_items(limit=25):
if item.is_folder:
print(list(item.get_items(2))) # print the first to element on this folder.
elif item.is_file:
if item.is_photo:
print(item.camera_model) # print some metadata of this photo
elif item.is_image:
print(item.dimensions) # print the image dimensions
else:
# regular file:
print(item.mime_type) # print the mime type
It throws this error: Client Error: 403 Client Error: Forbidden for url: https://graph.microsoft.com/v1.0/me/drive/special/attachments | Error Message: Access denied
I need help here, as you can see in the attached screenshot, I have defined the correct scopes as well.
Have also checked similar articles but didn't find any luck.
Resource: https://pypi.org/project/O365/#onedrive
Thanks.
Modify the scopes to : scopes=['basic', 'message_all', 'openid', 'email', 'profile', 'offline_access', 'onedrive', 'onedriveall']

IBM Cloud Object Storage Connection issue Watson studio Python notebook

I have been trying to get my Python notebook in Watson Studio to connect to and retrieve data from my cloud storage for hours and read many tutorials but no idea why it is not working, code below:
credentials = {
'BUCKET': 'openai-data',
'URL': 'https://s3.private.us-east.cloud-object-storage.appdomain.cloud',
'SECRET_KEY': '',
'API_KEY': '*********************', #this key has been *d out but the value is there in my code
'RESOURCE_INSTANCE_ID': 'crn:v1:bluemix:public:cloud-object-storage:global:a/e448d36ef93f4d3ca55077db903d3461:51ce6e50-4e92-41d0-b002-5023e815cadc::',
'FILE': 'test_Y_smallsample.h5',
'ACCESS_KEY': ''
}
from ibm_botocore.client import Config
import ibm_boto3
cos = ibm_boto3.resource(service_name='s3',
ibm_api_key_id=credentials['API_KEY'],
ibm_service_instance_id=credentials['RESOURCE_INSTANCE_ID'],
ibm_auth_endpoint='https://iam.bluemix.net/oidc/token',
config=Config(signature_version='oauth'),
endpoint_url=credentials['URL'])
files = cos.Bucket('openai-data').objects.all()
for file in files:
print("Item: {0} ({1} bytes).".format(file.key, file.size))
this produces the error:
CredentialRetrievalError: Error when retrieving credentials from https://iam.bluemix.net/oidc/token: HttpCode(400) - Retrieval of tokens from server failed.
same result if I use "https://iam.cloud.ibm.com/identity/token" for the ibm_auth_endpoint
I've also tried a separate connection with HMAC credentials as well, but can't find any tutorials that show you how to incorporate those either...
Please help!
Thanks
This can be caused due to the use of invalid apikey. To get an apikey value, go to the 'Service credentials' menu of your storage instance and then click on "View credentials" of the "WDP-Project-Management-..." and see the value in the 'apikey' field.
This issue does not seem to be caused by invalid endpoint_url, bu anyway, to get the endpoint_url, go to Buckets > 'your bucket' > Configuration, and then choose an endpoint according to you needs (Private/Public/Direct). When filling the field, use "https://".
See below a code snippet to get data from a cvs file directly:
import pandas as pd
import ibm_boto3
from ibm_botocore.client import Config
cos = ibm_boto3.client(service_name='s3',
ibm_api_key_id='<apikey>',
ibm_auth_endpoint="https://iam.ng.bluemix.net/oidc/token",
config=Config(signature_version='oauth'),
endpoint_url="<endpoint>")
obj = cos.get_object(Bucket='<bucket_name>', Key='<csv_file>')
df = pd.read_csv(obj['Body'])

upload 2 files to google drive and python

I wont upload 2 file to google drive with python and google script (not API)
I would also like to send the name of the file
I got this answer to my first question
You can do this by publishing a web app to run as "Me"(you) with access: "Anyone, even anonymous".
Server side:
function doPost(e){
const FOLDER_ID = '###FOLDER_ID###';
var name = e.parameter.name;
saveFile(e.postData.contents,name,FOLDER_ID);
return 'Success';
}
function saveFile(data,name,id) {
data = Utilities.newBlob(Utilities.base64DecodeWebSafe(data));
DriveApp.getFolderById(id)
.createFile(data.setName(name))
}
Client side:
import requests, base64
url = '###WEB_APP_PUBLISHED_URL###'
name = '###FILENAME###'
requests.post(url+'?name='+name,data=base64.urlsafe_b64encode(open('##UPLOAD FILE PATH##','rb').read()))
This answer helps me send one file without its name
I saw you could do it that way
But I did not understand what I was changing on the server side
files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
What I need to change on the server side to get the file?
thanks

Why is Python script to download .xlsx from Sharepoint failing only for some URLs?

Using the Python Office365-REST-Python-Client I have written the following Python function to download Excel spreadsheets from Sharepoint (based on the answer at How to read SharePoint Online (Office365) Excel files in Python with Work or School Account? )
import sys
from urlparse import urlparse
from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.file import File
xmlErrText = "<?xml version=\"1.0\" encoding=\"utf-8\"?><m:error"
def download(sourceURL, destPath, username, password):
print "Download URL: {}".format(sourceURL)
urlParts = urlparse(sourceURL)
baseURL = urlParts.scheme + "://" + urlParts.netloc
relativeURL = urlParts.path
if len(urlParts.query):
relativeURL = relativeURL + "?" + urlParts.query
ctx_auth = AuthenticationContext(baseURL)
if ctx_auth.acquire_token_for_user(username, password):
try:
ctx = ClientContext(baseURL, ctx_auth)
web = ctx.web
ctx.load(web)
ctx.execute_query()
except:
print "Failed to execute Sharepoint query (possibly bad username/password?)"
return False
print "Logged into Sharepoint: {0}".format(web.properties['Title'])
response = File.open_binary(ctx, relativeURL)
if response.content.startswith(xmlErrText):
print "ERROR response document received. Possibly permissions or wrong URL? Document content follows:\n\n{}\n".format(response.content)
return False
else:
with open(destPath, 'wb') as f:
f.write(response.content)
print "Downloaded to: {}".format(destPath)
else:
print ctx_auth.get_last_error()
return False
return True
This function works fine for some URLs but fails for others, printing the following "file does not exist" document content on failure (newlines and whitespace added for readability):
<?xml version="1.0" encoding="utf-8"?>
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code>
-2130575338, Microsoft.SharePoint.SPException
</m:code>
<m:message xml:lang="en-US">
The file /sites/path/to/document.xlsx does not exist.
</m:message>
</m:error>
I know that the username and password are correct. Indeed changing the password results in a completely different error.
I have found that this error can occur when either the document doesn't exist, or when there are insufficient permissions to access the document.
However, using the same username/password, I can download the document with the same URL in a web browser.
Note that this same function consistently works fine for some .xlsx URLs in the same Sharepoint repository, but consistently fails for some other .xlsx URLs in that same Sharepoint repository.
My only guess is that there are some more fine-grained permissions that need to me managed. But I'm completely ignorant to these if they exist.
Can anybody help me to resolve why the failure is occurring and figure out how to get it working for all the required files that I can already download in a web browser?
Additional Notes From Comments Below
The failures are consistent for some some URLs. The successes are consistent for other URLs. Ie, for one URL, the result is always the same - it does not come and go.
The files have not moved or been deleted. I can download them using browsers/PCs which have never accessed those files previously.
The source of the URLs is Sharepoint itself. Doing a search in Sharepoint includes those files in the results list with a URL below each file. This is the URL that I'm using for each file. (For some files the script works and for others it does not; for all files the browser works for the same URL.)
The URLs are all correctly encoded. In particular, spaces are encoded with %20.

Categories