Я пытаюсь создать инструмент для взаимодействия с Sharepoint, чтобы начать переход нескольких старых процессов от использования Sharepoint в качестве реляционной базы данных и переместить эти данные в фактическую базу данных и автоматизировать несколько ручных задач среди другие вещи.Python 3 + NTLM + Sharepoint
Окружающая среда, с которой я работаю, является сервером Sharepoint 2013 с использованием аутентификации NTLM. Мне нужно использовать python3, чтобы иметь возможность использовать набор библиотек, которые впоследствии будут использованы для использования данных. Python работает через 64-разрядный Anaconda. У меня нет административной власти над сервером sharepoint вообще, просто возможность читать и изменять информацию определенных страниц.
Проблема, с которой я столкнулся, заключается в аутентификации с использованием модулей NTLM и Sharepoint вместе. Следующий фрагмент кода работает просто отлично для вывода HTML с сайта, как если бы это был браузер:
from <<password management library>> import KEY
from requests_ntlm import HttpNtlmAuth
import requests,getpass
#Configuration
domain='domain'
srv="sharepoint.company.com"
creds=KEY(srv,getpass.getuser()) #Secure credential retrieval
user='{0}\\{1}'.format(domain,creds.USERNAME).upper()
srvaddr='https://{0}'.format(srv)
site='/sites/path/to/site/'
site_url='{0}{1}'.format(srvaddr,site)
#Auth via Requests_NTLM
opener=HttpNtlmAuth(user,creds.getpass())
#Interface via Requests
s = sharepoint.SharePointSite(site_url, opener)
r = requests.get(srvaddr, auth=opener)
Используя документацию, исходный код содержится в документации Sharepoint библиотеки и несколько StackOverflow сообщений (которые ссылаются на питоне 2 библиотеки), я попытался реплицировать это, используя модуль sharepoint. В то время как выше может успешно пройти проверку подлинности, следующий фрагмент кода получает 401 Несанкционированной Ошибку:
import sharepoint,requests,getpass,urllib
from ntlm3.HTTPNtlmAuthHandler import HTTPNtlmAuthHandler
from <<password management library>> import KEY
from requests_ntlm import HttpNtlmAuth
from urllib.request import BaseHandler, HTTPPasswordMgrWithDefaultRealm, build_opener
#Configuration
domain='domain'
srv="sharepoint.company.com"
creds=KEY(srv,getpass.getuser()) #Secure credential retrieval
user='{0}\\{1}'.format(domain,creds.USERNAME).upper()
srvaddr='https://{0}'.format(srv)
site='/sites/path/to/site/'
site_url='{0}{1}'.format(srvaddr,site)
#Auth via urllib Opener
def basic_auth_opener(url, username, password):
password_manager = HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, url, username, password)
auth_handler = HTTPNtlmAuthHandler(password_manager) #PreemptiveBasicAuthHandler(password_manager)
opener = build_opener(auth_handler)
return opener
print('Auth as {0}@{1}'.format(user,srvaddr))
opener = basic_auth_opener(srvaddr, user, creds.getpass())
#urllib.request.install_opener(opener)
print('Open {0}'.format(site_url))
#Interface via Sharepoint module
s = sharepoint.SharePointSite(site_url, opener)
for sp_list in s.lists:
print (sp_list.id, sp_list.meta['Title'])
Я знаю, что полномочия работать и имеют право на доступ к сайту, так как первый фрагмент кода работает просто отлично. Второй просто получает ошибку 401, и я весь день погружаюсь во внутренние работы urllib, запросов, python-ntlm и запросов-ntlm, пытаясь понять, почему один работает, а другой нет.
стек ошибок для справки:
HTTPErrorTraceback (most recent call last)
<ipython-input-41-af721d5620e7> in <module>()
31 #Interface via Sharepoint module
32 s = sharepoint.SharePointSite(site_url, opener)
---> 33 for sp_list in s.lists:
34 print (sp_list.id, sp_list.meta['Title'])
C:\Anaconda3\lib\site-packages\sharepoint\lists\__init__.py in __iter__(self)
78
79 def __iter__(self):
---> 80 return iter(self.all_lists)
81
82 def __getitem__(self, key):
C:\Anaconda3\lib\site-packages\sharepoint\lists\__init__.py in all_lists(self)
34 if not hasattr(self, '_all_lists'):
35 xml = SP.GetListCollection()
---> 36 result = self.opener.post_soap(LIST_WEBSERVICE, xml)
37
38 self._all_lists = []
C:\Anaconda3\lib\site-packages\sharepoint\site.py in post_soap(self, url, xml, soapaction)
30 if soapaction:
31 request.add_header('Soapaction', soapaction)
---> 32 response = self.opener.open(request, timeout=self.timeout)
33 return etree.parse(response).xpath('/soap:Envelope/soap:Body/*', namespaces=namespaces)[0]
34
C:\Anaconda3\lib\urllib\request.py in open(self, fullurl, data, timeout)
470 for processor in self.process_response.get(protocol, []):
471 meth = getattr(processor, meth_name)
--> 472 response = meth(req, response)
473
474 return response
C:\Anaconda3\lib\urllib\request.py in http_response(self, request, response)
580 if not (200 <= code < 300):
581 response = self.parent.error(
--> 582 'http', request, response, code, msg, hdrs)
583
584 return response
C:\Anaconda3\lib\urllib\request.py in error(self, proto, *args)
508 if http_err:
509 args = (dict, 'default', 'http_error_default') + orig_args
--> 510 return self._call_chain(*args)
511
512 # XXX probably also want an abstract factory that knows when it makes
C:\Anaconda3\lib\urllib\request.py in _call_chain(self, chain, kind, meth_name, *args)
442 for handler in handlers:
443 func = getattr(handler, meth_name)
--> 444 result = func(*args)
445 if result is not None:
446 return result
C:\Anaconda3\lib\urllib\request.py in http_error_default(self, req, fp, code, msg, hdrs)
588 class HTTPDefaultErrorHandler(BaseHandler):
589 def http_error_default(self, req, fp, code, msg, hdrs):
--> 590 raise HTTPError(req.full_url, code, msg, hdrs, fp)
591
592 class HTTPRedirectHandler(BaseHandler):
HTTPError: HTTP Error 401: Unauthorized
Библиотека Shareplum принимает requests_ntlm .HttpNtlmAuth для аутентификации и, похоже, работает. Отправляется, если это соответствует моим потребностям – Sethionic