Skip to content

Commit c4b4e82

Browse files
authored
Merge pull request #11787 from GlobalDataverseCommunityConsortium/Anubis_fix
SignedUrl Fix when using http connector
2 parents f214ee4 + 52e538a commit c4b4e82

File tree

4 files changed

+30
-0
lines changed

4 files changed

+30
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
In prior versions of Dataverse, configuring a proxy to forward to Dataverse over an http connection could result in failure of signed Urls (e.g. for external tools). This version of Dataverse supports having a proxy send an X-Forwarded-Proto header set to https to avoid this issue.

doc/sphinx-guides/source/api/external-tools.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ The signed URL mechanism is more secure than exposing API tokens and therefore r
174174
- For tools invoked via a GET call, Dataverse will include a callback query parameter with a Base64 encoded value. The decoded value is a signed URL that can be called to retrieve a JSON response containing all of the queryParameters and allowedApiCalls specified in the manfiest.
175175
- For tools invoked via POST, Dataverse will send a JSON body including the requested queryParameters and allowedApiCalls. Dataverse expects the response to the POST to indicate a redirect which Dataverse will use to open the tool.
176176

177+
.. note::
178+
179+
**For Dataverse site administrators:** When Dataverse is behind a proxy, signed URLs may not work correctly due to protocol mismatches (HTTP vs HTTPS). Please refer to the :ref:`signed-urls-forwarded-proto-header` section to ensure signed URLs work properly in proxy environments.
180+
177181
API Token
178182
^^^^^^^^^
179183

doc/sphinx-guides/source/installation/config.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ First of all, confirm that access is denied! If you are in fact able to access t
9494

9595
Still feel like activating this option in your configuration? - Have fun and be safe!
9696

97+
.. _signed-urls-forwarded-proto-header:
98+
99+
Using X-Forwarded-Proto for Signed URLs
100+
+++++++++++++++++++++++++++++++++++++++
101+
102+
If you use a proxy such as Apache or Nginx, or have a firewall such as Anubis, and they are configured to forward traffic to Dataverse over HTTP
103+
(i.e. your proxy receives user calls over HTTPS but forwards locally to Dataverse over HTTP), signed URLs, used by external tools and
104+
upload apps (such as DVWebloader), are likely to fail unless you configure your proxy to send an X-Forwarded-Proto HTTP Header.
105+
This allows Dataverse to recognize that the communication from the user was over HTTPS and that validation of signed URLs should assume
106+
they started with https:// (rather than http:// as received from the proxy).
97107

98108
.. _PrivacyConsiderations:
99109

src/main/java/edu/harvard/iq/dataverse/api/auth/SignedUrlAuthMechanism.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import java.net.URLDecoder;
1818
import java.nio.charset.StandardCharsets;
19+
import java.util.logging.Logger;
1920

2021
import static edu.harvard.iq.dataverse.util.UrlSignerUtil.SIGNED_URL_TOKEN;
2122
import static edu.harvard.iq.dataverse.util.UrlSignerUtil.SIGNED_URL_USER;
@@ -33,6 +34,8 @@ public class SignedUrlAuthMechanism implements AuthMechanism {
3334
@Inject
3435
protected PrivateUrlServiceBean privateUrlSvc;
3536

37+
private static final Logger logger = Logger.getLogger(SignedUrlAuthMechanism.class.getCanonicalName());
38+
3639
@Override
3740
public User findUserFromRequest(ContainerRequestContext containerRequestContext) throws WrappedAuthErrorResponse {
3841
String signedUrlRequestParameter = getSignedUrlRequestParameter(containerRequestContext);
@@ -72,6 +75,18 @@ private User getAuthenticatedUserFromSignedUrl(ContainerRequestContext container
7275
}
7376
if (targetUser != null && userApiToken != null) {
7477
String signedUrl = URLDecoder.decode(uriInfo.getRequestUri().toString(), StandardCharsets.UTF_8);
78+
79+
logger.fine("Original URL: " + containerRequestContext.getUriInfo().getRequestUri().toString());
80+
String forwardedProto = containerRequestContext.getHeaderString("X-Forwarded-Proto");
81+
logger.fine("X-Forwarded-Proto is: " + forwardedProto);
82+
83+
84+
if (forwardedProto != null && !forwardedProto.isEmpty()) {
85+
if ("https".equalsIgnoreCase(forwardedProto) && signedUrl.toLowerCase().startsWith("http:")) {
86+
signedUrl = "https" + signedUrl.substring(4);
87+
}
88+
}
89+
7590
String requestMethod = containerRequestContext.getMethod();
7691
String signedUrlSigningKey = JvmSettings.API_SIGNING_SECRET.lookupOptional().orElse("") + userApiToken.getTokenString();
7792
boolean isSignedUrlValid = UrlSignerUtil.isValidUrl(signedUrl, userId, requestMethod, signedUrlSigningKey);

0 commit comments

Comments
 (0)