PrincipalPermission on PageLoad - c#

I'm a newbie about the usage of Asp.NET membership capabilities and I want to know if it could be a good practice to deny the access of a whole page using code like this:
public partial class AdminPage : Page
{
[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
protected void Page_Load(object sender, EventArgs e)
{
...
}
}
I suspect that it is not a good way to do things, but I would like to know why !
Thanks.

Small point-- put the attribute on the class. This will cause the page to raise a Security Exception as soon as you navigate to it without appropriate rights. To keep users from viewing this page, check their credentials before displaying the URL. The attribute on the class is the strong guarantee that no ordinary user will run so much as a line of the code in that class.
Yes, this is a good technique for these reasons:
The attribute works when the thread principle and the HttpContext User object are set, with a suitable IPrincipal and IIdentity. (All this would happen in the Request Authentication event in global asax) These interfaces are defined by Microsoft, well documented and available in any context, any application that runs on a MS Operating system. So any half competent developer you grab off the street could be familiar with this before they start to read your code.
Also, since Thread's IPrincipal and IIdentity are used by Microsoft (it could have been any large company with a large user base), it's battle tested code. You can still do something stupid, but the existing patterns are there to help you fall into the pit of success.
On the other hand, if you are putting a custom object into Session, a magic cookie or some other token, then the maintenance developer will have to learn how it works from scratch and then review it to see if has exploitable vulnerabilities.

I think you will need a base class for all your pages, e.g.:
public abstract class BasePage : Page
{
// Note:
// 1. check on init, not on load
// 2. override protected method, not handle event
protected override OnInit(EventArgs e)
{
// check permissions here
}
}

Related

global.asax.cs authorize events for webapi need lock?

I am working on a web api and each request is authenticated with Authorize annotation on methods i.e. [Authorize (roles="trader")]
Based on the logs I can tell that multiple requests are entering the Application_PostAcquireRequestState event simultaneously.
As roles are loaded in Application_PostAcquireRequestState event, there can be race condition and some of the calls fail randomly.
I am not sure if I am on right track. The event is application level and Application.Lock() may fix the issue and like to know if it is the correct solution.
I have noticed a couple of calls to the web api failed, which were originated simultaneously.
I appreciate your help.
Global.ascs.cs
protected void Application_PostAcquireRequestState()
{
//Application.Lock();
//get user roles and verify access...
...
//Application.Unlock();
}
controller.cs
[Authorize(Roles = "Trader")]
public async Task<IHttpActionResult> GetOrder(long id)
{
//get order
}
You are wrong, this event, as well as a bunch of others (BeginRequest, AuthenticateRequest, AcquireRequestState etc.) is technically an application-level event (Application_...), however, actually it is a request-level event and multiple copies of the same handler are fired concurrently for different requests.
This means that the sender argument of the handler gives you exact execution context and is intended to be used like
protected void Application_PostAcquireRequestState( object sender, EventArgs e )
{
HttpApplication app = (HttpApplication)sender;
HttpContext ctx = app.Context; // current context
// with the current context in hand you can pretty much access anything
// including the Request, Response and last but not least, User
}
No need for locking or any other means of throttling.
I am only not sure why would you verify the access here, considering the MVC/WebAPI will do it in a moment in the pipeline, based on the Authorize and roles you put there.

CurrentUser custom identity and attributes

REWRITTEN QUESTION
I have an ASP.NET MVC 4 site that uses forms auth.
It also needs to retrieve custom user object from a service call and then set it to the HttpCurrent.User.Context.
this works fine but I realised that when it hits the post authenticate request that it will hit it several times per request - not good.
Global.asax.cs:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
IIdentity ui = HttpContext.Current.User.Identity;
MyMembershipUser myUser = new MyMembershipUser (ui.Name);
MyCustomPrincipal myPrincipal = new MyCustomPrincipal (ui, myUser);
HttpContext.Current.User = myPrincipal;
}
}
I cant entirely cache the user for a number of reasons so lets not go there.
so this gets executed a few times per request. This means for every hit, it calls the DB.
Some views on the site use the custom principal to display some user specific details only if they are authenticated. if they aren't, then it wont display it. But if they are authenticated, it gets the principal and casts it to "MyCustomPrincipal" so I can grab the properties I need to display.
How can I prevent these multiple hits?
I tried creating a custom Authorize attribute and doing the above code in there, it works but fails when it renders the view which can see the user is authenticated but fails to do the cast because at that point, the User Identity/principal is still set to the Generic principal.
typical code in the view:
#if (Helpers.UserContext.IsAuthenticated)
{
#: tmpStatus = '#Helpers.UserContext.User.Status';
}
UserContext.IsAuthenticated just returns HttpContext.Current.User.Identity.IsAuthenticated
User in UserContext does the casting:
return HttpContext.Current.User as MyCustomPrincipal
I hope this clarifies the question more!
I want to avoid multiple hits happening on the PostAuthenticateRequest but not sure why those hits are happening. I am not even sure if it is the right place to place it. I want to make sure that the Context User is all setup for subsequent accesses/requests to it without having to call the service layer to get the details again.
thanks
you minimise some action by check if authenticated
//assuming something like....
public override void Init() {
base.Init();
// handlers managed by ASP.Net during Forms authentication
PostAuthorizeRequest += new EventHandler(PostAuthHandler);
}
// try screen out some calls that arent authenticated yet.
public void PostAuthHandler(object sender, EventArgs e) {
if (Request.IsAuthenticated) {
//.... try a break to see how often
}
}
EDIT: But careful of multiple hits due to script and content bundling / loading.
Check the Request.Url value. Is it changing.
Also Note the thread Id. See Debug.Windows.Threads
The thread may also be changing.
Consider thread safety before you attempt any caching / global singletons etc.
You may wish consider moving some code to a controller Or Base Controller

Managing AutoFac lifetime scopes per session and request in asp.net mvc 3

I want to use AutoFac in a web application. I have the root container, a child container per session and a child container per request. I'm trying to figure out what the/a best way is to manage these lifetime scopes. In the Global.asax.cs I have added the following:
protected void Application_Start(object sender, EventArgs e)
{
var container = ...;
}
protected void Session_Start(object sender, EventArgs e)
{
var sessionScope = container.BeginLifetimeScope("session");
Session["Autofac_LifetimeScope"] = sessionScope;
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
var sessionScope = (ILifetimeScope) Session["Autofac_LifetimeScope"];
var requestScope = sessionScope.BeginLifetimeScope("httpRequest");
HttpContext.Current.Items["Autofac_LifetimeScope"] = requestScope;
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var requestScope = (ILifetimeScope)HttpContext.Current.Items["Autofac_LifetimeScope"];
requestScope.Dispose();
}
protected void Session_End(object sender, EventArgs e)
{
var sessionScope = (ILifetimeScope)Session["Autofac_LifetimeScope"];
sessionScope.Dispose();
}
protected void Application_End(object sender, EventArgs e)
{
container.Dispose();
}
How can I tell AutoFac to use my requestScope as the starting point for getting dependencies, so that the implementations I register as InstancePerLifetimeScope will be resolved using my requestScope?
If that is not possible, can I get AutoFac to create its per-request lifetime scope out of my sessionScope?
Or am I on the wrong track here? Could there be an other way of making AutoFac aware of this hierarchy?
Any help or other comments are appreciated.
In response to Steven.
I'm still in the early stages of prototyping, but possible things you could have in the sessionScope:
UserPreferences
Authentication and authorization context (e.g. user identity and roles)
Not related to the application I'm going to build, but in a e-commerce environment, the shopping cart could be session scoped. This is probably the best concrete example. It is something that you expect to live longer than a request, but shorter than the application.
There could be more than this, but if I have a strategy for the UserPreferences, Authentication and Authorization, then that strategy could also be applied to other components that will be created later.
A possible alternative is to get all the necessary information at the beginning of the request and place these configured components in the request scope. It will give me the result I expect, but it doesn't match the model I have in my mind about application->session->request hierarchy. I'm hoping to create a system that makes sense, since I'm definitely not the one that is going to maintain it.
What you'll need to do is implement your own Autofac.Integration.Mvc.ILifetimeScopeProvider. This interface is what governs how/where request lifetime scopes get generated. The default one, Autofac.Integration.Mvc.RequestLifetimeScopeProvider, handles creation, disposal, and maintenance of lifetime scopes on a per-request basis.
You can browse the code for RequestLifetimeScopeProvider here, which I highly recommend doing if you plan on undertaking this. It's the best sample I can think of containing working code showing the responsibility of one of these things.
Your implementation of ILifetimeScopeProvider will be where you grab the session child container, spawn the request container from that, and, at the end of the request, clean up the request container. You may also want to create the session container in there if it doesn't exist. Handling cleanup/disposal of the session container may be tricky in there, but from a design perspective, it'd be nice if it was all in one place rather than some in the provider, some in your application class.
Once you have your ILifetimeScopeProvider you'll use it when you set up your dependency resolver.
var scopeProvider = new MyCustomLifetimeScopeProvider(container, configAction);
var resolver = new AutofacDependencyResolver(container, scopeProvider);
DependencyResolver.SetResolver(resolver);
A couple of words of warning about the notion of a session-level scope:
Your memory footprint could be huge. You're going to end up with a lifetime scope for every user on your system. While a request lifetime pops up and goes away pretty quickly, these session-level scopes will live potentially a long time. If you have a lot of session-scoped items, you're going to have a pretty good sized memory usage for each user. If people "abandon" their sessions without properly logging out, that's all the longer these things will live.
Lifetime scopes and their contents aren't serializable. Looking at the code for LifetimeScope, it's not marked [Serializable]... and even if it was, the resolved objects living in there are not necessarily all marked serializable. This is important because it means your session-level lifetime scope might work on a single box with in-memory session, but if you deploy to a farm with SQL session or a session service, things will fall apart because the session can't serialize your stored scope. If you choose not to serialize the scope, then you have a different scope for each user across machines - also a potential problem.
Session isn't always rehydrated. If the handler being accessed (e.g., the web form) doesn't implement IRequiresSessionState, the session won't be rehydrated (whether it's in-proc or not). Web forms and the MvcHandler implement that by default so you won't see any issues, but if you have custom handlers that require injection you'll hit some snags since "Session" won't exist for those requests.
Session_End doesn't always fire. Per the docs on SessionStateModule.End, if you use out-of-proc session state you won't actually get the Session_End event, so you won't be able to clean up.
Given the restrictions, it's generally good to try to stay away from session-stored scopes. However... if that's what you're going to do, the ILifetimeScopeProvider is the way to do it.

When is it safe to do a Response.Redirect() without throwing an exception?

I have an intermediary class extending System.Web.UI.Page for all of my pages that require authentication. The class mostly does custom authentication handling.
When a user with insufficient access attempts to visit a page, I try to redirect the user back to the login page while preventing any further page events from being executed (ie. Page_load). The first solution that came to mind was the default implementation of Response.Redirect. Of course the downside to this is the possibility of ThreadAbortExceptions being thrown.
So my question is this: When (if at all) during the page life cycle is it actually safe to execute Response.Redirect() without ThreadAbortException ever being thrown?
public class CustomPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (!IsValid())
Response.Redirect("login.aspx", true);
}
}
It's never "safe" if you're passing true as the second parameter - it will always throw the exception. Internally, Response.Redirect() calls Response.End(), which directly aborts the current thread.
The only "safe" way to truncate an HttpRequest without having an exception thrown is by using HttpApplication.CompleteRequest(), but this will result in further code execution in the current request.
Curious, why are you doing this yourself? If anything, you should be using one of the authentication providers (ultimately, FormsAuthentication can be customized to handle almost any scenario you can think of).
Then, you can use the authorization element in your web.config file to indicate what pages/directories are not able to be accessed by anonymous users. ASP.NET will take care of the rest, redirecting the user to the login page you specify, as well as redirecting back when the user has logged in.
If you don't want a ThreadAbort exception you should pass False to the endResponse parameter. Of course this means you have to process the rest of the page, which is hard to get right.
Unless you are doing something really stupid like holding a lock, it is perfectly safe to throw a ThreadAbort exception in an ASP.NET page.
Another option is to use a Server.Transfer. This has better performance than a redirect, but it too uses ThreadAbort exceptions.

Earliest access to the .net lifecycle

After looking at the .net on IIS7 application lifecycle:
http://msdn.microsoft.com/en-us/library/ms178473.aspx
For maximum performance, I want to find a way to get my code started as soon as the HttpContext object is created but before HttpApplication is. (it's easy to run code after the HttpApplication class is loaded but before any of it's event are triggered by using the contructor of an HTTP Module like this:
public class AuthModule : IHttpModule
{
public AuthModule()
{
HttpContext.Current.Response.Write("hello world");
HttpContext.Current.Response.End();
}
#region IHttpModule Members
public void Dispose()
{ }
public void Init(HttpApplication context)
{ }
#endregion
}
I know that i won't get access to the User object, but i won't need it.
You cannot ever be sure your code starts before the HttpApplication instance is created, since these instances may be reused.
Also, running code at this stage is beyond the scope of the pipeline. It should make you ask yourself whether it's really a sensible thing to do.
And what's this about performance? You really think the time to create an instance of HttpApplication is going to register in your performance?
Take a step back and reconsider.
Look at the life-cycle events on MSDN. You can consider using one of those events if you want something earlier than the normal page events.

Categories

Resources