Merge "Avoid logging sensitive info in http requests."
This commit is contained in:
commit
e4692518b4
|
@ -21,6 +21,7 @@ OpenStack Client interface. Handles the REST calls and responses.
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
|
import hashlib
|
||||||
import imp
|
import imp
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
|
@ -39,6 +40,7 @@ from cinderclient import exceptions
|
||||||
import cinderclient.extension
|
import cinderclient.extension
|
||||||
from cinderclient.openstack.common import importutils
|
from cinderclient.openstack.common import importutils
|
||||||
from cinderclient.openstack.common.gettextutils import _
|
from cinderclient.openstack.common.gettextutils import _
|
||||||
|
from oslo_utils import encodeutils
|
||||||
from oslo_utils import strutils
|
from oslo_utils import strutils
|
||||||
|
|
||||||
osprofiler_web = importutils.try_import("osprofiler.web")
|
osprofiler_web = importutils.try_import("osprofiler.web")
|
||||||
|
@ -145,6 +147,7 @@ class SessionClient(adapter.LegacyJsonAdapter):
|
||||||
|
|
||||||
class HTTPClient(object):
|
class HTTPClient(object):
|
||||||
|
|
||||||
|
SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
|
||||||
USER_AGENT = 'python-cinderclient'
|
USER_AGENT = 'python-cinderclient'
|
||||||
|
|
||||||
def __init__(self, user, password, projectid, auth_url=None,
|
def __init__(self, user, password, projectid, auth_url=None,
|
||||||
|
@ -198,6 +201,16 @@ class HTTPClient(object):
|
||||||
|
|
||||||
self._logger = logging.getLogger(__name__)
|
self._logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def _safe_header(self, name, value):
|
||||||
|
if name in HTTPClient.SENSITIVE_HEADERS:
|
||||||
|
encoded = value.encode('utf-8')
|
||||||
|
hashed = hashlib.sha1(encoded)
|
||||||
|
digested = hashed.hexdigest()
|
||||||
|
return encodeutils.safe_decode(name), "{SHA1}%s" % digested
|
||||||
|
else:
|
||||||
|
return (encodeutils.safe_decode(name),
|
||||||
|
encodeutils.safe_decode(value))
|
||||||
|
|
||||||
def http_log_req(self, args, kwargs):
|
def http_log_req(self, args, kwargs):
|
||||||
if not self.http_log_debug:
|
if not self.http_log_debug:
|
||||||
return
|
return
|
||||||
|
@ -210,7 +223,8 @@ class HTTPClient(object):
|
||||||
string_parts.append(' %s' % element)
|
string_parts.append(' %s' % element)
|
||||||
|
|
||||||
for element in kwargs['headers']:
|
for element in kwargs['headers']:
|
||||||
header = ' -H "%s: %s"' % (element, kwargs['headers'][element])
|
header = ("-H '%s: %s'" %
|
||||||
|
self._safe_header(element, kwargs['headers'][element]))
|
||||||
string_parts.append(header)
|
string_parts.append(header)
|
||||||
|
|
||||||
if 'data' in kwargs:
|
if 'data' in kwargs:
|
||||||
|
|
|
@ -33,13 +33,16 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
import hashlib
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from cinderclient.openstack.common.apiclient import exceptions
|
from cinderclient.openstack.common.apiclient import exceptions
|
||||||
from cinderclient.openstack.common import importutils
|
from cinderclient.openstack.common import importutils
|
||||||
|
from oslo_utils import encodeutils
|
||||||
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
|
||||||
|
|
||||||
|
|
||||||
class HTTPClient(object):
|
class HTTPClient(object):
|
||||||
|
@ -97,6 +100,16 @@ class HTTPClient(object):
|
||||||
|
|
||||||
self.cached_token = None
|
self.cached_token = None
|
||||||
|
|
||||||
|
def _safe_header(self, name, value):
|
||||||
|
if name in SENSITIVE_HEADERS:
|
||||||
|
encoded = value.encode('utf-8')
|
||||||
|
hashed = hashlib.sha1(encoded)
|
||||||
|
digested = hashed.hexdigest()
|
||||||
|
return encodeutils.safe_decode(name), "{SHA1}%s" % digested
|
||||||
|
else:
|
||||||
|
return (encodeutils.safe_decode(name),
|
||||||
|
encodeutils.safe_decode(value))
|
||||||
|
|
||||||
def _http_log_req(self, method, url, kwargs):
|
def _http_log_req(self, method, url, kwargs):
|
||||||
if not self.debug:
|
if not self.debug:
|
||||||
return
|
return
|
||||||
|
@ -108,7 +121,8 @@ class HTTPClient(object):
|
||||||
]
|
]
|
||||||
|
|
||||||
for element in kwargs['headers']:
|
for element in kwargs['headers']:
|
||||||
header = "-H '%s: %s'" % (element, kwargs['headers'][element])
|
header = ("-H '%s: %s'" %
|
||||||
|
self._safe_header(element, kwargs['headers'][element]))
|
||||||
string_parts.append(header)
|
string_parts.append(header)
|
||||||
|
|
||||||
_logger.debug("REQ: %s" % " ".join(string_parts))
|
_logger.debug("REQ: %s" % " ".join(string_parts))
|
||||||
|
|
|
@ -186,3 +186,30 @@ class ClientTest(utils.TestCase):
|
||||||
# AuthorizationFailure exception, check exceptions.from_response
|
# AuthorizationFailure exception, check exceptions.from_response
|
||||||
# is not getting called.
|
# is not getting called.
|
||||||
self.assertFalse(mock_from_resp.called)
|
self.assertFalse(mock_from_resp.called)
|
||||||
|
|
||||||
|
|
||||||
|
class ClientTestSensitiveInfo(utils.TestCase):
|
||||||
|
def test_req_does_not_log_sensitive_info(self):
|
||||||
|
self.logger = self.useFixture(
|
||||||
|
fixtures.FakeLogger(
|
||||||
|
format="%(message)s",
|
||||||
|
level=logging.DEBUG,
|
||||||
|
nuke_handlers=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
secret_auth_token = "MY_SECRET_AUTH_TOKEN"
|
||||||
|
kwargs = {
|
||||||
|
'headers': {"X-Auth-Token": secret_auth_token},
|
||||||
|
'data': ('{"auth": {"tenantName": "fakeService",'
|
||||||
|
' "passwordCredentials": {"username": "fakeUser",'
|
||||||
|
' "password": "fakePassword"}}}')
|
||||||
|
}
|
||||||
|
|
||||||
|
cs = cinderclient.client.HTTPClient("user", None, None,
|
||||||
|
"http://127.0.0.1:5000")
|
||||||
|
cs.http_log_debug = True
|
||||||
|
cs.http_log_req('PUT', kwargs)
|
||||||
|
|
||||||
|
output = self.logger.output.split('\n')
|
||||||
|
self.assertNotIn(secret_auth_token, output[1])
|
||||||
|
|
Loading…
Reference in New Issue