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