12
12
use PHPUnit \Framework \Assert ;
13
13
use stdClass ;
14
14
15
- use function array_fill_keys ;
16
15
use function array_reverse ;
17
16
use function count ;
18
17
use function current ;
38
37
*/
39
38
final class EventObserver implements CommandSubscriber
40
39
{
41
- /** @var array */
42
- private static $ defaultIgnoreCommands = [
43
- // failPoint and targetedFailPoint operations
44
- 'configureFailPoint ' ,
45
- // See: https://github.com/mongodb/specifications/blob/master/source/command-monitoring/command-monitoring.rst#security
46
- 'authenticate ' ,
47
- 'saslStart ' ,
48
- 'saslContinue ' ,
49
- 'getnonce ' ,
50
- 'createUser ' ,
51
- 'updateUser ' ,
52
- 'copydbgetnonce ' ,
53
- 'copydbsaslstart ' ,
54
- 'copydb ' ,
55
- 'isMaster ' ,
56
- 'hello ' ,
40
+ /**
41
+ * These commands are always considered sensitive (i.e. command and reply
42
+ * documents should be redacted).
43
+ *
44
+ * @see https://github.com/mongodb/specifications/blob/master/source/command-monitoring/command-monitoring.rst#security
45
+ * @var array
46
+ */
47
+ private static $ sensitiveCommands = [
48
+ 'authenticate ' => 1 ,
49
+ 'saslStart ' => 1 ,
50
+ 'saslContinue ' => 1 ,
51
+ 'getnonce ' => 1 ,
52
+ 'createUser ' => 1 ,
53
+ 'updateUser ' => 1 ,
54
+ 'copydbgetnonce ' => 1 ,
55
+ 'copydbsaslstart ' => 1 ,
56
+ 'copydb ' => 1 ,
57
+ ];
58
+
59
+ /**
60
+ * These commands are only considered sensitive when the command or reply
61
+ * document includes a speculativeAuthenticate field.
62
+ *
63
+ * @see https://github.com/mongodb/specifications/blob/master/source/command-monitoring/command-monitoring.rst#security
64
+ * @var array
65
+ */
66
+ private static $ sensitiveCommandsWithSpeculativeAuthenticate = [
67
+ 'ismaster ' => 1 ,
68
+ 'isMaster ' => 1 ,
69
+ 'hello ' => 1 ,
57
70
];
58
71
59
72
/** @var array */
@@ -72,13 +85,21 @@ final class EventObserver implements CommandSubscriber
72
85
/** @var Context */
73
86
private $ context ;
74
87
75
- /** @var array */
76
- private $ ignoreCommands = [];
88
+ /**
89
+ * The configureFailPoint command (used by failPoint and targetedFailPoint
90
+ * operations) is always ignored.
91
+ *
92
+ * @var array
93
+ */
94
+ private $ ignoreCommands = ['configureFailPoint ' => 1 ];
77
95
78
96
/** @var array */
79
97
private $ observeEvents = [];
80
98
81
- public function __construct (array $ observeEvents , array $ ignoreCommands , string $ clientId , Context $ context )
99
+ /** @var bool */
100
+ private $ observeSensitiveCommands ;
101
+
102
+ public function __construct (array $ observeEvents , array $ ignoreCommands , bool $ observeSensitiveCommands , string $ clientId , Context $ context )
82
103
{
83
104
assertNotEmpty ($ observeEvents );
84
105
@@ -88,13 +109,12 @@ public function __construct(array $observeEvents, array $ignoreCommands, string
88
109
$ this ->observeEvents [self ::$ supportedEvents [$ event ]] = 1 ;
89
110
}
90
111
91
- $ this ->ignoreCommands = array_fill_keys (self ::$ defaultIgnoreCommands , 1 );
92
-
93
112
foreach ($ ignoreCommands as $ command ) {
94
113
assertIsString ($ command );
95
114
$ this ->ignoreCommands [$ command ] = 1 ;
96
115
}
97
116
117
+ $ this ->observeSensitiveCommands = $ observeSensitiveCommands ;
98
118
$ this ->clientId = $ clientId ;
99
119
$ this ->context = $ context ;
100
120
}
@@ -270,6 +290,30 @@ private function handleEvent($event): void
270
290
return ;
271
291
}
272
292
293
+ if (! $ this ->observeSensitiveCommands && $ this ->isSensitiveCommand ($ event )) {
294
+ return ;
295
+ }
296
+
273
297
$ this ->actualEvents [] = $ event ;
274
298
}
299
+
300
+ /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */
301
+ private function isSensitiveCommand ($ event ): bool
302
+ {
303
+ if (isset (self ::$ sensitiveCommands [$ event ->getCommandName ()])) {
304
+ return true ;
305
+ }
306
+
307
+ /* If the command or reply included a speculativeAuthenticate field,
308
+ * libmongoc will already have redacted it (CDRIVER-4000). Therefore, we
309
+ * can infer that the command was sensitive if its command or reply is
310
+ * empty. */
311
+ if (isset (self ::$ sensitiveCommandsWithSpeculativeAuthenticate [$ event ->getCommandName ()])) {
312
+ $ commandOrReply = $ event instanceof CommandStartedEvent ? $ event ->getCommand () : $ event ->getReply ();
313
+
314
+ return (array ) $ commandOrReply === [];
315
+ }
316
+
317
+ return false ;
318
+ }
275
319
}
0 commit comments