Session getting cleared with Authorize attribute? - c#

I am trying to customize my Authorize attribute so that it redirects the user to appropriate page if he is not authorized.
This is my code till now:
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
public string ErrorMessage { get; set; }
public string WebConfigKey { get; set; }
private const string UnauthorizedAccessMessage = "UnauthorizedAccessMessage";
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
HttpContext.Current.Session["foo"] = "bar";
base.HandleUnauthorizedRequest(filterContext);
if (string.IsNullOrEmpty(WebConfigKey))
throw new ArgumentNullException("WebConfigKey parameter is missing. WebConfigKey should give the actual page/url");
string configValue = ConfigurationManager.AppSettings[WebConfigKey];
if (string.IsNullOrEmpty(configValue))
throw new Exception(WebConfigKey + "'s value is null or empty");
if (!configValue.StartsWith("http"))
HttpContext.Current.Response.Redirect(WebUIUtils.GetSiteUrl() + configValue);
else
HttpContext.Current.Response.Redirect(configValue);
filterContext.Controller.TempData[UnauthorizedAccessMessage] = ErrorMessage;
HttpContext.Current.Session[UnauthorizedAccessMessage] = ErrorMessage;
}
}
Problem is whatever I store in Session or TempData in this method gets lost when the user arrives in some action method in controller after redirect is done from this method. I checked Session.Keys/TempData.Keys etc. But all values are lost. Probably something is happening in base.HandleUnauthorizedRequest(filterContext);. But I guess that calling to base is important.
Can anybody tell me the exact reason of this behavior and how do I prevent it from happening?

Form authorization and Session are distinct concepts for IIS. You can be authorized but your session can be not valid (for example try to restart the application pool).
Try with this custom attribute:
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (filterContext.Result == null)
{
if (filterContext.HttpContext.Session != null )
{
//add checks for your configuration
//add session data
// if you have a url you can use RedirectResult
// in this example I use RedirectToRouteResult
RouteValueDictionary rd = new RouteValueDictionary();
rd.Add("controller", "Account");
rd.Add("action", "LogOn");
filterContext.Result = new RedirectToRouteResult("Default", rd);
}
}
}
}

Related

ASP.Net Identity 2 - Why doesn't my filter work?

I've tried creating an easy filter to see if the user is in a role called "System Administrator", basically short hand for having to do [Authorize(Roles = "System Administrator")]. I thought it would be fairly simple, but I'm also fairly new to MVC so perhaps I'm overlooking something.
Here's my code:
using System.Web.Mvc;
namespace site_redesign_web.Filters
{
public class SystemAdminFilter : ActionFilterAttribute
{
string SysAdminRole = "System Administrator";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.User != null)
{
var userSysAdmin = filterContext.RequestContext.HttpContext.User.IsInRole(SysAdminRole) == true;
filterContext.ActionParameters["IsSysAdmin"] = userSysAdmin;
}
}
}
}
Can some one suggest where am I going wrong? A huge plus would be if the person isn't a System Administrator it would direct them to Home/NoPermissions.
Thank you!
Updated: Fixing all issues.
AJ. Here you go...
Finally fixed the problem
using ActionFilterAttribute
using System.Web.Mvc;
namespace site_redesign_web.Filters
{
public class SystemAdminFilter : ActionFilterAttribute
{
string SysAdminRole = "System Administrator";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.User != null)
{
var userSysAdmin = filterContext.RequestContext.HttpContext.User.IsInRole(SysAdminRole) == true;
if(!userSysAdmin)
{
filterContext.Result = new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary{
{"controller", "Home"},
{"action", "Index"}
});
}
}
}
}
}
and your Controller should be
[SystemAdminFilter] // at controller level
public SomeController : Controller
{
}
or you can also use it for a particular Action by annotating like this
public SomeController : Controller
{
[SystemAdminFilter] // at Action level
public ActionResult SomeAction()
{
// perform your actions
}
It will work because I manually passed in the User with his role in the Application_AuthorizeRequest in Global.asax
protected void Application_AuthorizeRequest(Object sender, EventArgs e)
{
FormsAuthenticationTicket formsAuthenticationTicket = new FormsAuthenticationTicket("Aravind", true, 30);
FormsIdentity formsIdentityId = new FormsIdentity(formsAuthenticationTicket);
GenericPrincipal genericPrincipal = new GenericPrincipal(formsIdentityId, new string[] { "SystemUser" }); //TEST with this redirected to Home Index place
HttpContext.Current.User = genericPrincipal ;
}
The next test I made was with this
GenericPrincipal genericPrincipal = new GenericPrincipal(formsIdentityId, new string[] { "System Administrator" }); //TEST with this did not perform an action
Since you are dealing with authorization, I would extend AuthorizeAttribute instead of ActionFilterAttribute which is mode general. You need to override only one method - HandleUnauthorizedRequest which is executed when authorization fails. Default implementation of AuthorizeAttribute already handles role based authorization for you.
public class SystemAdminAttribute : AuthorizeAttribute
{
private const string SysAdminRole = "System Administrator";
public SystemAdminFilter()
{
//this defines the role that will be used to authorize the user:
this.Roles = SysAdminRole;
}
//if user is not authorized redirect to "Home/NoPermissions" page
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if(!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
else
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Home", action = "NoPermissions" }));
}
}
}
Once your attribute is implemented, decorate corresponding Controllers or Actions with it:
[SystemAdmin]
public SysAdminController : Controller
{
}

asp.net mvc validate [HttpPost] ActionResult()

I need to implement a ActionFilterAttribute [POST] ActionResult() in the controller. The problem is that I try to “redirect” to a page if validation failed... But it does not work. Validation runs, but then returns to the ActionResult() next line and finally when the view is returned, only then “redirected” to the page listed in the validation. Ultimately what I need is to stop the ActionResult() statements and “redirect” to the page listed in the validation. I tried OnActionExecuting() and OnActionExecuted() but does not work any
I need to...
filterContext.HttpContext.Response.Redirect (loginUrl, true);
Run away, “redirecting” the page indicated
My code:
[HelperSomeValidations("")]
[HttpPost]
public ActionResult Create(Pais pais)
{
try
{
PaisBLL.saveNew(pais);
}
catch (Exception ex)
{
ViewBag.error = ex;
return View(“Error”);
}
return RedirectToAction(“Index”);
}
public class HelperSomeValidations : ActionFilterAttribute
{
public HelperSomeValidations(String permiso)
{
this.permiso = permiso;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var user = filterContext.HttpContext.Session["coco"];
if (user == null) //validates if the user just login
{
//send them off to the login page
var url = new UrlHelper(filterContext.RequestContext);
var loginUrl = url.Content(“~/Usuario/Login”);
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
else
{
if (permission != “”)
{
//does some validations with “permission”
}
}
}
}
Thks!
I know this doesn't solve the problem you have posted but I feel it's a better solution. I would personally use an AuthoriseAttribute here instead as this is what it's designed todo.
public class Authorise : AuthorizeAttribute
{
private readonly string _permissionSystemName;
public Authorise()
{
}
public Authorise(string permissionSystemName)
{
_permissionSystemName = permissionSystemName;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//DO some logic and return True or False based on whether they are allowed or not.
return false;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
area = filterContext.HttpContext.Request.RequestContext.RouteData.Values["area"],
controller = "Generic",
action = "PermissionDenied"
})
);
}
}
Usage would be along the lines of:
[Authorise("SomePermissionName")]
public class MyController : Controller
{
}
Instead of calling filterContext.HttpContext.Response.Redirect(loginUrl, true), you need to set the filterContext.Result to a RedirectResult.

Customize Authorize Filter attribute parameter

I have the following requirement to implement the Access Control list
public class SecurityObject{
public string Key{get;set;}
public string DisplayName{get;set;}
public bool isAllowed{get;set;}
}
public class Role{
List<SecurityObject> AccessibleObjects{get;set;}
}
Currently I use forms authentication for basic authorization. Below is my code
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public override void Init()
{
this.PostAuthenticateRequest += new
EventHandler(MvcApplication_PostAuthenticateRequest);
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie =
HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket =
FormsAuthentication.Decrypt(encTicket);
string[] userData = ticket.UserData.Split(new string[] { "___" },
StringSplitOptions.None);
string[] roles = null;
if (userData.Length > 1)
{
roles = userData[1].Split(',');
}
MyCustomIdentity identity = new MyCustomIdentity(ticket);
GenericPrincipal principle = new GenericPrincipal(identity, roles);
HttpContext.Current.User = principle;
}
}
}}
My current controller class
public class AdminController : Controller
{
[HttpPost, Authorize, ValidateAntiForgeryToken]
public ActionResult SaveUser(UserDetailViewModel viewModel)
{
}
}
My Target controller class
public class AdminController : Controller
{
[HttpPost, Authorize(ACLKey="USR_SAVE"), ValidateAntiForgeryToken]
public ActionResult SaveUser(UserDetailViewModel viewModel)
{
}
}
I want my action method to be decorated with ACLKey and I would like to check whether the User Role has the given key and based on that I need to execute or return HttpUnauthorizedResult page, even for Ajax requests from jQuery.
I referred many like Customizing authorization in ASP.NET MVC But i didnt find a way to execute both forms authentication and my custom ACLKey check.
How do i parse the value USR_SAVE and process custom authentication using CustomAuthorizeFilter?
You can try like this
public class FeatureAuthenticationAttribute : FilterAttribute, IAuthorizationFilter
{
public string AllowFeature { get; set; }
public void OnAuthorization(AuthorizationContext filterContext)
{
var filterAttribute = filterContext.ActionDescriptor.GetFilterAttributes(true)
.Where(a => a.GetType() ==
typeof(FeatureAuthenticationAttribute));
if (filterAttribute != null)
{
foreach (FeatureAuthenticationAttribute attr in filterAttribute)
{
AllowFeature = attr.AllowFeature;
}
List<Role> roles =
((User)filterContext.HttpContext.Session["CurrentUser"]).Roles;
bool allowed = SecurityHelper.IsAccessible(AllowFeature, roles);
if (!allowed)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
}
In you action method
[FeatureAuthentication(AllowFeature="USR_SAVE")]
public ActionResult Index()
{
}
Hope this will help you!
You can use a filter attribute:
public class ACLCheckAttribute : FilterAttribute, IActionFilter
In OnActionExecuting, you can grab USR_SAVE. Without knowing where it comes from, I would assume that it comes from:
The Form: you can grab any form values from the context passed into ONActionExecuting, by navigating to the HttpContext.Request.Form collection
Session, etc.: HttpContext would also have these.
The action method: From an attribute, using the context passed in for the action, it has a list of ActionParameters that can be accessed like a dictionary, allowing you to check and extract your value
If somewhere else, please comment where. You can apply this attribute to a controller or method, or globally set it by adding it to the globalfilters collection (GlobalFilters.Filters.Add()), or in the FilterConfig file in the App_Start folder.

Using Action Filters on MVC C# using query String

Im using class name RightCheckerAttribute to check user permission in MVC3 application...
So the RightCheckerAttribute class is like this...
public bool isAdmin { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContextBase context = filterContext.HttpContext;
bool result = Convert.ToBoolean(context.Request.QueryString["isAdmin"].ToString());
if (isAdmin != result)
{
RouteValueDictionary redirecttargetDictionary = new RouteValueDictionary();
redirecttargetDictionary.Add("action", "NoPermission");
redirecttargetDictionary.Add("controller","Singer");
filterContext.Result = new RedirectToRouteResult(redirecttargetDictionary);
}
//base.OnActionExecuting(filterContext);
}
So in Method i applying this have head as..
[RightChecker (isAdmin=true)]
Im Executing this method as this..
http://localhost:5576/Singer/DeleteSinger?isAdmin=true
The problem is whether I'm passing true or false... I got result variable as false... And I'm getting:
Exception[Null Object references]...
It seems you are not passing the isAdmin=false or isAdmin=true in your query string. It works for me. However you will need to handle the situation where you are not passing the querystring parameter. Check my implementation. As mentioned in the comments section of the question, it is not secured enough to pass this through a query string.
public class RightChecker : ActionFilterAttribute
{
public bool IsAdmin;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
bool result = false;
if (filterContext.HttpContext.Request.QueryString["isAdmin"] != null)
{
bool.TryParse(filterContext.HttpContext.Request.QueryString["isAdmin"].ToString(), out result);
}
if (IsAdmin != result)
{
//your implementation
}
}
}
Your action method
[RightChecker(IsAdmin=true)]
public ActionResult AttCheck()
{
return View();
}
check rights from querystring is not really safe.
you can try this:
[link] "Security aware" action link?
but due to mvc 3 api changes , some code obsoleted in ActionIsAuthorized Method , you can fix it youself , see my question asked here [link] https://stackoverflow.com/questions/10545018/how-to-get-authorizationfilters-from-filterproviders
Seems like maybe the context.Request.QueryString["isAdmin"].ToString() is causing a NullReferenceException.
Try
var param = context.Request.QueryString["isAdmin"] as string ?? "false";
var result = param == "true";
Pass this in your ViewData shown below:
public ActionResult Test(bool testParam)
{
ViewData["isAdmin"] = testParam;
return View();
}

custom attribute to redirect based user object property (asp.net mvc)

I was using a custom authorize attribute, to restrict users without subscription from accessing some actions
public class IsSubscriptionActive : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//check if user logged in , if not return false
//get user object from request
if(UserObject.IsSubscriptionActive)
return true;
else
return false;
}
}
The problem here is that doing this redirects users to login page regardless of whether the user is logged in or not.
So, I want to use the default authorize attribute as it is, but have another attribute which will check for subscription status and redirect.
How can I do this?
Not tested but try it out:
public class IsSubscribedAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.Identity == null ||
!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result =
new RedirectResult(System.Web.Security.FormsAuthentication.LoginUrl
+ "?returnUrl=" +
filterContext.HttpContext.Server.UrlEncode
(filterContext.HttpContext.Request.RawUrl));
}
if (isSubscribed)//check subscription here.
{
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.Result = new HttpUnauthorizedResult();
}//you can set the statuscode/result as you like?
}
}

Categories