Skip to content

Commit 101f704

Browse files
committed
PYTHON-952 - Redact command and reply documents for sensitive commands
1 parent 5c9f97e commit 101f704

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

pymongo/monitoring.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ def _handle_exception():
149149
finally:
150150
del einfo
151151

152+
# Note - to avoid bugs from forgetting which if these is all lowercase and
153+
# which are camelCase, and at the same time avoid having to add a test for
154+
# every command, use all lowercase here and test against command_name.lower().
155+
_SENSITIVE_COMMANDS = set(
156+
["authenticate", "saslstart", "saslcontinue", "getnonce", "createuser",
157+
"updateuser", "copydbgetnonce", "copydbsaslstart", "copydb"])
158+
152159

153160
class _CommandEvent(object):
154161
"""Base class for command events."""
@@ -201,7 +208,10 @@ def __init__(self, command, database_name, *args):
201208
# Command name must be first key.
202209
command_name = next(iter(command))
203210
super(CommandStartedEvent, self).__init__(command_name, *args)
204-
self.__cmd = command
211+
if command_name.lower() in _SENSITIVE_COMMANDS:
212+
self.__cmd = {}
213+
else:
214+
self.__cmd = command
205215
self.__db = database_name
206216

207217
@property
@@ -229,10 +239,15 @@ class CommandSucceededEvent(_CommandEvent):
229239
"""
230240
__slots__ = ("__duration_micros", "__reply")
231241

232-
def __init__(self, duration, reply, *args):
233-
super(CommandSucceededEvent, self).__init__(*args)
242+
def __init__(self, duration, reply, command_name,
243+
request_id, connection_id, operation_id):
244+
super(CommandSucceededEvent, self).__init__(
245+
command_name, request_id, connection_id, operation_id)
234246
self.__duration_micros = _to_micros(duration)
235-
self.__reply = reply
247+
if command_name.lower() in _SENSITIVE_COMMANDS:
248+
self.__reply = {}
249+
else:
250+
self.__reply = reply
236251

237252
@property
238253
def duration_micros(self):

test/test_monitoring.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import datetime
1516
import sys
1617
import time
1718
import warnings
@@ -1229,6 +1230,34 @@ def test_first_batch_helper(self):
12291230
self.assertEqual(started.request_id, succeeded.request_id)
12301231
self.assertEqual(started.connection_id, succeeded.connection_id)
12311232

1233+
def test_sensitive_commands(self):
1234+
listeners = self.client._event_listeners
1235+
1236+
self.listener.results.clear()
1237+
cmd = SON([("getnonce", 1)])
1238+
listeners.publish_command_start(
1239+
cmd, "pymongo_test", 12345, self.client.address)
1240+
delta = datetime.timedelta(milliseconds=100)
1241+
listeners.publish_command_success(
1242+
delta, {'nonce': 'e474f4561c5eb40b', 'ok': 1.0},
1243+
"getnonce", 12345, self.client.address)
1244+
results = self.listener.results
1245+
started = results['started'][0]
1246+
succeeded = results['succeeded'][0]
1247+
self.assertEqual(0, len(results['failed']))
1248+
self.assertIsInstance(started, monitoring.CommandStartedEvent)
1249+
self.assertEqual({}, started.command)
1250+
self.assertEqual('pymongo_test', started.database_name)
1251+
self.assertEqual('getnonce', started.command_name)
1252+
self.assertIsInstance(started.request_id, int)
1253+
self.assertEqual(self.client.address, started.connection_id)
1254+
self.assertIsInstance(succeeded, monitoring.CommandSucceededEvent)
1255+
self.assertEqual(succeeded.duration_micros, 100000)
1256+
self.assertEqual(started.command_name, succeeded.command_name)
1257+
self.assertEqual(started.request_id, succeeded.request_id)
1258+
self.assertEqual(started.connection_id, succeeded.connection_id)
1259+
self.assertEqual({}, succeeded.reply)
1260+
12321261

12331262
class TestGlobalListener(unittest.TestCase):
12341263

0 commit comments

Comments
 (0)