示例#1
0
    def forward(self, name, *args, **kw):
        """
        Forward call to command named ``name`` over XML-RPC.

        This method will encode and forward an XML-RPC request, and will then
        decode and return the corresponding XML-RPC response.

        :param command: The name of the command being forwarded.
        :param args: Positional arguments to pass to remote command.
        :param kw: Keyword arguments to pass to remote command.
        """
        if name not in self.Command:
            raise ValueError('%s.forward(): %r not in api.Command' %
                             (self.name, name))
        server = getattr(context, 'request_url', None)
        self.log.info("Forwarding '%s' to %s server '%s'", name, self.protocol,
                      server)
        command = getattr(self.conn, name)
        params = [args, kw]
        try:
            return self._call_command(command, params)
        except Fault, e:
            e = decode_fault(e)
            self.debug('Caught fault %d from server %s: %s', e.faultCode,
                       server, e.faultString)
            if e.faultCode in errors_by_code:
                error = errors_by_code[e.faultCode]
                raise error(message=e.faultString)
            raise UnknownError(
                code=e.faultCode,
                error=e.faultString,
                server=server,
            )
示例#2
0
    def forward(self, name, *args, **kw):
        """
        Forward call to command named ``name`` over XML-RPC.

        This method will encode and forward an XML-RPC request, and will then
        decode and return the corresponding XML-RPC response.

        :param command: The name of the command being forwarded.
        :param args: Positional arguments to pass to remote command.
        :param kw: Keyword arguments to pass to remote command.
        """
        server = getattr(context, 'request_url', None)
        self.log.info("Forwarding '%s' to %s server '%s'", name, self.protocol,
                      server)
        command = getattr(self.conn, name)
        params = [args, kw]
        try:
            return self._call_command(command, params)
        except Fault as e:
            e = decode_fault(e)
            self.debug('Caught fault %d from server %s: %s', e.faultCode,
                       server, e.faultString)
            if e.faultCode in errors_by_code:
                error = errors_by_code[e.faultCode]
                raise error(message=e.faultString)
            raise UnknownError(
                code=e.faultCode,
                error=e.faultString,
                server=server,
            )
        except SSLError as e:
            raise NetworkError(uri=server, error=str(e))
        except ProtocolError as e:
            # By catching a 401 here we can detect the case where we have
            # a single IPA server and the session is invalid. Otherwise
            # we always have to do a ping().
            session_cookie = getattr(context, 'session_cookie', None)
            if session_cookie and e.errcode == 401:
                # Unauthorized. Remove the session and try again.
                delattr(context, 'session_cookie')
                try:
                    principal = getattr(context, 'principal', None)
                    delete_persistent_client_session_data(principal)
                except Exception as e:
                    # This shouldn't happen if we have a session but it isn't fatal.
                    pass

                # Create a new serverproxy with the non-session URI
                serverproxy = self.create_connection(
                    os.environ.get('KRB5CCNAME'), self.env.verbose,
                    self.env.fallback, self.env.delegate)
                setattr(context, self.id,
                        Connection(serverproxy, self.disconnect))
                return self.forward(name, *args, **kw)
            raise NetworkError(uri=server, error=e.errmsg)
        except socket.error as e:
            raise NetworkError(uri=server, error=str(e))
        except (OverflowError, TypeError) as e:
            raise XMLRPCMarshallError(error=str(e))
示例#3
0
class JSONServerProxy(object):
    def __init__(self, uri, transport, encoding, verbose, allow_none):
        type, uri = urllib.splittype(uri)
        if type not in ("http", "https"):
            raise IOError("unsupported XML-RPC protocol")
        self.__host, self.__handler = urllib.splithost(uri)
        self.__transport = transport

        assert encoding == 'UTF-8'
        assert allow_none
        self.__verbose = verbose

        # FIXME: Some of our code requires ServerProxy internals.
        # But, xmlrpclib.ServerProxy's _ServerProxy__transport can be accessed
        # by calling serverproxy('transport')
        self._ServerProxy__transport = transport

    def __request(self, name, args):
        payload = {'method': unicode(name), 'params': args, 'id': 0}
        version = args[1].get('version', VERSION_WITHOUT_CAPABILITIES)
        payload = json_encode_binary(payload, version)

        if self.__verbose >= 2:
            root_logger.info('Request: %s',
                             json.dumps(payload, sort_keys=True, indent=4))

        response = self.__transport.request(
            self.__host,
            self.__handler,
            json.dumps(payload),
            verbose=self.__verbose >= 3,
        )

        try:
            response = json_decode_binary(json.loads(response))
        except ValueError, e:
            raise JSONError(str(e))

        if self.__verbose >= 2:
            root_logger.info(
                'Response: %s',
                json.dumps(json_encode_binary(response, version),
                           sort_keys=True,
                           indent=4))
        error = response.get('error')
        if error:
            try:
                error_class = errors_by_code[error['code']]
            except KeyError:
                raise UnknownError(
                    code=error.get('code'),
                    error=error.get('message'),
                    server=self.__host,
                )
            else:
                raise error_class(message=error['message'])

        return response['result']
示例#4
0
 def create_connection(self,
                       ccache=None,
                       verbose=False,
                       fallback=True,
                       delegate=False):
     try:
         xmlrpc_uri = self.env.xmlrpc_uri
         principal = get_current_principal()
         setattr(context, 'principal', principal)
         # We have a session cookie, try using the session URI to see if it
         # is still valid
         if not delegate:
             xmlrpc_uri = self.apply_session_cookie(xmlrpc_uri)
     except ValueError:
         # No session key, do full Kerberos auth
         pass
     urls = self.get_url_list(xmlrpc_uri)
     serverproxy = None
     for url in urls:
         kw = dict(allow_none=True, encoding='UTF-8')
         kw['verbose'] = verbose
         if url.startswith('https://'):
             if delegate:
                 kw['transport'] = DelegatedKerbTransport()
             else:
                 kw['transport'] = KerbTransport()
         else:
             kw['transport'] = LanguageAwareTransport()
         self.log.info('trying %s' % url)
         setattr(context, 'request_url', url)
         serverproxy = ServerProxy(url, **kw)
         if len(urls) == 1:
             # if we have only 1 server and then let the
             # main requester handle any errors. This also means it
             # must handle a 401 but we save a ping.
             return serverproxy
         try:
             command = getattr(serverproxy, 'ping')
             try:
                 response = command()
             except Fault, e:
                 e = decode_fault(e)
                 if e.faultCode in self.__errors:
                     error = self.__errors[e.faultCode]
                     raise error(message=e.faultString)
                 else:
                     raise UnknownError(
                         code=e.faultCode,
                         error=e.faultString,
                         server=url,
                     )
             # We don't care about the response, just that we got one
             break
         except KerberosError, krberr:
             # kerberos error on one server is likely on all
             raise errors.KerberosError(major=str(krberr), minor='')
示例#5
0
文件: rpc.py 项目: zhoubh/freeipa
    def __request(self, name, args):
        print_json = self.__verbose >= 2
        payload = {'method': unicode(name), 'params': args, 'id': 0}
        version = args[1].get('version', VERSION_WITHOUT_CAPABILITIES)
        payload = json_encode_binary(
            payload, version, pretty_print=print_json)

        if print_json:
            logger.info(
                'Request: %s',
                payload
            )

        response = self.__transport.request(
            self.__host,
            self.__handler,
            payload.encode('utf-8'),
            verbose=self.__verbose >= 3,
        )

        if print_json:
            logger.info(
                'Response: %s',
                json.dumps(json.loads(response), sort_keys=True, indent=4)
            )

        try:
            response = json_decode_binary(response)
        except ValueError as e:
            raise JSONError(error=str(e))

        error = response.get('error')
        if error:
            try:
                error_class = errors_by_code[error['code']]
            except KeyError:
                raise UnknownError(
                    code=error.get('code'),
                    error=error.get('message'),
                    server=self.__host,
                )
            else:
                kw = error.get('data', {})
                kw['message'] = error['message']
                raise error_class(**kw)

        return response['result']
示例#6
0
    def create_connection(self,
                          ccache=None,
                          verbose=None,
                          fallback=None,
                          delegate=None,
                          ca_certfile=None):
        if verbose is None:
            verbose = self.api.env.verbose
        if fallback is None:
            fallback = self.api.env.fallback
        if delegate is None:
            delegate = self.api.env.delegate
        if ca_certfile is None:
            ca_certfile = self.api.env.tls_ca_cert
        context.ca_certfile = ca_certfile

        rpc_uri = self.env[self.env_rpc_uri_key]
        try:
            principal = get_principal(ccache_name=ccache)
            stored_principal = getattr(context, 'principal', None)
            if principal != stored_principal:
                try:
                    delattr(context, 'session_cookie')
                except AttributeError:
                    pass
            setattr(context, 'principal', principal)
            # We have a session cookie, try using the session URI to see if it
            # is still valid
            if not delegate:
                rpc_uri = self.apply_session_cookie(rpc_uri)
        except (errors.CCacheError, ValueError):
            # No session key, do full Kerberos auth
            pass
        urls = self.get_url_list(rpc_uri)

        proxy_kw = {
            'allow_none': True,
            'encoding': 'UTF-8',
            'verbose': verbose
        }

        for url in urls:
            # should we get ProtocolError (=> error in HTTP response) and
            # 401 (=> Unauthorized), we'll be re-trying with new session
            # cookies several times
            for _try_num in range(0, 5):
                if url.startswith('https://'):
                    if delegate:
                        transport_class = DelegatedKerbTransport
                    else:
                        transport_class = KerbTransport
                else:
                    transport_class = LanguageAwareTransport
                proxy_kw['transport'] = transport_class(protocol=self.protocol,
                                                        service='HTTP',
                                                        ccache=ccache)
                logger.info('trying %s', url)
                setattr(context, 'request_url', url)
                serverproxy = self.server_proxy_class(url, **proxy_kw)
                if len(urls) == 1:
                    # if we have only 1 server and then let the
                    # main requester handle any errors. This also means it
                    # must handle a 401 but we save a ping.
                    return serverproxy
                try:
                    command = getattr(serverproxy, 'ping')
                    try:
                        command([], {})
                    except Fault as e:
                        e = decode_fault(e)
                        if e.faultCode in errors_by_code:
                            error = errors_by_code[e.faultCode]
                            raise error(message=e.faultString)
                        else:
                            raise UnknownError(
                                code=e.faultCode,
                                error=e.faultString,
                                server=url,
                            )
                    # We don't care about the response, just that we got one
                    return serverproxy
                except errors.KerberosError:
                    # kerberos error on one server is likely on all
                    raise
                except ProtocolError as e:
                    if hasattr(context, 'session_cookie') and e.errcode == 401:
                        # Unauthorized. Remove the session and try again.
                        delattr(context, 'session_cookie')
                        try:
                            delete_persistent_client_session_data(principal)
                        except Exception:
                            # This shouldn't happen if we have a session but
                            # it isn't fatal.
                            pass
                        # try the same url once more with a new session cookie
                        continue
                    if not fallback:
                        raise
                    else:
                        logger.info('Connection to %s failed with %s', url, e)
                    # try the next url
                    break
                except Exception as e:
                    if not fallback:
                        raise
                    else:
                        logger.info('Connection to %s failed with %s', url, e)
                    # try the next url
                    break
        # finished all tries but no serverproxy was found
        raise NetworkError(uri=_('any of the configured servers'),
                           error=', '.join(urls))
示例#7
0
    def create_connection(self,
                          ccache=None,
                          verbose=None,
                          fallback=None,
                          delegate=None,
                          ca_certfile=None):
        if verbose is None:
            verbose = self.api.env.verbose
        if fallback is None:
            fallback = self.api.env.fallback
        if delegate is None:
            delegate = self.api.env.delegate
        if ca_certfile is None:
            ca_certfile = self.api.env.tls_ca_cert
        try:
            rpc_uri = self.env[self.env_rpc_uri_key]
            principal = get_principal(ccache_name=ccache)
            stored_principal = getattr(context, 'principal', None)
            if principal != stored_principal:
                try:
                    delattr(context, 'session_cookie')
                except AttributeError:
                    pass
            setattr(context, 'principal', principal)
            # We have a session cookie, try using the session URI to see if it
            # is still valid
            if not delegate:
                rpc_uri = self.apply_session_cookie(rpc_uri)
        except (errors.CCacheError, ValueError):
            # No session key, do full Kerberos auth
            pass
        context.ca_certfile = ca_certfile
        urls = self.get_url_list(rpc_uri)
        serverproxy = None
        for url in urls:
            kw = dict(allow_none=True, encoding='UTF-8')
            kw['verbose'] = verbose
            if url.startswith('https://'):
                if delegate:
                    transport_class = DelegatedKerbTransport
                else:
                    transport_class = KerbTransport
            else:
                transport_class = LanguageAwareTransport
            kw['transport'] = transport_class(protocol=self.protocol,
                                              service='HTTP',
                                              ccache=ccache)
            self.log.info('trying %s' % url)
            setattr(context, 'request_url', url)
            serverproxy = self.server_proxy_class(url, **kw)
            if len(urls) == 1:
                # if we have only 1 server and then let the
                # main requester handle any errors. This also means it
                # must handle a 401 but we save a ping.
                return serverproxy
            try:
                command = getattr(serverproxy, 'ping')
                try:
                    command([], {})
                except Fault as e:
                    e = decode_fault(e)
                    if e.faultCode in errors_by_code:
                        error = errors_by_code[e.faultCode]
                        raise error(message=e.faultString)
                    else:
                        raise UnknownError(
                            code=e.faultCode,
                            error=e.faultString,
                            server=url,
                        )
                # We don't care about the response, just that we got one
                break
            except KerberosError as krberr:
                # kerberos error on one server is likely on all
                raise errors.KerberosError(message=unicode(krberr))
            except ProtocolError as e:
                if hasattr(context, 'session_cookie') and e.errcode == 401:
                    # Unauthorized. Remove the session and try again.
                    delattr(context, 'session_cookie')
                    try:
                        delete_persistent_client_session_data(principal)
                    except Exception as e:
                        # This shouldn't happen if we have a session but it isn't fatal.
                        pass
                    return self.create_connection(ccache, verbose, fallback,
                                                  delegate)
                if not fallback:
                    raise
                serverproxy = None
            except Exception as e:
                if not fallback:
                    raise
                else:
                    self.log.info('Connection to %s failed with %s', url, e)
                serverproxy = None

        if serverproxy is None:
            raise NetworkError(uri=_('any of the configured servers'),
                               error=', '.join(urls))
        return serverproxy