Site-level forms authentication w/IIS7 - asp.net

I've spent the entire day trying to get this to work, though it seems as if it's meant to be an out-of-the-box functionality for IIS7. I just can't figure what I'm goin wrong.
I want to have a web site (say, the default web site, that's fine) configured for forms authentication. By which I mean to say that regardless how many web applications are configured under this web site, any time an anonymous user tries to access a restricted resource they are sent to the same login page, which gathers their credentials and sends them back to the resource they wanted in the first place.
So I've set the authentication on the web site as follows - basically all off, except: anonymous (which I assume needs to be on so that the unsecured stuff is visible without logging in), and forms authentication. I have forms authentication configured to use a login page within a configured application, so: [default web site\auth\login.aspx]
I have an unsecured application configured, which of course is fine.
I have another application which has some unsecured content at its root ([default web site\test\readme.html]), and another directory where I've added a config file that has the <deny users="?"/> (so, [default web site\test\secure\readme.html]) in a config file. Of course my intention is that an anonymous users try to get resources in this directory they will be redirected to the login page for the whole site.
To my surprise, what happens is this - if I turn off anonymous access for the application I want to secure, rather than sending me to the login page configured at the web site level, I just see an unauthorized message in the browser. If I turn anon on for the secured app then no challenge is ever done and everyone can just see all resources without logging in.
Am I missing something here? Shouldn't web applications configured within a web site all act the same way, and use the sites' authentication scheme? Am I wrong about this being a feature or am I just doing something wrong to make it happen?
I also (after goofing with it for a while) set the login page under the 'Error pages' section of the main web site to handle 401 status, without any luck.

I don't think the asp.net handler is invoked for static files unless you configure it to be. Adding a handlers section for html files in the root config will allow your app using forms authentication to handle html files as well.
<system.web>
<compilation>
<buildProviders>
<add extension=".html" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
</system.web>
<system.webServer>
<handlers>
<add name="html" verb="GET, HEAD, POST, DEBUG" path="*.html" type="System.Web.UI.PageHandlerFactory" />
</handlers>
</system.webServer>

Related

How do I add a http handler without ssl to my asp.net secure web app?

I have an old asp.net (non-core, non-mvc) https webapp which has a number of IHttpHandlers which serve files using a setup in my web.config like so:
<system.webServer>
<handlers>
<add name="DocumentAttachmentHandler"
path="*/Secure/DocumentAttachment/*/*/*/*/*.*"
type="[company].[product].WebApp.AttachmentHandlers.DocumentAttachmentHandler, [company].[product].WebApp"
verb="GET"/>
I want to add a new handler that is localhost only (only accessible internally) and is http instead of https.
This is what I added:
<add name="MyFileHandler"
path="*/Public/My/*/*.*"
type="[company].[product].WebApp.AttachmentHandlers.MyAttachmentHandler, [company].[product].WebApp"
verb="GET" />
But my breakpoint in the handler doesn't hit when I call:
http://localhost:44300/[product]/Public/My/[fileId]/[filename].[ext]
...because my webapp is https. It does hit when I change my entire webapp to http, but I obviously can't leave it like that ;-)
I tried setting path="http://localhost:44300/[product]/Public/My/*/*.*" and adding allowPathInfo="true" ...but that didn't work.
All my web searches return telling me how to make something secure, when I want to make mine less secure (sort of).
Please can someone tell me how I should go about doing this?

IIS Dynamic IP restrictions in web.config location

I'm trying to use IIS Dynamic IP Restrictions to throttle requests from the same IP. I have the module running and the requests are nicely throttled if I edit the dynamic restrictions settings from the IIS UI. This is nice however I need to have different rates on different URLs. Login should be for example more strict than static resources. I'm trying to use locations in web.config to achieve this.
<configuration>
<location path="foo">
<system.webServer>
<security>
<dynamicIpSecurity enableLoggingOnlyMode="true">
<denyByRequestRate enabled="true" maxRequests="1"
requestIntervalInMilliseconds="5000" />
</dynamicIpSecurity>
</security>
</system.webServer>
</location>
</configuration>
Unfortunately, this doesn't apply. I'm quite sure it has nothing to do with my app because it doesn't work also on a static web with one HTML file. I'm also quite sure that the location path is correct, because the requests are blocked if I add ...<deny users="*" />.
This is not possible. From the module description:
This module can be configured such that the analysis and blocking
could be done at the Web Server or the Web Site level.
Internally this is implemented as HttpModule (native HttpModule that is). HttpModule runs for every single request - location doesn't affect them. For reference check out
Exclude certain pages from using a HTTPModule
So your only other option (if you need to support this exact module) is to organize your site to several mini-applications instead.
Like
/ -> root web application
/Content -> web application with static content
/Login -> web application with login functionality
And in every single mini-application create web.config with appropriate rules.

New Asp.Net MVC5 project produces an infinite loop to login page

I am creating a brand new projet with Visual Studio 2013, I choose Asp.Net MVC and the framework 4.5.1 The project is created, then, I do nothing else than F5 to start the default web page. Unfortunately, it produces a redirect to the login page which is redirecting into the login page too. Here is a short version of the url I have in the browser:
http://localhost:5285/Account/Login?ReturnUrl=%2FAccount%2FLogin%3FReturnUrl%3D%252FAccount%252FLogin%253FReturnUrl%253D%25252FAccount%25252FLogin%25253FReturnUrl%25253D%2525252FAccount%2525252FLogin%2525253FReturnUrl%2525253D%252525252FAccount%252525252FLogin%252525253FReturnUrl%252525253D%25252525252FAccount%25252525252FLogin%25252525253FReturnUrl%25252525253D%2525252525252FAccount%2525252525252FLogin%2525252525253FReturnUrl%2525252525253D%252525252525
I do not have any error in the Event Viewer. But in the screen I see :
"HTTP Error 404.15 - Not Found The request filtering module is
configured to deny a request where the query string is too long."
The website is running with the default setting in IIS Express. How can I fix this problem? I am guessing something is wrong with my Visual Studio 2013?
Edit
It works if I create a brand new website and I host it in IIS. But if I create a new website (without modifying anything) and just hit play (which start IIS Express by default), it doesn't.
Edit 2
I have deleted every websites in the Documents\IISExpress\config\applicationhost.config. I have recompiled everything, and it created this entry :
<siteDefaults>
<logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
<traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
</siteDefaults>
<applicationDefaults applicationPool="Clr4IntegratedAppPool" />
<virtualDirectoryDefaults allowSubDirConfig="true" />
</sites>
I am still getting the error with IIS Express, not with IIS.
Highlight the project in Visual Studio
Open the 'Properties' panel on the right (or press F4)
Set 'Windows Authentication' to 'Disabled'
Set 'Anonymous Authentication' to 'Enabled'
You are missing [AllowAnonymous] attribute on login action.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
// code....
}
2nd possibility, specific to IIS Express only: is that, if you created same default WebApplication1 project multiple times, playing with different authentication settings, IIS Express stored additional authentication settings in it's configuration file. Something like:
<location path="WebApplication1">
<system.webServer>
<security>
<authentication>
<windowsAuthentication enabled="true" />
<anonymousAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
</location>
</configuration>
Configurations are in user's Documents folder Documents\IISExpress\config\, and you should look for:
applicationhost.config
Then just delete xml node <location path="WebApplication1"> mentioned above.
Update for VS 2015+
If you're using Visual Studio 2015 or higher, check this path for the config file:
$(solutionDir)\.vs\config\applicationhost.config
Each solution will have its own config file.
This issue is because of the authentication mode selected(by default) by the MVC 5 Template, which triggers the ReturnUrl Style of redirection that might lead to an infinite loop if not configured correctly.
To disable OWIN startup discovery,add this key to your webconfig file.
<add key="owin:AutomaticAppStartup" value="false"/>
I had to remove (Source Link):
<authorization>
<deny users="?" />
</authorization>
I know I may be late, and this is not directly for the OP's question. But if anyone in the future come here, one more check about AllowAnonymous and Authorize attribute is that, you have to check all child actions too.
For example, I had my Layout (which the Login page also use) that call 2 child actions for breadcrumbs and sidebar, and they did not have AllowAnonymous attribute (the Controller had Authorize attribute).
Hope this help.
In IIS, Select you website and check for Authentication, If you are using Forms Authentication then -
Set 'Windows Authentication' to 'Disabled' ,
Set 'Anonymous Authentication' to 'Enabled'
Set 'Forms Authentication' to 'Enabled'
ASP.Net MVC 5 template adds Microsoft.Owin and related libraries to the project. Since Owin infrastructure doesn't require Forms Authentication, the template also introduces the following key in web.config.
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
Presence of this key could be a reason for undesirable looping back to Login page. Commenting it may help fix the problem for some people.
I faced the same problem because my MVC project was configured for .Net 4.5 but I was using .Net 4.0 as my application pool in IIS. Switched it to .Net 4.5 application pool and the problem was fixed. I hope this helps some one else!
TL:DR? Do not call a protected web API (any web API which requires Authorization) from an authorization page such as ~/Account/Login (which, by itself, does NOT do this.). If you do you will enter into an infinite redirect loop on the server-side.
Cause
I found that the culprit was, indirectly, AccountController::Authorize and the fact that AccountController is decorated with [Authorize].
The root cause was Sammy() being called from HomeViewModel() (Line 6 of home.viewmodel.js), which was accessing a "protected web API". This was being done for /Account/Login, which resulted in /Account/Login redirecting to itself.
Confirmation
You can confirm this is the cause of your problem through several methods:
Decorate AccountController::Authorize with [AllowAnonymous]
Comment out the Sammy() calls made during viewmodel construction.
Solution
The solution was to only emit the app bundle (a.k.a "~/bundles/app") for views which already required authorization. To my knowledge /Account/ views are classic MVC-based views, and are not part of the app datamodel/viewmodel, but I had mistakenly moved the bundle Scripts.Render(#"~/bundles/app") call into _Layout.cshtml (causing protected web API calls to be made for all MVC views, including /Account/.)
in my case: in my _layout.cshtml, i use Html.Action to call Action from Authorize Controller: ex: Html.Action("Count", "Product") -> loop error
fix: decorate by [AllowAnonymous] attribute in that Action (or remove these Html helper from _layout)
I just dealt with this issue for hours on end.
For me, it was in the Startup.Auth.cs file.
This code, when commented out, stopped the redirect loop.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
Please be aware that this is potentially harmful advice, it's rarely a good idea to modify an applicationhost config file directly, there are usually tools that will do this for you, safely (for example, from within Visual Studio.) Before proceeding, be sure to create a backup copy of this file in the event your IIS Express becomes trashed.
To fix this problem, I took the default IIS configuration file located here :
C:\Windows\System32\inetsrv\config\applicationHost.config
To my document
%userprofile%\documents\iisexpress\config\applicationhost.config
And it worked.
This was because I had some Windows Authentification set and not the anonymous account.
Make sure you have no actions in pipeline that have authorize attribute.
In my case, my layout had navigation menu controller which was missing allowAnonymous attribute.
I solved the same problem thanks to this accepted answer: ASP.NET Login Redirect Loop when user not in role.
It is possible that the controller containing Login action is decorated with an AuthorizeAttribute (even a custom one) while the login action is not decorated with AllowAnonymous attribute. Removing AuthorizeAttribute from the controller and adding AllowAnonymous to login action may be a possible solution.
These answers are more or less pieces of the same puzzle; I'll try to put everything in one place.
Problem that OP described hit my application the moment I implemented the OWIN pipeline and AspNET Identity.
So let's see how to fix it...
OWIN Startup
I guess you need it, because if you don't, then you don't need authentication, and I guess you do.
Except it you're using some old-style authentication, and I guess you don't.
So, don't remove either the OWIN startup attribute...
[assembly: OwinStartupAttribute(typeof(YourApp.Probably_App_Start.SomethingLikeAuthConfig))]
...or the configuration line...
<add key="owin:AppStartup" value="YourApp.Probably_App_Start.SomethingLikeAuthConfig" />
Access restriction on controllers
Now we cleared this up, you need the authentication. This means either each of your controller needs the [Authorize] attribute, or you can do the same to all controllers in one place by registering the thing globally (e.g. in RegisterGlobalFilters(), add line filter.Add(new AuthorizeAttribute())).
In the former case (when securing each controller separately) skip this part, just go to the next one.
In the latter case all of your controllers will be secured against unauthorized acces, so you need an entry point for that authorization - unprotected Login() action.
Just add...
[AllowAnonymous]
...and you should be good.
OWIN cookie configuration
When your user logs in, his browser stores encrypted (hopefully!) cookie in order to simplify things for the system. So, you need cookie - don't delete the line that says UseCookieAuthentication.
What you really have to do is turn off the IIS integrated authentication mechanism for your web application. This means switching off Windows Authentication (Disabled) and enable letting any user in, at least as long as IIS Express is now concerned, by setting Anonymous Authentication (Enabled).
When you start your web site, this will in turn copy these settings into IIS Express configuration (applicationhost.config), and there you should see these two lines:
<windowsAuthentication enabled="false" />
<anonymousAuthentication enabled="true" />
You might have the authorization config in your web.config that says deny users="?". It means the authorization subsystem is instructed to prevent anonymous users from entering.
With OWIN, this still works as designed. You either have to remove this, or make your anonymous user able to access the Login page by using something like...
<location path="Account/Login">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
HTH
I had similar issues where it was in an infinite loop when calling back to the website locally. It turns out that when debugging locally it was redirecting the ports. I updated port numbers in the project properties screen but left the Azure definition the same in the cloud project and everything started to work as expected.
I had the same issue with my Asp.Net MVC 4 project. I resolved it by going to Startup.cs and commenting out the line for ConfigureAuth(app)
public void Configuration(IAppBuilder app)
{
//ConfigureAuth(app);
}
I also made sure that I had Windows Authentication enabled in IIS for my project, and all other authentication options disabled.
For me, this turned out to be caused by my LoginViewModel containing references to translation resources files, apparently being protected by authentication. I removed those references, and the problem was solved.
For me, removing the following block fixed it:
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
Assume
<authentication mode="None" />
in my case it was a very wired problem , i decorated the home controller by non existent role. so it causes a redirection loop.
Go to to your applicationhost.config file and set anonymousauthentication = "true"
<authentication>
<anonymousAuthentication enabled="true" userName="" />
<windowsAuthentication enabled="true">
<providers>
<add value="Negotiate" />
<add value="NTLM" />
</providers>
</windowsAuthentication>
</authentication>

IIS7 Mixed Mode Authentication

We're getting ready to start migrating some of our IIS6 sites to IIS7, and the application currently uses Forms Authentication. We have started getting some requests from various sites to use the Windows Authentication for the users. While this is easy enough to implement (and I've shown internally that there is no issue with the app, as expected) the question then is how to continue to keep Forms authentication for when Integrated Windows doesn't work. I've seen several walkthroughs on how to have it configured on IIS6, and I could do the same thing on IIS7, but then I have to turn on Classic Mode processing. Any solution should also be back portable to IIS6, if possible, to keep the build tree simple.
So what are my options on this? Do I setup the app with Integrated Windows Authentication in IIS7, Forms Auth in the web.config, and redirect 401 errors to an "error page" allowing them to login using forms, then back to the regular app?
The case when Forms is likely to be needed is going to be reserved for Contract workers, our support staff, and if someone needs to access it on their site from their Extranet. So primarily it's for our staff to login to check functionality and confirm bug reports. I suggested we just maintain that for our support staff to work, we need a Windows login that will always be live, and then we'll just enforce local responsibility on who can login to the site, but I'm told that we would do better to have Forms Authentication.
Any thoughts? I can post some of the links of the articles I've already read through if that would help the forum better narrow my needs.
tl;dr: How to do mixed mode authentication (forms, windows) in IIS7 without changing to classic pipeline and still be able to use the build in IIS6 if possible.
No, that's not quite right, but I can't do a code block in a comment reply, so I'll post a new answer ...
The following code block allows me to control anon access from IIS7 without having to muck about in the metabase (where GUI changes on IIS6 get applied)
<location path="WindowsLogin.aspx" >
<system.web>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="false" />
<windowsAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</location>
thanks for getting back to me, I have been playing round with several of the implementations on and off for a few weeks now, that I've read about on the internet (javascript, 401, 2 virtual directories) but still havnt really found anything that works as I wanted. We will be potentially rolling it out to more than one client-each with different hardware/setups even different versions of iis, so wanted it to be as generic as possible. Ive come up against a brick wall on a couple of the suggested solutions...
when you say for IIS7+ you removed anon access in web config, I assume like this: -
<location path="Authent/WinLogin.aspx" >
<system.webServer>
<security>
<authorization>
<add accessType="Deny" users="?" />
</authorization>
</security>
</system.webServer>
</location>
I spent a few days trying to get this to work, with a slight difference... I wanted the first login screen to present the forms login with an button underneath "Login With Windows Authentication".
I eventually gave up on all these techniques, as I never could quite get the satisfactory results. My workaround was as follows, and works perfectly:
Create a separate website "LoginWithIntegratedSecurity"
Set this up with integrated security
This web site creates a temporary "User Hash Key" in the database, which identifies the user
Redirects back to LogonPage in Forms Authentication website with Hash key in url
LogonPage in Forms Authentication checks for Hash key, and logs user in after database check
So if the User clicks the button "Login with windows Authentication", the server redirects to the windows authentication site (passing the "ReturnUrl"). This site challenges and logs in user, then redirects back, again passing the "ReturnUrl" as well as the HashKey.
This all happens very fast, and appears pretty seamless.
I know its a hacky workaround, but for my case it worked well.

Securing ELMAH while yet making it possible to access it via RSS Reader

We use ELMAH error exception logging in our application. I'd like to keep ELMAH secure from regular users while still making it available to administrators/developers of the application.
When you set security with forms authentication in the web.config you then lose the ability to access the RSS feed. I'd like to be able to secure ELMAH but yet still pass through authentication to the axd to be able to access the RSS feed (i.e. /elmah.axd/rss) from a RSS reader.
Thinking that http authentication would be proper as then I can probably get to the rss feed with the following url syntax http://username:password#somedomain.com/elmah.axd/rss I assume you would need to set authentication mode="windows" on that specific path in the web.config. One issue pops up though is how do you set credentials on a virtual file?
Looking at Google brings back this article on CodeProject on how to set up authentication passthrough with cookies. Is this a good solution to my problem?
Is there another way that is better to be able to access the RSS feed while still being secure?
Thanks.
Supporting HTTP Authentication and Forms Authentication in a Single ASP.NET Web Site
Basically you add a dll called MADAM to your project adjust your web.config and configure which file(s) you want to authenticate as Basic instead of Forms:
<configuration>
<configSections>
<sectionGroup name="madam">
<section name="userSecurityAuthority" type="System.Configuration.SingleTagSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<section name="formsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionSectionHandler, Madam" />
</sectionGroup>
</configSections>
...
<madam>
<userSecurityAuthority ... />
<formsAuthenticationDisposition>
<discriminators all="[true|false]">
...
</discriminators>
</formsAuthenticationDisposition>
</madam>
...
<system.web>
<httpModules>
<add name="FormsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionModule, Madam" />
<add name="AuthenticationModule" type="MADAM Authentication Module Type" />
</system.web>
</configuration>
This was easy to set up and solved my problem of being able to authenticate elmah.axd and still be able to subscribe to the RSS feed with Basic authentication credentials.
Side note MADAM is written by the same guy that wrote ELMAH, coincidence?
Depends on the client I guess - I know some desktop readers (sure others do, as well) support feeds that require authentication, and provide a login box when first requesting it - not sure what they are doing behind the scenes to make it work though.

Resources