MVC 4 - Losing custom principal between beginrequest and endrequest - c#

In my project (c#), we have an HttpModule that creates a custom Principal that we attach to the CurrentPrincipal.
This is working in all of our MVC3 apps and in our classic ASP.Net apps.
We have an AuthorizeAttribute override we use to secure our Controller methods - seems pretty standard.
The problem is that in the custom authorizeAttribute, the user (httpContext.User) is a RolePrincipal and not the custom principal.
To troubleshoot, I put some handlers in my global.asax to trap beginrequest() and endrequest(). Well, in BeginRequest my User is what we expect - the custom principal. In EndRequest, the user is a RolePrincipal again. The web.config declarations of the HttpModule are good - I can step thru the HttpModule's code.
Does anyone know what's going on? We have a custom HttpModule, but I can't modify that code for this project (it's being used everywhere and it works fine).
This is my first MVC4 project - I'm wondering if MVC4 does something differently.
Code below. Is there any info I've left out?
edit: added authorizationattribute code.
Code
(In HttpModule)
private void BeginRequest(object Sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
var Id = new TASBIdentity();
context.User = new TASBPrincipal(Id);
Thread.CurrentPrincipal = context.User;
(etc...)
(In global.asax)
void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
var user = context.User; // user is correct type
}
void Application_EndRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
var user = context.User; // user is default type (not correct)
}
(In the authorizeattribute)
public class SecuredByFunctionAttribute : AuthorizeAttribute
{
private readonly string _functionKey;
public SecuredByFunctionAttribute(string functionKey)
{
_functionKey = functionKey;
}
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
return httpContext.User.IsInRole(_functionKey);
}

Related

use session in Web Api 2

I have read that an effective way to use enable session in web api 2 is like so:
protected void Application_PostAuthorizeRequest()
{
System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.ReadOnly);
}
I have also created a class that inherits from AuthorizationFilterAttribute and overrides the OnAuthorization method.
But this event is never called - what am I doing wrong?
You could try creating a HttpModule:
public class WebApiSessionModule : IHttpModule
{
protected virtual void OnPostAuthorizeRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (this.IsWebApiRequest(context))
{
context.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.ReadOnly);
}
}
}
You'll need to add this to your web.config in
<system.web>
<httpModules>

How to handle custom security on each page?

This might sound like a stupid question, but I am about to implement a custom security database and framework for a new site. I was wondering how best to handle this.
NOTE: I am NOT using the ASP.NET Membership for this, I am using a custom database and everything custom for user management.
There will be several levels of security, so I am a bit stumped on this without making it too difficult. The only thing I could think of so far is check on EVERY PAGE in the Page_Load if they have the right security:
protected void Page_Load(object sender, EventArgs e)
{
CustomUser user = Session["User"] as CustomUser;
if(user != null && user.CanAccessFeature("TopicModeration"))
{
//initialize page elements
}
else
{
Response.Redirect("Default.aspx?featureDenied=TopicModeration", false);
Context.ApplicationInstance.CompleteRequest();
}
}
That works fine, but if I have dozens of pages that have different restrictions, it can get a bit repetitive. Does anybody have any thoughts on this? Should I inherit from System.Web.Page for each security feature, and use that on the page instead?
Thanks!
May i suggest the following approach:
Create a custom controller class as such:
public class CustomController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
CustomUser user = Session["User"] as CustomUser;
if(user != null && user.CanAccessFeature("TopicModeration"))
{
base.OnActionExecuting(filterContext);
}
else
{
filterContext.Result = new RedirectResult("Default.aspx?featureDenied=TopicModeration", false);
Context.ApplicationInstance.CompleteRequest();
}
}
}
Then you may have your controllers where you want that check to inherit from this controller.
You can create a Base Class and make all master pages (or pages) inherit that class.
Here is an example when a Master Page inherits a class.
Class for all master pages to inherit.
public class PageBase: System.Web.UI.MasterPage
{
protected override void OnLoad(EventArgs e)
{
//Put your security code here...
base.OnLoad(e);
}
}
Here is a Master page inheriting the class above.
public partial class Site1ColMaster : MySite.PageBase
{
protected void Page_Load(object sender, EventArgs e)
{
//Master page
}
}

Web Api 2 Stateless with Users

I believe I understand the basics of sessionless/stateless REST but I am having problems with implementation in Asp.Net Web Api 2 because I haven't used it before. I have set up ApiControllers that use a custom System.Web.Http.AuthorizeAttribute like this.
public class ApiAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization != null)
{
//Set identity??
return;
}
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
I have a database that contains users and I need to use them for getting privileges to get/post/put/delete things but dont want to use a session. I have never worked with the asp.net Identity so I am not familiar with its features and capabilities.
My idea for implementation is to use user credentials or api secret signing to authenticate and get privileges for a user for every request. The question is, by using a AuthorizeAttribute or something similar, how do i give the controller(s) during that one request the user information if their credentials were correct?
UPDATE:
Is using this.User (ApiController.User) session based or can it be used for that single request. If so, how does one set it
You can use HttpContext.Items to hold user data for current requests.
After setting identity based on Auth header , you can have
System.Web.HttpContext.Current.Items["userdata"]=userDataObject,
Another approach would be write your own action filter for authentication (but take utmost care)and pass data to controller.
public class MyAuthAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//do authorization here
base.OnActionExecuting(filterContext);
// Create object parameter.
filterContext.ActionParameters["userdata"] = new User("John", "Smith");
}
}
then in controller
[MyAuthAttribute]
ActionResult SomeAction(User userdata) //this will have user data
{
}
It looks like that using IPrincipal and setting HttpContext.Current.User will allow the ApiControllers to access that user through using
this.User
with web api not having access to the session
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization != null)
{
//Check user credentials/token here
//Get internal user
IPrincipal principal = new MyOwnCustomPrincipal(internalUser);
HttpContext.Current.User = principal;
return;
}
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}

Dependency Injection into global.asax

Injecting dependencies in Global.asax does not seem to always work. Sometimes it does, sometimes I get a ContextDisposedException (it seems that the problem occurs when I'm doing a Page.Redirect ??). I'm in an ASP.NET WebForm context.
Here is my code:
public class Global : HttpApplication
{
[Inject]
public UserManager UserManager { get; set; }
private void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
GlobalSecurityContext.SetPrincipal(User);
string path = Request.AppRelativeCurrentExecutionFilePath;
if (path.Contains(".aspx"))
{
// Get the current user
var userData = UserManager.GetByIdWithLogin(User.Identity.Name);
if (userData != null)
{
LoginDataDTO data = userData.LoginData;
if (data.XXX && ...)
{
Response.Redirect(...);
}
}
}
}
}
protected void Session_End(Object sender, EventArgs e)
{
UserManager.Logout();
}
}
In this post How to inject dependencies into the global.asax.cs, Mark Seemann says that one should not use Dependency Injection in global.asax because global.asax IS the Composition Root.
So what is the best way to solve my problem since I don't want to directly call my UserManager because the constructor needs a repository
public UserManager(IGenericRepository repository) : base(repository)
{
}
and the GenericRepository has itself a constructor that needs a IContext
public GenericRepository(IContext context)
{
}
I could probably do new UserManager(new GenericRepository(new MyContext)) but
I will not reuse the same context for the whole request
I need to add a reference on my AccessLayer in the GUI, what I would like to avoid
Just as an information, currently I'm injecting the Context like this:
// Dynamically load the context so that we dont have a direct reference on it!
string contextType = // read type from web.config
if (!String.IsNullOrEmpty(contextType))
{
Type context = Type.GetType(contextType);
Bind<IContext>().To(context).InRequestScope();
}
Any help would be greatly appreciated !
[Edit]:
Changing the UserProperty property like this works:
public UserManager UserManager
{
get { return ServiceLocator.Current.GetInstance<UserManager>(); }
}
In this case you can build your Ninject container, and use it a Service Locator for this particular instance (since you're in the Composition Root - you can't inject anything at this point).

OnActionExecuting equivalent in standard asp.NET?

Is there an equivalent for MVC.NET's OnActionExecuting in standard asp.NET? ?
I thought it would be Page_Load since OnActionExecuting would be called each time an action is executed (or the page loads). But I'm running into inheritance issues when I try to use Page_Load instead.
Since it is very difficult to make my solution work with a Page_Load I'm thinking I might not have the best ... solution.
Any thoughts on whether they are equivalent or close enough?
Background:
I'm converting a piece of an MVC3 application into a standard .NET to wrap in a SharePoint Web Part.
Here's the MVC code I'm trying to translate, as you can see its the user security bits I'm translating:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
if (!SiteCacheProvider.ItemCached(enmCacheKey.SiteSetting)) {
if (filterContext.IsImplementedGeneralPrincipal()) {
IUserProfile userProfile = ((IGeneralPrincipal)filterContext.HttpContext.User).UserProfile;
SiteCacheProvider.ChangeSiteSetting(userProfile.SiteID);
}
}
base.OnActionExecuting(filterContext);
}
First, take on account that no Actions are in ASP.NET because the model is different (Event-Based) - There're no methods(actions) which you can decorate with Action Filters, it's all about the Page-Cycle events.
Second, In ASP.NET, you may use HTTP modules (HttpApplication.BeginRequest particularly) in order to intercept incoming requests to your application pages by adding your required logic.
From MSDN:
HTTP Modules use to intercept HTTP requests for modifying or utilize
HTTP based requests according to needs like authentication,
authorization, session/state management, logging, modifying Response,
URL rewriting, Error handling, Caching....
For example:
using System;
using System.Web;
using System.Collections;
public class HelloWorldModule : IHttpModule
{
public string ModuleName
{
get { return "HelloWorldModule"; }
}
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)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("<h1>HelloWorldModule: Beginning of Request</h1><hr>");
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("<hr><h1>HelloWorldModule: End of Request</h1>");
}
public void Dispose()
{
}
}

Categories

Resources