Skip to content

Commit cbd5cef

Browse files
authored
Merge pull request #33398 from nextcloud/enh/noid/sensitive-methods-apps
allow apps to specify methods carrying sensitive parameters
2 parents 5f40bd1 + 6941c91 commit cbd5cef

File tree

5 files changed

+92
-10
lines changed

5 files changed

+92
-10
lines changed

lib/private/AppFramework/Bootstrap/RegistrationContext.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ class RegistrationContext {
121121
/** @var ServiceRegistration<ICalendarProvider>[] */
122122
private $calendarProviders = [];
123123

124+
/** @var ParameterRegistration[] */
125+
private $sensitiveMethods = [];
126+
124127
/** @var LoggerInterface */
125128
private $logger;
126129

@@ -304,6 +307,14 @@ public function registerUserMigrator(string $migratorClass): void {
304307
$migratorClass
305308
);
306309
}
310+
311+
public function registerSensitiveMethods(string $class, array $methods): void {
312+
$this->context->registerSensitiveMethods(
313+
$this->appId,
314+
$class,
315+
$methods
316+
);
317+
}
307318
};
308319
}
309320

@@ -430,6 +441,11 @@ public function registerUserMigrator(string $appId, string $migratorClass): void
430441
$this->userMigrators[] = new ServiceRegistration($appId, $migratorClass);
431442
}
432443

444+
public function registerSensitiveMethods(string $appId, string $class, array $methods): void {
445+
$methods = array_filter($methods, 'is_string');
446+
$this->sensitiveMethods[] = new ParameterRegistration($appId, $class, $methods);
447+
}
448+
433449
/**
434450
* @param App[] $apps
435451
*/
@@ -712,4 +728,11 @@ public function getCalendarRoomBackendRegistrations(): array {
712728
public function getUserMigrators(): array {
713729
return $this->userMigrators;
714730
}
731+
732+
/**
733+
* @return ParameterRegistration[]
734+
*/
735+
public function getSensitiveMethods(): array {
736+
return $this->sensitiveMethods;
737+
}
715738
}

lib/private/Log.php

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@
3636
*/
3737
namespace OC;
3838

39+
use Exception;
3940
use Nextcloud\LogNormalizer\Normalizer;
41+
use OC\AppFramework\Bootstrap\Coordinator;
4042
use OCP\Log\IDataLogger;
43+
use Throwable;
4144
use function array_merge;
4245
use OC\Log\ExceptionSerializer;
4346
use OCP\ILogger;
@@ -228,7 +231,7 @@ public function log(int $level, string $message, array $context = []) {
228231
$this->crashReporters->delegateBreadcrumb($entry['message'], 'log', $context);
229232
}
230233
}
231-
} catch (\Throwable $e) {
234+
} catch (Throwable $e) {
232235
// make sure we dont hard crash if logging fails
233236
}
234237
}
@@ -300,19 +303,19 @@ public function getLogLevel($context) {
300303
/**
301304
* Logs an exception very detailed
302305
*
303-
* @param \Exception|\Throwable $exception
306+
* @param Exception|Throwable $exception
304307
* @param array $context
305308
* @return void
306309
* @since 8.2.0
307310
*/
308-
public function logException(\Throwable $exception, array $context = []) {
311+
public function logException(Throwable $exception, array $context = []) {
309312
$app = $context['app'] ?? 'no app in context';
310313
$level = $context['level'] ?? ILogger::ERROR;
311314

312315
// if an error is raised before the autoloader is properly setup, we can't serialize exceptions
313316
try {
314-
$serializer = new ExceptionSerializer($this->config);
315-
} catch (\Throwable $e) {
317+
$serializer = $this->getSerializer();
318+
} catch (Throwable $e) {
316319
$this->error("Failed to load ExceptionSerializer serializer while trying to log " . $exception->getMessage());
317320
return;
318321
}
@@ -338,7 +341,7 @@ public function logException(\Throwable $exception, array $context = []) {
338341
if (!is_null($this->crashReporters)) {
339342
$this->crashReporters->delegateReport($exception, $context);
340343
}
341-
} catch (\Throwable $e) {
344+
} catch (Throwable $e) {
342345
// make sure we dont hard crash if logging fails
343346
}
344347
}
@@ -361,7 +364,7 @@ public function logData(string $message, array $data, array $context = []): void
361364
}
362365

363366
$context['level'] = $level;
364-
} catch (\Throwable $e) {
367+
} catch (Throwable $e) {
365368
// make sure we dont hard crash if logging fails
366369
}
367370
}
@@ -401,4 +404,26 @@ private function interpolateMessage(array $context, string $message, string $mes
401404
}
402405
return array_merge(array_diff_key($context, $usedContextKeys), [$messageKey => strtr($message, $replace)]);
403406
}
407+
408+
/**
409+
* @throws Throwable
410+
*/
411+
protected function getSerializer(): ExceptionSerializer {
412+
$serializer = new ExceptionSerializer($this->config);
413+
try {
414+
/** @var Coordinator $coordinator */
415+
$coordinator = \OCP\Server::get(Coordinator::class);
416+
foreach ($coordinator->getRegistrationContext()->getSensitiveMethods() as $registration) {
417+
$serializer->enlistSensitiveMethods($registration->getName(), $registration->getValue());
418+
}
419+
// For not every app might be initialized at this time, we cannot assume that the return value
420+
// of getSensitiveMethods() is complete. Running delegates in Coordinator::registerApps() is
421+
// not possible due to dependencies on the one hand. On the other it would work only with
422+
// adding public methods to the PsrLoggerAdapter and this class.
423+
// Thus, serializer cannot be a property.
424+
} catch (Throwable $t) {
425+
// ignore app-defined sensitive methods in this case - they weren't loaded anyway
426+
}
427+
return $serializer;
428+
}
404429
}

lib/private/Log/ExceptionSerializer.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public function __construct(SystemConfig $systemConfig) {
109109
$this->systemConfig = $systemConfig;
110110
}
111111

112-
public const methodsWithSensitiveParametersByClass = [
112+
protected array $methodsWithSensitiveParametersByClass = [
113113
SetupController::class => [
114114
'run',
115115
'display',
@@ -190,8 +190,8 @@ private function filterTrace(array $trace) {
190190
$sensitiveValues = [];
191191
$trace = array_map(function (array $traceLine) use (&$sensitiveValues) {
192192
$className = $traceLine['class'] ?? '';
193-
if ($className && isset(self::methodsWithSensitiveParametersByClass[$className])
194-
&& in_array($traceLine['function'], self::methodsWithSensitiveParametersByClass[$className], true)) {
193+
if ($className && isset($this->methodsWithSensitiveParametersByClass[$className])
194+
&& in_array($traceLine['function'], $this->methodsWithSensitiveParametersByClass[$className], true)) {
195195
return $this->editTrace($sensitiveValues, $traceLine);
196196
}
197197
foreach (self::methodsWithSensitiveParameters as $sensitiveMethod) {
@@ -289,4 +289,11 @@ public function serializeException(\Throwable $exception) {
289289

290290
return $data;
291291
}
292+
293+
public function enlistSensitiveMethods(string $class, array $methods): void {
294+
if (!isset($this->methodsWithSensitiveParametersByClass[$class])) {
295+
$this->methodsWithSensitiveParametersByClass[$class] = [];
296+
}
297+
$this->methodsWithSensitiveParametersByClass[$class] = array_merge($this->methodsWithSensitiveParametersByClass[$class], $methods);
298+
}
292299
}

lib/public/AppFramework/Bootstrap/IRegistrationContext.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,15 @@ public function registerCalendarRoomBackend(string $class): void;
306306
* @since 24.0.0
307307
*/
308308
public function registerUserMigrator(string $migratorClass): void;
309+
310+
/**
311+
* Announce methods of classes that may contain sensitive values, which
312+
* should be obfuscated before being logged.
313+
*
314+
* @param string $class
315+
* @param string[] $methods
316+
* @return void
317+
* @since 25.0.0
318+
*/
319+
public function registerSensitiveMethods(string $class, array $methods): void;
309320
}

tests/lib/Log/ExceptionSerializerTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ private function bind(array &$myValues): void {
4848
throw new \Exception('my exception');
4949
}
5050

51+
private function customMagicAuthThing(string $login, string $parole): void {
52+
throw new \Exception('expected custom auth exception');
53+
}
54+
5155
/**
5256
* this test ensures that the serializer does not overwrite referenced
5357
* variables. It is crafted after a scenario we experienced: the DAV server
@@ -65,4 +69,16 @@ public function testSerializer() {
6569
$this->assertSame(ExceptionSerializer::SENSITIVE_VALUE_PLACEHOLDER, $serializedData['Trace'][0]['args'][0]);
6670
}
6771
}
72+
73+
public function testSerializerWithRegisteredMethods() {
74+
$this->serializer->enlistSensitiveMethods(self::class, ['customMagicAuthThing']);
75+
try {
76+
$this->customMagicAuthThing('u57474', 'Secret');
77+
} catch (\Exception $e) {
78+
$serializedData = $this->serializer->serializeException($e);
79+
$this->assertSame('customMagicAuthThing', $serializedData['Trace'][0]['function']);
80+
$this->assertSame(ExceptionSerializer::SENSITIVE_VALUE_PLACEHOLDER, $serializedData['Trace'][0]['args'][0]);
81+
$this->assertFalse(isset($serializedData['Trace'][0]['args'][1]));
82+
}
83+
}
6884
}

0 commit comments

Comments
 (0)