📜 ⬆️ ⬇️

Using XmlRPC through a proxy server for a host with authorization

Immediately make a reservation that we are talking about Python 2.X.

The task: to force xmlrpclib in Python to work through a proxy server with Basic and NTLM authorization, as well as with a host requiring authentication and Cookies.

I needed this for the bugreport system in our application, where when sending an error message to TRAC , a ticket with a description, logs, and other things should be created. Communication with TRAC goes through xmlRPC (using XmlRpcPlugin ). Application users mainly work behind a proxy server within the corporate network.
')
This is accomplished through the creation of a transport based on urllib , which redirects XML requests through a proxy server.

On the Internet you can find a couple of examples to support a proxy without authorization, written on the first urllib . At first I tried to take this example and add authorization to it, but in the end it became clear that it is better to rewrite it under urllib2 , where it is much easier to do this.

This transport option also supports operation without a proxy server (if a direct connection is available, and the specified proxy server is not, then the connection will occur directly - this is a feature of urllib2).

Python-ntlm is used to support NTLM authentication.

Just in case, I warn you that the code is presented only as an example and requires mandatory testing and modification for your needs.

Example of use:

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




The transport script itself:

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


PS
For anyone interested in urllib2, I recommend to look at urllib2 - The Missing Manual - an excellent document, which describes in detail the features of working with it, in particular, error handling and exceptions.

Source: https://habr.com/ru/post/116867/


All Articles