Setting a post-authentication View for Windows Authentication - c#

I have an MVC4 Intranet application (using the default template). I am using Windows Authentication as my login system, however, i want to be able to capture some details from the user the first time they register with the site.
Use Cases
First time user authenticates using their AD login (currently working). They are presented with an 'Enter your Details' View.
Second time user authenticates using their AD login. They are taken
straight to the home screen.
Cheers,
Dave

Create a custom AuthorizeAttribute like this:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private UnitOfWork _unitOfWork = new UnitOfWork();
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = false;
var username = httpContext.User.Identity.Name;
// Some code to find the user in the database...
var user = _unitOfWork.UserRepository.Find(username);
if(user != null)
{
// Check if there are Details for the user in the database
if(user.HasDetails)
{
isAuthorized = true;
}
}
return isAuthorized;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!AuthorizeCore(filterContext.HttpContext))
{
// If not authorized, redirect to the Details action
// of the Account controller...
var action = filterContext.RouteData.Values["action"];
if(filterContext.Controller is AccountController
&& action.Equals("Details"))
{
// Do nothing
}
else
{
filterContext.Result = new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary {
{"controller", "Account"}, {"action", "Details"}
}
);
}
}
}
}
Then, you can use it in your Controllers like this:
[MyAuthorize]
public class HomeController : Controller
{
}
Or, you can register it as a global action filter in your Global.asax file like this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyAuthorizeAttribute());
}

Related

C# .NET 6.0 How to redirect an unauthorized user to an unauthorizedpage

I would like to redirect the unauthorized user to a unauthorizedpage. Authorization is Roles based. For example [Authorize(Roles = "Admin")] I'm looking for a general solution. I don't want to write a redirect in every controllor/endpoint. I'm using Windows Auth with the Negotiate protocol.
I'm using the AuthorizeAttribute. When the user is unauthorized for a view then the application shows a blank HTML page to the user.
I tried multiple CustomAttributes, Configure AccesDeniedPaths, HandleUnauthorizedRequest. But every way ended in a blank HTML page.
I hope someone has an solution.
CustomAuthorizeAttribute
public class CustomAuthorizeAttribute : ActionFilterAttribute
{
public string Roles { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//if user isn't logged in.
if (filterContext.HttpContext.User.Identity == null || !filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectResult("/Unauthorized/");
}
var user = filterContext.HttpContext.User;
//Check user rights here
if (!user.IsInRole(Roles))
{
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.Result = new RedirectResult("/Unauthorized/");
}
}
}
Controller
[CustomAuthorize(Roles = "Admin")]
[HttpGet]
public IActionResult Index()
{
return View();
}
ASP.NET has a defualt [Authorize] attribute which you can add to an arbitrary action.
Eg:
[HttpGet]
[Authorize]
public async Task<ActionResult<IEnumerable<Classes>>> GetClasses()
{
return await _context.Classes.ToListAsync();
}
This will by default redirect the user to the login page if an unauthorized user tries to access a forbidden page.
However, if you want to redirect to a custom page. You could try writing a custom filter attribute like this.
public class CustomAuthorizeAttribute : 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));
}
//Check user rights here
if (userNotRight)
{
filterContext.HttpContext.Response.StatusCode = 302;
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
and use it in a controller like this,
[HttpGet]
[CustomAuthorize]
public async Task<ActionResult<IEnumerable<Classes>>> GetClasses()
{
return await _context.Classes.ToListAsync();
}
If you would like to authorize based on roles for the custom filter attribute. You could either
1. write a custom authorize attribute and add it along with the filter attribute.
public class AuthorizeAdmin : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authenticated
return false;
}
var user = httpContext.User;
if (user.IsInRole("Admin")) // Your desired role
{
return true;
}
}
}
controller:
[HttpGet]
[CustomAttribute]
[AuthorizeAdmin]
public async Task<ActionResult<IEnumerable<Classes>>> GetClasses()
{
return await _context.Classes.ToListAsync();
}
2. you could directly check it along with the custom filter attribute
public class CustomAuthorizeAttribute : ActionFilterAttribute
{
// Check if is in "Admin" role
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authenticated
return false;
}
var user = httpContext.User;
if (user.IsInRole("Admin")) // Your desired role
{
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));
}
//Check user rights here
if (userNotRight)
{
filterContext.HttpContext.Response.StatusCode = 302;
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
}
controller:
[HttpGet]
[CustomAttribute]
public async Task<ActionResult<IEnumerable<Classes>>> GetClasses()
{
return await _context.Classes.ToListAsync();
}

Skip filter execution based on another filter asp .net

I have an action that is being authorized as following:
[Authorize(Roles = "Admin, Agency, Subscribed, Normal")]
public ActionResult LocationProfile()
{}
what I need is to add another filter that gets executed before the authorization filter and if the result is true is doesn't execute the authorize attribute and proceeds to execute my action directly (LocationProfile())
is there any way to accomplish this task
You will have to roll your own version of the Authorize attribute that has that functionality built in. Included from the C# corner post linked above:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
Entities context = new Entities(); // my entity
private readonly string[] allowedroles;
public CustomAuthorizeAttribute(params string[] roles)
{
this.allowedroles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorize = false;
foreach (var role in allowedroles)
{
var user = context.AppUser.Where(m => m.UserID == GetUser.CurrentUser/* getting user form current context */ && m.Role == role &&
m.IsActive == true); // checking active users with allowed roles.
if (user.Count() > 0)
{
authorize = true; /* return true if Entity has current user(active) with specific role */
}
}
return authorize;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
In the AuthorizeCore method, you need to add your check to account for the situation describe.

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
{
}

Allow user to visit [Authorize] pages - MVC

My project got pages with [Authorize] where user have to log in to visit those pages.
Upon successful login with same userid and password as in database, the current users id get stored in session. But how do I do I authenticate/allow user to visit pages with [Authorize]?
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(User u)
{
if (ModelState.IsValid) //this is check validity
{
using (UserEntities db = new UserEntities())
{
var v = db.Users.Where(a=>a.UserName.Equals(u.UserName) && a.Password.Equals(u.Password)).FirstOrDefault();
if (v != null)
{
Session["LoggedUserID"] = u.Id.ToString();
Session["UserFullname"] = u.Name.ToString();
return RedirectToAction("AfterLogin");
}
}
}
return View(u);
}
Any help is much appreciate. Thanks.
If you absolutely want to manage login and security yourself using Session, You can create your own action filter which checks whether session has a user id set to it.
Something like this
public class AuthorizeWithSession : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.HttpContext.Session == null ||
context.HttpContext.Session["LoggedUserID"]==null)
{
context.Result =
new RedirectToRouteResult(new RouteValueDictionary(
new {controller = "Account", action = "Login"}));
}
base.OnActionExecuting(context);
}
}
Now decorate this action filter on your secure actions/controllers
[AuthorizeWithSession]
public class TeamController : Controller
{
}
You should have your own role management if you want to control what the users can do.
Each user should have one or more roles, each role can have a set of permissions and you can create an action filter that inherits from AuthorizeAttribute to make sure it is executed as early as possible.
Inside the AuthorizeCore method of the AuthorizeAttribute , you will see if the user is authenticated or not, and if he is authenticated then you can read his identity, read his roles and permissions from the database and compare it to a value passed to the role.
ex:
public class RequireRoleAttribute : AuthorizeAttribute
{
public RoleEnum[] RequiredRoles { get; set; }
public RequireRoleAttribute()
{
}
public RequireRoleAttribute(params RoleEnum[] roles)
: this()
{
RequiredRoles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var principle = httpContext.User;
if (principle == null || principle.Identity == null || !principle.Identity.IsAuthenticated)
{
return false;
}
if (RequiredRoles != null)
{
if (!HasRole(RequiredRoles))
{
httpContext.Response.Redirect("/AccessDenied");
}
}
return base.AuthorizeCore(httpContext);
}
public bool HasRole(RoleEnum[] roles)
{
foreach (var role in roles)
{
if (HasRole(role))
return true;
}
return false;
}
public bool HasRole(RoleEnum role)
{
return true if the user role has the role specified (read it from database for example)
}
}
Then in your controller, just annotate the controller or action with the attribute
[RequireRole(RoleEnum.Administator)]
public class MySecureController : Controller
{
}

.Net Web Api - Override AuthorizationFilter

Hello I have a web api controller inside a mvc web site.
I'm trying to allow access to the controller using 2 rules:
User is admin or the request came from local computer;
I'm new to AuthorizationFilterAttribute but I tried to write one that limit access
to local request only:
public class WebApiLocalRequestAuthorizationFilter : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (actionContext.Request.IsLocal())
{
return;
}
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Content = new StringContent("Username and password are missings or invalid");
}
}
Then I decorated my controller with 2 attributes as
[Authorize(Roles = "Admin")]
[WebApiLocalRequestAuthorizationFilter]
public class ContactController : ApiController
{
public ContactModel Get(int id)
{
ContactsService contactsService = new ContactsService();
return contactsService.GetContactById(id).Map<ContactModel>();
}
}
But as I suspected , now, in order to access the controller I need to be admin and the request should be made from localhost. How can I do it?
Kind regards,
Tal Humy
One solution is to create a class that inherits from AuthorizeAttribute
e.g. something like this
public class MyAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool accessAllowed = false;
bool isInGroup = false;
List<string> roleValues = Roles.Split(',').Select(rValue => rValue.Trim().ToUpper()).ToList();
foreach (string role in roleValues)
{
isInGroup = IdentityExtensions.UserHasRole(httpContext.User.Identity, role);
if (isInGroup)
{
accessAllowed = true;
break;
}
}
//add any other validation here
//if (actionContext.Request.IsLocal()) accessAllowed = true;
if (!accessAllowed)
{
//do some logging
}
return accessAllowed;
}
...
}
Then you can use it like so:
[MyAuthorizeAttribute(Roles = "Support,Admin")]
In the above code, IdentityExtensions checks for, and caches, ActiveDirectory roles which also allows us to fake the current user having roles by changing the cache.

Categories