Rewriting custom tag attributes using IIS Url Rewrite 2.0 and ARR - iis

I've developed a custom grid control that uses data-* attributes to configure how the grid is supposed to work (in a similar vein to how Bootstrap data API components work. For a particular deployment, I'm having to proxy my web application into another web application using IIS and Application Request Routing (ARR) + URL Rewrite. The proxying part is all done, I'm currently trying to configure the outbound rules for rewriting urls to match. For instance, I currently have rules set up such as:
Rewrite HTTP redirects by updating the Location: header.
Rewrite Html content for URIs in standard tags (e.g., A, Area, base, etc.)
Rewrite Css content for URI's that are relative (e.g. /cassette.axd -> /blog/cassette.axd).
The last issue I am having, is getting the URL rewrite module to accept my urls in data attributes, e.g., if my grid is such like:
<table data-grid data-query="/api/users/">
Should be rewritten as
<table data-grid data-query="/blog/api/users/">
I stress that all other tags, such as <a href and <img src work as expected and even a custom <property value tag is correctly rewritten. Just seems to by hypenated attributes.
I've tried adding a <customTags> section, with my custom tags in:
<customTags>
<tags name="Bootgrid">
<tag name="table" attribute="data-query" />
<tag name="table" attribute="data-update" />
<!-- This next tag WORKS -->
<tag name="property" attribute="value" />
</tags>
</customTags>
However, the above is not matching any attributes that have a hyphen. Not sure if this is actually solvable or not because I can't see anything in IIS configuration to set these.
Also annoyingly once you've created a set of Custom Tags in IIS, you can't seem to edit them again. :-/

I had the same issue, and it appears (although not confirmed by Microsoft) that IIS cannot handle a custom tag that contains a -
A work around that worked for me was to use another outbound Rule. In this example I am attempting to replace the data-zoom-image attribute within an img tag (You will need to replace the <img with <table and data-zoom-image with data-query in both the "match" and "action"
<rule name="RewriteRelativePathsCustomTags1" preCondition="IsHtml" enabled="true">
<match filterByTags="None" pattern="<img ([^>]*)data-zoom-image="(.*?)"([^>]*)>" />
<action type="Rewrite" value="<img {R:1}data-zoom-image=&quotYOUR VALUE TO REWRITE i.e /blog{R:2}"{R:3}>" />
</rule>
<preConditions>
<preCondition name="IsHtml">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
Hope this helps

ARR on IIS seems to have issues with tags that include attributes with a dash (-) in them.
Updating to v3.0.1952 seems to have solved the issue for me, but I'm still investigating.

Rather belated, but this was fixed back in 2015 in the Release To Web version (2.0.1952):
IMPORTANT - Changes in this release
Windows 10 and Windows Server 2016 Support - It is now possible to install URL Rewrite Module 2.0 on Windows 10 or Windows Server 2016 with this release
Custom attributes containing dashes are now supported. This is required as HTML 5 has the following rules for determining HTML attribute names: http://www.w3.org/TR/html-markup/syntax.html#syntax-attributes
Incorporates Hotfix for URL Rewrite 2.0 (June 2014) as in KB2974666

Related

Applying different Content Security Policies to different directories with NWebSec

I've got an ASP.NET MVC website with a heavily customised Umbraco 6 backend as the site's CMS.
I've been upgrading the content security policy (CSP) headers all across the site, which I am doing by use of NWebsec, and the website now happily uses CSP 3 strict-dynamic and there are nonces on every script tag, and everything works fine.
Unfortunately, I haven't been able to apply the same changes to the Umbraco admin area, so most of that does not work at all.
So what I want to do is apply the strict CSP 3 policy to the public-accessible parts of the website, and apply a relaxed CSP policy to the locked-down admin area.
The Umbraco admin area sits under a subdirectory /umbraco/ so I thought the best way to implement this would be to use two different location elements in the site's Web.config file.
So my Web.config now looks something like:
<!-- Specific CSP for Umbraco -->
<location path="~/umbraco">
<nwebsec>
...
<content-Security-Policy enabled="true">
...
<script-src self="true" unsafeInline="true" unsafeEval="true">
<add source="data:" />
</script-src>
...
</content-Security-Policy>
</nwebsec>
</location>
<!-- default CSP for everything else -->
<location path=".">
<nwebsec>
...
<content-Security-Policy enabled="true">
...
<script-src self="true" unsafeInline="true" unsafeEval="false" strictDynamic="true">
</script-src>
...
</content-Security-Policy>
</nwebsec>
</location>
But this applies the default config to the whole site.
I'm not sure whether I've got the config wrong, or maybe NWebSec doesn't support what I'm trying to do, or there's some specific issue with redirects or something else.
Fixed by creating a separate Web.config in the /umbraco subdirectory.
Main Web.config:
<location path="." allowOverride="true">
<nwebsec>
...
<content-Security-Policy enabled="true">
...
<script-src self="false" unsafeInline="true" unsafeEval="false" strictDynamic="true">
<add source="www.example.com" />
</script-src>
...
</content-Security-Policy>
</nwebsec>
</location>
Web.config in the /umbraco subdirectory:
<location path="." allowOverride="true">
<nwebsec>
...
<content-Security-Policy enabled="true">
...
<script-src self="true" unsafeInline="true" unsafeEval="true" strictDynamic="false">
<clear/>
<add source="www.other-example.com" />
</script-src>
...
</content-Security-Policy>
</nwebsec>
</location>
The config in the subdirectory overrides the main Web.config - so strictDynamic="false" switches off use of those CSP3 nonces, and the clear element removes all pre-existing elements in the collection so a new set of domains can be used.

Match the content within a tag from a Non-HTML response in URL Rewrite

When going through a proxy server (A), any self-referential links sent from the apps server (B) need to be re-written to use the proxy as a host instead.
Here's an example:
Response from (B) contains: path
Proxy (A) needs to rewrite as: path
Normally, this is done by creating an outbound rule that inspects html responses for tags that contain urls, looks for references to to the apps server, and rewrites them.
Here's a normal rule GUI version:
<outboundRules>
<rule name="Outbound Links" preCondition="IsHTML" enabled="true">
<match filterByTags="A, Form, IFrame, Img, Input, Link, Script" pattern="(https?:\/\/proxy|^)\/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
<action type="Rewrite" value="http://apps/{R:2}" />
</rule>
Where IsHTML is defined as:
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="text\/html" />
</preCondition>
The problem is that some of the page content is returned via an XHR request. Minimally, this fails the HTML precondition.
but I can expand the rule to also include content types of xhr
However, URL Rewrite still has trouble parsing the returned text into tags because it is not valid HTML.
Here's an example of what the response looks like:
|6383|updatePanel|ctl00_mainContentPlaceHolder_contentUpdatePanel|
<div id="ctl00_mainContentPlaceHolder_resultsPanel">
path
</div>
...
|0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||0|hiddenField|
However, when I do this, I get the error:
Sys.WebForms.PageRequestManagerParserErrorException:
The message received from the server could not be parsed.
You cannot modify XHR requests coming back from the ASP.NET. Doing so would be to attempt a Man In The Middle Attack (which your proxy is acting as), but Microsoft has good reason to prevent.
Here's a dummy message to explore the syntax ASP.NET uses in the response:
1|#||2|52|updatePanel|ctl00_mainContentPlaceHolder_firstUpdatePanel|
<p> New Content For First Update Panel </p>
The header starts with 1|#| | and then the number of updates in the rest of the message (2)
Then each update section follows the pattern:
|char_len|update_type|id_of_field_to_update|
New contents to insert into field
The len in each section must exactly equal the number of characters to follow. So finding and replacing content in these messages is extremely fickle.
The best recommendation is to simply return a relative URL that is server agnostic so the client can be redirected relative to their current domain.

Importing google polymer in Orchard cms

I am trying below
RegisterLink(new LinkEntry { Rel = "import", Href = Url.Content("~/Themes/SomeTheme/components/font-roboto/roboto.html") });
in my orchid layout, for using polymer. however this request is throwing a 404(on network tab in chrome.).
I am very much new to Orchid cms and hence struggling with this. Any help on this.
Note: I found that I have a class ResourceManager which implements IResourceManager. I am not sure if this is where I need to do make some changes. So adding this note as well.
Thanks
You need to place a web.config inside Themes/SomeTheme/components folder (same as ThemeMachine/Styles) making one modification:
<handlers accessPolicy="Script,Read">
<add name="StaticFileHandler" path="*" verb="*" modules="StaticFileModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
</handlers>
Remove (if existing) all web.config files in children folders.
You really need a web server to host polymer assets unless you disable web security. It can be any web server server. In addition, the ~ directive probably wouldn't be recognized by chrome file loader.

IIS File Download without Extension

I've got a .NET Web API 2 application, I've hooked up the api to send me a file id and from there I get the unique file from the server.
Example:
Download
I need it to be a unique id since there could be multiples of the file in the repo. However, when I try to click the download button I get a :
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
I was thinking a re-write rule might be a good action, but I dont really want to rewrite it, i just want to allow anything /api/attachment no matter what the rest.
I've already got one rewrite rule since my page is a single-page-application to direct responses to the Default.cshtml like:
<rewrite>
<rules>
<rule name="Default" stopProcessing="true">
<match url="^(?!Lib|api|Assets|Views|Directives|Services|Controllers|signalr).*" />
<action type="Rewrite" url="Default.cshtml" />
</rule>
</rules>
</rewrite>
any thoughts on best way to achieve this?
I was able to resolve by creating an iframe and setting the src to the download like:
$("body").append('<iframe name="downloadFrame" id="download_iFrame" style="display:none;" src="" />');
and then in the C# I set the header like:
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");

Is it possible to get the current machine name in IIS 7.5 Url Rewrite Module Rules?

The HTTP_HOST and SERVER_NAME server variables give me the host name from the HTTP request (which can be an IP address or the load-balanced DNS based on how the request was made). I could not find a server variable that will give me actual machine name (i.e., the value of the COMPUTERNAME environment variable).
I am trying to set-up some redirection rules on a server-farm and there are some rules based on what the current machine name is (e.g., internal machines have int in their name). I don't want to create separate rules for each machine, and instead want to have some conditional logic based on the current machine name. I cannot seem to find a way to get hold of the machine name.
Any ideas?
In IIS7 The computer name isn't one of the built-in server variables. However all is not lost, with a bit of work using a custom UrlRewrite provider you can surface your machine name in a rewrite rule.
Scott Forsyth has actually built something like this already and has written a blog post describing its use, and provided the source and a pre-built binary + installer:
URLRewrite ServerNameVariable Provider
For the sake of preserving this information in the event of that article disappearing here are loosely the steps:
Start by creating a new class library project in Visual Studio. You can find the steps to do this here:
Developing a Custom Rewrite Provider for URL Rewrite Module (IIS.NET)
They are in essence (in case the link dies):
Create a Class Library project and call it something like ServerNameProvider. You need to make sure the project is a .NET 2.0 or 3.5 project. IIS7.5 managed code support still targets the 2.0 runtime.
Rename the default Class1.cs file to a name that reflects the provider purpose, for example: ServerName.cs - and just make sure the class name in the source reflects this as well.
Add a reference to: %ProgramFiles%\Reference Assemblies\Microsoft\IIS\Microsoft.Web.Iis.Rewrite.dll.
In the project properties create a strong name key (on the signing tab)
Add a post-build event to install the provider assembly in your dev PC GAC (just for testing):
CALL "%VS90COMNTOOLS%\vsvars32.bat" > NULL
gacutil.exe /if "$(TargetPath)"
Note, if using Visual Studio 2010 then the environment variable %VS90COMNTOOLS% should be changed to %VS100COMNTOOLS%.
Open up the ServerName.cs file and make sure your class implements the Microsoft.Web.Iis.Rewrite.IRewriteProvider interface:
using System.Collections.Generic;
using Microsoft.Web.Iis.Rewrite;
namespace ServerNameVariable
{
public class ServerName : IRewriteProvider
{
public void Initialize(IDictionary<string, string> settings,
IRewriteContext rewriteContext)
{
}
public string Rewrite(string value)
{
return System.Environment.MachineName;
}
}
}
Build the project. On your local PC the assembly will be installed into the GAC.
Register the provider with IIS:
appcmd.exe set config -section:system.webServer/rewrite/providers /+"[name='ServerNameVariable',type='ServerNameVariable.ServerName, ServerNameVariable, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5854ff76fb5c07af']" /commit:apphost
Make sure the PublicKeyToken value in the command line above matches your assembly's public key token. You can extract that value by doing sn.exe -T <assemblyfile.dll>, for example:
e:\AppDev\..bin\Debug> sn.exe -T ServerNameVariable.dll
Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
Public key token is 5854ff76fb5c07af
The next thing to do is use your new provider in a rewrite rule, for example, here's the example Scott gave which is an outbound rule:
<outboundRules>
<rule name="Set Custom Header" enabled="true">
<match serverVariable="RESPONSE_X_Machine_Name" pattern=".*" />
<action type="Rewrite" value="{ServerNameVariable:}" />
</rule>
</outboundRules>
And here's a simple inbound rule that redirects to google.com if the machine name is BOB:
<rewrite>
<rules>
<rule name="TestServerVariableProvider"
enabled="true"
stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{ServerNameVariable:}" pattern="BOB" />
</conditions>
<action type="Redirect"
url="http://google.com"
appendQueryString="false"
redirectType="Found" />
</rule>
</rules>
</rewrite>

Resources