1313use OC \Core \Controller \ClientFlowLoginV2Controller ;
1414use OC \Core \Service \LoginFlowV2Service ;
1515use OCA \GlobalSiteSelector \AppInfo \Application ;
16+ use OCA \GlobalSiteSelector \ConfigLexicon ;
1617use OCA \GlobalSiteSelector \UserDiscoveryModules \IUserDiscoveryModule ;
1718use OCA \GlobalSiteSelector \Vendor \Firebase \JWT \JWT ;
1819use OCA \GlobalSiteSelector \Vendor \Firebase \JWT \Key ;
1920use OCP \AppFramework \Http \StandaloneTemplateResponse ;
2021use OCP \Authentication \IApacheBackend ;
2122use OCP \HintException ;
2223use OCP \Http \Client \IClientService ;
24+ use OCP \IAppConfig ;
2325use OCP \IConfig ;
2426use OCP \IRequest ;
2527use 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