mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 07:33:27 -06:00
7e4b0a072e
Change port to 8880 to not conflict with a running IPA v1 instance Encode incoming values from unicode as utf-8 before sending to LDAP
158 lines
5.0 KiB
Python
Executable File
158 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import sys
|
|
import SimpleXMLRPCServer
|
|
import logging
|
|
import xmlrpclib
|
|
import re
|
|
import threading
|
|
import commands
|
|
from ipalib import api
|
|
from ipa_server import conn
|
|
from ipa_server.servercore import context
|
|
import ipalib.load_plugins
|
|
from ipalib.util import xmlrpc_unmarshal
|
|
import traceback
|
|
|
|
PORT=8888
|
|
|
|
class StoppableXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
|
|
"""Override of TIME_WAIT"""
|
|
allow_reuse_address = True
|
|
|
|
def serve_forever(self):
|
|
self.stop = False
|
|
while not self.stop:
|
|
self.handle_request()
|
|
|
|
class LoggingSimpleXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
|
|
"""Overides the default SimpleXMLRPCRequestHander to support logging.
|
|
Logs client IP and the XML request and response.
|
|
"""
|
|
|
|
def parse(self, given):
|
|
"""Convert the incoming arguments into the format IPA expects"""
|
|
args = []
|
|
kw = {}
|
|
for g in given:
|
|
kw[g] = unicode(given[g])
|
|
return (args, kw)
|
|
|
|
def _dispatch(self, method, params):
|
|
"""Dispatches the XML-RPC method.
|
|
|
|
Methods beginning with an '_' are considered private and will
|
|
not be called.
|
|
"""
|
|
|
|
# this is fine for our test server
|
|
uid = commands.getoutput('/usr/bin/id -u')
|
|
krbccache = "FILE:/tmp/krb5cc_" + uid
|
|
|
|
func = None
|
|
try:
|
|
# FIXME: don't hardcode host and port
|
|
context.conn = conn.IPAConn("localhost", 389, krbccache)
|
|
try:
|
|
# check to see if a matching function has been registered
|
|
func = funcs[method]
|
|
except KeyError:
|
|
raise Exception('method "%s" is not supported' % method)
|
|
(args, kw) = xmlrpc_unmarshal(*params)
|
|
return func(*args, **kw)
|
|
finally:
|
|
# Clean up any per-request data and connections
|
|
# for k in context.__dict__.keys():
|
|
# del context.__dict__[k]
|
|
pass
|
|
|
|
def _marshaled_dispatch(self, data, dispatch_method = None):
|
|
try:
|
|
params, method = xmlrpclib.loads(data)
|
|
|
|
# generate response
|
|
if dispatch_method is not None:
|
|
response = dispatch_method(method, params)
|
|
else:
|
|
response = self._dispatch(method, params)
|
|
# wrap response in a singleton tuple
|
|
response = (response,)
|
|
response = xmlrpclib.dumps(response, methodresponse=1)
|
|
except:
|
|
# report exception back to client. This is needed to report
|
|
# tracebacks found in server code.
|
|
e_class, e = sys.exc_info()[:2]
|
|
# FIXME, need to get this number from somewhere...
|
|
faultCode = getattr(e_class,'faultCode',1)
|
|
tb_str = ''.join(traceback.format_exception(*sys.exc_info()))
|
|
faultString = tb_str
|
|
response = xmlrpclib.dumps(xmlrpclib.Fault(faultCode, faultString))
|
|
|
|
return response
|
|
|
|
def do_POST(self):
|
|
clientIP, port = self.client_address
|
|
# Log client IP and Port
|
|
logger.info('Client IP: %s - Port: %s' % (clientIP, port))
|
|
try:
|
|
# get arguments
|
|
data = self.rfile.read(int(self.headers["content-length"]))
|
|
|
|
# unmarshal the XML data
|
|
params, method = xmlrpclib.loads(data)
|
|
|
|
# Log client request
|
|
logger.info('Client request: \n%s\n' % data)
|
|
|
|
response = self._marshaled_dispatch(
|
|
data, getattr(self, '_dispatch', None))
|
|
|
|
# Log server response
|
|
logger.info('Server response: \n%s\n' % response)
|
|
except Exception, e:
|
|
# This should only happen if the module is buggy
|
|
# internal error, report as HTTP server error
|
|
print e
|
|
self.send_response(500)
|
|
self.end_headers()
|
|
else:
|
|
# got a valid XML-RPC response
|
|
self.send_response(200)
|
|
self.send_header("Content-type", "text/xml")
|
|
self.send_header("Content-length", str(len(response)))
|
|
self.end_headers()
|
|
self.wfile.write(response)
|
|
|
|
# shut down the connection
|
|
self.wfile.flush()
|
|
self.connection.shutdown(1)
|
|
|
|
# Set up our logger
|
|
logger = logging.getLogger('xmlrpcserver')
|
|
hdlr = logging.FileHandler('xmlrpcserver.log')
|
|
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
|
|
hdlr.setFormatter(formatter)
|
|
logger.addHandler(hdlr)
|
|
logger.setLevel(logging.INFO)
|
|
|
|
# Set up the server
|
|
XMLRPCServer = StoppableXMLRPCServer(("",PORT), LoggingSimpleXMLRPCRequestHandler)
|
|
|
|
XMLRPCServer.register_introspection_functions()
|
|
|
|
# Get and register all the methods
|
|
api.env.server_context = True
|
|
api.finalize()
|
|
for cmd in api.Method:
|
|
logger.info("registering %s" % cmd)
|
|
XMLRPCServer.register_function(api.Method[cmd], cmd)
|
|
|
|
funcs = XMLRPCServer.funcs
|
|
|
|
print "Listening on port %d" % PORT
|
|
try:
|
|
XMLRPCServer.serve_forever()
|
|
except KeyboardInterrupt:
|
|
XMLRPCServer.server_close()
|
|
print "Server shutdown."
|