Session access disable for asp.net bundle requests - asp.net

I am using asp.net and MVC4 for my application and also i am using bundling for css and js files.
When i look into my trace files, i observed that all my bundle requests are using session. i.e, all bundle requests are passing through sessionstatemodule.
My trace looks like below.
155. NOTIFY_MODULE_START ModuleName="Session", Notification="REQUEST_ACQUIRE_STATE", fIsPostNotification="false" 06:59:43.480
156. AspNetPipelineEnter Data1="System.Web.SessionState.SessionStateModule" 06:59:43.480
157. AspNetSessionDataBegin 06:59:43.480
158. AspNetSessionDataEnd 06:59:43.996
159. AspNetPipelineLeave Data1="System.Web.SessionState.SessionStateModule" 06:59:43.996
160. NOTIFY_MODULE_COMPLETION ModuleName="Session", Notification="REQUEST_ACQUIRE_STATE", fIsPostNotificationEvent="false", CompletionBytes="0", ErrorCode="The operation completed successfully. (0x0)" 06:59:43.996
161. NOTIFY_MODULE_END ModuleName="Session", Notification="REQUEST_ACQUIRE_STATE", fIsPostNotificationEvent="false", NotificationStatus="NOTIFICATION_CONTINUE" 06:59:43.996
I think i dont need session access for my bundle requests. How can i disable the session access for my bundle requests?

If I understand your question correctly you want to disable session state for your static resources. For this you can do two things:
1) Disable SessionState for Controller
For that you need to import System.Web.SessionState namespace and you then decorate your controller with following line of code:
[SessioState(SessionStateBehavior.Disabled)
public class HomeController: Controller
{
}
For more information you can visit following link:
Controlling Session State Behavior
2) Create Static Resources
IIS Setup:
Create two website in your inetpub directory.
www.domain.com // For main site
static.domain.com // Foe static resources
Now point them to same physical directory i.e.
C:\inetpub\www.domain.com
Redirect domain.com to www.domain.com
Redirect any domain.com request to www.domain.com.
so that any domain.com request must be redirected to www.domain.com
because cookie set for domain.com will also be shared by all sub
domain including static.domain.com hence it is much important steps
** Code changes**
Add below code in your web.config file:
<appSettings>
<add key="StaticSiteName" value="static.domain.com"/>
<add key="StaticDomain" value="http://static.domain.com"/>
<add key="MainDomain" value="http://www.domain.com"/>
</appSettings>
use PreApplicationStartMethod and Microsoft.Web.Infrastructure to dynamically register HTTP module in pre-application startup stage
public class PreApplicationStart
{
public static void Start()
{
string strStaticSiteName = ConfigurationManager.AppSettings["StaticSiteName"];
string strCurrentSiteName = HostingEnvironment.SiteName;
if (strCurrentSiteName.ToLower() == strStaticSiteName.ToLower())
{
DynamicModuleUtility.RegisterModule(typeof(StaticResource));
}
}
}
public class StaticResource : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
string strUrl = context.Request.Url.OriginalString.ToLower();
//HERE WE CAN CHECK IF REQUESTED URL IS FOR STATIC RESOURCE OR NOT
if (strUrl.Contains("Path/To/Static-Bundle/Resource") == false)
{
string strMainDomain = ConfigurationManager.AppSettings["MainDomain"];
context.Response.Redirect(strMainDomain);
}
}
public void Dispose()
{
}
}
Add an Extension Method
public static class Extensions
{
public static string StaticContent(this UrlHelper url, string contentPath)
{
string strStaticDomain = ConfigurationManager.AppSettings["StaticDomain"];
return contentPath.Replace("~", strStaticDomain);
}
}
Now use #Url.StaticContent() from view so that it will render static resource url with static.domain.com whether it is image, script, CSS, or bundles or wherever we want to refer cookieless domain. for e.g.
<link href="#Url.StaticContent("~/Content/Site.css")" rel="Stylesheet" />
<script src="#Url.StaticContent("~/Scripts/jquery-1.7.1.js")" type="text/javascript"></script>
<script src="#Url.StaticContent("~/bundles/jquery")" type="text/javascript"></script>
<img src="#Url.StaticContent("~/Images/heroAccent.png")" alt="" />
Visit below link for full information as article is pretty big:
Cookie less domain for bundling and static resources
Hope this will help you to achieve your goal.

Related

HttpModule isn't processing request authentication

I have an HttpHandler that I'm trying to use to put a little security layer over a certain directory in my site, but it's behaving strangely.
I've got it registered like this in my Web.Config: no longer valid since I'm in IIS 7.5
<httpHandlers>
<add verb="*" path="/courses/*" type="CoursesAuthenticationHandler" />
I can't tell if it's actually being called or not, because regardless of the code, it always seems to do nothing. On the flip side, if there are any errors in the code, it does show me an error page until I've corrected the error.
Here's the handler itself:
using System;
using System.Web;
public class CoursesAuthenticationHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
if (!context.Request.IsAuthenticated)
context.Response.Redirect("/");
}
}
So... that's pretty much it. The handler is being registered and analyzed at compile time, but doesn't actually do what it's expected to.
Edit: I realized that I'm using IIS 7.5 and that does indeed have an impact on this implementation.
For IIS 7, here's the Web.Config registration I used:
<handlers accessPolicy="Read, Execute, Script">
<add name="CoursesAuthenticationHandler"
verb="*"
path="/courses/*"
type="CoursesAuthenticationHandler"
resourceType="Unspecified" />
Edit 2: Progress! When not logged in, requests made to the /courses/ directory are redirected to the login page. However, authenticated requests to the /courses/ directory return empty pages...
Edit 3: Per #PatrickHofman's suggestion, I've switched to using an HttpModule.
The Web.Config registration:
<modules>
<add name="CourseAuthenticationModule" type="CourseAuthenticationModule" />
The code:
using System;
using System.Web;
public class CourseAuthenticationModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
public void BeginRequest(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context;
HttpRequest request = context.Request;
HttpResponse response = context.Response;
if (request.Path.ToLower().StartsWith("/courses/") && !request.IsAuthenticated)
{
response.Redirect("/");
}
}
}
Now the problem is that !request.IsAuthenticated is always false. If I'm logged in, and navigate to the /courses/ directory, I'm redirected to the homepage.
What's the deal?
I think the last problem lies in the fact that a HttpHander handles stuff. It is the end point of a request.
Since you didn't add anything to the request, the response will end up empty.
Are you looking for HttpModules? They can be stacked.
As a possible solution when only files are necessary: read the files yourself in the request by either reading and writing to response or use TransmitFile. For ASP.NET pages you need modules.

Execute some code for each request for ASP.NET (aspx and cshtml )

Is there a way to write some code that would be executed for each request to a .aspx or a .cshtml page in asp.net 4.5 apart from using a base page class. it is a very huge project and making changes to all pages to use a base page is a nightmare. Also i am not sure how would this be done for a cshtml page since they don't have a class.
Can we use the Application_BeginRequest and target only the aspx and cshtml files since the website is running in integrated mode.?
basically, i have to check if a user who is accessing the website has a specific ip address against a database and if yes then allow access otherwise redirect.
we are using IIS8 and ASP.Net 4.5 and ASP.Net Razor Web Pages
Also i am not sure how would this be done for a cshtml page since they don't have a class.
You could place a _ViewStart.cshtml file whose contents will get executed on each request.
Alternatively you could write a custom Http Module:
public class MyModule: IHttpModule
{
public void Init(HttpApplication app)
{
app.BeginRequest += new EventHandler(OnBeginRequest);
}
public void Dispose()
{
}
public void OnBeginRequest(object s, EventArgs e)
{
// this code here's gonna get executed on each request
}
}
and then simply register this module in your web.config:
<system.webServer>
<modules>
<add name="MyModule" type="SomeNamespace.MyModule, SomeAssembly" />
</modules>
...
</system.webServer>
or if you are running in Classic Mode:
<system.web>
<httpModules>
<add name="MyModule" type="SomeNamespace.MyModule, SomeAssembly" />
</httpModules>
</system.web>
basically, i have to check if a user who is accessing the website has
a specific ip address against a database and if yes then allow access
otherwise redirect.
Inside the OnBeginRequest method you could get the current user IP:
public void OnBeginRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication;
var request = app.Context.Request;
string ip = request.UserHostAddress;
// do your checks against the database
}
Asp.net MVC filters are especially designed for that purpose.
You would implement ActionFilterAttribute like this (maybe put this new class in a Filters folder in your webapp solution):
public class IpFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string ip = filterContext.HttpContext.Request.UserHostAddress;
if(!testIp(ip))
{
if (true /* You want to use a route name*/)
filterContext.Result = new RedirectToRouteResult("badIpRouteName");
else /* you want an url */
filterContext.Result = new RedirectResult("~/badIpController/badIpAction");
}
base.OnActionExecuting(filterContext);
}
private bool testIp(string inputIp)
{
return true /* do you ip test here */;
}
}
Then you have to decorate any action that would perform the ipcheck with IpFilter like so :
[IpFilter]
public ActionResult AnyActionWhichNeedsGoodIp()
{
/* do stuff */
}

Logging server-wide request data (including POST data) in IIS 6 / ASP.NET webforms

Here's the big picture. We're running a server in IIS 6 that hosts several web sites and applications, and we're in the process of moving the whole thing to a different data center with a slightly different setup. We've notified our users and updated our DNS info so that theoretically everyone will be happily hitting the new server from day 1, but we know that someone will inevitably fall through the cracks.
The powers that be want a "Listener" page/handler that will receive all requests to the server and log the entire request to a text file, including (especially) POST data.
That's where I'm stuck. I don't know how to implement a single handler that will receive all requests to the server. I vaguely understand IIS 6 redirection options, but they all seem to lose the POST data on the redirect. I also know a little about IIS 6's built-in logging, but it ignores POST data as well.
Is there a simple(ish) way to route all requests to the server so that they all hit a single handler, while maintaining post data?
EDIT: This is in WebForms, if that matters, but other solutions (if small) are definitely worth considering.
If all the requests are POST's to ASP.NET forms then you could plugin a HttpModule to capture and log this data.
You wouldn't have to rebuild all your applications to deploy this either. All it would take is to drop the HttpModule into each application's /bin folder and add it to the <httpModules> section of your web.config files. For example:
using System;
using System.Diagnostics;
using System.Web;
public class SimpleLogger : IHttpModule
{
private HttpApplication _application;
public void Dispose() { }
public void Init(HttpApplication context)
{
_application = context;
context.BeginRequest += new EventHandler(Context_BeginRequest);
}
void Context_BeginRequest(object sender, EventArgs e)
{
foreach (string key in _application.Request.Form.AllKeys)
{
// You can get everything on the Request object at this point
// Output to debug but you'd write to a file or a database here.
Debug.WriteLine(key + "=" + _application.Request.Form[key]);
}
}
}
In your web.config file add the logger:
<httpModules>
<add name="MyLogger" type="SimpleLogger, SimpleLogger"/>
</httpModules>
Be careful though. If your site captures credit card details or other sensitive data. You may need to ensure this is filtered out or have it encrypted and away from personel who should have no need to see this information.
Also if you're logging to files, make sure the log files are outside any public facing web folders.
Here is code of custom HTTP module we use to log HTTP POST request data.
using System;
using System.Web;
namespace MySolution.HttpModules
{
public class HttpPOSTLogger : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
if (sender != null && sender is HttpApplication)
{
var request = (sender as HttpApplication).Request;
var response = (sender as HttpApplication).Response;
if (request != null && response != null && request.HttpMethod.ToUpper() == "POST")
{
var body = HttpUtility.UrlDecode(request.Form.ToString());
if (!string.IsNullOrWhiteSpace(body))
response.AppendToLog(body);
}
}
}
}
}
Do not forget to register it in web.config of you application.
Use system.WebServer section for IIS Integrated Model
<system.webServer>
<modules>
<add name="HttpPOSTLogger" type="MySolution.HttpModules.HttpPOSTLogger, MySolution.HttpModules" />
</modules>
</system.webServer>
Use system.web section for IIS Classic Model
<system.web>
<httpModules>
<add name="HttpPOSTLogger" type="MySolution.HttpModules.HttpPOSTLogger, MySolution.HttpModules"/>
</httpModules>
</system.web>
IIS log Before applying module:
::1, -, 10/31/2017, 10:53:20, W3SVC1, machine-name, ::1, 5, 681, 662, 200, 0, POST, /MySolution/MyService.svc/MyMethod, -,
IIS log After applying module:
::1, -, 10/31/2017, 10:53:20, W3SVC1, machine-name, ::1, 5, 681, 662, 200, 0, POST, /MySolution/MyService.svc/MyMethod, {"model":{"Platform":"Mobile","EntityID":"420003"}},
Full article:
https://www.codeproject.com/Tips/1213108/HttpModule-for-logging-HTTP-POST-data-in-IIS-Log

Session is null in IRouteHandler.GetHttpHandler with Asp.net routing

I'm trying to get Session enabled in the GettHttpHandler method of my IRouteHandler classes but session is always null. Could someone tell me what I'm doing wrong?
In global.asax I have
RouteTable.Routes.Add("All", new Route("{*page}", new MyRouteHandler()));
The MyRouteHandler class where Session is null looks like this:
public class MyRouteHandler : IRouteHandler, IRequiresSessionState
{
public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string test = HttpContext.Current.Session["test"].ToString();
return BuildManager.CreateInstanceFromVirtualPath("~/Page.aspx", typeof(Page)) as Page;
}
}
I made a small test app that shows the problem.
Could someone tell me what I'm doing wrong?
Edited to add:
Yes, I really need session data in the route handler. There are many reasons but one easily explainable is when the user can switch to browse the site in preview mode.
The site consists of a hierarchy of dynamic pages (/page1/page2...) in the database that can be published normally or to preview. A content producer browsing the site can choose to view just normal pages or also those published to preview. The browsing mode is stored in the user's session so therefor the route handler needs to know the browsing mode to be able to solve the requested page.
So I really need the session already at that stage.
I have explained reason behind this problem in this answer. And now I have found a solution to the problem!
You create a custom HttpHandler class:
class MyHttpHandler : IHttpHandler, IRequiresSessionState
{
public MyRequestHandler RequestHandler;
public RequestContext Context;
public MyHttpHandler(MyRequestHandler routeHandler, RequestContext context)
{
RequestHandler = routeHandler;
Context = context;
}
public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
public bool IsReusable
{
get { throw new NotImplementedException(); }
}
}
It is important to add IRequiresSessionState interface, otherwise IIS does not load session for this request. We do not need to implement logic of ProcessRequest and IsReusable, but class must implement the IHttpHandler interface.
You change your RouteHandler implementation:
public class MyRequestHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MyHttpHandler(this, requestContext);
}
public IHttpHandler DelayedGetHttpHandler(RequestContext requestContext)
{
// your custom routing logic comes here...
}
}
You simply move your original, Session dependent logic to DelayedGetHttpHandler function and in the GetHttphandler function you return an instance of the helping MyHttpHandler class.
Then, you hook your handling logic to the HttpApplication.PostAcquireRequestState event, e.g. in the Global.asax:
public class Global : HttpApplication
{
public override void Init()
{
base.Init();
PostAcquireRequestState += Global_PostAcquireRequestState;
}
}
For more reference, check this page: https://msdn.microsoft.com/en-us/library/bb470252(v=vs.140).aspx. It explains the request lifecycle and why I use the PostAcquireRequestState event.
In the event handler, you invoke your custom RouteHandling function:
void Global_PostAcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Handler is MyHttpHandler) {
var handler = HttpContext.Current.Handler as MyHttpHandler;
HttpContext.Current.Handler = handler.RouteHandler.DelayedGetHttpHandler(handler.Context);
}
}
And that's it. Works for me.
I am not sure that you can do this (although I may be wrong). My recollection is that IRequiresSessionState indicates that an HttpHandler needs session state, rather than the route handler (which is responsible for giving you a handler appropriate to the route).
Do you really need the session in the route handler itself and not the handler it gives out?
Well I know this is old thread but just putting up the answer here if anyone like me falls in the same scenario, I found an answer here
What you do is just add a runAllManagedModulesForAllRequests="true" attribute to your modules tag in web.config like below
<system.webServer>
.....
<modules runAllManagedModulesForAllRequests="true">
........
</modules>
......
</system.webServer>
However this is not a good solution as it calls managed module everytime, i am using
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
add it in modules section of web.config, this a better solution than the previous one.

Need url's to be non secure when moving away from a secured link (without hardcoded url's in html)?

I have an asp.net site. It has an order form which is accessible at https://secure.example.com/order.aspx. The links on the site do not include the domain name. So for example the home page is 'default.aspx'.
The issue is that if I click on a link like the home page from the secure page, the url becomes https://secure.example.com/default.aspx instead of http://www.example.com/default.aspx.
What's a good way to handle this? The scheme should automatically work using any domain name based on where it's launched from. So if the site is launched from 'localhost', moving away from the secured page, the url's should be http://localhost/...
The navigation links are in a master page.
I suppose the best solution for this would be a http module.
The simplest implementation of it is posted below. useUnsecureConnection variable contains the value indicating whether moving away is required (should be calculated by yourself).
public class SecurityModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(application_BeginRequest);
}
#endregion
#region Events Handling
protected void application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = ((HttpApplication)(sender));
HttpRequest request = application.Request;
HttpResponse response = application.Response;
// here should be you condition to determine
// whether to move away from secure page or not
bool useUnsecureConnection = true;
if (useUnsecureConnection && request.IsSecureConnection)
{
string absoluteUri = request.Url.AbsoluteUri;
response.Redirect(absoluteUri.Replace("https://", "http://"), true);
}
}
#endregion
}
And and of course don't forget to register module in your web.config:
<httpModules>
<!--Used to redirect secure connections to the unsecure ones
if necessary-->
<add name="Security"
type="{YourNamespace}.Handlers.SecurityModule,
{YourAssembly}" />
...
</httpModules>
</system.web>
BTW, for localhost the condition may looks like:
useUnsecureConnection = request.IsLocal;
which will be true if the IP address of the request originator is 127.0.0.1 or if the IP address of the request is the same as the server's IP address.

Resources