I need to write some code to find an ID in my database of a Project.
Users are coupled to a project and all the projects have a lot of connections to other objects, such as Sessions.
Now I need to check before running any Actions, if the user trying to access the Session, is connected to the same project as the session is connected to.
For this i want to use an [Attribute] on the Actions.
MVC: creating a custom [AuthorizeAttribute] which takes parameters?
This question and answer got me started, but i'm having trouble using the constructor of the controller to get my Project ID
the goal is that i can write some code in each constructor, of all my controllers of objects depending on the Projects, find the project ID, and make it accessible (public), so my [customauthorize] will have access to this project ID to check whether the user has access or not.
My problem:
public class SessionController : Controller {
NASDataContext _db = new NASDataContext();
public SessionController() {
var test = RouteData;
var ses = _db.Sessies.First(q=>q.Ses_ID==1);
}
How do I access my routedata? RouteData is null, HttpContext is null and Request is null.
I need the ID in the url, which is in the routedata...
I would suggest placing this check in the Model rather than the Controller. In the Controller you'll need to decorate each action that requires this check, remember this is going execute code on every action you apply it to so you probably don't want to apply it at Controller level to start with. The simpler approach is to implement the check once in the Model then you have no 'concern' in your Controller for access rights. This will make the testing of this access right check possible as you'll only have the test in one place.
This is what i did now to fix it and i'm quite happy about it.
Module Partial:
public partial class Module {
public string FullName {
get {
return Mod_Code + " " + Mod_Titel;
}
}
public string ShortName {
get {
return Mod_Code;
}
}
public bool IsAccessible() {
return this.Projecten.IsAccessible();
}
}
Projects Partial:
public partial class Projecten {
public string FullName {
get {
if (Proj_Kortenaam == Proj_Naam)
return Proj_Kortenaam;
return Proj_Kortenaam + " " + Proj_Naam;
}
}
public string ShortName {
get {
return Proj_Kortenaam;
}
}
public bool IsAccessible() {
return IsAccessible(HttpContext.Current.User);
}
public bool IsAccessible(IPrincipal user) {
//this code checks if the user can access or not
return MvcApplication.projectToegankelijk(user, this._Proj_ID);
}
}
then in the Modules controller
[NonAction]
public ActionResult noRights() {
ViewData["delError"] = "You have no rights.";
return View("Error");
}
//
// GET: /Modules/Details/5
public ActionResult Details(int id) {
var mod = _db.Modules.First(q => q.Mod_ID == id);
if (mod.IsAccessible()) {
return View(mod);
}
return noRights();
}
I think this works pretty neat :)
Related
Is it possible to pass into the ModelBinder which implementation you want to use inline?
Given the following definitions:
public interface ISomeInterface
{
string MyString{get;set;}
}
public class SomeInterfaceImplementation_One : ISomeInterface
{
private string _MyString;
public string MyString
{
get {return "This is implementation One " + _MyString ; }
set { _MyString = value; }
}
}
public class SomeInterfaceImplementation_Two : ISomeInterface
{
private string _MyString;
public string MyString
{
get {return "This is implementation Two" + _MyString ; }
set { _MyString = value; }
}
}
Given this route in asp.net mvc core:
public ActionResult InterfaceWithInlineImplementation([ModelBinder(typeof(SomeBinder))]ISomeInterface SomeInterface)
{
//Return actionresult
}
I do not want a different ModelBinder class for each implementation rather I would like each route to specify which implementation inline.
So something like:
[UseImplementation(SomeInterfaceImplementation_One)]
public ActionResult InterfaceWithInlineImplementation([ModelBinder(typeof(SomeBinder))]ISomeInterface SomeInterface)
{
}
Or:
public ActionResult InterfaceWithInlineImplementation([ModelBinder(typeof(SomeBinder), ConcreteType = SomeInterfaceImplementation_Two )]ISomeInterface SomeInterface)
{
}
This way the SomeBinder class can access which implementation is being requested in the BindModelAsync method of SomeBinder : IModelBinder class.
public class SomeBinder : Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder
{
public Task BindModelAsync(Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
string valueFromBody = string.Empty;
using (var sr = new StreamReader(bindingContext.HttpContext.Request.Body))
{
valueFromBody = sr.ReadToEnd();
}
if (string.IsNullOrEmpty(valueFromBody))
{
return Task.CompletedTask;
}
var settings = new JsonSerializerSettings()
{
ContractResolver = new InterfaceContractResolver(), // Need requested implementation from InterfaceWithInlineImplementation() method
};
var obj = JsonConvert.DeserializeObject(valueFromBody, [**Need Requested Implementation from Method**], settings);
bindingContext.Model = obj;
bindingContext.Result = ModelBindingResult.Success(obj);
return Task.CompletedTask;
}
Use generics.
public class SomeBinder<TConcreteType> : IModelBinder
{
}
Then your signature becomes
public ActionResult InterfaceWithInlineImplementation(
[ModelBinder(typeof(SomeBinder<SomeInterfaceImpelemtation_One>))]ISomeInterface SomeInterface)
Then deserialization is:
JsonConvert.DeserializeObject<TConcreteType>(json)
However based on your last comment it sounds like you just need to Prevent overposting instead of this convoluted model binding.
So lets say the client knows that the server implementation has security methods and tries to match the signature hoping everything get deseriazled for example. Its being explicit as to what you're expecting. And you're explicitly expecting only the contract definition and nothing more.
Excerpt:
Mass assignment typically occurs during model binding as part of MVC. A simple example would be where you have a form on your website in which you are editing some data. You also have some properties on your model which are not editable as part of the form, but instead are used to control the display of the form, or may not be used at all.
public class UserModel
{
public string Name { get; set; }
public bool IsAdmin { get; set; }
}
So the idea here is that you only render a single input tag to the markup, but you post this to a method that uses the same model as you used for rendering:
[HttpPost]
public IActionResult Vulnerable(UserModel model)
{
return View("Index", model);
}
However, with a simple bit of HTML manipulation, or by using Postman/Fiddler , a malicious user can set the IsAdmin field to true. The model binder will dutifully bind the value, and you have just fallen victim to mass assignment/over posting:
So how can you prevent this attack? Luckily there's a whole host of different ways, and they are generally the same as the approaches you could use in the previous version of ASP.NET. I'll run through a number of your options here.
Continue to article...
I have a windows authentication MVC app that needs the username to do a lookup to determine if links are visible and set authorization. Note: I do visibility/Authorization with roles as well.
I need the username so I am currently doing it in OnAuthentification (not sure if this is the right place). I am splicing the username down to put it on the main page and say welcome, User. (presentation purposes)
[Authorize]
public abstract class ApplicationController : Controller
{
public static bool IsApprover;
protected override void OnAuthentication(AuthenticationContext filterContext)
{
base.OnAuthentication(filterContext);
if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated == true)
{
string userName = User.Identity.Name.Remove(0, 16).Replace('.', ' ').ToLower();
HttpContext.Application["UserName"] = TitleCase(userName, "Nothing");
//Initialize Values
HttpContext.Application["IsApprover"] = false; //used for link visibility
IsApprover = false; //used for Authorization
//do db lookup and set IsApprover values
}
}
}
So, I set the values above. I am not including the entity framework code just to be brief. The above works fine and every controller inherits from ApplicationController.
I also have
public class CustomAuthorizationValue : AuthorizeAttribute
{
private bool localIsAllowed;
public CustomAuthorizationValue(bool isAllowed)
{
localIsAllowed = isAllowed;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Request.IsLocal)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authorized => no need to go any further
return false;
}
return localIsAllowed;
}
return false;
}
}
For Authorization I use:
[CustomAuthorizationValue(IsApprover)]
public ActionResult Approve()
{
//code
}
For Visibility in Razor I use
#if((bool)#HttpContext.Current.Application["IsApprover"] == true)
{
<li>Approve (#HttpContext.Current.Application["ApproveCount"])</li>
}
This works fine but I have 2 different variables to use,
one for visibility (HttpContext.Current.Application["IsApprover"])
and
one for Authorization (IsApprover).
Is there a more elegant solution?
Is there another place to put the code rather than override void OnAuthentication?
Is there a way I can just set 1 variable for visibility and Authorization rather than having 2?
Is this the best practice or am I way off?
The above works fine and every controller inherits from
ApplicationController.
Hmmmm. You are storing user specific information information in the wrong scope:
HttpContext.Application["UserName"] = TitleCase(userName, "Nothing");
HttpContext.Application["IsApprover"] = false;
In ASP.NET, the Application scope is shared among ALL users of your website. So you have a concurrency issue here.
You should use the HTTP Context scope instead:
HttpContext.Items["UserName"] = TitleCase(userName, "Nothing");
HttpContext.Items["IsApprover"] = false;
Is there a more elegant solution?
You could use a view model:
public class MyViewModel
{
public string UserName { get; set; }
public bool IsApprover { get; set; }
}
and then have a couple of extension methods to work more easily:
public static class HttpContextExtensions
{
private const string MyViewModelKey = "__MyViewModel__";
public static MyViewModel GetMyViewModel(this HttpContextBase context)
{
return (MyViewModel)context.Items[MyViewModelKey];
}
public static void SetMyViewModel(this HttpContextBase context, MyViewModel model)
{
context.Items[MyViewModelKey] = model;
}
}
and then use those extension methods:
if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
{
string userName = User.Identity.Name.Remove(0, 16).Replace('.', ' ').ToLower();
bool isApprover = ... do db lookup and set IsApprover value
var model = new MyViewModel
{
UserName = TitleCase(userName, "Nothing"),
IsApprover = isApprover,
}
this.HttpContext.SetMyViewModel(model);
}
and in your view:
#if(HttpContext.GetMyViewModel().IsApprover)
{
<li>
<a href="#Url.Action("Approve", "Approve")">
Approve (#HttpContext.Current.Application["ApproveCount"])
</a>
</li>
}
NOTE: In this anchor text once again you seem to be using the Application scope to store user specific information such as ApproveCount which we discussed earlier.
Is this the best practice or am I way off?
Well, I would probably use claims based authentication and store this information (IsApprover, ...) as claims in the current user.
I'm working on a asp.net mvc3 solution that has 3 projects Data, Service, and Web. I've been using interfaces to abstract the service layer as much as possible so the web only knows about the service layer, and not the Data where the true domain models are held. The web project uses view models and simply passes things to the service model as broken out parameters vs a domain object. For example creation of a user I'd use an interface like this.
public interface IUserService
{
void CreateUser(string userName, string firstName, string lastName....);
}
But after thinking about it for a while something like GetUsers I'd need to return a domain object of some type, and this would require me adding a data reference in the web project.
public interface IUserService
{
void CreateUser(string userName, string firstName, string lastName....);
**IEnumerable<User>** GetUsers();
}
So I think I have two choices, either break my domain objects into their own project which all projects then have reference to or possibly add the data reference to the web project. I think the first option is the best but I'm curious if there are other options. Thanks
Instead of returning User, I would:
// MyCompany.Data Project
public interface IUserService
{
IUserServiceResult<IUser> CreateUser(IUser User);
IUserServiceResult<IEnumerable<IUser>> GetUsers();
}
public interface IUserServiceResult<T>
{
bool IsSuccessful { get; }
string UserErrorMessage { get; }
T Data { get; }
}
public interface IUser
{ // Some Getter Properties
}
// MyCompany.Service
public class UserService : IUserService
{
public UserServiceResult<User> CreateUser(IUser User)
{
var result = new UserServiceResult<User>();
if (User == null)
{
// log the error AND
result.UserErrorMessage = "User information was not valid.";
// or
throw new ArgumentNullException("User");
}
// example only
result.IsSuccessful =
(Context.Users.FirstOrDefault(x => x.Email == User.Email) == null)
if (result.IsSuccessful)
{
User newUser;
// create user...
result.Data = newUser;
}
return result;
}
public IUserServiceResult<IEnumerable<IUser>> GetUsers()
{
// Similar to above, can check for authentication
// Maybe return IsSuccessful = false,
// UserErrorMessage = "Requires administrative privileges".
// or result.Data = new List<User>();
}
}
public class UserServiceResult<T> : IUserServiceResult<T>
{
bool IsSuccessful { get; set; }
string UserErrorMessage { get; set; }
T Data { get; set; }
}
public class User : IUser { } //
I like having the service or data tier always return a result type with a generic typed data. I find it especially helpful when passing it back to jQuery.
One way to do it is to have two separate projects, one for you Data classes, and one for your Models/ViewModels.
Controller makes a request to the service
Service retrieves data objects (I.E. User) with your repository
Either manually map a User to a UserModel or use http://automapper.codeplex.com/
Return the IEnumerable to the controller.
Now the controller works with the UserModel instead of the User. Which keeps your web application out of messing with your data classes.
You can also put the interfaces for your service into the models project and allow consumers of the Rest service access to the models and interfaces.
If I want only administrator to access the action called "ManagerUser", I know I can do this:
[Authorize( Roles = Constants.ROLES_ADMINISTRATOR )]
public ActionResult ManageUser( string id )
{
}
What if I want to give everyone access except to administrator? I do not want to write all roles up there on function :|.
Any recommendations/way outs?
You can create your own custom Authorize attribute, something like "AuthorizeAllExceptAdmin." Within that class you would simply need to check whether or not the current user was an admin, and if they were reject it, otherwise accept it.
Here's a good tutorial, but you'll probably end up with something like:
public class AuthorizeAllExceptAdmin : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return !httpContext.User.IsInRole(Constants.ROLES_ADMINISTRATOR);
}
}
Then your controller method becomes:
[AuthorizeAllExceptAdmin]
public ActionResult SomethingOnlyNonAdminsCanDo()
{
}
Here's an example of the custom attribute that takes in roles to deny.
public class DoNotAuthorize : AuthorizeAttribute
{
private IEnumerable<string> _rolesToReject;
public DoNotAuthorize(IEnumerable<string> rolesToReject)
{
_rolesToReject = rolesToReject;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (var role in _rolesToReject)
{
if (httpContext.User.IsInRole(role))
return false;
}
return true;
}
}
Then your controller method becomes:
[DoNotAuthorize(new [] {Constants.ROLES_ADMINISTRATOR})]
public ActionResult SomethingOnlyNonAdminsCanDo()
{
}
I would put some thought into it before choosing one of the above options. If you think you'll have several methods (or entire controllers) with similar authorization requirements (i.e, several actions an admin can not perform) then I would stick with the non-parameterized custom attribute. This way, you can evolve them all together (by only changing the custom attribute) later on. For example, maybe later on you want admins to be able to go into a special mode where they can perform these actions.
Alternatively, if the autorization is more varied amongst the actions, then using the parameterized list makes sense, since they'll evolve relatively independently.
Besides creating a custom AuthorizeAttribute, suggested by manu, you could use PrincipalPermission, with a Deny-SecurityAction:
[PrincipalPermission(SecurityAction.Deny, Role="Administrator")]
In my app I don't use roles so I have to query the database to determine whether the user has access or not. The benefits of the code below is that you can redirect the user to a certain action very easily. I explained the code in my blog post at http://blog.athe.la/2009/12/implementing-permission-via-windows-authentication-in-asp-mvc-using-action-filters/
public class DatabaseRepository()
{
private readonly DatabaseDataContext db = new DatabaseDataContext();
public bool UserHasPermission(string userLogon) {
return (from permission this.db.Permissions
where permission.HasPermissionSw == true
select permission).Contains(userLogon);
}
}
public class UserHasPermission: ActionFilterAttribute
{
private readonly DatabaseRepository databaseRepository = new DatabaseRepository();
private readonly string redirectAction;
public UserHasPermission(string redirectTo)
{
this.redirectAction = redirectTo;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string userLogon = filterContext.HttpContext.User.Identity.Name;
if (!this.databaseRepository.UserHasPermission(userLogon))
{
string routeController = filterContext.Controller.ControllerContext.RouteData.Values["controller"];
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = routeController, action = this.redirectAction }));
}
}
}
Your controller would then look something like this:
[UserHasPermission("NoAccess")]
public ActionResult SecretArea()
{
// run all the logic
return View();
}
public ActionResult NoAccess()
{
return View();
}
I am starting to dabble with ASP.Net MVC. One question I have is on best practices for protecting user data. For example in the scenario of Sales people, they should only be able to view their own data.
e.g.
SalesData/Edit/14
It is very easy to change the "14" to view other data which they may/or may not have access to.
At this point, I am thinking in my controllers to check for who is logged in, and checking if they have access to the "id" that is getting requested. The problem I see with this, is that this will be application wide, and I am looking for best practices on how to approach this. Should I be looking at CustomControllers? Filters? or what? Any articles/references for how to tackle this would be appreciated.
Set up your methods for retrieving data from your database repository in such a way that you can pass the UserID of the currently logged in person as a parameter. You can then use a permissions table to filter the data to only that data for which the user has access.
The permissions table would have two fields: UserID and ContentID. Once this is set up, it's fairly straightforward to set up CRUD screens so that someone with administrative privileges can set content permissions.
The problem I see with this, is that
this will be application wide,
Then you need common service that handles it. Suprisingly, I would call it IAuthorisationService.
and I
am looking for best practices on how
to approach this. Should I be looking
at CustomControllers? Filters? or
what?
Whichever way you choose you should use common IAuthorisationService above.
From my experience I can tell that it is easier to inject the service into controller and use it on every action:
/* Interfaces */
public interface IAuthorisationService {
bool CanEdit(YourItem item);
}
public interface ICurrentUserProvider {
YourUserEntity GetCurrentUser();
}
/* Implementations */
public class HttpUserProvider : ICurrentUserProvider {
public YourUserEntity GetCurrentUser() {
return HttpContext.Current.User.Principal as YourUserEntity;
}
}
public calss RolesAuthorisationService : IAuthorisationService {
ICurrentUserProvider userProvider
public RolesAuthorisationService(ICurrentUserProvider userProvider) {
this.userProvider = userProvider;
}
public bool CanEdit(YourItem item) {
var u = userProvider.GetCurrentUser();
if (u == null)
return false;
return item.Owner == u && u.IsInRole("EditYourItem");
}
}
/* Controller */
public class MyController: Controller {
IAuthorisationService authorisation;
public MyController(IAuthorisationService authorisation) {
this.authorisation = authorisation;
}
public ActionResult Edit(int id) {
var item = GetTheItembyIdSomehow();
if (!authorisation.CanEdit(item))
return new HttpUnauthorizedResult();
// Can do this
}
}
Then you can use ControllerFactory to inject the required dependencies automatically into the controllers:
class DependencyInjectionContainer : WindsorContainer {
public DependencyInjectionContainer() {
RegisterDependencies();
}
private void RegisterDependencies() {
// Services
Register(
AllTypes.Of<IDiscoverableService>()
.FromAssembly(typeof(IDiscoverableService).Assembly)
.Configure(c => c.LifeStyle.Transient)
.WithService.FromInterface()
);
// Controllers
Register(
AllTypes.Of<IController>()
.FromAssembly(typeof(DependencyInjectionContainer).Assembly)
.Configure(c => c.LifeStyle.Transient)
);
}
}
class WindsorControllerFactory : DefaultControllerFactory, IDisposable {
private readonly IWindsorContainer container;
public WindsorControllerFactory() {
container = new DependencyInjectionContainer();
}
protected override IController GetControllerInstance(Type controllerType) {
if (controllerType == null)
return base.GetControllerInstance(controllerType);
return (IController) container.Resolve(controllerType);
}
public void Dispose() {
container.Dispose();
}
}
I use IPrincipal and Authorize(Roles='...') attribute to limit access to actions. IPrincipal is then injected into service layer and user IIdentity is used to filter data.
Example: Users create tasks. Every user can see his tasks. GetTask(int taskId) method first filters by CreatedBy field using identifier from IIdentity and then takes task with specified id. If user doesn't have access to data, method will not return any rows.