Avoid logging sensitive info in http requests.
This patch follows the same approach as other OpenStack python clients, by adding a safe header method to hash sensitive information. Change-Id: I980ea7411b1e7f6d47d0a75d58de87b0f944d0d9 Closes-bug: #1516689
This commit is contained in:
parent
aa06b2dd54
commit
5efb5964f7
@ -21,6 +21,7 @@ OpenStack Client interface. Handles the REST calls and responses.
|
||||
from __future__ import print_function
|
||||
|
||||
import glob
|
||||
import hashlib
|
||||
import imp
|
||||
import itertools
|
||||
import logging
|
||||
@ -39,6 +40,7 @@ from cinderclient import exceptions
|
||||
import cinderclient.extension
|
||||
from cinderclient.openstack.common import importutils
|
||||
from cinderclient.openstack.common.gettextutils import _
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import strutils
|
||||
|
||||
osprofiler_web = importutils.try_import("osprofiler.web")
|
||||
@ -145,6 +147,7 @@ class SessionClient(adapter.LegacyJsonAdapter):
|
||||
|
||||
class HTTPClient(object):
|
||||
|
||||
SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
|
||||
USER_AGENT = 'python-cinderclient'
|
||||
|
||||
def __init__(self, user, password, projectid, auth_url=None,
|
||||
@ -198,6 +201,16 @@ class HTTPClient(object):
|
||||
|
||||
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):
|
||||
if not self.http_log_debug:
|
||||
return
|
||||
@ -210,7 +223,8 @@ class HTTPClient(object):
|
||||
string_parts.append(' %s' % element)
|
||||
|
||||
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)
|
||||
|
||||
if 'data' in kwargs:
|
||||
|
@ -33,13 +33,16 @@ try:
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import hashlib
|
||||
import requests
|
||||
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient.openstack.common import importutils
|
||||
from oslo_utils import encodeutils
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
|
||||
|
||||
|
||||
class HTTPClient(object):
|
||||
@ -97,6 +100,16 @@ class HTTPClient(object):
|
||||
|
||||
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):
|
||||
if not self.debug:
|
||||
return
|
||||
@ -108,7 +121,8 @@ class HTTPClient(object):
|
||||
]
|
||||
|
||||
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)
|
||||
|
||||
_logger.debug("REQ: %s" % " ".join(string_parts))
|
||||
|
@ -188,3 +188,30 @@ class ClientTest(utils.TestCase):
|
||||
# AuthorizationFailure exception, check exceptions.from_response
|
||||
# is not getting 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
Block a user