Restrict users accessing other users' data - c#

I'm having a problem of designing a common functionality of hiding information created by a user from other users. As an example,to edit Products created by USER1, normally we use one of following.
/Product/Edit/Id/1
/Product/Edit?Id=1
My concern is, if USER2 got the Id, 1, he also able to access Product with Id=1, which was created by USER1. How to restrict USER2 accessing USER1'S data? This may needs to apply for every module in the project. Is there a common way to achieve this? Thanks

If you are keeping state of what user is accessing the data. You can add a "WHERE CreatedBy = {YOURLOGGEDINUSER}" to this query and throughout your application. Then even if he gets the ID correct no data would be returned.

Assuming that you have enabled some sort of ASP.Net Authentication (The user has proved who they are) then you now need to think about the Authorization (what the user is allowed to do).
It doesn't help that these two terms are often combined or used interchangeably. In MVC a custom AuthorizeAttribute is often used to do both.
For managing records, the current logged on user is accessed via the IPrincipal from HttpContext.Current.User.
The user id is usually set at HttpContext.User.Current.Identity.Name although you may need to do a null check if not every route is authenticated.

Related

Assigning access rights to roles in asp.net mvc

Most articles/examples I'm finding regarding access rights for asp.net mvc are related to restricting access to specific controllers using roles but I'm trying to figure out how can specific access rights be assigned to a user that belongs to a specific role.
My scenario is rather simple as the only role that requires access rights at the user level is the "Staff Members" role:
Admin: Access to all features.
Staff: Access to specific features.
Member: No access to specific features.
Ideally, I'd like to implement something similar to the below
#if (#User.IsInRole("IsAdmin") || (#User.IsInRole("IsStaff") &&
#User.HasAccess("DownloadData"))
{
<a href='#Url.Action("DownloadData"....
</a>
}
I've got a separate table where I store the staff access rights and since these are assigned at the user level, I'm using the same Id generated in AspNetUsers so a simple EF/SQL Linq join does the trick when I log in to get the relevant access rights for a specific staff member.
Now my questions are:
Can I expand the #User (Principal) to have a scenario similar to the above by introducing a new function such has HasAccess where I could pass the Access Right that needs to be checked for the specific staff member.
If 1. can't be done, would passing the logged-in user access right to the ViewModel used to build my page be a viable option? Is it too risky? Am I wrong to assume that this should be ok since this is server based code and wouldn't be passed along to the client side?
If 1 & 2 are not suitable, what is the best/recommended method to achieve this?
Thanks
The easiest way would be to create an extension method on IPrincipal or IClaimsPrincipal. This way you can unify the access rights definitions in a single place. If you have lots of access rights checks, maybe you need to add the access rights as claims (if you're using claims) or cache them somehow so you don't need a database access everytime (if they are stored on the database).
Also, you're right that it is the same if you pass the access right to the view, because the view is rendered to HTML. But, IMHO, the first option is much better as you don't need to clutter your Controller with Access Rights checks.

Add a Custom property to ASP.NET MVC Identity after user login

I am trying to add an item to the users Identity, but I think this could also be done another way.
I have added a few custom fields to the User Identity, but what I am trying to do is once the user has successfully logged in, I check if they are assigned to multiple branches(Store Locations) and then offer a list for the user to select which Branches they want data to be displayed for.
I have done this successfully, but now I want to store each of the branches in the users session/ cookie/ Identity (not sure what terminology to use). The user is displayed a number of checkboxes, and once they click save, I am unsure of what to do.
I need to save it in this function:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectBranch(params string[] branchNames)
{
foreach (var branch in branchNames)
{
//add branch to session/cookie/identity
}
return RedirectToAction("Index");
}
What steps do I need to take to be able to do this?
It depends on what you end goals are. Should the choice of branches be persistent or transient? Based on your comment, it sounds like you're wanting to save it for the current session, but then make the user choose again the next time they come back. If that's what you application truly needs, fine, but it seems to me that something like this should either be saved permanently, with the ability for the user to update those choices when they see fit, or completely temporary, i.e. for the current request, such as filtering a set of results by a branch or branches.
Storing for only the current browser session begs the question of whether the user will realize that their choices are being persisted across additional views, and conversely, whether they'll understand why they have to continually set branches each time they come back to the site.
That said, your choices:
Permanent - Store on user entity. Add a M2M between ApplicationUser and StoreBranch (or whatever).
Transient - Set in Session.
Technically, you can use claims, but they aren't really a good fit for this. Claims should be used when either 1) the data being stored is not applicable to every user or 2) the data being stored is transient in nature, but should survive the session. A good example use of a claim would be storing an auth token from something like Facebook. Not every user will necessarily have a Facebook auth token, so it's not something you would want as a database column, and there's generally a lifetime for that auth token, making it temporary but still something you would need to hold on to even if the session was destroyed.
Based on your description of what you want to achieve, Session is your best bet, but I would argue strongly that there's probably value in persisting this choice permanently, as long as the use can alter it later. To save it to the session, I would literally just save your string array directly to the session (no need for the for loop):
Session["BranchNames"] = branchNames;
I would tell you to use Identity claims
What is a Claim?
A Claim is a statement about the user makes about itself, it can be user
name, first name, last name, gender, phone, the roles user assigned
to, etc…
You can know more about them here

ASP.NET Roles Authentication - Using Roles as Activities?

I want to go one step further than simple roles based authorisation (Admin, User, Super User etc)
and instead do Activity based authorisation .
My thinking was to assign activities to logged in users which related to whether or not they could perform a action.
For example
CreateUser
ReadUser
UpdateUser
DeleteUser
I would create pages that relate to the above activities
i.e
CreateUser.aspx
on each page i would do a check to see if the authenticated user does in fact have rights to access the activity.
i would do this by making use of Roles.
for example
IsInRole("CreateUser")
Previous to this i could assign the Activities (Roles) to the authenticated user after successful login
My only real concern with this is that by doing this when i authenticate the user and build the authentication cookie it will include alot (potentially) of Roles for each user.
for example i currently have 60 activities in my system (but this could increase as we add more features - each feature is in itselve a new activity)
If the authentication cookie has to carry approx 60+ roles (activities) would that cause any known issues?
Can anyone suggest an alternative approach ?
You may want to look into IdentityModel framework. It has the base class for building a custom Authorize module to verify permissions based on Resource-Action pattern. But this is built for .NET 4.5, not sure what your platform is.
.NET 4.5 also includes SessionAuthenticationModule (SAM) for web authentication. SAM can cache the roles between user calls, so that you don't have to send them back and forth in a cookie. Here is some more information on how it works.
Use Operations and Permissions, as described in Ayende's blog. He has lots of articles on the topic.
http://ayende.com/blog/3109/rhino-security-overview-part-i
http://ayende.com/blog/tags/rhino-security
What you want is a capability list approach.
The solution to this is a mapping of roles to capabilities, similar to this:
>Online Anon User Admin
Article ReadOnly ReadWrite ReadWrite
Article.List ReadOnly ReadOnly ReadOnly
Article.Edit Hidden ReadWrite ReadWrite
Article.Delete Hidden ReadOnly ReadWrite
Article.Title.Edit * * ReadWrite
In practice, these will be your coordinates:
>(system state)
The system may be "Online, Offline, Maintenance" and maybe more.
Use the initial > to find the start of your matrix in the file (you'll have many of these). In C# you'll have an enum.
On the same line are the roles:
Anon User Admin
Then on the left side you'll have the capabilities scoped into namespaces and actions:
<item>
<item>.<action>
<item>.<field>.<action>
<item>.<field>.<value>.<action>
The cells will contain one of these values:
Hidden, ReadOnly, ReadWrite or *
The * will mean "inherit" from the parent item or field.
This way you'll be able to fine-tune the permissions based on items, actions, roles and the current system state.
A simple parser translating the list into an in-memory structure will do. Don't put this on a DB, it will be a pain. Keeping it on the text-file/in-memory level is better. Add a FileSystemWatcher to read that file whenever it is changed for additional functionality and leverage lazy loading. Also, store it in Application state memory, not in a session.
Remember: the default will be Hidden (not even read access, the item/action will be completely inaccessible to that role.
Your real concern will then be which roles you'll really need (in my experience a role pretty much maps to an UML actor, maybe with some slight variances), and what the items/fields/values and actions really are. When you write an item you can really mean a group of items. There is no need to map the capability list directly unto a database/entity or code structure. The capability list is on a higher language level, it is semantic and bound to the domain, not to the code (I want to stress this because it's the real power behind this approach).
Once you have implemented this approach with a simple parser and helper object (Information Expert Principle is well advised, avoid Singletons) you'll be able to reuse it in many applications.

Persist User Data in ASP.NET MVC

Similar questions have been asked before but I'm still without an answer and have spent a decent amount of time trying to find one.
The scenario is this. We have an ASP.NET MVC application which is using Forms Authentication / LINQ-to-SQL data model.
Each user can be associated with 1 or more Accounts. Upon login, the application checks how many Accounts they're associated with.
0 = Go to error page and let them know they have no access
1 = Set The User Data to use that account
2 or more = Go to a page which allows them to select which account they'd like to use (with ability to change during their visit)
How would you store this information?
Furthermore, I'd like to use this Account as the base for my controller actions. i.e. Data on subsequent pages they visit will be related to the Account they've selected.
Singleton cough comes to mind but am unsure how to implement that.
An approach which I'm currently investigating is a Base Controller that all controllers will inherit from that will
Check whether a user is logged in.
If so, check whether they have an Account Selected
No - redirect them to Account Selection page
Yes - proceed with original request
What is a recommended/best-practice way of doing this?
Thanks
Marko
Don't use a base controller. You can accomplish this using action filters. This will give you the point of intercept for checking whether they are logged on, whether there is an account selected, and even redirecting them to the error or account selection page. All you have to do is set filterContext.Result during the action filter's OnActionExecuting method to prevent the request from going through. You have complete access to session, temp data, cookies, and the whole HttpContext during the action, just as you would in the controller. Also you can property inject dependencies using a filter attribute filter provider, so that should give you any data access you need.
As far as modeling the data, I am not too familiar with Linq to SQL, but I think a normal one to many should do the trick:
User (1) <-------> (0..*) Account
public class User
{
public virtual ICollection<Account> Accounts { get; protected internal set; }
}
public class Account
{
public int UserId { get; protected internal set; }
public virtual User User { get; protected internal set; }
}
Update: Sorry, I misunderstood what you meant by "store". In MVC, there are only a few ways you can store it - Session, Cookie, and Cache (and TempData, which is just short-term session) are the most popular choices. My choice would depend. Session is probably the easiest, but if you are deployed to a server farm with a load balancer, you need to think about what would happen if the user's session jumps physical machines. Will the session remain intact?
As Jeremy says there is also cookie. No worries about load balancing here, but the semantics are a little harder to deal with than session. For example you have to send a redirect to write the cookie before you can read it, and I've never liked the fact that you have to add an expired cookie to delete one. Since this data is part of your security, you also may want to encrypt the cookie value.
If you use cache, the data will most likely still end up living in memory somewhere, like session (unless you are using a SQL session provider). Cache would probably be my last choice, since we use Azure and their cache doesn't support a lot of great MVC features. You also have the same problem with load balancers moving the user to a different machine in the cluster, where the data may have to be re-cached.
Either way, you should still use action filters for this instead of a base Controller class.
What type of scale are you talking about? Are we talking about a million users or a couple thousand?
My first thought is to create a dictionary with the key being the login username (assuming it's unique) and the value to be an array of associated accounts(key or all the data). I would then put the dictionary into cache. Expiring it whenever a new association is created.
There are a couple of problems with this approach. First, how fast are new associations being created? If they are constantly being created, then the cache is a moot point. You'd always being going to the DB. Second, if you have millions of users/associations putting all them into cache may not be practical.
Another possibility is a session state server, this would be solely dedicated to storing the relationships.
Yet another possibility is querying the database each time, depending on the size of the data set this would work. When the data set grew to a size where pulling real time data each time is not practical you could architect a solution that fits your needs.
As for persisting the selected account between requests, The options are either cookies, url or database(could be a field on the user i.e. CurrentAccount, this approach is a bit of a kludge).
Since you are using MVC I'd use the URL, with routing and a custom route constraint you could create a url that contained the account. Since the user has to login, you already know the user identity.
Example: http://www.acme.com/{account}/edit/
Checking if a user is logged in could be handled in an action filter or Application_AuthenticateRequest in the Global.asax. Authentication is fairly well implemented in ASP.NET. Heck a lot of it is driven by configuration values in the web.config.
After the authentication has been confirmed the account redirection could take place in the same method. Or you could wait and check in an action filter.

ASP.NET: Custom MembershipProvider with a custom user table

I've recently started tinkering with ASP.NET MVC, but this question should apply to classic ASP.NET as well. For what it's worth, I don't know very much about forms authentication and membership providers either.
I'm trying to write my own MembershipProvider which will be connected to my own custom user table in my database. My user table contains all of the basic user information such as usernames, passwords, password salts, e-mail addresses and so on, but also information such as first name, last name and country of residence.
As far as I understand, the standard way of doing this in ASP.NET is to create a user table
without the extra information and then a "profile" table with the extra information. However, this doesn't sound very good to me, because whenever I need to access that extra information I would have to make one extra database query to get it.
I read in the book "Pro ASP.NET 3.5 in C# 2008" that having a separate table for the profiles is not a very good idea if you need to access the profile table a lot and have many different pages in your website.
Now for the problem at hand... As I said, I'm writing my own custom MembershipProvider subclass and it's going pretty well so far, but now I've come to realize that the CreateUser doesn't allow me to create users in the way I'd like. The method only takes a fixed number of arguments and first name, last name and country of residence are not part of them.
So how would I create an entry for the new user in my custom table without this information at hand in CreateUser of my MembershipProvider?
I think you should go on with your approach and add a new function in your implementation, I mean, overload the CreateUser method and have a CustomMembershipUser (that extends the MembershipUser) as a parameter.
In that way, before using the provider, cast it to your CustomMembershipProvider and use the overloaded method.
I agree with your analysis that you should keep both membership and profile information in the same table. Since you are correct that you are restricted by the number of parameters that CreateUser takes, you will need to design your field so that non-membership profile attributes are nullable. This does not mean that you will have required fields that are null in the database, however. Instead, you can you the below snippet:
string username = .../ retrieve username here
Membership.CreateUser(username , password, email);
ProfileBase newProfile = Profile.Create(username); //since the user has just been created, all properties will be blank
//set all entered properties
newProfile.SetPropertyValue("MyProp1", myProp1Value);
...
newProfile.SetPropertyValue("MyPropN", myPropNValue);
newProfile.Save();
In this way, you leverage ASP.NET's membership providers to create the user and save profile data, but to your end user it is a single atomic operation.

Categories