Pull to refresh

Использование XmlRPC через прокси-сервер для хоста с авторизацией

Reading time7 min
Views2.7K
Сразу оговоримся, что речь идет о Python 2.X.

Задача: заставить xmlrpclib в Python работать через прокси-сервер с авторизацией Basic и NTLM, а также с хостом, требующим авторизацию и Cookies.

Мне это было нужно для системы багрепортов в нашем приложении, где при отправки сообщения об ошибке в TRAC должен создаваться тикет с описанием, логами, и прочим. Общение с TRAC'ом идет как раз через xmlRPC (используя XmlRpcPlugin). Пользователи приложения в основном работают за прокси-сервером внутри корпоративной сети.

Реализуется это через создание транспорта на основе urllib, который перенаправляет XML-запросы через прокси-сервер.

В интернете можно найти пару примеров для поддержки прокси без авторизации, написанных на первом urllib. Сначала я попытался взять такой пример и добавить к нему авторизацию, но в итоге стало понятно, что лучше переписать его под urllib2, где это сделать гораздо проще.

Данный вариант транспорта поддерживает также работу без прокси-сервера (если прямое соединение доступно, а указанный прокси-сервер — нет, то соединение произойдет напрямую — это особенность urllib2).

Для поддержки NTLM-авторизации используется python-ntlm.

На всякий случай предупреждаю, что код представлен только в качестве примера и требует обязательного тестирования и модификации под ваши нужды.

Пример использования:

Copy Source | Copy HTML
  1. serverURL = "http://some.server.com/xmlrpc"
  2.  
  3. xmlTransport= UrllibTransport()
  4. server = xmlrpclib.ServerProxy(serverURL, transport = xmlTransport)




Сам скрипт транспорта:

Copy Source | Copy HTML
  1. # -*- coding: utf8 -*-
  2.  
  3. # Requires python-ntlm (http://code.google.com/p/python-ntlm/) package
  4. from ntlm import HTTPNtlmAuthHandler
  5.  
  6. import sys, os, tempfile, pickle
  7. import xmlrpclib, getpass, string
  8. import base64, urllib2, cookielib
  9. from urllib import unquote, splittype, splithost, getproxies
  10. import urllib2
  11.  
  12. #################################
  13.  
  14. useProxy = True
  15. useAuthOnProxy = True
  16.  
  17. proxyUser = "username"
  18. proxyPassword = "password"
  19. proxyServer = "http://proxy.org:3128"
  20.  
  21. httpAuthName = "user"
  22. httpAuthPassword = "password"
  23. serverTopLevelURL = "http://my.server.com"
  24.  
  25. #################################
  26.  
  27. class UrllibTransport(xmlrpclib.Transport):
  28.     def request(self, host, handler, request_body, verbose= 0):
  29.         self.verbose = verbose
  30.  
  31.         if useProxy:
  32.             if useAuthOnProxy:
  33.                 self.proxyurl = "http://" + proxyUser + ":" \
  34.                                     + proxyPassword + "@" \
  35.                                     + proxyServer[7:]
  36.             else:
  37.                 self.proxyurl = proxyServer
  38.         else:
  39.             self.proxyurl = None
  40.  
  41.         puser_pass = None
  42.  
  43.         if self.proxyurl is not None:
  44.             type, r_type = splittype(self.proxyurl)
  45.             phost, XXX = splithost(r_type)
  46.  
  47.             if '@' in phost:
  48.                 user_pass, phost = phost.split('@', 1)
  49.                 if ':' in user_pass:
  50.                     user, password = user_pass.split(':', 1)
  51.                     puser_pass = base64.encodestring(
  52.                                    '%s:%s' % (unquote(user),unquote(password))).strip()
  53.  
  54.             proxies = {'http':'http://%s' % phost}
  55.  
  56.         host = unquote(host)
  57.         address = "http://%s%s" % (host, handler)
  58.  
  59.         request = urllib2.Request(address)
  60.         request.add_data(request_body)
  61.         request.add_header('User-agent', self.user_agent)
  62.         request.add_header("Content-Type", "text/xml")
  63.  
  64.         # HTTP Auth
  65.         password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
  66.         top_level_url = serverTopLevelURL
  67.         password_mgr.add_password(None,
  68.                                   top_level_url,
  69.                                   httpAuthName,
  70.                                   httpAuthPassword)
  71.         handler = urllib2.HTTPBasicAuthHandler(password_mgr)
  72.  
  73.         # Cookies
  74.         cj = cookielib.CookieJar()
  75.  
  76.         if puser_pass:
  77.             # NTLM
  78.             passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
  79.             passman.add_password(None, serverTopLevelURL, user, password)
  80.  
  81.             authNTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)
  82.             request.add_header('Proxy-authorization', 'Basic ' + puser_pass)
  83.  
  84.             proxy_support = urllib2.ProxyHandler(proxies)
  85.  
  86.             opener = urllib2.build_opener(handler, proxy_support,
  87.                                           urllib2.HTTPCookieProcessor(cj),
  88.                                           authNTLM)
  89.         elif self.proxyurl:
  90.             # Proxy without auth
  91.             proxy_support = urllib2.ProxyHandler(proxies)
  92.             opener = urllib2.build_opener(proxy_support,
  93.                                           handler,
  94.                                           urllib2.HTTPCookieProcessor(cj))
  95.         else:
  96.             # Direct connection
  97.             proxy_support = urllib2.ProxyHandler({})
  98.             opener = urllib2.build_opener(proxy_support,
  99.                                           handler,
  100.                                           urllib2.HTTPCookieProcessor(cj))
  101.  
  102.         urllib2.install_opener(opener)
  103.         response = urllib2.urlopen(request)
  104.  
  105.         return self.parse_response(response)


P.S.
Для всех, кто интересуется urllib2, рекомендую посмотреть urllib2 — The Missing Manual — отличный документ, где подробно описаны особенности работы с ним, в частности, обработка ошибок и исключений.
Tags:
Hubs:
Total votes 8: ↑7 and ↓1+6
Comments0

Articles