IIS Rewrite Rule is not setting HTTP_COOKIE - iis

I'm working with a client who has a mobile site setup through a third party. Currently, we check through IIS whether a user agent matches any of your standard mobile agents in which case we redirect the user to the mobile version m.whatever.com.
One of the rules we have requires us to set the cookie to a value of 0 when the user wants to see the mobile site again.
<rules>
<rule name="if httpcookie is , set it to 0" stopProcessing="true">
<match url="^(.*)$" />
<conditions>
<add input="{HTTP_COOKIE}" pattern="mobileoptout=1" />
</conditions>
<serverVariables>
<set name="HTTP_COOKIE" value="mobileoptout=0" />
</serverVariables>
<action type="None" />
</rule>
</rules>
As per the above, we're matching on the URL and the cookie value. I have tested these independently and they work as expected. However, at the end of this rule, the value for the cookie MobileOptOut is still 1 and not 0.
I've searched and tried all the examples available on numerous sites but have been completely unable to understand why the value of the cookie is not being changed.
The domain for the cookie is [whatever.com] which is the same as www.whatever.com and based on previous tests it can read from the cookie to validate a condition.
Any ideas?
Including an additional attempt which does not work either:
<rules>
<rule name="set cookie">
<match url="(.*)" />
<serverVariables>
<set name="HTTP_COOKIE" value="optout=1" />
<set name="{HTTP_COOKIE}" value="optout=2" />
</serverVariables>
<action type="None" />
</rule>
</rules>

Thanks to #cheesemacfly I looked into using the outbound rules, which for some reason I completely overlooked.
The solution uses a single inbound rule to check two conditions.
<rule name="MobileOptOut=1 Stop Processing Rules" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="mobileoptout=1" />
<add input="{HTTP_COOKIE}" pattern="MobileOptOut=1" />
</conditions>
<action type="None" />
</rule>
This will handle the first request with the querystring and all subsequent requests with the cookie that will be created after this rule finishes.
The outbound rule is as follows:
<outboundRules>
<rule name="if querystring=1" preCondition="If mobileoptout query = 1">
<match serverVariable="RESPONSE_Set_Cookie" pattern="." />
<action type="Rewrite" value="mobileoptout=1; Domain=site.local; Path=/;" />
</rule>
<preConditions>
<preCondition name="If mobileoptout query = 1">
<add input="{QUERY_STRING}" pattern="mobileoptout=1" />
</preCondition>
</preConditions>
</outboundRules>
This will check that first condition of if querystring is mobileoptout=1. If true, it will set a cookie in the response named 'mobileoptout' with a value of 1 in the root domain that will expire with the session.
This is exactly what I was overlooking.

First, to make sure your rule can work, you have to setup the allowed server variables.
To do so, in the iis manager, under the URL Rewrite section, click on View Server Variables...:
You then can add a new variable by clicking Add... on the right.
In your case, you want to add HTTP_COOKIE:
From here, your rule (as following) should be working:
<rules>
<rule name="if httpcookie is , set it to 0" stopProcessing="true">
<match url="^(.*)$" />
<conditions>
<add input="{HTTP_COOKIE}" pattern="mobileoptout=1" />
</conditions>
<serverVariables>
<set name="HTTP_COOKIE" value="mobileoptout=0" />
</serverVariables>
<action type="None" />
</rule>
</rules>
Note that the cookie is rewritten only for the request.
Meaning the client cookies won't be changed but the request hitting the page will have the new cookie values when the rule is triggered.

Related

Keycloak behind IIS Reverse Proxy

I just cant get my reverse proxy to work properly and I hope that someone can help me with that.
A few Informations:
1 VM Windows Server 2019,IIS 10 (with ARR and URL Rewrite Module),"keycloak" App under the "Default Website", proxy-address-forwarding="true" were added in the standalone.xml
keycloak is locally available at "localhost:8080". The default website is available from intern network (Port 80 is open, 8080 is closed). I want to use the IIS as a reverse proxy for keycloak. It should look like the following URL.
Request: "http://server_fqdn/keycloak" -> IIS Reverse Proxy -> localhost:8080
At first I tried it without "/keycloak" and it worked perfectly. After I added "/keycloak" it just shows 404 Errors. I saw that it tries to open "http://server_fqdn/auth" instead of "http://server_fqdn/keycloak/auth". If I enter "/keycloak/auth" manually it works. My first thought was to just write another Blank Inbound Rule which redirects "http://server_fqdn/auth" to "http://server_fqdn/keycloak/auth". It works, but now there is another problem. If i want to enter the admin console I get an error which says "Invalid parameter: redirect_uri".
It stops at the following URL (not complete, but the necessary part is there)
http://server_fqdn/keycloak/auth/realms/master/protocol/openid-connect/auth?client_id=security-admin-console&redirect_uri=http%3A%2F%2Fserver_fqdn%2Fkeycloak%2Fauth%2Fadmin%2Fmaster%2Fconsole%2F&state=.....
If i remove %2Fkeycloak after "redirect_uri" it works and i get the keycloak login screen. Maybe someone can help me here.
Inbound Reverse Proxy Rule:
<rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
<match url="^keycloak/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="http://localhost:8080/{R:1}" />
<serverVariables>
</serverVariables>
</rule>
Outbound Reverse Proxy Rule:
<outboundRules>
<clear />
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1" enabled="true">
<match filterByTags="A, Area, Base, Form, Head, IFrame, Img, Input, Link, Script" pattern="^http://localhost:8080/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true">
</conditions>
<action type="Rewrite" value="http://server_fqdn/keycloak/{R:1}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
Inbound Reverse Proxy Rule:
<rule name="keycloak" enabled="true" stopProcessing="true">
<match url="^auth/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Redirect" url="http://server_fqdn/keycloak/{R:0}" redirectType="Permanent" />
</rule>

Remove Namespace Prefix From MediaWiki URL with IIS10 URL Rewrite

I have a MediaWiki installation hosted in IIS10. I am attempting to use the URL Rewrite module to remove the namespace prefix from some MediaWiki article URLs.
In MediaWiki, articles outside the "Main" namespace show as foo.com/wiki/Namespace:Article_Title
I only need to remove the 'Bar:' Namespace prefix, others can remain intact
Restriction: I am unable to move these articles into the Main namespace
The desired result would present content from foo.com/wiki/Bar:Article_Title but display as foo.com/wiki/Article_Title.
Existing Inbound URL Rewrite
I have one URL rewrite already in place, per Microsoft's doc for MediaWiki on IIS, which removes the query string from the url. Here is my rewrite rule based on that guidance:
<rule name="Clean-WikiArticlePages" stopProcessing="false">
<match url="^wiki/(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="/w/index.php?title={UrlEncode:{R:1}}" />
</rule>
What I've tried so far
I've tried both an Inbound and Outbound rule, to no effect.
Inbound rule:
<rule name="Clean-Namespace" enabled="true">
<match url="^wiki/(Meetings:)(.*)" />
<action type="Rewrite" url="/wiki/{R:2}" />
</rule>
Outbound rule:
<outboundRules>
<rule name="Remove-Namespace" preCondition="IsHTML" enabled="true">
<match filterByTags="A" pattern="^wiki/Bar:(.*)" />
<action type="Rewrite" value="/wiki/{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
I think it is possible to achieve this if you only want to rewrite for Bar.
You want the URL displayed as foo.com/wiki/Article_Title and load content from /wiki/Bar:Article_Title?
Then you should redirect all /wiki/Bar:Article_Title request to foo.com/wiki/Article_Title. Then rewrite foo.com/wiki/Article_Title back to /wiki/Bar:Article_Title request.
But please keep in mind this only work for static namespace. Because the rewritten request unable to get the namespace of original request before redirection.
Not sure if below rules achieve your requirement
When you access
foo.com/wiki/Bar:Article_Title ------redirect----->foo.com/wiki/Article_Title
-------rewrite------> foo.com/wiki/Bar:Article_Title-------rewrite---->foo.com/w/index.php?title=bar%3AArticle_Title
<rule name="redirect" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/wiki/bar:Article_Title$" />
</conditions>
<action type="Redirect" url="wiki/Article_Title" redirectType="Temporary" />
</rule>
<rule name="rewrite">
<match url="^wiki/Article_Title$" />
<action type="Rewrite" url="wiki/bar:Article_Title" />
</rule>
<rule name="Clean-WikiArticlePages" enabled="true" stopProcessing="true">
<match url="^wiki/(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="/w/index.php?title={UrlEncode:{R:1}}" />
</rule>

IIS Rewrite IP:Port to {domain}/{thing}

What I'm trying to do:
I own a domain, let's say blahblahblah.com
On the server, it points to :80 and :443 properly - this is working
I want to remap so that if a user visits blahblahblah.com/thing1 then it maps to localhost:5000
Similarly, I also want to remap so that if a user visits blahblahblah.com/thing2 then it maps to another server and port on my local network (not exposed to the internet)
I essentially want to use my webserver to communicate with other servers on my network and other ports through "sub directories" or whatever they are called in this instance (site/subdir, site2/subdir). I've been trying to solve this issue for days! I've installed ARR (and enabled the Proxy) and the URL Rewrite modules on my IIS.
I've attempted god knows how many different rewrite templates on SO. I can get partial success, in which the route /thingx/ resolves, but all the resources are referencing blahblahblah.com and (appropriately) can't find the resources for the site at that address.
Current rewrite (resolves some resources at blahblahblah.com/thing1, but others are misrouted):
<rewrite>
<rules>
<rule name="Thing1" enabled="true">
<match url="(thing1*)" />
<action type="Rewrite" url="http://localhost:5000/{R:0}" />
</rule>
</rules>
</rewrite>
EDIT: I've updated my rules to the below, as per this article from Microsoft Docs: Reverse Proxy with URL Rewrite v2 and Application Request Routing . These rewrites supposedly do exactly what I need, but the result is not the same in my case, and I still have no clue why.
<rules>
<rule name="Thing1" enabled="true">
<match url="^thing1/(.*)" />
<action type="Rewrite" url="https://localhost:5000/{R:0}" />
</rule>
</rules>
<outboundRules>
<rule name="Add application prefix" preCondition="IsHTML">
<match filterByTags="A" pattern="^/(.*)" />
<conditions>
<add input="{URL}" pattern="^/(thing1)/.*" />
</conditions>
<action type="Rewrite" value="/{C:1}/{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
More Notes:
localhost:5000 works as expected
localhost/thing1 resolves in 404 Not Found
blahblahblah.com/thing1 resolves in pulling in the default HTML page, but none of the assets (javascript, css, etc), they return 404 Not Found.
EDIT: It may be important to note that these rules have been written into the default site (bound to :80, :443) on IIS' web.config. Writing these rules in C:\Windows\System32\inetsrv\config\applicationHost.config results in a 500.
Any feedback on what I'm doing wrong?
Part of this was due to the way SPAs are handled (# and history mode), but I ended up solving with the below webconfig for IIS, which allows me to nest everything under a /foobar endpoint:
<rewrite>
<rules>
<rule name="Subdirectory Index" stopProcessing="true">
<match url="^foobar/index\.html$" ignoreCase="false" />
<action type="None" />
</rule>
<rule name="Subdirectory Routes" stopProcessing="true">
<match url="." ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="/foobar/index.html" />
</rule>
</rules>
</rewrite>

IIS Rule to Redirect certain paths to another domain

I am looking for help to write a URL rewrite rule for IIS.
I want the rule to ignore the following
ttp://localhost:8080/myapp/somepag.html and serve it from another site running on IIS.
I want to do a URL rewrite on the following
ttp://localhost:8080/theirApp/somepage.html
and serve the content back to the browser as if it came from localhost
I know the second bit can be done, as we use it to "reverse proxy" a Restful web service. What I dont know if if I can set the "theirApp" condition
<rule name="Proxy" stopProcessing="true">
<match url="^theirApp/([0-9]+)/([_0-9a-z-]+)/?$"/>
<action type="Rewrite" url="http://www.theirApp.com/{R:1}" />
<serverVariables>
<set name="HTTP_X_UNPROXIED_URL" value="??????????" />
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
</rule>
I've also tried :
<rule name="all domains to www.domainB.com/my-folder" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^theirApp$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="http://www.theirApp.com/{R:1}" />
</rule>
Where R1 I am thinking is the rest of the URL after the theirApp
Thanks all
Folks,
The problem wasn't the Rewrite rule I was using so much as I had not properly configured the IIS ARR module on Azure this site Use Azure as a Reverse Proxy Helped me out.

Capture part of URL to use in Outbound rule for rewrite module in IIS

Is there a way to capture part of the url in an outbound rule to use as value for the re-write?
Right now, I'm using a precondition, where I have an input with a pattern against the {REQUEST_URI}. I'd like to use a capture group from the request URI in the outbound rule that uses this precondition. I tried {C:1} but that didn't work.
Precondition:
<preCondition name="Html Response" logicalGrouping="MatchAll">
<add input="{REQUEST_URI}" pattern="myapp(.*)" />
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^(text/html)" />
</preCondition>
Outbound rule:
<rule name="ResponseRewriteRelative" preCondition="Html Response" stopProcessing="true">
<match filterByTags="A, Link" pattern="^/(.*)" />
<action type="Rewrite" value="{C:1}/{R:1}" />
</rule>
where {C:1} would be the capture group from precondition "myapp(.*)"
So, it'd go from
http://myapp40.com
to rewrite links in the response to something similar to
40/originalrelativelink
Thanks!
I just found out that you can add a condition to the outbound rule per se. Just answering here in case there's any other clueless person struggling with the rewrite rules :)
Rule would look something like:
<rule name="ResponseRewriteRelative" preCondition="Html Response" stopProcessing="true">
<match filterByTags="A, Link" pattern="^/(.*)" />
<action type="Rewrite" value="{C:1}/{R:1}" />
<conditions>
<add input="{REQUEST_URI}" pattern="myapp(.*)" />
</conditions>
</rule>

Resources