We are currently developing an ASP.NET MVC 5.1 application for deployment to customer sites where we will not control their IIS configuration. The application uses ASP.NET Identity 2.0.0 for authentication and user management. During internal testing we have different instances in virtual directories (as separate applications and under separate application pools) on our test server running Windows Server 2012 R2 with IIS 8.
I have had a bug reported that attempting to login with a URL like -
https://server.domain.com/VirtualDirectory/Account/Login?ReturnUrl=%2fVirtualDirectory
Results in a loop whereby the user is logged in but is redirected back to the login page instead of the application root/home page. The obvious standout point here is the missing trailing slash from the virtual directory name. If an encoded trailing slash is provided, or the returnUrl is omitted or not a local URL, then the application correctly redirects successfully.
This is not an issue with our login logic as a user who is already logged in and at the root of the application will be redirected back to the login page simply by removing the trailing slash after the virtual directory name to leave-
According to IIS generates courtesy redirect when folder without trailing slash is requested-
"When a browser requests a URL such as http://www.servername.de/SubDir, the browser is redirected to http://www.servername.de/SubDir/. A trailing slash is included at the end of the URL... Internet Information Server (IIS) first treats SubDir as a file that it should give back to the browser. If this file cannot be found, IIS checks to see if there is a directory with this name. If a directory with this name exists, a courtesy redirect with a 302 "Object moved" response message is returned to the browser. This message also contains the information about the new location of the directory with the trailing slash. In turn, the browser starts a new GET request to the URL with the trailing slash."
I am in fact though getting the following response from Fiddler-
GET https://server.domain.com/VirtualDirectory
302 Redirect to /VirtualDirectory/Account/Login?ReturnUrl=%2fVirtualDirectory
The default route is unmodified from the Microsoft templates-
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The home controller is decorated with an [Authorize] attribute which would of course require an unauthenticated user to login.
The Web.config settings pertinent to authentication are-
<authentication mode="None">
<forms cookieless="UseCookies" loginUrl="~/Account/Login" name="OurCompanyAuthentication" timeout="120" />
</authentication>
<authorization>
<allow users="?" />
<allow users="*" />
</authorization>
The forms element has proven necessary with experimentation to correctly map to the login page and prevent inherited configuration looking for a login.aspx page at the root of the application. The configuration matches that of Startup.Auth.cs which is-
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieHttpOnly = true, //In supported browsers prevent JavaScript from accessing the authentication cookie
CookieName = "OurCompanyAuthentication",
CookiePath = VirtualPathUtility.ToAbsolute("~/"),
ExpireTimeSpan = new TimeSpan(hours: 2, minutes: 0, seconds: 0), //Cookie expires two hours after it is issued
LoginPath = new PathString("/Account/Login"),
SlidingExpiration = true //Cookie will be re-issued on requests more than halfway through expiration window
});
The question-
What is unconditionally generating the 302 redirect to the login page with the returnUrl unmodified/uncorrect (this happens regardless of if the user was already logged in), and how can I restore the described behaviour of performing a 302 redirect with the slash appended.
If I can conditionally direct to the login page with a correct return URL then so much the better, but the primary requirement is avoiding the incorrect redirect to the login page and subsequent loop in the first place. If the 302 redirect to the application root is then followed by a further redirect to the login page (where the user is not authenticated or their ticket has expired) then that is acceptable.
I've looked into URL rewriting but the domain and virtual path are not known to developers in advance as these may be different on each customer site - as is the use or otherwise of virtual directories on the host server.
CookiePath = VirtualPathUtility.ToAbsolute("~")note the slash is not there - Imran Qadir Baksh - Baloch