summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/plugins/xmlclient.py29
-rw-r--r--ipalib/rpc.py53
-rw-r--r--ipaserver/plugins/xmlserver.py29
-rw-r--r--tests/test_ipalib/test_rpc.py16
-rw-r--r--tests/util.py7
5 files changed, 132 insertions, 2 deletions
diff --git a/ipalib/plugins/xmlclient.py b/ipalib/plugins/xmlclient.py
new file mode 100644
index 000000000..fa5afb553
--- /dev/null
+++ b/ipalib/plugins/xmlclient.py
@@ -0,0 +1,29 @@
+# Authors:
+# Jason Gerard DeRose <jderose@redhat.com>
+# Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+XML-RPC client plugin.
+"""
+
+from ipalib import api
+
+if 'in_server' in api.env and api.env.in_server is False:
+ from ipalib.rpc import xmlclient
+ api.register(xmlclient)
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index e7823ef95..e845b8939 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -1,5 +1,6 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
+# Rob Crittenden <rcritten@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
@@ -31,7 +32,8 @@ Also see the `ipaserver.rpcserver` module.
from types import NoneType
import threading
-from xmlrpclib import Binary, Fault, dumps, loads
+from xmlrpclib import Binary, Fault, dumps, loads, ServerProxy, SafeTransport
+import kerberos
from ipalib.backend import Backend
from ipalib.errors2 import public_errors, PublicError, UnknownError
from ipalib.request import context
@@ -161,15 +163,62 @@ def xml_loads(data):
return (xml_unwrap(params), method)
+class KerbTransport(SafeTransport):
+ """
+ Handles Kerberos Negotiation authentication to an XML-RPC server.
+ """
+
+ def get_host_info(self, host):
+
+ (host, extra_headers, x509) = SafeTransport.get_host_info(self, host)
+
+ # Set the remote host principal
+ service = "HTTP@" + host.split(':')[0]
+
+ try:
+ (rc, vc) = kerberos.authGSSClientInit(service)
+ except kerberos.GSSError, e:
+ raise e # FIXME: raise a PublicError
+
+ try:
+ kerberos.authGSSClientStep(vc, "")
+ except kerberos.GSSError, e:
+ raise e # FIXME: raise a PublicError
+
+ extra_headers += [
+ ('Authorization', 'negotiate %s' % kerberos.authGSSClientResponse(vc))
+ ]
+
+ return (host, extra_headers, x509)
+
+
class xmlclient(Backend):
"""
Forwarding backend for XML-RPC client.
"""
+ connection_name = 'xmlconn'
+
def __init__(self):
super(xmlclient, self).__init__()
self.__errors = dict((e.errno, e) for e in public_errors)
+ def connect(self, ccache=None, user=None, password=None):
+ if hasattr(context, self.connection_name):
+ raise StandardError(
+ '%s.connect(): context.%s already exists in thread %r' % (
+ self.name, self.connection_name, threading.currentThread().getName()
+ )
+ )
+ conn = ServerProxy(self.env.xmlrpc_uri,
+ transport=KerbTransport(),
+ allow_none=True,
+ )
+ setattr(context, self.connection_name, conn)
+
+ def get_connection(self):
+ return getattr(context, self.connection_name)
+
def forward(self, name, *args, **kw):
"""
Forward call to command named ``name`` over XML-RPC.
@@ -197,6 +246,8 @@ class xmlclient(Backend):
response = command(xml_wrap(params))
return xml_unwrap(response)
except Fault, e:
+ self.debug('Caught fault %d from server %s: %s', e.faultCode,
+ self.env.xmlrpc_uri, e.faultString)
if e.faultCode in self.__errors:
error = self.__errors[e.faultCode]
raise error(message=e.faultString)
diff --git a/ipaserver/plugins/xmlserver.py b/ipaserver/plugins/xmlserver.py
new file mode 100644
index 000000000..51b990ffb
--- /dev/null
+++ b/ipaserver/plugins/xmlserver.py
@@ -0,0 +1,29 @@
+# Authors:
+# Jason Gerard DeRose <jderose@redhat.com>
+# Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+XML-RPC client plugin.
+"""
+
+from ipalib import api
+
+if 'in_server' in api.env and api.env.in_server is True:
+ from ipaserver.rpcserver import xmlserver
+ api.register(xmlserver)
diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py
index bc8936ab6..30175e3bf 100644
--- a/tests/test_ipalib/test_rpc.py
+++ b/tests/test_ipalib/test_rpc.py
@@ -22,7 +22,7 @@ Test the `ipalib.rpc` module.
"""
import threading
-from xmlrpclib import Binary, Fault, dumps, loads
+from xmlrpclib import Binary, Fault, dumps, loads, ServerProxy
from tests.util import raises, assert_equal, PluginTester, DummyClass
from tests.data import binary_bytes, utf8_bytes, unicode_str
from ipalib.frontend import Command
@@ -184,6 +184,20 @@ class test_xmlclient(PluginTester):
"""
_plugin = rpc.xmlclient
+ def test_connect(self):
+ (o, api, home) = self.instance('Backend', in_server=False)
+
+ # Test that StandardError is raised if conntext.xmlconn already exists:
+ context.xmlconn = 'The xmlrpclib.ServerProxy instance'
+ e = raises(StandardError, o.connect)
+ assert str(e) == '%s.connect(): context.%s already exists in thread %r' % (
+ 'xmlclient', 'xmlconn', threading.currentThread().getName()
+ )
+
+ del context.xmlconn
+ o.connect()
+ assert isinstance(context.xmlconn, ServerProxy)
+
def test_forward(self):
"""
Test the `ipalib.rpc.xmlclient.forward` method.
diff --git a/tests/util.py b/tests/util.py
index f5899dfab..631d4a05c 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -295,6 +295,13 @@ class PluginTester(object):
o = api[namespace][self.plugin.__name__]
return (o, api, home)
+ def tearDown(self):
+ """
+ nose tear-down fixture.
+ """
+ for name in context.__dict__.keys():
+ delattr(context, name)
+
class dummy_ugettext(object):
__called = False