URL Rewrite redirection based on PostAuthenticate results - c#

Using Url Rewrite module, I want to drive a rewrite based upon some value retrieved during a custom authentication process.
During the PostAuthenticateRequest I attempt to set the HTTP header with HttpContext.Current.Request.Headers.Add("name", "value"); which is visible on the request object before it leaves the HTTPModule.
However in the URL Rewrite, a very basic condition fails since there's no text under the HTTP_name.
<rule name="customrule" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_name}" pattern=".+" /> <!-- doesn't work -->
<!-- <add input="{HTTP_name}" pattern=".*" /> works -->
</conditions>
<action type="Rewrite" url="https://someotherdomain/{R:0}" />
</rule>
Changing the pattern on the condition to .* lets the rule pass but the URL comes out as https:///{R:0}. If I manually add the name Header before requesting the resource from the server it is able to find data. Unfortunately I don't have the data on the until after a request is made.
Can I use headers across the IIS modules? How can I get the value from the PostAuthenticate to the URL Rewrite?

Per this blog http://blogs.iis.net/wonyoo/relationship-between-application-request-routing-and-url-rewrite-modules the ARR implementation occurs at some point after the URL Rewrite and is the actual proxy for external servers.
As I understand it, the Url Rewrite module pulls the headers early on in the request pipeline. As such the Url Rewrite module wouldn't have access to the headers. The pipeline continues to execute through Authentication & PostAuthentication and eventually hands over to Application Request Routing the responsibility to be the proxy.

Related

Replace one word of domain URL in IIS

I moved my project to a new server (from abc.com/eco to abc2.com/eco) and created a HTTP redirect rule to redirect every abc.com/eco requests to abc2.com/eco. which works fine on abc.com/eco requests.
The problem is, Urls after eco does not get redirected.
For example:
abc.com/eco/departments/main.aspx?id=123
does not redirect to
abc2.com/eco/departments/main.aspx?id=123
The following Url rewrite rule doesnt work also:
<rule name="Redirects to abc2.com" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^abc.*(com|net)$" />
</conditions>
<action type="Redirect" url="http://abc2.com/{R:0}" />
</rule>
I looked over tens of questions but all are asking about the subdirectory replace.
Similar questions but not answering mine:
Question 1
Question 2
The rule is working properly on my side.
Have you cleaned cache before testing a new rewrite rule with long term permanent redirect.
If you didn't clean the browser cache, your previous HTTP redirection will keep redirecting your URL to http://abc2/eco

IIS Rewrite rule with Angular routing

I am building an application that is an ASP.NET MVC and Angular 1.x hybrid. I use MVC as a shell and then layered Angular on top of it. I did this for a couple of reasons. First, it provided me with the ability to create an HTML helper class for script references to support cache busting. Second, it allows me to "push" a set of server side configurations to angular for things like web service URLs, etc. All of this seems to be working ok except for a single issue.
Currently, I am having to process a couple of IIS rewrite rules to make all of this work properly. In testing in a staged environment today, I published a link to Facebook that does not appear to work properly though and I'm not really sure why. Based on my understanding of the rule syntax, I thought it would work, but isn't.
Here are the IIS rewrite rules I currently have in web.config and why I have each rule:
<system.webServer>
<rewrite xdt:Transform="Replace">
<rules>
<rule name="cachebust">
<match url="([\S]+)(/v-[0-9]+/)([\S]+)" />
<action type="Rewrite" url="{R:1}/{R:3}" />
</rule>
<rule name="baseindex" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
<rule name="non-www" stopProcessing="true">
<match url="(.*)" negate="false"></match>
<conditions>
<add input="{HTTP_HOST}" pattern="^exampledomain\.org$" negate="true"></add>
</conditions>
<action type="Redirect" url="http://exampledomain.org/{R:1}"></action>
</rule>
</rules>
</rewrite>
</system.webServer>
1) The "cachebust" rule is used for script cache busting. The HTML helper I wrote takes the path of the script file and inserts a fake version # into the path. For example, "scripts/example.js" would become "scripts/v-123456789/example.js", where "123456789" are the ticks from the current date and time. This rule will rewrite the URL back to the original but since the page is output with the version stamped path, it will force my angular scripts to be reloaded by the browser in the event that they change. This rule appears to be working fine. Credit to Mads for this: https://madskristensen.net/blog/cache-busting-in-aspnet/
2) The "baseindex" rule is used to rewrite the URL so that ASP.NET will always serve the index.cshtml page that is used as the root for my site. This rule also appears to work fine. Credit to this SO QA: How do I configure IIS for URL Rewriting an AngularJS application in HTML5 mode?
3) The "non-www" rule is the problematic one. The goal of the rule is to redirect all www requests to non-www requests based on ScottGu's blog post (link below) about canonical host names and how they affect SEO. This rule works perfectly fine for www.example.org as it redirects the URL to example.org, but it fails when the URL looks like this: www.example.org/entity/1 where entity is a detail page for id = 1. In practice, it fails for www.example.org/about too.
Since my web services require CORS to be enabled as they are on separate domains, this also needs to happen for that.
https://weblogs.asp.net/scottgu/tip-trick-fix-common-seo-problems-using-the-url-rewrite-extension
For sake of completeness: HTML 5 mode is enabled for Angular and my route to the specified page is defined as such:
.state('entityDetail', {
url: '/entity/{id}',
templateUrl: 'app/pages/entity/entityDetail.html',
controller: 'entityDetailController',
controllerAs: 'entityDetailCtrl'
})
Also, my _Layout.cshtml contains the base href of:
<base href="/" />
and script references like such (except for the angular scripts that require the cachebust rule listed above):
<script type="text/javascript" src="scripts/jquery-2.2.0.min.js"></script>
I've tried several different versions of the rule, but they all lead to different issues. Since there are so many different things at play here, I am concerned that I am overlooking something or that I am wrong in my thinking on how this "should" work.
Any help would be greatly appreciated.
It took some trial and error to figure this all out, but wanted to post the answer I finally came up with in the event that someone else ever tries to marry ASP.NET MVC and Angular 1.x together while allowing cache busting in Google Chrome.
It turned out to be a couple of things:
1) The order of the rules.
2) The stopProcessing flag and when it should be enabled.
In summary, to get this to work, I built the rules so that all requests must be redirected to www.exampledomain.com and then stop processing rules until the reprocessed request happens (this time www. will be guaranteed). Then, the cachebust rule must happen BEFORE the rewrite to the base index of "/", otherwise, the entire HTML document is returned by the server when each of the script files that must be "busted" load. This was really the majority of my issue from the very beginning. The whole process was honestly a little confusing so if this answer is not sufficient, please comment and I will try my best to better articulate the "whys" I found in my research. Hope this helps someone else though...it only took 10 days to figure out. :)
<system.webServer>
<rewrite xdt:Transform="Replace">
<rules>
<rule name="forcewww" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^exampledomain.com$" />
</conditions>
<action type="Redirect" url="http://www.exampledomain.com/{R:0}" />
</rule>
<rule name="cachebust">
<match url="([\S]+)(/v-[0-9]+/)([\S]+)" />
<action type="Rewrite" url="{R:1}/{R:3}" />
</rule>
<rule name="baseindex">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
Instead of writing redirect rules in an app.config file, you can use the following in your Program.cs file:
var builder = WebApplication.CreateBuilder(args); // Followed by service configurations...
var app = builder.Build(); // followed by app configurations...
// The following will fix your redirect woes:
app.UseStaticFiles();
app.MapFallbackToFile("index.html");

How to rewrite a URL without leaving the current page in C#?

I want to Re-write my URL without leaving the current.
I find large number of post related to URL Re-writing, but i did'n get success.
I want if user enter this URL -
http://localhost:16185/Company/CareerWebsite.aspx?org_name=hire-people
URL automatically convert into this format -
http://localhost:16185/hire-people
but the original page (Company/CareerWebsite.aspx?org_name=hire-people) does not leave.
Means, user did't see the original URL(Company/CareerWebsite.aspx?org_name=hire-people) in browser. User can only see virtual URL like /hire-people.
Thanks for help...!!!
Well, if you want to do it directly same way as you described you need to do Redirect 301 or 302. For url-rewriting you'l probably need to install urlRewrite module for iis.
So far you'l need some kind of following url-rewrite rule in web.config file:
<rule name="RedirectUserFriendlyURL1" stopProcessing="true">
<match url="^Company/CareerWebsite\.aspx$" />
<conditions>
<add input="{QUERY_STRING}" pattern="^org_name=([^=&]+)$" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" />
</rule>

MVC4 Bundling Cache Headers

I want to change the cache headers sent from a bundle request. Currently it is varying by User-Agent but I don't want it to, is there a way to change the headers sent by a bundle request?
After a quick look in the System.Web.Optimization assembly I can see the headers get set in Bundle.SetHeaders which is a private static function so I don't think its possible although I would love to be proven wrong.
This isn't something that we currently expose today. We only expose the Cacheability property on the BundleResponse that a IBundleTransform could change. And yes we explicitly set the following things:
HttpCachePolicyBase cachePolicy = context.HttpContext.Response.Cache;
cachePolicy.SetCacheability(bundleResponse.Cacheability);
cachePolicy.SetOmitVaryStar(true);
cachePolicy.SetExpires(DateTime.Now.AddYears(1));
cachePolicy.SetValidUntilExpires(true);
cachePolicy.SetLastModified(DateTime.Now);
cachePolicy.VaryByHeaders["User-Agent"] = true;
We have a work item our backlog to open this up and make this more extensible/customizable in the future.
There is a workaround around it as mentioned in janv8000's comment on this response. You need to add the following URL rewrite rule to your web server:
<system.webServer>
<rewrite>
<outboundRules>
<rule name="Cache Bundles" preCondition="IsBundles" patternSyntax="ExactMatch">
<match serverVariable="RESPONSE_Vary" pattern="User-Agent" />
<action type="Rewrite" value="Accept-Encoding" />
</rule>
<preConditions>
<preCondition name="IsBundles" patternSyntax="Wildcard">
<add input="{URL}" pattern="*/bundles/*" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
Obviously you need to pay attention to have all your bundles in your bundles folder or change the IsBundles precondition accordingly.

How to redirect with "www" URL's to without "www" URL's or vice-versa?

I am using ASP.NET 2.0 C#. I want to redirect all request for my web app with "www" to without "www"
www.example.com to example.com
Or
example.com to www.example.com
Stackoverflow.com is already doing this, I know there is a premade mechanism in PHP (.htaccess) file. But how to do it in asp.net ?
Thanks
There's a Stackoverflow blog post about this.
https://blog.stackoverflow.com/2008/06/dropping-the-www-prefix/
Quoting Jeff:
Here’s the IIS7 rule to remove the WWW
prefix from all incoming URLs. Cut and
paste this XML fragment into your
web.config file under
<system.webServer> / <rewrite> / <rules>
<rule name="Remove WWW prefix" >
<match url="(.*)" ignoreCase="true" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.domain\.com" />
</conditions>
<action type="Redirect" url="http://domain.com/{R:1}"
redirectType="Permanent" />
</rule>
Or, if you prefer to use the www
prefix, you can do that too:
<rule name="Add WWW prefix" >
<match url="(.*)" ignoreCase="true" />
<conditions>
<add input="{HTTP_HOST}" pattern="^domain\.com" />
</conditions>
<action type="Redirect" url="http://www.domain.com/{R:1}"
redirectType="Permanent" />
</rule>
I've gone with the following solution in the past when I've not been able to modify IIS settings.
Either in an HTTPModule (probably cleanest), or global.asax.cs in Application_BeginRequest or in some BasePage type event, such as OnInit I perform a check against the requested url, with a known string I wish to be using:
public class SeoUrls : IHttpModule
{
#region IHttpModule Members
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
}
public void Dispose()
{
}
#endregion
private void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
HttpContext ctx = ((HttpApplication) sender).Context;
IHttpHandler handler = ctx.Handler;
// Only worry about redirecting pages at this point
// static files might be coming from a different domain
if (handler is Page)
{
if (Ctx.Request.Url.Host != WebConfigurationManager.AppSettings["FullHost"])
{
UriBuilder uri = new UriBuilder(ctx.Request.Url);
uri.Host = WebConfigurationManager.AppSettings["FullHost"];
// Perform a permanent redirect - I've generally implemented this as an
// extension method so I can use Response.PermanentRedirect(uri)
// but expanded here for obviousness:
response.AddHeader("Location", uri);
response.StatusCode = 301;
response.StatusDescription = "Moved Permanently";
response.End();
}
}
}
}
Then register the class in your web.config:
<httpModules>
[...]
<add type="[Namespace.]SeoUrls, [AssemblyName], [Version=x.x.x.x, Culture=neutral, PublicKeyToken=933d439bb833333a]" name="SeoUrls"/>
</httpModules>
This method works quite well for us.
The accepted answer works for a single URL or just a few, but my application serves hundreds of domain names (there are far too many URLs to manually enter).
Here is my IIS7 URL Rewrite Module rule (the action type here is actually a 301 redirect, not a "rewrite"). Works great:
<rule name="Add WWW prefix" >
<match url="(.*)" ignoreCase="true" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\.(.+)$" />
</conditions>
<action type="Redirect" url="http://www.{HTTP_HOST}/{R:1}"
appendQueryString="true" redirectType="Permanent" />
</rule>
In order to answer this question, we must first recall the definition of WWW:
World Wide Web:
n. Abbr. WWW
The complete set of documents residing on all Internet servers that use the HTTP protocol, accessible to users via a simple point-and-click system.
n : a collection of internet sites that offer text and graphics and sound and animation resources through the hypertext transfer protocol.
By default, all popular Web browsers assume the HTTP protocol. In doing so, the software prepends the 'http://' onto the requested URL and automatically connect to the HTTP server on port 80. Why then do many servers require their websites to communicate through the www subdomain? Mail servers do not require you to send emails to recipient#mail.domain.com. Likewise, web servers should allow access to their pages though the main domain unless a particular subdomain is required.
Succinctly, use of the www subdomain is redundant and time consuming to communicate. The internet, media, and society are all better off without it.
Using the links at the top of the page, you may view recently validated domains as well as submit domains for real-time validation.
Apache Webserver:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
Windows Server/IIS:
There is no way.
You can use Url Rewriter from Code Plex. With the same syntax.
RewriteCond %{HTTP_HOST} !^(www).*$ [NC]
RewriteRule ^(.*)$ http://www.%1$1 [R=301]
Source
This is usually handled by your web server directly in the configuration. As you mentioned, the .htaccess file does this for the Apache web server -- it has nothing to do with PHP. Since you're using ASP, it's a near certainty your server is IIS. I know there is a way to set up this direct with IIS, but I don't know what it is. You may be aided in your search by knowing you should be googling for things related to "IIS redirect", not "ASP redirect".
That said, you CAN do it in PHP, and almost certainly ASP as well, but you'll have to have hitting any URL at the wrong domain invoke an ASP script that performs the redirect operation (using appropriate API calls or by setting headers directly). This will necessitate some URL rewriting or somesuch on the part of the server so that all URLs on the wrong host are handled by your script... just do it directly at the server in the first place :)
We did this on IIS 6 quite simply.
We essentially created a second virtual server that had nothing on it than a custom 404 page .aspx page.
This page caught any requests for WHATEVERSERVER.com/whateverpage.aspx and redirected to the real server by changing the URL to be www.whateverserver.com/whateverpage.aspx.
Pretty simple to setup, and has the advantage that it will work with any domains that come in to it (if you have multiple domains for instance) without having to setup additional rules for each one. So any requests for www.myoldserver.com/xxx will also get redirected to www.whateverserver.com/xxx
In IIS 7, all this can be done with the URL writing component, but we prefer to keep the redirects off on this virtual server.
In case you are using IIS 7, simply navigate to URL rewrite and add the canonical domain name rule.
P.S. Its to make sure that you get redirected from domain.com to www.domain.com
This version will:
Maintain the http/https of the incoming request.
Support various hosts in case you need that (e.g. a multi-tenant app that differentiates tenant by domain).
<rule name="Redirect to www" stopProcessing="true">
<match url="(.*)" />
<conditions trackAllCaptures="true">
<add input="{CACHE_URL}" pattern="^(.+)://" />
<add input="{HTTP_HOST}" negate="true" pattern="^www\.(.+)$" />
</conditions>
<action type="Redirect" url="{C:1}://www.{HTTP_HOST}/{R:1}" />
</rule>

Categories