FormsAuthenticationModule Authenticate event not firing when using ASP.NET MVC - asp.net

We are using the HttpModule to hook in to the FormsAuthenticationModule and subscribe to the Authenticate event. When we use web forms this event fires in the module. When we are using MVC this event is not firing.
I have tried using the [Authorize] attribute on the Controllers and location in web.config (even though this isn't best practice) to try and get this event to fire but it still does not.
The event does fire when using the Cassini webserver but does not fire on IIS 7.5 or IIS Express. We are running ASP.NET MVC 2 using .NET 3.5
EDIT
The Authentication event fires when we request a .aspx or .ashx file. If we request an extensionless file or a .css or .js it does not fire either.
An new ASP.NET MVC application will fire this event for every file requested.
Any suggestions?

Our web.config was missing the runAllManagedModulesForAllRequests="true" from the modules element in system.webServer. Once this was added all web requests receive the Authorisation event from FormsAuthenticationModule.
<system.webServer>
....
<modules runAllManagedModulesForAllRequests="true">
....
</system.webServer>

Navigating to an aspx page does not test if forms authentication is working in MVC, you have to navigate to a route. I saw your answer and that's what I had in mind. Instead of the inefficient runAllManagedModulesForAllRequests="true" I suggest removing the managedHandler precondition:
<remove name="FormsAuthentication"/>
<add name="FormsAuthentication" preCondition="" type="System.Web.Security.FormsAuthenticationModule"/>
<remove name="DefaultAuthentication"/>
<add name="DefaultAuthentication" preCondition="" type="System.Web.Security.DefaultAuthenticationModule"/>
<remove name="RoleManager"/>
<add name="RoleManager" preCondition="" type="System.Web.Security.RoleManagerModule"/>
<remove name="UrlAuthorization"/>
<add name="UrlAuthorization" preCondition="" type="System.Web.Security.UrlAuthorizationModule"/>
<remove name="UrlRoutingModule-4.0"/>
<add name="UrlRoutingModule-4.0" preCondition="runtimeVersionv4.0" type="System.Web.Routing.UrlRoutingModule"/>

I don't think it's the best way to solve it, but I'm also using a combination of MVC and formpages and set all the authorisation in the web.config
<location path="[path]">
<system.web>
<authorization>
<allow users="[username]" roles="[role]"/>
<deny users="*"/>
</authorization>
</system.web>
</location>

Related

Url Authorization with MVC and ASP.NET Identity

I want to secure specific folders and resources in my application that are outside of the routes for my mvc application. I want these resources to only be available to authenticated users (which role is not of concequence as long as they are authenticated).
Initially it seemed that the UrlAuthorizationModule would be the answer. I followed this article, Understanding IIS 7.0 URL Authorization, and I can get the module to work in the sense that it responds to the configuration elements in the web.config.
My current problem is that I think it is enacting the rules based on the anonymous user in IIS and not the authenticated user in asp.net identity.
Test Environment
I use a standard html file for testing instead of trying to load a script as this would also be loaded outside of the MVC pipeline.
In Visual Studio 2015.
New default .net 4.6.2 web project
MVC template
Authentication = Individual User Accounts
IIS 8 (for testing outside Visual Studio)
Authentication -> Anonymous Authentication (enabled)
Add to web.config
<configuration>
...
<location path="Data">
<system.webServer>
<security>
<authorization>
<clear/>
<add accessType="Deny" users="*"/>
<add accessType="Allow" users="?"/>
</authorization>
</security>
</system.webServer>
</location>
...
</configuration>
Add to folder structure
/Data/Protected.html // this file just has some basic Hello World content to display so you can see if it is loaded or not.
Observed Results
With this configuration everything in the Data path is always denied, it does not matter if the user is authenticated or not.
The same is true if I switch the 2 lines for Deny and Allow in the web.config.
If I completely remove the line with Deny then access is always allowed even when the user is not authenticated.
If I add a role and use roles with the role name instead of users attribute the role is also completely ignored.
Now What?
What am I missing? How can I get the Url Authorization module to work with MVC/WebAPI and ASP.NET Identity Individual user accounts or is this simply not doable?
I am open to alternative ideas as well, maybe the answer is to write a custom HttpModule or HttpHandler?
Side notes
Why & Specifics
These resources are javascript files, in short only a portion of the scripts should be available to unauthenticated users. There are 2 directories in the root, one for the authenticated part of the app and one for the non-authenticated part of the app. The reason for this has nothing to do with user authorization or security in the application, it is to limit the exposed surface area of the application to non-authenticated requests.
[TL;DR;]
Go to "Complete root web.config" section to see the needed web.config setup.
Test this in incognito-mode to prevent browser caching issues!
And use Ctrl+F5 because scripts and html files get cached.
First deny access to all anonymous users in the root web.config.
<authorization>
<deny users="?"/>
</authorization>
The web.config here allows one folder to be publicly accessible. This folder, in my example here, is called css and sits in the root of the MVC application. For the css folder I add the following authorization to the root web.config:
<location path="css">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
You can add more of these location paths if you want more public folders.
While all other files will not be accessible until the user logs in, the css folder and its contents will always be accessible.
I have also added a static file handler to the root web.config, This is critical as you want the request to be managed by the asp.net pipeline for the specific file type(s):
<handlers>
<add name="HtmlScriptHandler" path="*.html" verb="*" preCondition="integratedMode" type="System.Web.StaticFileHandler" />
</handlers>
Complete root web.config
<system.web>
<authentication mode="None" />
<authorization>
<deny users="?"/>
</authorization>
<compilation debug="true" targetFramework="4.6.2" />
<httpRuntime targetFramework="4.6.2" />
</system.web>
<location path="css">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
</modules>
<handlers>
<add name="HtmlScriptHandler" path="*.html" verb="*" preCondition="integratedMode" type="System.Web.StaticFileHandler" />
</handlers>
</system.webServer>
ASP.NET by default will only apply the allow and deny rules to files handled by the managed handler. Static files are not managed by the managed handler.
You could also set: (Don't do this, if not really needed!)
<modules runAllManagedModulesForAllRequests="true">
With runAllManagedModulesForAllRequests="true" all the HTTP modules will run on every request, not just managed requests (e.g. .aspx, ashx). This means modules will run on every .jpg ,.gif ,.css ,.html, .pdf, ... request.
One important thing
You don't have to add the UrlAuthorizationModule to the modules section as it is already part of the ASP.NET pipeline. This means, it will run only for managed files, not static!
If you now remove and then re-add the UrlAuthorizationModule to the modules section, it will run under precondition "integratedMode" and not under "managedHandler" anymore! And will therefore have access to static files.
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
If you set the precondition to managed:
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />, then the UrlAuthorizationModule will not restrict access to static files anymore.
You can test this by accessing a script file in the scripts folder successfully while being logged out. Hit Ctrl+F5 to make sure you get a fresh copy of the script file.
Difference between ASP.NET UrlAuthorization <--> IIS URL Authorization
It is important to keep in mind that the managedHandler precondition
is on the ASP.NET UrlAuthorization module. The precondition tells you
that the URL authorization module is invoked only when the code that
handles the request is mapped to managed code, typically an .aspx or
.asmx page. IIS URL Authorization, on the other hand, applies to all
content. You can remove the managedHandler precondition from the
ASP.NET Url Authorization module. It is there to prevent a performance
penality you have to pay when every request (such as a request to
.html or .jpg pages) would have to go through managed code.
P.S.: Some web.config attributes are case sensitive!

ASP.NET httpHandlers & handlers

I am confused about httpHandlers in system.web and handlers in system.webServer. What is the difference between these two configuration? And how and when to use them?
Actually another question is for modules as well: httpModules in system.web and modules in system.webServer
The system.webServer section in the Web.config file specifies settings for IIS 7.0 that are applied to the Web application. The system.WebServer is a child of the configuration section. For more information, see IIS 7.0: system.webServer Section Group (IIS Settings Schema).
and <system.web> specifies the root element for the ASP.NET configuration section and contains configuration elements that configure ASP.NET Web applications and control how the applications behave. httpHandlers & handlers are same.
To register an HTTP handler for IIS 6.0 use should:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="SampleHandler.new"
type="SampleHandler, SampleHandlerAssembly" />
</httpHandlers>
</system.web>
</configuration>
To register an HTTP handler for IIS 7.0 use should:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="SampleHandler.new"
type="SampleHandler, SampleHandlerAssembly" />
</httpHandlers>
</system.web>
<system.webServer>
<add name=SampleHandler" verb="*" path="SampleHandler.new"
Modules="IsapiModule"
scriptProcessor="FrameworkPath\aspnet_isapi.dll"
resourceType="File" />
</system.webServer>
</configuration>
Read more Here
<system.web> is the configuration section for asp.net, traditionally this is where you would define your httpHandlers and httpModules.
With the introduction of IIS 7 (2007) the web server and asp.net got much more integrated and a completely new IIS configuration system was introduced.
As part of this the location for handler and module definitions was moved to <system.webServer>
If you are still using IIS6 (stop it) or use classic pipeline mode in IIS7+ you need to have your definitions under <system.web>, if you are using integrated pipeline mode in IIS7+ put them under <system.webServer>. You should not have them in both sections.

ServiceStack and SignalR together in same project

It is somewhat trivial question, but I am using SignalR and ServiceStack in single Asp.Net host application.
Means, it is simple Asp.Net blank application, ServiceStack is running on / and it is showing default page using Razor. Running perfectly.
Now, I added SignalR asp.net host. Added startup class and created hub to listen and broadcast chat message.
I have wrote client code in default page only. Now, things are working fine. Means, API and SignalR are both running on local machine.
Now, the question is, is this the right way of doing things? Means, are there two different processes hitting IIS. Or is there any way I can chain process to single process.
Or even part of ServiceStack API I can make real-time.
Please let me know if any further information is required.
Yes its possible, but you cannot run ServiceStack on Owin at the moment (as far as I know)
So you need to run ServiceStack in a specific location.
<location path="ssapi">
<system.web>
<httpHandlers>
<add path="*" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*"/>
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add path="*" name="ServiceStack.Factory" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
</handlers>
</system.webServer>
</location>
You may need to remove the handlers for owin/signalr stuff from the location too.
Alternatively you can setup SignalR on a specific path and remove ServiceStack from that path.
i.e
<location path="signalr">
<system.web>
<httpHandlers>
<remove type="ServiceStack.HttpHandlerFactory, ServiceStack" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<remove name="ServiceStack.Factory" />
</handlers>
</system.webServer>
</location>
I know the question focused on SignalR, but ServiceStack added support for Server-Sent Events in v4.0.31. Basicaly, this is a very long-lived HTTP request that streams to the client, allowing for real-time server "push"
This feature is supported by most modern browsers, and polyfills can be used to support IE back to 8. ServiceStack also provides a C# client.

the PostAcquireRequestState event cached but “Context.user” is null

I have an asp.net website. I used form Authentication for authenticate users. I used an httpmodule in my project. This module works fine in visual studio development server. But when I hosted it on IIS7, the PostAcquireRequestState event cached but “Context.user” is null even the user is authenticated.
Any Idea??...
I Use this config for Custom Module:
<system.webServer>
<modules>
<remove name="FormsAuthentication"/>
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition=""/>
<add name="MyModule" type="MyModule" />
</modules>
</system.webServer>
and it work fine on iis
#Alireza, It's most likely that the pipeline mode of your application pool is set to integrated. You need to change it to classic and your problem would be solved then.

How to do Forms Authentication on purely HTML pages using ASP.NET?

I am using forms authentication in IIS7 to password-protect a dev site, but the authentication seems to get by-passed when the site contains only static HTML files + login.aspx + web.config.
When I renamed the files to .aspx, I am prompted with the login form
I am not doing anything fancy. I have a very simple login script and it should just redirect to index.html afterward.
Any suggestions? To summarize, the entire site is using HTML (for now) and needs to be password protected.
<authentication mode="Forms">
<forms name="appNameAuth" path="/" loginUrl="~/login.aspx" defaultUrl="index.html" protection="All" timeout="525600">
<credentials passwordFormat="Clear">
<user name="[user]" password="[password]" />
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
In IIS7 if you want to protect *.html or *.htm files (or other non .net extensions) under forms authentication then add the following lines to your web.config:
<compilation>
<buildProviders>
<add extension=".html" type="System.Web.Compilation.PageBuildProvider" />
<add extension=".htm" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
AND
<system.webServer>
<handlers>
<add name="HTML" path="*.html" verb="GET, HEAD, POST, DEBUG" type="System.Web.UI.PageHandlerFactory" resourceType="Unspecified" requireAccess="Script" />
<add name="HTM" path="*.htm" verb="GET, HEAD, POST, DEBUG" type="System.Web.UI.PageHandlerFactory" resourceType="Unspecified" requireAccess="Script" />
</handlers>
</system.webServer>
To make the HTML files locked down by your forms authetication, you need have them served by ASP.NET. You can do this in IIS by associating the extension(s) you need (eg. .html, .htm, etc) with the aspnet_isapi.dll.
Onces ASP.NET is servicing those files you can specify the permissions for them just like any aspx page.
For more information refer to MSDN:
By default, IIS processes static
content itself - like HTML pages and
CSS and image files - and only hands
off requests to the ASP.NET runtime
when a page with an extension of
.aspx, .asmx, or .ashx is requested.
IIS 7, however, allows for integrated
IIS and ASP.NET pipelines. With a few
configuration settings you can setup
IIS 7 to invoke the
FormsAuthenticationModule for all
requests. Furthermore, with IIS 7 you
can define URL authorization rules for
files of any type. For more
information, see Changes Between IIS6
and IIS7 Security, Your Web Platform
Security, and Understanding IIS7 URL
Authorization.
Long story short, in versions prior to
IIS 7, you can only use forms
authentication to protect resources
handled by the ASP.NET runtime.
Likewise, URL authorization rules are
only applied to resources handled by
the ASP.NET runtime. But with IIS 7 it
is possible to integrate the
FormsAuthenticationModule and
UrlAuthorizationModule into IIS's HTTP
pipeline, thereby extending this
functionality to all requests.
Although this is an old question, I find the link in pomarc's answer really useful. Below is the summary which is suit for IIS7.
In your web.config, add or modify <handlers> under <system.webServer>:
<handlers>
<add name="HTML" path="*.html" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" />
</handlers>
Replace verb value with your required one; scriptProcessor value with correct path of your environment.
Then, add or modify <compilation> and <httpHandlers> under <system.web>:
<compilation debug="false" strict="false" explicit="true">
<buildProviders>
<!--Add below so .html file will be handled by ASP.NET (for use of Forms Authentication)-->
<add extension=".html" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
<httpHandlers>
<!--Add below so .html file will be handled by ASP.NET (for use of Forms Authentication)-->
<add verb="GET, HEAD, POST, DEBUG" path="*.html" type="System.Web.UI.PageHandlerFactory" />
</httpHandlers>
Replace verb value with your required one.
You may also include more extension separated by comma ','
I've solved the same problem a few days ago, by following the post by fr33m3 # 11-21-2007, 3:19 PM on this thread:
http://forums.asp.net/t/1184547.aspx
follow all the steps from 2. to 5. and you're done!
hope this can help you like it helped me.

Resources