GFlisch / Arc4u.Guidance.Doc

Other
5 stars 1 forks source link

(Guidance 2022.2.1.14) Set all the forwarded headers, not only the prefix #235

Open vvdb-architecture opened 6 months ago

vvdb-architecture commented 6 months ago

Currently, the guidance generates code in the back-end services that fills in the PathBase with the contents of X-Forwarded-Prefix value (if present), to correct the base paths used in various scenarios:

 // Always replace the virtual path of this backend with the one from the yarp. Required for swagger and hangfire when hosted in IISHost!
        app.Use((context, next) =>
        {
            var pathBase = context.Request.Headers["X-Forwarded-Prefix"];
            if (!string.IsNullOrWhiteSpace(pathBase))
                context.Request.PathBase = new PathString(pathBase);
            return next();
        });

This works because it assumes that the service shares the same host name and scheme as the Yarp. In fact, it is assumed that the PathBase is always /Yarp, except in Development scenarios where the PathBase will be empty (because the Yarp is also hosted on localhost, but using another port).

However, if a controller method needs to compute the URI of its endpoint, it should be able to compute it like this:

                var uriBuilder = new UriBuilder(Request.Scheme, Request.Host.Host);
                if (Request.Host.Port is not null)
                    uriBuilder.Port = Request.Host.Port.Value;
                uriBuilder.Path = Request.PathBase.ToUriComponent() + "/whatever";

                var endpoint = uriBuilder.ToString();

This works except in Development scenarios. because the Host will still be the service host, not the Yarp host!

To correct this, the above code should also set the other forwarded headers like this:

        // Always replace the scheme, host and pathbase of this backend with the ones forwarded by Yarp. Required for swagger and hangfire when hosted in IISHost!
        app.Use((context, next) =>
        {
            const string HeadedrPrefix = "X-Forwarded-";    // this can change

            var pathBase = context.Request.Headers[HeadedrPrefix + "Prefix"];
            if (!string.IsNullOrWhiteSpace(pathBase))
                context.Request.PathBase = new PathString(pathBase);

            var forwardedHost = context.Request.Headers[HeadedrPrefix + "Host"];
            if (!string.IsNullOrWhiteSpace(forwardedHost))
                context.Request.Host = HostString.FromUriComponent(forwardedHost);

            var forwardedProto = context.Request.Headers[HeadedrPrefix + "Proto"];
            if (!string.IsNullOrWhiteSpace(forwardedProto))
                context.Request.Scheme = forwardedProto;

            return next();
        });

Note that the X-Forwarded- has been explicitly factored out, since this is something that can be changed (see The section about X-Forwarded- in the documentation).