From 96bb5ecac07255fd4b6149c617c5ef23b7e7c84f Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Mon, 29 Aug 2016 14:49:44 +0200
Subject: [PATCH] rpcserver: assume version 1 for unversioned command calls
When a command is called on the server over RPC without its version
specified, assume version 1 instead of the highest known version.
This ensures backward compatibility with old clients, which do not support
versioned commands and understand only the first version of any given
command.
https://fedorahosted.org/freeipa/ticket/6217
Reviewed-By: David Kupka <dkupka@redhat.com>
---
ipaserver/rpcserver.py | 43 +++++++++++++++++++++++++++----------------
1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index e48dc3498d6ed8feb6ea44a9a678a8b8c50e8d9b..dd446ae849076d350c97ce9cd6c5a704783f39c0 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -42,7 +42,7 @@ from ipalib import plugable, errors
from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES
from ipalib.frontend import Local
from ipalib.backend import Executioner
-from ipalib.errors import (PublicError, InternalError, CommandError, JSONError,
+from ipalib.errors import (PublicError, InternalError, JSONError,
CCacheError, RefererError, InvalidSessionPassword, NotFound, ACIError,
ExecutionError, PasswordExpired, KrbPrincipalExpired, UserLocked)
from ipalib.request import context, destroy_context
@@ -311,6 +311,21 @@ class WSGIExecutioner(Executioner):
if 'wsgi_dispatch' in self.api.Backend:
self.api.Backend.wsgi_dispatch.mount(self, self.key)
+ def __get_command(self, name):
+ try:
+ # assume version 1 for unversioned command calls
+ command = self.api.Command[name, '1']
+ except KeyError:
+ try:
+ command = self.api.Command[name]
+ except KeyError:
+ command = None
+
+ if command is None or isinstance(command, Local):
+ raise errors.CommandError(name=name)
+
+ return command
+
def wsgi_execute(self, environ):
result = None
error = None
@@ -319,6 +334,7 @@ class WSGIExecutioner(Executioner):
name = None
args = ()
options = {}
+ command = None
e = None
if not 'HTTP_REFERER' in environ:
@@ -345,11 +361,9 @@ class WSGIExecutioner(Executioner):
(name, args, options, _id) = self.simple_unmarshal(environ)
if name in self._system_commands:
result = self._system_commands[name](self, *args, **options)
- elif (name not in self.api.Command or
- isinstance(self.api.Command[name], Local)):
- raise CommandError(name=name)
else:
- result = self.Command[name](*args, **options)
+ command = self.__get_command(name)
+ result = command(*args, **options)
except PublicError as e:
if self.api.env.debug:
self.debug('WSGI wsgi_execute PublicError: %s', traceback.format_exc())
@@ -363,9 +377,9 @@ class WSGIExecutioner(Executioner):
os.environ['LANG'] = lang
principal = getattr(context, 'principal', 'UNKNOWN')
- if name and name in self.Command:
+ if command is not None:
try:
- params = self.Command[name].args_options_2_params(*args, **options)
+ params = command.args_options_2_params(*args, **options)
except Exception as e:
self.info(
'exception %s caught when converting options: %s', e.__class__.__name__, str(e)
@@ -380,7 +394,7 @@ class WSGIExecutioner(Executioner):
type(self).__name__,
principal,
name,
- ', '.join(self.Command[name]._repr_iter(**params)),
+ ', '.join(command._repr_iter(**params)),
result_string)
else:
self.info('[%s] %s: %s: %s',
@@ -698,24 +712,21 @@ class xmlserver(KerberosWSGIExecutioner):
# TODO
# for now let's not go out of our way to document standard XML-RPC
return u'undef'
- elif (method_name in self.api.Command and
- not isinstance(self.api.Command[method_name], Local)):
+ else:
+ self.__get_command(method_name)
+
# All IPA commands return a dict (struct),
# and take a params, options - list and dict (array, struct)
return [[u'struct', u'array', u'struct']]
- else:
- raise errors.CommandError(name=method_name)
def methodHelp(self, *params):
"""get method docstring for XML-RPC introspection"""
method_name = self._get_method_name('system.methodHelp', *params)
if method_name in self._system_commands:
return u''
- elif (method_name in self.api.Command and
- not isinstance(self.api.Command[method_name], Local)):
- return unicode(self.Command[method_name].doc or '')
else:
- raise errors.CommandError(name=method_name)
+ command = self.__get_command(method_name)
+ return unicode(command.doc or '')
_system_commands = {
'system.listMethods': listMethods,
--
2.7.4