I am trying to create a custom HttpModule which controls which users can view a site.
I am trying to leverage Windows Authentication to do this.
On an individual page, I would probably do something like this:
if (HttpContext.Current.User.Identity.Name.Contains("jsmith"))
{
Response.Write("You do not have the correct permissions to view this site.");
Response.End();
}
But because I want to make this more configurable at the application level, I would like to use an HttpModule.
Here is the start that I have made on the code:
using System;
using System.Web;
public class CustomAuthHttpModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
context.EndRequest += new EventHandler(OnEndRequest);
}
void OnBeginRequest(object sender, EventArgs e) { }
void OnEndRequest(object sender, EventArgs e)
{
HttpApplication appObject = (HttpApplication)sender;
HttpContext contextObject = appObject.Context;
if (contextObject.User.Identity.Name.Contains("jsmith"))
{
contextObject.Response.Clear();
contextObject.Response.End();
}
}
}
I would be fine with using the code I have, if I could put it in the OnBeginRequest() function. But the User property is not created in the HttpContext object until OnEndRequest() runs.
Running the code earlier would prevent the application from doing the extra work of producing this output, since some users are just going to be blocked from access in the end.
Can someone suggest a solution to this - is this happening because my module is running before the Windows Auth module, or what?
... or, maybe there is an easier way to do what I am trying to do with IIS or file system permissions?
You want the AuthenticateRequest event.
AuthenticateRequest event
Have you tried to implement the method in the global.aspx? OnSessionStart?
Besides I would use hasRole or some other group-Property instead of contains and username.
Why write an http module for this. If this is asp.net web forms then why not simply use built in stuff like LoginView http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.loginview.aspx
Related
Ok, so I have quite a task here:
The background of this project is very complex and fully covered by NDA's so I'll just state what I am trying to do without the background.
So what I need is a way to record every request made to an MVC application and every response from it.
Furthermore, I also need a way to "reply" the requests exactly as they were sent.
I was hoping that I could create some solution that "loads" the MVC application, Self hosts or runs in IIS, get requests, records them and passed them verbatim to the MVC application which would then act exactly like any other MVC app.
I could then create a second solution that "loads" the MVC app but instead of opening it up to request it would read the events from the event store and "replays" them in the MVC app.
Now I have no clue where to even start. This kinda thing is way out of my comfort zone.
If there is another solution for how I can record and replay request (and responses) then please let me know.
Even if there is a way to intercept a request in MVC before it starts doing all of its authentication and routing malarkey then that would be a great starting point. I would also need to know where I can capture the response at the very last second before it is sent.
Many thanks for your time
Andy
A HttpModule would work just fine for your scenario:
using System;
using System.Web;
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule()
{
}
public String ModuleName
{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
/*...*/
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
/*...*/
}
public void Dispose() { }
}
The code and more information available here.
I'd like to know if there is any technology to control communications between the client and the server in a web application (ASP.NET)
Example:
Number of requests
Check that no repeat a request
Check that an operation was performed
WorkFlow
The client sends the request "A"
The server receives the request "A", and responds
The server marks the request "A" as answered
The client resends the request "A"
The server answers that the request "A" was answered
You could intercept the request in the following method, in the Global.asax file:
protected void Application_BeginRequest(object sender, EventArgs e)
{
var request = ((System.Web.HttpApplication)(sender)).Context.Request;
//here you can evaluate and take decisions about the request
}
In any ASP.NET application you can use the HttpApplication events to track the needed changes. For example, you could track it using the BeginRequest and/or EndRequest events:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if(MyGlobalFlags.TrackingRequests){
// do stuff
}
}
protected void Application_EndRequest(object sender, EventArgs e)
{
if(MyGlobalFlags.TrackingRequests){
// do stuff
}
}
By personal opinion, I would use a globlal flag that I could turn off easily if I wanted.
If you are talking about an ASP.NET MVC application, I would also recommend using ActionFilters in the actions you want to track. You could implement your own ActionFilter class and track those changes OnActionExecuted and/or OnResultExecuted. I would still use the global flag to turn off the tracking without changing code.
public class MyTrackingActionFilter: ActionFilterAttribute{
public override OnActionExecuted(ActionExecutedContext filterContext)
{
if(MyGlobalFlags.TrackingRequests){
// do stuff
}
}
public override OnResultExecuted(ActionExecutedContext filterContext)
{
if(MyGlobalFlags.TrackingRequests){
// do stuff
}
}
}
As a note, I wouldn't try to do heavy stuff in these events. If the track requires heavy database manipulation that can run in parallel, I recommend you to use a queue system while using the thread pool.
The MSDN documentation says:
HttpContext.RemapHandler Method - Enables you to specify a handler for the request.
I am trying to move the processing of the request from one handler to another depending on a condition in the first handler. The HttpContext.RemapHandler method seems to initialise an instance of the second handler but not call the HttpHandler.ProcessRequest method; the response is empty.
Does the HttpContext.RemapHandler method do what I think it should - transfer processing to a new HttpHandler and calling the HttpHandler.ProcessRequest method? Or should I be using another approach such as another method or an HttpModule?
EDIT:
Turns out I should be using a HTTPHandlerFactory. I have the solution working nicely now.
So what exactly is HttpContext.RemapHandler for?
You can use HttpContext.RemapHandler as you specified, however if another HttpHandler calls RemapHandler (e.g. ASP.NET MVC which registers MvcHandler in PostResolveRequestCache) your IHttpModule will never fire. This is maybe why IHttpHandler.Process was never called.
If this is your issue, you can simply define a route to ignore in MvcApplication.RegisterRoutes like this:
routes.IgnoreRoute("your_path/{*pathInfo}");
Also, remember that with Visual Studio Web Development Server and IIS6, RemapHandler will not work.
Here is an example of how to select the right way to remap the handler based on whether or not Integrated Pipeline is activated AND still be able to access the session:
public void Init(HttpApplication application)
{
if (HttpRuntime.UsingIntegratedPipeline)
// For IIS 7 and IIS 8
application.PostAuthorizeRequest += Application_PostAuthorizeRequest;
else
// For IIS 6
application.PostMapRequestHandler += Application_PostMapRequestHandler;
}
private void Application_PostAuthorizeRequest(object sender, EventArgs e)
{
((HttpApplication)sender).Context.RemapHandler(_myHandler);
}
private void Application_PostMapRequestHandler(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Handler = _myHandler;
}
The difference between using a HttpHandlerFactory and HttpModule in this case is that the latter allows you to decide when to use which IHttpHandler regardless of ASP.NET IHttpHandler mappings. More on MSDN: HTTP Handlers and HTTP Modules Overview.
I am writing a custom c# HttpModule that will handle requests from all file types. As a simple proof of concept I have setup the module by adding a reference to the httpModules section of the web config and added application extensions for the demo IIS website with a reference to the aspnet_isapi.dll so that it currently only intercepts request for ".htm" files
But even if there is no significant code in the "OnBeginRequest" event (code below) it causes an infinite redirect loop. I am using IIS 5 on XP Anyone got any ideas?
So far I have only seen HttpModule examples for use with ASPX files but surely you can configure the for any file type?
#region IHttpModule Members
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
}
///
///
///
///
public void OnBeginRequest(Object s, EventArgs e)
{
HttpApplication context = s as HttpApplication;
Uri currentURL = context.Request.Url;
string pageName = currentURL.Segments.Last().ToLower();
}
#endregion
OK. The problem was actually in the HttpModule itself.
It appears that you have to use the HttpApplication context in order for it to render on the client.
For Example after you have performed all your custom logic you need to write to the context:
context.Response.Write("/n/r");
//or
context.Response.Redirect("test.htm");
Everything then renders as you would expect
I'm working with linq to sql, and therefore need to store my DataContext for future use for each thread (I've read this article: http://www.west-wind.com/weblog/posts/246222.aspx
regarding ways to implement a shared context). What I want to know though, is how do I create a single key that both the global.asax file will know and so will the webpage without hardcoding it, and if i do hardcode it the key must be specific for each user.
Thank you very much!
Vondiplo
Have you considered something like the IContainerAccessor from the Castle.Windsor framework?
Then you can do something like
public class GlobalApplication : System.Web.HttpApplication, IContainerAccessor
{
private static readonly WindsorContainer _container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
public IWindsorContainer Container
{
get { return _container; }
}
}
With Container becoming accessible through the entire app like
var accessor = HttpContext.Current.ApplicationInstance as IContainerAccessor;
var controller = accessor.Container.Resolve<IDataContext>("myDataContext");
This will require some research into Castle Windsor and its IoC capabilities, but imo they will be very useful to you.
Add the DataContext into request scope:
In global.asax.cs:
HttpContext.Current.Items["HardcodedKey"] = dataContext;
In the page:
DataContext dc = (DataContext) HttpContext.Current.Items["HardcodedKey"];
The .Items collection is scoped to an individual request, so for a given key, each request will reference a different item.
Well it sounds like you want to look at Page.Cache. This is a collection that is available at an application level. It is available in all sessions for all users.
Not sure why you can't use session in Global.asax - you just need to ensure you're calling it from the right place.
By default, there's very little in the Global.asax, but there are a number of methods you can implement if you want, and you'll probably want something along the lines of (tested locally):
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
// Pick up your session id here, create a new context and away you go?
var sessionId = Session.SessionID;
Session.Add("sessionId", sessionId);
}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
// Noting comment above, clean up your context if needs be.
}
Then in your site you can have something like:
protected void Page_Load(object sender, EventArgs e)
{
Literal1.Text = Session["sessionId"].ToString();
}
I'm not sure that Session is the right place for you to store this, and you'll want to do some performance testing to see if it's going to handle the sorts of loads you are expecting.