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, )
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))
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']
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='')
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']
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))
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