Capturing a Value in a Cookie using URL Rewrite for IIS7 - iis-7

I need to write a URL Rewrite rule for my IIS 7.5 website that captures a value in a particular cookie, and then uses that value to construct a URL. For instance, the incoming requests looks like this:
GET http://myserver.com/test.aspx HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0
Host: myserver.com
Cookie: foo=bar; bat=bar
I'd like to route them to this (based on the "foo" cookie value):
http://myserver.com/bar/test.aspx
fter reviewing the documentation and searching for examples, I'm stumped! Thanks for your help.

Answering my own question, here's a working example. The pattern may need additional work depending on what characters require supporting, but the following rule will will use the discovered cookie value and route to the discovered server--and the server can be specified by IPv4 address or by name (alphanumeric-and-period).
<rule name="Route Base On Cookie" stopProcessing="true">
<match url="^(.*)" />
<conditions>
<add input="{HTTP_COOKIE}" pattern="foo=(.*?);" />
</conditions>
<action type="Rewrite" url="http://{C:1}/{R:0}" />
</rule>

#Geoffrey To make your code support returning any cookie value, I'd recommend this pattern:
<add input="{HTTP_COOKIE}" pattern="foo=(.*?);" />
As a reminder, the {HTTP_COOKIE} value looks like this for example:
Cookie: foo=myexamplevalue; expires=Wed, 03-May-2014 22:31:08 GMT; path=/; HttpOnly\r\n

The following rule will use the discovered cookie value and route to the discovered path:
<rule name="Route Base On Cookie" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_COOKIE}" pattern="^(.+; )?foo=([^;]*)(;.+)?$" />
</conditions>
<action type="Rewrite" url="https://{HTTP_HOST}/{C:2}/{R:0}" />
</rule>
The pattern supports several cookies and doesn't depend on the order of foo in cookie (when it is the last, browser doesn't append ';'):
both foo=bar; bat=bar and bat=bar; foo=bar work fine.
It works correctly when you have another cookie with the same substring such as barfoo.
{C:2} corresponds to the second capture in cookie, i.e. value of foo in pattern="...";
{R:0} corresponds to whole url in <match url="...">. IIS uses path part only without host name, i.e. /test.aspx.
NB. It may be not secure to use value from cookie in path as is. Possibly you should match against the list of expected values (bar|bar2|bar3|bar4).

Related

IIS URL Rewrite for modifying query parameter on outbound redirect response

I'm trying to figure out a way to modify a single query string parameter within the Location header of a HTTP 302 Found (redirect) response.
For example, if the Location header in the response is:
https://example.com/path?param1=a&param2=z&param3=c
I would like it to be rewritten as:
https://example.com/path?param1=a&param2=b&param3=c
Is this possible using an outbound IIS URL Rewrite rule?
According to your description, I suggest you could try to use below url rewrite rule to achieve your requirement.
<outboundRules>
<!-- This rule changes the domain in the HTTP location header for redirection responses -->
<rule name="Change Location Header">
<match serverVariable="RESPONSE_LOCATION" pattern="^https://example.com/path?param1=a&param2=(.+)&param3=c" />
<conditions>
<add input="{RESPONSE_STATUS}" pattern="^301" />
</conditions>
<action type="Rewrite" value="https://example.com/path?param1=a&param2=b&param3=c"/>
</rule>
</outboundRules>

ASP.NET 4 WebApi: route with back slash

I have a WebApi-route api/{type}({id})/{prop}
and I want to call it with url like /api/User(domain\username)/groups - the key point is "\" in id value. I send it from the client url-encoded i.e. as:
api/User(domain%5Cusername)/groups. But the route is ignored and I'm getting 404.
How to pass back slash into a route's argument?
As #ATerry suggested in comments the problem is not with ASP.NET but in HTTP.SYS + IIS. Back-slashes are replaced by HTTP.SYS onto forward-slashes even before coming to IIS.
We can work this around with help of UrlRewrite IIS-module as it has access to original (undecoded) url.
For my example I came up with the following rule.
<rule name="allow backslash" stopProcessing="true">
<match url="api/(.*)\((.*)\)(.*)" />
<action type="Rewrite" url="api/{R:1}({C:1}{C:2}{C:3}){R:3}" logRewrittenUrl="true" />
<conditions>
<add input="{UNENCODED_URL}" pattern="\((.*)(%5C)(.*)\)" />
</conditions>
</rule>
It's not ideal as it's very specific. It'd more useful to have a generic rule which just processes %5C.
The idea is to catch an url with %5C and rewrite it to put it back. It's a little bit weird but it works.
Besides the rule we need to set allowDoubleEscaping=false in system.webServer/security/requestFiltering:
<security>
<requestFiltering allowDoubleEscaping="true">
</requestFiltering>
</security>
With this rule the value come into a Mvc/Api controller will be encoded (with %). So we'll have to decode it:
public virtual DomainResult GetObjectProp(string type, string id, string prop)
{
id = Uri.UnescapeDataString(id);
}

Regex to redirect a url using url rewrite

OK, I'm wondering if someone can lend a hand with a regex I'm trying to write.
Basically, what I want to do is use IIS urlrewrite module to do a redirect to a specific URL if the user accesses a URL on another site. The only catch is I have to also capture a bit of the query string, and move it into the redirect.
so here is the input, the URL that a user may access would look like:
https://of.example.com/sfsv3.aspx?waform=pro&language=en
I want to match that URL (either http or https, case insensitive), and capture from it also one piece of information, the two letter language code. then the url i want to forward the user to looks like:
http://example.com/ca/en/ppf
(where en is replaced by whatever i captured above)
So, I'm working with IIS Rewrite module, and I've gotten my input data and regex in, so far the regex pattern I have is this:
https?://of.example.com/sfsv3.aspx\?waform=pro&(language=(..))
so basically i'm matching the whole string, plus a group and a subgroup for language and it's code. in the IIS test pattern dialog, this is working.
I get the following
{R:1} language=en
{R:2} en
great! so then my IIS rewrite rule should look like this to redirect the user:
<system.webServer>
<rewrite>
<rules>
<rule name="test" stopProcessing="true" enabled="true">
<match url="https?://of.example.com/sfsv3.aspx\?waform=pro&(language=(..))" ignoreCase="true" />
<action type="Redirect" url="http://www.example.com/ca/{R:2}/ppf" />
</rule>
</rules>
</rewrite>
</system.webServer>
this all seems right to me. however, the redirect is not occurring. it seems to have a problem with the part \? (an escaped question mark to mark the start of the query string). if this is included, then the redirect simply does not happen.
Can you help me figure out how to get it work?
for the record, I figured it out. this is a special case of regex, running it inside a web.config as part of a urlrewrite action. in that case, you can't handle the query string with simple regex, you have to put in conditions on the query string. Here's what eventually ended up working:
<system.webServer>
<rewrite>
<rules>
<rule name="redirect" stopProcessing="true" stopProcessing="true" enabled="true">
<match url="sfsv3.aspx\.aspx" ignoreCase="true"/>
<conditions>
<add input="{QUERY_STRING}" pattern="subject=PROPRCH" />
<add input="{QUERY_STRING}" pattern="(..)/subject" />
</conditions>
<action type="Redirect" url="https://www.example.com/ca/{C:1}/forms/ppf" appendQueryString="false"/>
</rule>
</rules>
</rewrite>
</system.webServer>

IIS rewrite rule for basic auth on the querystring

I am trying to automatically log in users to an Xwiki install via basic auth. This is because help is stored in the wiki, but we want the retrieval process to be transparent to the user.
We push the user off to a url (via an <a> tag) like:
http://username:password#xwiki.example.org/xwiki/bin/view/Main?basicauth=1
This works fine in every browser except Internet Explorer (see: http://support.microsoft.com/kb/834489. Unfortunately, 80% of our user base uses Internet Explorer and it is not an option to have them type in the credentials manually.
Currently, we have IIS 7.5 sitting in front of Xwiki and proxying all requests to the Tomcat instance on another server. This works fine. To solve my problem, I thought I could use a IIS rewrite rule to turn a url like this:
http://xwiki.example.org/xwiki/bin/view/Main?basicauth=1&_username=username&_password=password
into this:
http://username:password#xwiki.example.org/xwiki/bin/view/Main?basicauth=1&_username=username&_password=password
The idea being that IIS would substitute the _username/_password querystring parameters into the URL and pass it off to Tomcat, and Xwiki would ignore the extra parameters.
I have created a URL rewrite rule like:
<rule name="BasicAuthRewrite" enabled="true">
<match url="https?://(.+)&?_username=(.+)&_password=(.+)" />
<action type="Rewrite" url="http://{R:2}:{R:3}#xwiki.example.org/{R:1}" />
</rule>
When I go 'Test pattern' in IIS and supply my url, all the backreferences ({R:x}) match up to the data I want. However, when I visit the URL in my browser, the rewrite rule fails to invoke.
Is there any way I can achieve my desired behaviour?
It is possible to do Basic authentication with URL rewrite on IIS. You should add the server variable HTTP_Authorization the value Basic followed by the username:password in base64. Remember to add the variable in the allowed variables
So for the user Aladdin with the password open sesame you the format would be Aladdin:open sesame and base64 encoded QWxhZGRpbjpvcGVuIHNlc2FtZQ==.
Which translates into
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
<rule name="SomeName" stopProcessing="true">
<match url="url/to/match" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="http://www.redirecturl.com/" appendQueryString="true" />
<serverVariables>
<set name="HTTP_Authorization" value="Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" />
</serverVariables>
</rule>
This should do:
<rule name="BasicAuthRewrite" stopProcessing="true">
<match url="(.*)" />
<conditions trackAllCaptures="true">
<add input="{QUERY_STRING}" pattern="basicauth=1&_username=(.+)&_password=(.+)" />
</conditions>
<action type="Rewrite" url="http://{C:1}:{C:2}#xwiki.example.org/{R:1}" appendQueryString="false" />
</rule>
Authorization cannot be delegated to ARR. Therefore, if the contents are highly sensitive in nature and require authorization, it is recommended that you do not enable cache.
ARR
But there is work around solution.
Solution
It appears this is not possible in IIS.

IIS UrlRewriter Outbound rules ignored if PreCondition is set

I have a very simple OutBound UrlRewriter rule that rewrites url's it finds in the body of the http response stream:
<rewrite>
<outboundRules>
<rule name="Scripted"
preCondition="IsHtml"
patternSyntax="ECMAScript"
stopProcessing="false">
<match filterByTags="None" pattern="http://someurl.com" />
<action type="Rewrite" value="http://anotherurl.com" />
</rule>
<preConditions>
<preCondition name="IsHtml" patternSyntax="Wildcard">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
The problem is that as soon as I turn on the preCondition no rewriting takes place.
I need to be able to use a pre-condition because the page is an ASP.NET page and uses ASP.NET script resources e.g. <script src="ScriptResource.axd?d=...." type="text/javascript" />.
By default script resources are gzip compressed and I want to keep them that way. Without the content type precondition the URL rewriter RewriteModule throws a 500.52 error - "Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("gzip")."
Using Fiddler I can see that Content-Type: text/html; charset=utf-8 is being sent in the response header but UrlRwriter seems unable to match this.
Why is this happening?
This is because the Server Variable HTTP_ACCEPT_ENCODING is not added to the allowed server variables list. Add it there (you can google how to in IIS).

Resources