Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for x-forwarded-prefix #23263

Closed
Tratcher opened this issue Jun 23, 2020 · 15 comments · Fixed by #49249
Closed

Support for x-forwarded-prefix #23263

Tratcher opened this issue Jun 23, 2020 · 15 comments · Fixed by #49249
Labels
affected-few This issue impacts only small number of customers api-approved API was approved in API review, it can be implemented area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlesware enhancement This issue represents an ask for new feature or an enhancement to an existing one help wanted Up for grabs. We would accept a PR to help resolve this issue severity-minor This label is used by an internal tool

Comments

@Tratcher
Copy link
Member

microsoft/reverse-proxy#13 (comment)

When requests traverse a reverse proxy it's common to change parts of the url like the scheme (TLS offloading). That information is sent to the app via additional x-forwarded-* headers. The Forwarded Headers middleware reads these headers and fixes up the request fields so that the application can still properly generate links.

One common manipulation that's not currently supported is to Trim the start of the request path and forward that missing information as part the x-forwarded-PathBase header.

Example:
Original url: https://external.com/pathbase/path?query
Transformed request:
http://internal/path?query
x-forwarded-proto: https
x-forwarded-host: external.com
x-forwarded-pathbase: /pathbase

x-forwarded-pathbase is now supported by YARP and enabled by default.
https://microsoft.github.io/reverse-proxy/articles/transforms.html

@Tratcher Tratcher added enhancement This issue represents an ask for new feature or an enhancement to an existing one area-middleware labels Jun 23, 2020
@BrennanConroy BrennanConroy added this to the Backlog milestone Jun 24, 2020
@damianh
Copy link

damianh commented Jul 8, 2020

I've extended HttpOverride with this functionality https://github.com/ProxyKit/HttpOverrides

@pksorensen
Copy link
Contributor

I did not get any pathbase headers and added it manually. Is this due to the PathRemovePrefix transform that i had to added it manually like below?

{
        "RouteId": "API",
        "ClusterId": "serviceprovider",
        "Match": {
          "Methods": [ "GET", "POST", "PUT", "DELETE", "PATCH" ],
          "Path": "/api/{**catchall}"

        },
        "Transforms": [
          { "PathRemovePrefix": "/api" },
          {
            "RequestHeader": "X-Forwarded-PathBase",
            "Append": "/api"
          }
        ]
      },

@Tratcher
Copy link
Member Author

@pksorensen let's keep YARP questions over at https://github.com/microsoft/reverse-proxy/.

/api isn't considered the path base in the above example. HttpRequest.PathBase is a field that's trimmed off the request path before routing starts. See the UsePathBase extension.

Your transforms look fine for your scenario.

@Tratcher Tratcher added affected-few This issue impacts only small number of customers severity-minor This label is used by an internal tool labels Nov 9, 2020 — with ASP.NET Core Issue Ranking
@krispenner
Copy link

krispenner commented Jan 26, 2021

@Tratcher I've been trying to get this to work myself and from searching it seems the more common header name used across other frameworks is X-Forwarded-Prefix I recommend searching yourself. Whereas if you search for X-Forwarded-PathBase only ASP .NET Core based results come up with most referencing back to this issue or the YARP project. Just thought maybe you should switch to what appears to be the more popular name of X-Forwarded-Prefix instead? Or are these some how different? From my understanding they appear to be identical in their usage.

Also if anyone else comes across this, I got this working (for my needs anyways) with the below code as I don't see any support from MS for it yet.

app.Use(async (context, next) =>
{
    if (context.Request.Headers.TryGetValue("X-Forwarded-PathBase", out var pathBase))
    {
        context.Request.PathBase = pathBase.Last();

        if (context.Request.Path.StartsWithSegments(context.Request.PathBase, out var path))
        {
            context.Request.Path = path;
        }
    }

    await next();
});

@Tratcher
Copy link
Member Author

Tratcher commented Feb 9, 2021

@krispenner can you give some references for that? Searching, I see a number of questions about it but very few actually supporting it.

@krispenner
Copy link

krispenner commented Feb 9, 2021

Hi @Tratcher, here are some of the examples I found and I could list another 10 if I kept going. There is obviously no standard for this yet, but I'm only suggesting using the Prefix name as it seems to be what the broader community is using in relation to this feature and it was also my first search as it seems more intuitive (at least to me). PathBase is very ASP.NET Core specific, is only found in relation to YARP (no other library that I can find) and I'd just prefer MS doesn't create any fragmentation if/when this becomes an official standard. Just my 2c.

  • Traefik reverse proxy (actual support)
    • The X-Forwarded-Prefix header can be queried to build such URLs dynamically.

  • Parasoft reverse proxy support (actual support)
    • Configure your reverse proxy to send the following headers to DTP: X-Forwarded-Prefix

  • GeneXus
    • There is a draft RFC request to Standarize a new Http Header for this scenario: "X-Forwarded-Prefix". However, is still not supported by many WebServers.

  • Apache Flask (actual support)
    • are you setting the x-forwarded-prefix header in your apache conf?

  • Kong API Gateway (actual support)
    • Kong will either send an existing X-Forwarded-Prefix header from a trusted sender or will generate a new X-Forwarded-Prefix header containing the entire path.

  • Spring Cloud API Gateway (actual support)
    • I was happy to see that X-Forwarded-Prefix was added in 2.0.2.RELEASE

  • Drupal support request
    • I expected that Drupal respects HTTP_X_FORWARDED_PREFIX and add this prefix to all href

  • Humio (actual support)
    • Humio requires the proxy to add the header X-Forwarded-Prefix

  • ProxyPrefix library
    • WSGI middleware to prefix SCRIPT_NAME with X-Forwarded-Prefix header. For services behind a reverse proxy so their URLs contain the proxied path.

@Tratcher
Copy link
Member Author

@krispenner thanks, that's a good list. I filed a matching issue for YARP.

@Tratcher Tratcher changed the title Support for x-forwarded-PathBase Support for x-forwarded-prefix Feb 13, 2021
@damianh
Copy link

damianh commented Jul 4, 2021

This should probably happen in 6.0 otherwise one is looking at significant amount of time before it's in an LTS release and won't be aligned with YARP

@voroninp
Copy link
Contributor

I see kong sets x-forwarded-path and x-forwarded-prefix

@ghost
Copy link

ghost commented Sep 13, 2022

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@amcasey amcasey added area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlesware and removed area-runtime labels Jun 2, 2023
@andwi
Copy link
Contributor

andwi commented Jul 2, 2023

It seams to me that it should be quite straightforward to use the existing pattern in ForwardedHeadersMiddleware and also set PathBase based on the X-Forwarded-Prefix header, unless I have misunderstood something. Will you accept a PR for this even if this issue does not have the help-wanted label?

@Tratcher
Copy link
Member Author

Tratcher commented Jul 5, 2023

Sure, give it a try. FYI this will need a fair number of tests, like path encoding, replacing an exisitng PathBase, etc.

@Tratcher Tratcher added the help wanted Up for grabs. We would accept a PR to help resolve this issue label Jul 5, 2023
@andwi
Copy link
Contributor

andwi commented Jul 8, 2023

As requested by @adityamandaleeka in #49249 here are the proposed api changes for this feature.

namespace Microsoft.AspNetCore.HttpOverrides
{
    [Flags]
    public enum ForwardedHeaders
    {
+        XForwardedPrefix = 1 << 3,
-        All = XForwardedFor | XForwardedHost | XForwardedProto
+        All = XForwardedFor | XForwardedHost | XForwardedProto | XForwardedPrefix
    }

    public static class ForwardedHeadersDefaults
    {
+        public static string XForwardedPrefixHeaderName { get; } = "X-Forwarded-Prefix";
+        public static string XOriginalPrefixHeaderName { get; } = "X-Original-Prefix";
    }
}

namespace Microsoft.AspNetCore.Builder
{
    public class ForwardedHeadersOptions
    {
+        public string ForwardedPrefixHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedPrefixHeaderName;
+        public string OriginalPrefixHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalPrefixHeaderName;
    }
}

It occurred to me also that the expanded definition of ForwardedHeaders.All in combination with RequireHeaderSymmetry can be a breaking change when the X-Forwarded-Prefix header is not included in the http request. So not sure anymore if ForwardedHeaders.All should be expanded. Is this an acceptable breaking change? Maybe it's enough to mention it in the release notes since the workaround is to just use the individual flags you need? It would be very strange if ForwardedHeaders.All did not include all flags.

@mitchdenny mitchdenny added the api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews label Jul 10, 2023
@ghost
Copy link

ghost commented Jul 10, 2023

Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.

@halter73
Copy link
Member

API Review Notes:

  • Moving the original header value to an X-Original header is not as good as putting it in a feature, but is consistent with our other X-Forwarded headers.
  • Anyone using ForwardedHeaders.All explicitly chose it. It's not the default for the middleware or anything like that. You need to recompile to pick up the new prefix because the enum value would be inlined.

API Approved!

namespace Microsoft.AspNetCore.HttpOverrides
{
    [Flags]
    public enum ForwardedHeaders
    {
+        XForwardedPrefix = 1 << 3,
-        All = XForwardedFor | XForwardedHost | XForwardedProto
+        All = XForwardedFor | XForwardedHost | XForwardedProto | XForwardedPrefix
    }

    public static class ForwardedHeadersDefaults
    {
+        public static string XForwardedPrefixHeaderName { get; } = "X-Forwarded-Prefix";
+        public static string XOriginalPrefixHeaderName { get; } = "X-Original-Prefix";
    }
}

namespace Microsoft.AspNetCore.Builder
{
    public class ForwardedHeadersOptions
    {
+        public string ForwardedPrefixHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedPrefixHeaderName;
+        public string OriginalPrefixHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalPrefixHeaderName;
    }
}

@halter73 halter73 added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews labels Jul 24, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Sep 1, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-few This issue impacts only small number of customers api-approved API was approved in API review, it can be implemented area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlesware enhancement This issue represents an ask for new feature or an enhancement to an existing one help wanted Up for grabs. We would accept a PR to help resolve this issue severity-minor This label is used by an internal tool
Projects
None yet
Development

Successfully merging a pull request may close this issue.

12 participants