Subir archivo a MS SharePoint usando Python OneDrive SDK

¿Es posible cargar un archivo en la biblioteca de documentos compartidos de un sitio de Microsoft SharePoint con el SDK de Python OneDrive ?

Esta documentación dice que debería ser (en la primera oración), pero no puedo hacer que funcione.

Puedo autenticar (con Azure AD) y cargar en una carpeta de OneDrive , pero al intentar cargar en una carpeta de SharePoint , recibo este error:

“Excepción de tipo ‘Microsoft.IdentityModel.Tokens. AudienceUriValidationFailedException ‘ fue lanzada”.

El código que estoy usando que devuelve un objeto con el error:

    (...authentication...) client = onedrivesdk.OneDriveClient('https://{tenant}.sharepoint.com/{site}/_api/v2.0/', auth, http) client.item(path='/drive/special/documents').children['test.xlsx'].upload('test.xlsx') 

    donde me gustaría subir en la web

    Puedo subir con éxito a https://{tenant}-my.sharepoint.com/_api/v2.0/ (note el ” -my ” después del {tenant} ) con el siguiente código:

     client = onedrivesdk.OneDriveClient('https://{tenant}-my.sharepoint.com/_api/v2.0/', auth, http) returned_item = client.item(drive='me', id='root').children['test.xlsx'].upload('test.xlsx') 

    ¿Cómo podría cargar el mismo archivo en un sitio de SharePoint ?

    (Las respuestas a preguntas similares ( 1 , 2 , 3 , 4 ) en Stack Overflow son demasiado vagas o sugieren un uso de una API diferente. Mi pregunta es si es posible usar el OneDrive Python SDK, y si es así, cómo hacerlo).


    Actualización : Aquí está mi código completo y salida. ( Los datos originales confidenciales se reemplazaron con un engaño similar ) .

     import re import onedrivesdk from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest # our domain (not the original) redirect_uri = 'https://example.ourdomain.net/' # our client id (not the original) client_id = "a1234567-1ab2-1234-a123-ab1234abc123" # our client secret (not the original) client_secret = 'ABCaDEFGbHcd0e1I2fghJijkL3mn4M5NO67P8Qopq+r=' resource = 'https://api.office.com/discovery/' auth_server_url = 'https://login.microsoftonline.com/common/oauth2/authorize' auth_token_url = 'https://login.microsoftonline.com/common/oauth2/token' http = onedrivesdk.HttpProvider() auth = onedrivesdk.AuthProvider(http_provider=http, client_id=client_id, auth_server_url=auth_server_url, auth_token_url=auth_token_url) should_authenticate_via_browser = False try: # Look for a saved session. If not found, we'll have to # authenticate by opening the browser. auth.load_session() auth.refresh_token() except FileNotFoundError as e: should_authenticate_via_browser = True pass if should_authenticate_via_browser: auth_url = auth.get_auth_url(redirect_uri) code = '' while not re.match(r'[a-zA-Z0-9_-]+', code): # Ask for the code print('Paste this URL into your browser, approve the app\'s access.') print('Copy the resulting URL and paste it below.') print(auth_url) code = input('Paste code here: ') # Parse code from URL if necessary if re.match(r'.*?code=([a-zA-Z0-9_-]+).*', code): code = re.sub(r'.*?code=([a-zA-Z0-9_-]*).*', r'\1', code) auth.authenticate(code, redirect_uri, client_secret, resource=resource) # If you have access to more than one service, you'll need to decide # which ServiceInfo to use instead of just using the first one, as below. service_info = ResourceDiscoveryRequest().get_service_info(auth.access_token)[0] auth.redeem_refresh_token(service_info.service_resource_id) auth.save_session() # Save session into a local file. # Doesn't work client = onedrivesdk.OneDriveClient( 'https://{tenant}.sharepoint.com/sites/{site}/_api/v2.0/', auth, http) returned_item = client.item(path='/drive/special/documents') .children['test.xlsx'] .upload('test.xlsx') print(returned_item._prop_dict['error_description']) # Works, uploads to OneDrive instead of SharePoint site client2 = onedrivesdk.OneDriveClient( 'https://{tenant}-my.sharepoint.com/_api/v2.0/', auth, http) returned_item2 = client2.item(drive='me', id='root') .children['test.xlsx'] .upload('test.xlsx') print(returned_item2.web_url) 

    Salida:

     Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown. https://{tenant}-my.sharepoint.com/personal/user_domain_net/_layouts/15/WopiFrame.aspx?sourcedoc=%1ABCDE2345-67F8-9012-3G45-6H78IJKL9M01%2N&file=test.xlsx&action=default 

    Finalmente encontré una solución, con la ayuda de ( usuario SO ) sytech.

    La respuesta a mi pregunta original es que al usar el SDK original de Python OneDrive , no es posible cargar un archivo en la carpeta Shared Documents de un sitio de SharePoint Online (al momento de escribir esto): cuando el SDK consulta el servicio de descubrimiento de recursos , descarta todos los servicios cuyo service_api_version no es v2.0 . Sin embargo, obtengo el servicio de SharePoint con v1.0 , por lo que se ha eliminado, aunque también se puede acceder a él mediante API v2.0.

    Sin embargo , al extender la clase ResourceDiscoveryRequest (en el SDK de OneDrive), podemos crear una solución para esto. Me las arreglé para subir un archivo de esta manera:

     import json import re import onedrivesdk import requests from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest, \ ServiceInfo # our domain (not the original) redirect_uri = 'https://example.ourdomain.net/' # our client id (not the original) client_id = "a1234567-1ab2-1234-a123-ab1234abc123" # our client secret (not the original) client_secret = 'ABCaDEFGbHcd0e1I2fghJijkL3mn4M5NO67P8Qopq+r=' resource = 'https://api.office.com/discovery/' auth_server_url = 'https://login.microsoftonline.com/common/oauth2/authorize' auth_token_url = 'https://login.microsoftonline.com/common/oauth2/token' # our sharepoint URL (not the original) sharepoint_base_url = 'https://{tenant}.sharepoint.com/' # our site URL (not the original) sharepoint_site_url = sharepoint_base_url + 'sites/{site}' file_to_upload = 'C:/test.xlsx' target_filename = 'test.xlsx' class AnyVersionResourceDiscoveryRequest(ResourceDiscoveryRequest): def get_all_service_info(self, access_token, sharepoint_base_url): headers = {'Authorization': 'Bearer ' + access_token} response = json.loads(requests.get(self._discovery_service_url, headers=headers).text) service_info_list = [ServiceInfo(x) for x in response['value']] # Get all services, not just the ones with service_api_version 'v2.0' # Filter only on service_resource_id sharepoint_services = \ [si for si in service_info_list if si.service_resource_id == sharepoint_base_url] return sharepoint_services http = onedrivesdk.HttpProvider() auth = onedrivesdk.AuthProvider(http_provider=http, client_id=client_id, auth_server_url=auth_server_url, auth_token_url=auth_token_url) should_authenticate_via_browser = False try: # Look for a saved session. If not found, we'll have to # authenticate by opening the browser. auth.load_session() auth.refresh_token() except FileNotFoundError as e: should_authenticate_via_browser = True pass if should_authenticate_via_browser: auth_url = auth.get_auth_url(redirect_uri) code = '' while not re.match(r'[a-zA-Z0-9_-]+', code): # Ask for the code print('Paste this URL into your browser, approve the app\'s access.') print('Copy the resulting URL and paste it below.') print(auth_url) code = input('Paste code here: ') # Parse code from URL if necessary if re.match(r'.*?code=([a-zA-Z0-9_-]+).*', code): code = re.sub(r'.*?code=([a-zA-Z0-9_-]*).*', r'\1', code) auth.authenticate(code, redirect_uri, client_secret, resource=resource) service_info = AnyVersionResourceDiscoveryRequest().\ get_all_service_info(auth.access_token, sharepoint_base_url)[0] auth.redeem_refresh_token(service_info.service_resource_id) auth.save_session() client = onedrivesdk.OneDriveClient(sharepoint_site_url + '/_api/v2.0/', auth, http) # Get the drive ID of the Documents folder. documents_drive_id = [x['id'] for x in client.drives.get()._prop_list if x['name'] == 'Documents'][0] items = client.item(drive=documents_drive_id, id='root') # Upload file uploaded_file_info = items.children[target_filename].upload(file_to_upload) 

    La autenticación para un servicio diferente le da un token diferente.