From 120d8467723acb58107fcdec55876ea7163850c8 Mon Sep 17 00:00:00 2001
From: Paul Millar <paul.millar@desy.de>
Date: Mon, 3 May 2021 14:34:48 +0200
Subject: [PATCH] pool: http allow client to send credentials when TLS is used

Motivation:

If dCacheView makes a GET request against the WebDAV for which it
supplies credentials and the door redirects dCacheView to a pool then
dCacheView will use the same credentials when making the GET request to
the pool. This bug is recorded as dCache/dcache-view#254.

Currently, the pool responds to the CORS preflight request indicating
that the client must not send credentials.  When faced with this
conflict, the web-browser fails the GET request.

It looks like it's currently impossible to prevent the web-browser from
resending the WebDAV-credentials to the pool (see whatwg/fetch#944).

Therefore, to support dCacheView, the pool must allow client
credentials, which (in turn) is only safe for TLS-protected transfers.

Modification:

Update pool's CORS configuration to allow the client to send a
credential for https transfers.

The pool continues to ban sending credentials for http (i.e.,
unencrypted) transfers.

Result:

dCacheView now works for redirected transfers for non-anonymous data
access, provided the WebDAV door is using TLS encryption and is
configured with 'webdav.redirect.allow-https' set to 'true'.  This, in
turn, requires the pool has TLS enabled and presents an X.509
certificate from a CA that the browser trust.

Target: master
Requires-notes: yes
Requires-book: no
Request: 7.1
Request: 7.0
Request: 6.2
Request: 6.1
Request: 6.0
Request: 5.2
Patch: https://rb.dcache.org/r/13018/
Acked-by: Tigran Mkrtchyan
Acked-by: Lea Morschel
---
 .../org/dcache/http/HttpTransferService.java    | 17 ++++++++++-------
 .../org/dcache/http/HttpsTransferService.java   |  7 +++++++
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/modules/dcache/src/main/java/org/dcache/http/HttpTransferService.java b/modules/dcache/src/main/java/org/dcache/http/HttpTransferService.java
index 9530d1f6d43..ab4c85c36e9 100644
--- a/modules/dcache/src/main/java/org/dcache/http/HttpTransferService.java
+++ b/modules/dcache/src/main/java/org/dcache/http/HttpTransferService.java
@@ -81,6 +81,15 @@ public HttpTransferService()
         super("http");
     }
 
+    CorsConfigBuilder corsConfigBuilder()
+    {
+        return CorsConfigBuilder.forAnyOrigin()
+                .allowNullOrigin()
+                .allowedRequestMethods(GET, PUT, HEAD)
+                .allowedRequestHeaders(CONTENT_TYPE, AUTHORIZATION, CONTENT_MD5,
+                        "Want-Digest", "suppress-www-authenticate");
+    }
+
     public int getChunkSize()
     {
         return chunkSize;
@@ -175,13 +184,7 @@ protected void addChannelHandlers(ChannelPipeline pipeline) throws Exception
             pipeline.addLast("custom-headers", new CustomResponseHeadersHandler(customHeaders));
         }
 
-        CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin()
-                .allowNullOrigin()
-                .allowedRequestMethods(GET, PUT, HEAD)
-                .allowedRequestHeaders(CONTENT_TYPE, AUTHORIZATION, CONTENT_MD5,
-                        "Want-Digest", "suppress-www-authenticate")
-                .build();
-        pipeline.addLast("cors", new CorsHandler(corsConfig));
+        pipeline.addLast("cors", new CorsHandler(corsConfigBuilder().build()));
 
         pipeline.addLast("transfer", new HttpPoolRequestHandler(this, chunkSize));
     }
diff --git a/modules/dcache/src/main/java/org/dcache/http/HttpsTransferService.java b/modules/dcache/src/main/java/org/dcache/http/HttpsTransferService.java
index 0606157c32f..1f01ea64be4 100644
--- a/modules/dcache/src/main/java/org/dcache/http/HttpsTransferService.java
+++ b/modules/dcache/src/main/java/org/dcache/http/HttpsTransferService.java
@@ -28,6 +28,7 @@
 import eu.emi.security.authn.x509.CrlCheckingMode;
 import eu.emi.security.authn.x509.OCSPCheckingMode;
 import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.cors.CorsConfigBuilder;
 import io.netty.handler.ssl.SslHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -123,6 +124,12 @@ static String getHost(URI url)
                 : host;
     }
 
+    @Override
+    CorsConfigBuilder corsConfigBuilder()
+    {
+        return super.corsConfigBuilder().allowCredentials();
+    }
+
     @Override
     protected URI getUri(HttpProtocolInfo protocolInfo, int port, UUID uuid)
             throws SocketException, CacheException, URISyntaxException {