feat(security): use richdocuments.federation_allowlist system config for federation server validation#599
feat(security): use richdocuments.federation_allowlist system config for federation server validation#599DeepDiver1975 wants to merge 15 commits into
Conversation
Replaces the always-true isServerAllowed() stub with a real check against ownCloud's federation trusted-servers list (OCA\Federation\TrustedServers). When TrustedServers is null (federation app not installed), all remote federation requests are denied. URL comparison strips trailing slashes and checks both http/https scheme variants to tolerate minor admin-input differences. Fixes OC10-100 (SSRF via federated endpoint, CVSS 7.1). Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Explicitly register FederationService in the app container so that TrustedServers (from the federation app) is injected when available, and null is passed when the federation app is not installed. Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
… test - Application.php: replace \OC::$server->query() with the already-captured $server variable for consistency and testability - FederationServiceTest: remove testIsServerAllowedReturnsFalseWhenListIsEmpty which was identical to testIsServerAllowedReturnsFalseForUntrustedServer Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
…tedServers The federation app is an optional runtime dependency not present in Phan's analysis path. Suppress PhanUndeclaredClass* at the five sites that reference TrustedServers, matching the project's established inline-suppression pattern. Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
…ration line Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
…allowlist system config isServerAllowed() now reads a PHP array from config.php via richdocuments.federation_allowlist. Absent/empty/non-array values deny all. Each entry is checked with trailing-slash stripping and http/https scheme swap to tolerate minor URL mismatches. Removes the optional federation-app dependency entirely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
No longer needs the federation app isInstalled() check or Phan suppression. IConfig is a core ownCloud interface, always available. Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Code ReviewOverviewThis PR replaces the 3 PHP files changed + 2 documentation files added.
|
jvillafanez
left a comment
There was a problem hiding this comment.
This is what I had in mind.
| // swap scheme and try again | ||
| if (\strpos($normalized, 'https://') === 0) { | ||
| $swapped = 'http://' . \substr($normalized, 8); | ||
| } elseif (\strpos($normalized, 'http://') === 0) { | ||
| $swapped = 'https://' . \substr($normalized, 7); | ||
| } else { | ||
| return false; | ||
| $swapped = null; | ||
| } | ||
|
|
||
| foreach ($allowlist as $entry) { | ||
| $e = \rtrim($entry, '/'); | ||
| if ($normalized === $e) { | ||
| return true; | ||
| } | ||
| if ($swapped !== null && $swapped === $e) { | ||
| return true; | ||
| } | ||
| } |
There was a problem hiding this comment.
If we don't care about the protocol, it might be easier to just ask for the trusted host (just oc.server.prv instead of https://oc.server.prv). Stripping the protocol from the incoming remote and then checking for the matching host should be easier, even if we would need to ensure it's http or https.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Allowlist entries are now plain domain names (e.g. 'cloud.example.com') without a scheme. isServerAllowed() strips the http/https scheme from the incoming URL before matching, so both http and https requests are accepted for any listed domain. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Code ReviewOverviewReplaces the
|
…h-prefix limitation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
jvillafanez
left a comment
There was a problem hiding this comment.
Just a small thing, but it looks good.
| return $server->getL10N($c->query('AppName')); | ||
| }); | ||
|
|
||
| $container->registerService(FederationService::class, function () use ($server) { |
There was a problem hiding this comment.
I'm not sure if this is needed because it should be auto-wired by the DI
ownCloud's SimpleContainer autowires constructor dependencies by type via reflection, so the manual registerService is redundant. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Summary
Config
```php
// config/config.php
'richdocuments.federation_allowlist' => [
'collab1.example.com',
'collab2.example.com',
],
```
Test plan
🤖 Generated with Claude Code