Skip to content

Commit be994fb

Browse files
Merge pull request #196 from n-iv/fix/webdav-redirect-preserve-method
fix: preserve method and URI when redirecting WebDAV through GSS
2 parents e09024c + 7f5bd61 commit be994fb

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

lib/ConfigLexicon.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
class ConfigLexicon implements ILexicon {
1818
public const GS_TOKENS = 'globalScaleTokens';
1919
public const LOCAL_TOKEN = 'localToken';
20+
public const REDIRECT_WEBDAV = 'redirectWebDAV';
2021

2122
#[\Override]
2223
public function getStrictness(): Strictness {
@@ -31,6 +32,7 @@ public function getAppConfigs(): array {
3132
return [
3233
new Entry(key: self::GS_TOKENS, type: ValueType::ARRAY, defaultRaw: [], definition: 'list of token+host to navigate through GlobalScale', lazy: true),
3334
new Entry(key: self::LOCAL_TOKEN, type: ValueType::STRING, defaultRaw: '', definition: 'local token to id instance within GlobalScale', lazy: true),
35+
new Entry(key: self::REDIRECT_WEBDAV, type: ValueType::BOOL, defaultRaw: false, definition: 'redirect WebDAV request on Master to Slaves', lazy: false),
3436
];
3537
}
3638

lib/Master.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
use OC\Core\Controller\ClientFlowLoginV2Controller;
1414
use OC\Core\Service\LoginFlowV2Service;
1515
use OCA\GlobalSiteSelector\AppInfo\Application;
16+
use OCA\GlobalSiteSelector\ConfigLexicon;
1617
use OCA\GlobalSiteSelector\UserDiscoveryModules\IUserDiscoveryModule;
1718
use OCA\GlobalSiteSelector\Vendor\Firebase\JWT\JWT;
1819
use OCA\GlobalSiteSelector\Vendor\Firebase\JWT\Key;
1920
use OCP\AppFramework\Http\StandaloneTemplateResponse;
2021
use OCP\Authentication\IApacheBackend;
2122
use OCP\HintException;
2223
use OCP\Http\Client\IClientService;
24+
use OCP\IAppConfig;
2325
use OCP\IConfig;
2426
use OCP\IRequest;
2527
use OCP\ISession;
@@ -48,6 +50,7 @@ public function __construct(
4850
private readonly Lookup $lookup,
4951
private readonly IRequest $request,
5052
private readonly IClientService $clientService,
53+
private readonly IAppConfig $appConfig,
5154
private readonly IConfig $config,
5255
private readonly LoggerInterface $logger,
5356
) {
@@ -272,6 +275,14 @@ protected function redirectUser($uid, $password, $location, array $options = [])
272275
// check for both possible direct webdav end-points
273276
$isDirectWebDavAccess = strpos($requestUri, 'remote.php/webdav') !== false;
274277
$isDirectWebDavAccess = $isDirectWebDavAccess || strpos($requestUri, 'remote.php/dav') !== false;
278+
279+
$authHeader = $this->request->getHeader('Authorization');
280+
$redirectWebDav = $this->appConfig->getValueBool(Application::APP_ID, ConfigLexicon::REDIRECT_WEBDAV);
281+
$hasBasicAuth = $redirectWebDav && $authHeader !== '' && str_starts_with(strtolower($authHeader), 'basic ');
282+
283+
// default redirect status code; overridden below for the 307 forward.
284+
$statusCode = 302;
285+
275286
// direct webdav access with old client or general purpose webdav clients
276287
if ($isClient && $isDirectWebDavAccess) {
277288
$this->logger->debug('redirectUser: client direct webdav request');
@@ -289,14 +300,26 @@ protected function redirectUser($uid, $password, $location, array $options = [])
289300
// fallback to v1
290301
$redirectUrl = 'nc://login/server:' . $location . '&user:' . urlencode($uid) . '&password:' . urlencode($appToken);
291302
}
303+
} elseif ($isDirectWebDavAccess && $hasBasicAuth) {
304+
// Third-party WebDAV clients authenticated with HTTP Basic
305+
// (curl, rclone, davfs2, sabre/dav based clients, generic DAV
306+
// consumers, etc.): forward the request as-is to the slave with
307+
// a 307 (RFC 9110 §15.4.8) so that PUT, PROPFIND, MKCOL, DELETE,
308+
// COPY and MOVE are not downgraded to GET, and the original
309+
// request URI is preserved end-to-end. The client re-issues the
310+
// same request to the slave, including the Authorization header
311+
// it already presented to the master.
312+
$this->logger->debug('redirectUser: third-party webdav request with Basic Auth, forwarding with 307');
313+
$redirectUrl = rtrim($location, '/') . $requestUri;
314+
$statusCode = 307;
292315
} else {
293316
$this->logger->debug('redirectUser: direct login so forward to target node');
294317
$jwt = $this->createJwt($uid, $password, $options);
295318
$redirectUrl = $location . '/index.php/apps/globalsiteselector/autologin?jwt=' . $jwt;
296319
}
297320

298321
$this->logger->debug('redirectUser: redirecting to: ' . $redirectUrl);
299-
header('Location: ' . $redirectUrl, true, 302);
322+
header('Location: ' . $redirectUrl, true, $statusCode);
300323
die();
301324
}
302325

0 commit comments

Comments
 (0)