def _check_ssl_cert(self): """Preflight the SSL certificate presented by the backend. This isn't 100% bulletproof, in that we're not actually validating the transport used to communicate with Ping++, merely that the first attempt to does not use a revoked certificate. Unfortunately the interface to OpenSSL doesn't make it easy to check the certificate before sending potentially sensitive data on the wire. This approach raises the bar for an attacker significantly.""" from pingpp import verify_ssl_certs if verify_ssl_certs and not self._CERTIFICATE_VERIFIED: uri = urlparse.urlparse(pingpp.api_base) try: certificate = ssl.get_server_certificate( (uri.hostname, uri.port or 443), ssl_version=3) der_cert = ssl.PEM_cert_to_DER_cert(certificate) except socket.error, e: raise error.APIConnectionError(e) except TypeError: # The Google App Engine development server blocks the C socket # module which causes a type error when using the SSL library if util.is_appengine_dev(): self._CERTIFICATE_VERIFIED = True warnings.warn( 'We were unable to verify Ping++\'s SSL certificate ' 'due to a bug in the Google App Engine development ' 'server. Please alert us immediately at ' '[email protected] if this message appears in your ' 'production logs.') return else: raise
def _handle_request_error(self, e): msg = ( "Unexpected error communicating with Ping++. " "If this problem persists, let us know at [email protected]." ) msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")" raise error.APIConnectionError(msg)
def request_raw(self, method, url, params=None, supplied_headers=None): """ Mechanism for issuing an API call """ if self.api_key: my_api_key = self.api_key else: from pingpp import api_key my_api_key = api_key if my_api_key is None: raise error.AuthenticationError( 'No API key provided. (HINT: set your API key using ' '"pingpp.api_key = <API-KEY>"). You can generate API keys ' 'from the Ping++ web interface. ' 'See https://www.pingxx.com/api for details.') abs_url = '%s%s' % (self.api_base, url) request_uri = url if method == 'get' or method == 'delete': if params: encoded_params = urlencode(list(_api_encode(params or {}))) abs_url = _build_api_url(abs_url, encoded_params) request_uri = _build_api_url(url, encoded_params) post_data = None elif method == 'post' or method == 'put': post_data = util.json.dumps(params).encode("utf-8") else: raise error.APIConnectionError( 'Unrecognized HTTP method %r. This may indicate a bug in the ' 'Ping++ bindings. ' % (method, )) headers = self.request_headers(my_api_key, method) if supplied_headers is not None: for key, value in six.iteritems(supplied_headers): headers[key] = value request_utc_timestamp = _get_utc_timestamp() headers['Pingplusplus-Request-Timestamp'] = request_utc_timestamp rsa_data = self.get_rsa_verify_data(post_data, request_uri, int(request_utc_timestamp)) util.log_debug('Signing data', data=rsa_data) privkey = self.get_private_key() if privkey is not None: headers['Pingplusplus-Signature'] = self.rsa_sign( privkey, rsa_data) rbody, rcode, rheaders = self.execute_request_with_retry( method, abs_url, headers, post_data) return rbody, rcode, rheaders, my_api_key
def request_raw(self, method, url, params=None): """ Mechanism for issuing an API call """ from pingpp import api_version from pingpp import accept_language my_accept_language = accept_language if self.api_key: my_api_key = self.api_key else: from pingpp import api_key my_api_key = api_key if my_api_key is None: raise error.AuthenticationError( 'No API key provided. (HINT: set your API key using ' '"pingpp.api_key = <API-KEY>"). You can generate API keys ' 'from the Ping++ web interface. See https://pingxx.com ' 'for details, or email [email protected] if you have any ' 'questions.') abs_url = '%s%s' % (pingpp.api_base, url) encoded_params = urllib.urlencode(list(_api_encode(params or {}))) if method == 'get' or method == 'delete': if params: abs_url = _build_api_url(abs_url, encoded_params) post_data = None elif method == 'post': post_data = json.dumps(params) else: raise error.APIConnectionError( 'Unrecognized HTTP method %r. This may indicate a bug in the ' 'Ping++ bindings. Please contact [email protected] for ' 'assistance.' % (method, )) ua = { 'bindings_version': version.VERSION, 'lang': 'python', 'publisher': 'pingpp', 'httplib': self._client.name, } for attr, func in [['lang_version', platform.python_version], ['platform', platform.platform], ['uname', lambda: ' '.join(platform.uname())]]: try: val = func() except Exception, e: val = "!! %s" % (e, ) ua[attr] = val
def _handle_request_error(self, e, url): if isinstance(e, urlfetch.InvalidURLError): msg = ("The Ping++ library attempted to fetch an " "invalid URL (%r). This is likely due to a bug " "in the Ping++ Python bindings." % (url, )) elif isinstance(e, urlfetch.DownloadError): msg = "There was a problem retrieving data from Ping++." elif isinstance(e, urlfetch.ResponseTooLargeError): msg = ("There was a problem receiving all of your data " "from Ping++.") else: msg = ("Unexpected error communicating with Ping++.") msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")" raise error.APIConnectionError(msg)
def _handle_request_error(self, e): if isinstance(e, requests.exceptions.RequestException): msg = ("Unexpected error communicating with Ping++. ") err = "%s: %s" % (type(e).__name__, str(e)) else: msg = ("Unexpected error communicating with Ping++. " "It looks like there's probably a configuration " "issue locally.") err = "A %s was raised" % (type(e).__name__, ) if str(e): err += " with error message %s" % (str(e), ) else: err += " with no error message" msg = textwrap.fill(msg) + "\n\n(Network error: %s)" % (err, ) raise error.APIConnectionError(msg)
def _handle_request_error(self, e): if e[0] in [ pycurl.E_COULDNT_CONNECT, pycurl.E_COULDNT_RESOLVE_HOST, pycurl.E_OPERATION_TIMEOUTED ]: msg = ("Could not connect to Ping++. Please check your " "internet connection and try again. If this problem " "persists, you should check Ping++'s service status at " "https://pingxx.com/status.") elif (e[0] in [pycurl.E_SSL_CACERT, pycurl.E_SSL_PEER_CERTIFICATE]): msg = ("Could not verify Ping++'s SSL certificate. Please make " "sure that your network is not intercepting certificates.") else: msg = ("Unexpected error communicating with Ping++.") msg = textwrap.fill(msg) + "\n\n(Network error: " + e[1] + ")" raise error.APIConnectionError(msg)
def _deprecated_request(self, impl, method, url, headers, params): warnings.warn( 'The *_request functions of APIRequestor are deprecated and ' 'will be removed in version 2.0. Please use the client classes ' ' in `pingpp.http_client` instead', DeprecationWarning, stacklevel=2) method = method.lower() if method == 'get' or method == 'delete': if params: url = self.build_url(url, params) post_data = None elif method == 'post': post_data = self.encode(params) else: raise error.APIConnectionError( 'Unrecognized HTTP method %r. This may indicate a bug in the ' 'Ping++ bindings. ' % (method, )) client = impl(verify_ssl_certs=self._client._verify_ssl_certs) return client.request(method, url, headers, post_data)
def request_raw(self, method, url, params=None): """ Mechanism for issuing an API call """ from pingpp import api_version from pingpp import accept_language my_accept_language = accept_language if self.api_key: my_api_key = self.api_key else: from pingpp import api_key my_api_key = api_key if my_api_key is None: raise error.AuthenticationError( 'No API key provided. (HINT: set your API key using ' '"pingpp.api_key = <API-KEY>"). You can generate API keys ' 'from the Ping++ web interface. See https://pingxx.com ' 'for details.') abs_url = '%s%s' % (pingpp.api_base, url) encoded_params = urllib.urlencode(list(_api_encode(params or {}))) if method == 'get' or method == 'delete': if params: abs_url = _build_api_url(abs_url, encoded_params) post_data = None elif method == 'post': post_data = util.json.dumps(params).encode("utf-8") else: raise error.APIConnectionError( 'Unrecognized HTTP method %r. This may indicate a bug in the ' 'Ping++ bindings. ' % (method, )) ua = { 'bindings_version': version.VERSION, 'lang': 'python', 'publisher': 'pingpp', 'httplib': self._client.name, } for attr, func in [['lang_version', platform.python_version], ['platform', platform.platform], ['uname', lambda: ' '.join(platform.uname())]]: try: val = func() except Exception as e: val = "!! %s" % (e, ) ua[attr] = val headers = { 'X-Pingpp-Client-User-Agent': util.json.dumps(ua), 'User-Agent': 'Pingplusplus/v1 PythonBindings/%s' % (version.VERSION, ), 'Authorization': 'Bearer %s' % (my_api_key, ), 'Accept-Language': my_accept_language } if method == 'post': headers['Content-Type'] = 'application/json;charset=UTF-8' privkey = self.get_private_key() if privkey is not None: headers['Pingplusplus-Signature'] = self.rsa_sign( privkey, post_data) if api_version is not None: headers['Pingplusplus-Version'] = api_version rbody, rcode = self._client.request(method, abs_url, headers, post_data) util.logger.info( 'API request to %s returned (response code, response body) of ' '(%d, %r)', abs_url, rcode, rbody) return rbody, rcode, my_api_key
def _handle_request_error(self, e): msg = ("Unexpected error communicating with Ping++.") msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")" raise error.APIConnectionError(msg)