[Moin-user] xmlrpc with NTLM and GivenAuth

Mark Scheufele mark.scheufele at diasemi.com
Tue Dec 21 08:48:33 EST 2010


Hi Moin users,

about a month ago I did ask for some hints how to get the xmlrpc access working under the following circumstances:

- moin version 1.9.3
- IIS with windows authentication SSPI(NTLM)
- moin authentication is auth = [GivenAuth(strip_windomain=True,autocreate=1)]

This means that the xmlrpc calls are only forwarded to the wiki after a successful ntlm authentication by the IIS webserver. The wiki then uses the REMOTE_USER variable to create or run the request under a specific account (this is explained here http://moinmo.in/HelpOnAuthentication)

When I run the following script:

import sys
import xmlrpclib

wikiurl = "http://nb-it-lt-ms/testwiki"
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2",allow_none=True)
mc=xmlrpclib.MultiCall(homewiki)
mc.getRPCVersionSupported()
mc.getPage("StartPage")

try:
	auth_token = homewiki.getAuthToken("mscheufe", "blah")
	if not auth_token:
		print "auth_token is empty"
	for i in mc():
		print i
except xmlrpclib.Fault as err:
	print str(err)

I get the following error message:

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    auth_token = homewiki.getAuthToken("mscheufe", "blah")
  File "c:\python26\lib\xmlrpclib.py", line 1199, in __call__
    return self.__send(self.__name, args)
  File "c:\python26\lib\xmlrpclib.py", line 1489, in __request
    verbose=self.__verbose
  File "c:\python26\lib\xmlrpclib.py", line 1243, in request
    headers
xmlrpclib.ProtocolError: <ProtocolError for nb-it-lt-ms/testwiki?action=xmlrpc2: 401 Unauthorized>

I managed to get the ntlm authentication against the webserver to work by writing my own xmlrpc.Transport object. (code see below). Now the ntlm authentication is working and my xmlrpc requests are forwarded to the wiki. But my calls are still not properly authenticated against the wiki by the xmlrpc interface.

Have a look at this sample:

import sys
sys.path.append("c:/Temp/MoinXmlRPC")
import xmlrpclib
from ntlmTransport import *

wikiurl = "http://nb-it-lt-ms/testwiki"
p=ntlmTransport()
homewiki = xmlrpclib.ServerProxy(wikiurl + "?action=xmlrpc2",allow_none=True,transport=p)
mc=xmlrpclib.MultiCall(homewiki)
mc.getRPCVersionSupported()
mc.getPage("StartPage")

try:
	auth_token = homewiki.getAuthToken("mscheufe", "blah")
	if not auth_token:
		print "auth_token is empty"
	for i in mc():
		print i
except xmlrpclib.Fault as err:
	print str(err)


The output of the script is:

auth_token is empty
2
<Fault 1: 'You are not allowed to read this page.'>

As one can see the xmlrpc calls are forwarded to the wiki but as the getAuthToken() method does not return a token I cannot authenticate against the wiki. 

At the minute I am stuck here. I really would be interested to get the xmlrpc interface working with GivenAuth. It would be great if someone could point me into the right direction how this problem could be solved.

Many thanks in advance,

mark

###################################
# ntlm xmlrpclib.Transport object #
###################################

import xmlrpclib,sys,httplib,base64
from types import *

#code for WindoewNtlmMessageGenerator orignates from http://stackoverflow.com/questions/2969481/ntlm-authentication-in-python

class WindoewNtlmMessageGenerator:
	def __init__(self,user=None):
		import win32api,sspi
		if not user:
			user = win32api.GetUserName()
		self.sspi_client = sspi.ClientAuth("NTLM",user)   

	def create_auth_req(self):
		import pywintypes
		output_buffer = None
		error_msg = None
		try:
			error_msg, output_buffer = self.sspi_client.authorize(None)             
		except pywintypes.error:           
			return None
		auth_req = output_buffer[0].Buffer
		auth_req = base64.b64encode(auth_req)
		return auth_req 

	def create_challenge_response(self,challenge):
		import pywintypes
		output_buffer = None
		input_buffer = challenge
		error_msg = None
		try:
			error_msg, output_buffer = self.sspi_client.authorize(input_buffer)
		except pywintypes.error:
			return None
		response_msg = output_buffer[0].Buffer        
		response_msg = base64.b64encode(response_msg) 
		return response_msg 

class ntlmTransport(xmlrpclib.Transport):
	
	def __init__(self,use_datetime=0):
		
		xmlrpclib.Transport.__init__(self,use_datetime)
		
	def request(self, host, handler, request_body, verbose=0):
		# issue XML-RPC request

		h = self.make_connection(host)
		if verbose:
			h.set_debuglevel(1)
		
		#run the ntlm handshake to get an auth token
		extra_headers=self.get_ntlm_header(h,handler,request_body)
		
		self.send_request(h, handler, request_body)
		self.send_host(h,host,extra_headers)
		self.send_user_agent(h)
		self.send_content(h, request_body)
		
		errcode, errmsg, headers = h.getreply()

		if errcode != 200:
			raise ProtocolError(
				host + handler,
				errcode, errmsg,
				headers
			)

		self.verbose = verbose

		try:
			sock = h._conn.sock
		except AttributeError:
			sock = None

		return self._parse_response(h.getfile(), sock)

	def get_ntlm_header(self,connection,handler,request_body):
		
		ntlm_gen = WindoewNtlmMessageGenerator()
		auth_req_msg = ntlm_gen.create_auth_req()
		
		extra_headers=[('Connection','Keep-Alive')]
	
		self.send_request(connection,handler,request_body)
		connection.putheader("Content-length","0")
		connection.putheader("Connection","Keep-Alive")
		connection.putheader('Authorization','NTLM'+' '+auth_req_msg)
		connection.endheaders()
		resp = connection._conn.getresponse()
		#always read from response otherwise the subsequent call with the current http connection handle won't work
		resp.read()
		
		#generate the NTLM auth_token
		challenge = resp.msg.get('WWW-Authenticate')
		challenge_dec = base64.b64decode(challenge.split()[1])
		auth_token = ntlm_gen.create_challenge_response(challenge_dec)
		extra_headers.append(('Authorization','NTLM'+' '+auth_token))
		return extra_headers

	def send_host(self,connection,host,extra_headers):
		host, not_used_headers, x509 = self.get_host_info(host)
		for key, value in extra_headers:
			connection.putheader(key, value)
_______________________________________________________________________________________

Dialog Semiconductor GmbH
Neue Str. 95
D-73230 Kirchheim
Managing Director: Dr. Jalal Bagherli
Chairman of the Supervisory Board: Gregorio Reyes
Commercial register: Amtsgericht Stuttgart: HRB 231181
UST-ID-Nr. DE 811121668


Legal Disclaimer: This e-mail communication (and any attachment/s) is confidential and 
contains proprietary information, some or all of which may be legally privileged. It is 
intended solely for the use of the individual or entity to which it is addressed. Access 
to this email by anyone else is unauthorized. If you are not the intended recipient, any
disclosure, copying, distribution or any action taken or omitted to be taken in reliance
on it, is prohibited and may be unlawful.




More information about the Moin-user mailing list