4

I have an IIS10 server with ARR 3.0 and URL Rewrite Module 2.1 that acts as a reverse proxy for several other web servers. The other servers run on different ports, so the IIS10 server provides 'friendly URLs' on port 80. URL rewriting is used to hand the request off to the back-end server.

One such server is Jenkins.

Jenkins has a warning message that tells you if the reverse proxy is well configured (more details here), and this warning message helped me find an issue in my reverse proxy.

The issue is that URL Rewrite is decoding and encoding my URLs in a way that by the time they reach Jenkins they are different from what the browser requested.

Example:

URL Rewrite Rule:

<rule name="Jenkins Rewrite" stopProcessing="true">
   <match url="(.*)" />
   <conditions>
     <add input="{HTTP_HOST}" pattern=".*jenkins.mydomain.*" />
     <add input="{HTTPS}" pattern="on" />
   </conditions>
   <action type="Rewrite" url="http://localhost:8080/{R:1}" appendQueryString="true" />
   <serverVariables>
     <set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
     <set name="HTTP_X_FORWARDED_SCHEMA" value="https" />
     <set name="HTTP_X_FORWARDED_PROTO" value="https" />
   </serverVariables>
 </rule>

When sending the following URL:

https://jenkins.mydomain/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

I noticed that the encoded characters where being decoded before triggering the rule, making {R:1} looking like this: /administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https:/jenkins.mydomain/manage/

After some research I found out that I could use {UNENCODED_URL} instead of {R:1} to get the request string before the decoding, so I adjusted my rule action:

<action type="Rewrite" url="http://localhost:8080{UNENCODED_URL}" appendQueryString="false" />

Unfortunately the URL Rewrite is encoding the URL again after my Rewrite, making the URL received by Jenkins double encoded:

/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%253A%252F%252Fjenkins.mydomain%252Fmanage%253F

Short summary:

When you look at this URL: /administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

What we have is: /administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/<parameter1>

where <parameter1> = https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

The slash characters in <parameter1> are encoded so that Jenkins can know what is part of the path and what is <parameter1>.

This means that, when the URL Rewrite Decodes the URL, <parameter1> gets mixed with the rest of the path.

The desired result is getting the URL exactly as the browser sent it but pointing to the localhost:

http://localhost:8080/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

Is there anyway to disable this Decoding/Encoding operations that URL Rewrite Module is doing?

PS: I found a blog post regarding URL Rewrite v2.1 features, and it says that there is a new flag that can be used to disable this behaviour, but I have no clue on how or where to set it.

In URL Rewrite versions prior to v7.1.1980, when one tries to use UNENCODED_URL, URL Rewrite will encode it which may lead to double encoding if the original URL was already encoded This is in violation of section 2.4 of RFC3986, which says "Implementations must not percent-encode or decode the same string more than once, as decoding an already decoded string might lead to misinterpreting a percent data octet as the beginning of a percent-encoding, or vice versa in the case of percent-encoding an already percent-encoded string." It also made the use of UNENCODED_URL impractical, especially in reverse forwarder scenarios with ARR where the backend servers expect the URL to be passed unmodified.

In v7.1.1980, we are adding a feature flag, useOriginalURLEncoding that allows you to turn off this non-compliant URL Encoding when set to true. The default behavior will remain unchanged (useOriginalURLEncoding is true by default).

Does anyone here have any idea of how to do it?

Jorge Martins
  • 321
  • 2
  • 10

2 Answers2

5

I managed to fix the issue, by setting useOriginalURLEncoding = false described in the post I referenced in the question.

To set the flag to go IIS Manager then select Configuration Editor and go to the section system.webServer/rewrite/rules, where you will find the useOriginalURLEncoding flag.

Set the flag to false, and URL Rewrite will no longer encode the URLs when using the {UNENCODED_URL} variable in the rules.

Jorge Martins
  • 321
  • 2
  • 10
0

You can achieve this with UrlEncode function. Change your rule to:

<action type="Rewrite" url="http://localhost:8080/{UrlEncode:{R:1}}" appendQueryString="true" />

UPDATE: Another way to solve the problem

<rule name="Jenkins Rewrite" stopProcessing="true">
   <match url="(.*)" />
   <conditions>
        <add input="{UNENCODED_URL}" pattern="(.*)" />
         <add input="{HTTP_HOST}" pattern=".*jenkins.mydomain.*" />
         <add input="{HTTPS}" pattern="on" />
    </conditions>
    <action type="Rewrite" url="http://localhost:8080{C:1}" appendQueryString="true" />
   <serverVariables>
     <set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
     <set name="HTTP_X_FORWARDED_SCHEMA" value="https" />
     <set name="HTTP_X_FORWARDED_PROTO" value="https" />
   </serverVariables>
 </rule>
Victor Leontyev
  • 8,488
  • 2
  • 16
  • 36
  • It doesn't work because the slash characters that were encoded before will not be encoded. If you look closely to the request url you will notice that the last piece is: `/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F` where: `%2F = /` – Jorge Martins Nov 07 '17 at 09:56
  • Hmm, I can't find any difference. Can you please try to change `Rewrite` word to `Redirect` and compare that result has problem with `/` – Victor Leontyev Nov 07 '17 at 10:51
  • The Redirect has the same issue as before. I edited the question. The real issue is that the encoded slash characters are belong to a parameter and not to a page in Jenkins. – Jorge Martins Nov 07 '17 at 14:59
  • Ok, maybe it is also better to include in your question the expected result. What you want to achieve – Victor Leontyev Nov 07 '17 at 15:43
  • The goal is to get exactly the same URL that the browser sent but pointing to localhost:8080. I just updated the question whith that information. – Jorge Martins Nov 07 '17 at 15:52
  • I've found another alternative solution as well. Please check my answer. But your is better – Victor Leontyev Nov 07 '17 at 16:41