Information about form sender - ASP.NET MVC - asp.net-mvc

I would like to create a group in my app. In model that group has a field Admin_ID to specify who is the owner. How to include that information in a form? With hidden field? I don't think this would be safe enough solution... Any other ideas?

In model that group has a field Admin_ID to specify who is the owner.
Then apply authentication (see the tutorial for your MVC version) so you know which user is logged in, use authorization to restrict access to admins only and in the controller assign the creating user's ID to the model when it is created:
[Authorize(Roles="Admin")]
public ActionResult Create(SomeModel modelToCreate)
{
// get user, depends on how your project is set up...
var user = GetLoggedOnUser();
modelToCreate.Admin_ID = user.ID;
}

If hidden field is not enough for security - don't include it there, but have a separate action that only does operation on your Admin group.
Sorry, can't give more details, as your question does not contain enough information.

You can always save the Admin_ID in the Session.

To better understand:
public class Group
{
public int A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string ID_Admin { get; set; }
}
where ID_Admin should be automatically generated when someone who is logged in want to submit that form (he need to fill only A, B and C fields). So let's say currently logged user has ID 42, and he want to submit that form (without any knowledge of that additional field of course) - and I want to include that information about his ID in final model submission.

Related

ASP MVC 5 Organizing Project To Avoid Duplicating Code

I am building an asp mvc 5 support ticket helpdesk application. The application will require users to signup to submit a support ticket. Users actions would be to update the ticket by adding notes like a thread.
Agents will manage the ticket and have additional permissions to edit the ticket and create internal as well as public notes and be able to view all tickets.
There is a site admin who can configure the site.
The issue is if I have a controller say called ticket controller, the main actions on the create or edit ticket are similar for both an agent and a user. The differences are that when a user creates a ticket they can only complete certain fields on the form where as an agent can update additional fields.
So what I'm ending up with is a lot of if then else statements in my controllers and views to check user roles inorder to restrict what form fields and actions are displayed to the different types of users. Also my viewmodels are exposing properties to a customer that they shouldn't have permissions to.
So my question is how do you organize this type of set up. Do you create a separate area for Agents and duplicate all the controllers and viewmodels to cater for this type of user.
Or would you just bloat the controllers and views with if then else statements for every different type of user role that is created?
Some advise on what would be best practice for this particular application would be appreciated.
The only benefit of creating an Area for agents is that I could drastically change the look and feel of the Agent portal, have a different url eg. mysite/agentdesk/tickets and it would be easier to maintain but at the expense of duplicating code.
/* Current Controller Logic and view model */
As you can see the in viewmodel exposes the status and priority properties which only an agent can set.
In the create method of the controller, you can see the teneray operator being used to determing if the user has the correct role to set the above properties.
public class TicketViewModel
{
public int Id { get; set; }
[Required]
public string Subject { get; set; }
[Required]
public string Description { get; set; }
// Only an agent can change the status
[Required]
public int Status { get; set; }
// Only an agent can change the priority
[Required]
public int Priority { get; set; }
public IEnumerable<StatusType> StatusTypes { get; set; }
public IEnumerable<PriorityLevel> PriorityLevels { get; set; }
}
public class TicketController : Controller
{
[Authorize]
public ActionResult Create()
{
var viewModel = new TicketViewModel
{
StatusTypes = _context.StatusTypes.ToList(),
PriorityLevels = _context.PriorityLevels.ToList()
};
return View(viewModel);
}
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(TicketViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.StatusTypes = _context.StatusTypes.ToList(),
viewModel.PriorityLevels = _context.PriorityLevels.ToList()
return View(viewModel);
}
bool agentRole = HttpContext.Current.User.IsInRole("Agent");
var ticket = new Ticket
{
CreatedBy = User.Identity.GetUserId(),
Subject = viewModel.Subject,
Description = viewModel.Description,
StatusId = agentRole ? viewModel.Status : 1,
PriorityId = agentRole ? viewModel.Priority : 1
};
_context.Tickets.Add(ticket);
_context.SaveChanges();
return RedirectToAction("Index", "Tickets");
}
}
I think an area would be the best way to go. The simple fact is that the complexity of your code is going to quickly spiral out of control otherwise. It's one thing to just show/hide form fields based on some role, but really, for security, this needs to be protected end-to-end. In other words, you would also need to check inside your action that properties are only being set with values if the user is allowed to access those properties. It's trivial to post things you shouldn't be able to edit, even if no form fields exist to allow that.
To get around the code-duplication issue, just don't duplicate code. That sounds a little trite, but there it is. Similar code in your action can be factored out into a base controller or just some helper class. Similar code in your views can be factored out into partials. Basically, anything that would be the same for both situations should go somewhere where the same code can be used in both situations.

Users in Multiple Organizations with Different Roles

I'm fairly new to setting up security for websites and am having trouble finding the correct architecture/design/pattern/best practice for the type of authentication/authorization I am needing in a .NET MVC environment. I don't even know what to call it in order to do more research. Below is an example of what I need to implement. What is this called? (I don't think it's multi-tennant.)
Joe works inventory for a few stores in a Grocery Store chain. Joe is an Inventory Manager(can edit items) for Store A, but just an Inventory Clerk(only view items) for Store B and has no access to Store C.
So Joe should be able to access the ActionResult Edit in the InventoryController if he is trying to edit Store A, but should not be able to access the same ActionResult Edit if he is trying to edit Store B or C.
The straight-forward Identity or Claims based authorization isn't enough for this scenario (I don't think), but I don't know the "name" of the design I need in order to do further research. What is this design called?
It's called object-level authorization (aka object-level security, aka fine-grained authorization, etc.). Basically, permissions are based on "ownership" of objects, or perhaps better put in this scenario, being owned by an object. You would need to set up a many-to-many relationship between stores and employees, with payload of a role/grant. For example:
public class StoreEmployee
{
[Key, Column(Order = 1)]
[ForeignKey("Store")]
public int StoreId { get; set; }
public virtual Store Store { get; set; }
[Key, Column(Order = 2)]
[ForeignKey("Employee")]
public int EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
public string Role { get; set; }
}
public class Store
{
...
public virtual ICollection<StoreEmployee> Employees { get; set; }
}
public class Employee
{
...
public virtual ICollection<StoreEmployee> Stores { get; set; }
}
With that, then you can use this relationship in your actions to verify whether a user has access:
if (!joe.Stores.Any(m => m.Store == storeA && m.Role == "Manager"))
{
return new HttpUnauthorizedResult();
}
Here, I kept things simple by just making Role a string. You could use a enum, or even an actual class that would also be persisted in your database. Or you could tie into the existing roles for users in general. It's up to you. You might also prefer to turn that into a custom action filter.
You could set this up as a multi tenant system. If every store is a tenant with its own user directory, then Joe would need to login to a different directory for store A then for store B and would get a another role assigned.
Joe would not be able to login to store C as he does not have an account in that directory.
If you want users to authenticate through a federated system, you'd need to set up a role per store and assign those based on which IdP the user came from.

How to save claims used in a MVC site using Thinktecture IdentityModel

I am working on a MVC web site with Claims Authentication and also using Thinktecture IdentityModel.
Each user has a set of CLAIMS: City, Username, Email, Roles, Birthdate.
I have 3 tables in the database: USERS, USERS_PROFILES and USERS_CLAIMS.
USERS contains the columns Username and Email;
USERS_PROFILES contains the columns City and Birthdate.
I am saving these values in these tables ... And I save the Roles in the USERS_CLAIMS table.
When I load a user I fill the ClaimsIdentity with the data from these tables.
THE QUESTION IS:
When I create a user should I, for example, save the email both in USERS table and in USERS_CLAIMS table?
It seems data replication but I am not sure ... Or should I save in only one of them?
What is your approach to this? And what kind of claims, beside roles, do you have that don't fit in a USERS or USERS_PROFILE table?
Thank You,
Miguel
As you're using MVC (Model View Controller), why don't you use Models ?
Your ClaimsIdentity is a model, just create a ClaimsIdentityModel.cs in your Model folder, and use it like this :
public class ClaimsIdentityModel
{
public string Username { get; set; }
public string Email { get; set; }
public string City { get; set; }
public Datetime Birthdate{ get; set; }
}
Then, when you load your user, just fill a ClaimsIdentityModel. And you're done.
As name of each table suggest, the values shall represent those only.
Users are identified as by usernames. Email is one of the claim done by the User.
Roles are also claims, so as City.
If you are creating profile table and adding city in profile, it shall be avoided to add it in Claims table. But you need to handle requirement of City as claim by queries Profile table and providing value as claim as needed.
ClaimsIdentity is System.Security.Principal.GenericIdentity type that is used to identify the user in claim based approach.
(Making Model will be helpful in the View)

Remote attribute in asp.net mvc – in some situations restricts our model

I’ve got an unexpected situation when using Remote Attribute in ASP.NET MVC3.
The model type I used:
using System;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace dTweets.Models
{
// at first time, user should create his account with unique username
// as in twitter.com, user do
public class UserMetadata
{
[HiddenInput]
internal int Identity { get; set; }
[Remote("IsUserExist", "Account")] // at any HttpPost, username should
// be unique – not appropriate if
// updating/editing this model later
[Required(ErrorMessage = "username should be unique")]
public string UserName { get; set; } // user cannot change it, later
[DataType(DataType.Password)]
public string Password { get; set; } // user can also change password, later
[DataType(DataType.MultilineText)]
public string About { get; set; } // Optional field – user can edit it later
}
[MetadataType(typeof(UserMetadata))]
[Bind(Include="UserName, Password, About")]
public partial class User
{
}
}
Remote attribute validates user unique name at account creation time. But when later user wants to update/change his account, Remote attribute did not allow to update model if keeping user unique name the same one.
This is not appropriate result because rarely user changes their unique user name. They just change other fields like About field or password etc.
[Note: at account creation time, I want to check user unique name so I used Remote attribute here, but at later time when updating user account I no longer need Remote attribute]
I must remove Remote attribute for updating this model later.
I want to update/change this model without changing user unique name (remote attribute is applied to this unique name).
one way to do this is to send ID value of this record in AdditionalFields named parameter like
[Remote("IsUserExist", "Account",AdditionalFields = "Identity")]
and then you can check for uniqueness across all rows except the ones that belong to current user. and don't forget to change signature of IsUserEsists action result to receive Identity like
public ActionResutl IsUserExists(string UserName, int Identity)
{
}
Can't you just change server side validation method to something like:
public ActionResult IsUserExists(string userName)
{
if (!UserService.UserNameExists(userName) || (CurrentUser.UserName == userName))
{
return "Yeah. Is it valid.";
}
}
You have current user, because he is logged in. As long as user can only edit his data, this will work.
This is one place where buddy metadata falls short.
Edit/Add scenarios require their own view models. One size fits all scenario validation attributes only work in very trivial business CRUD apps. Add and Edit actions happen in totally different contexts and are only transiently related. This concept is very similar to the DDD bounded context idea.

Alternative User management in ASP.NET MVC

I am in the planning phase of a new ASP.NET MVC application and one of the requirements is storing some user information that is not part of the standard set found in the User class that comes with ASP.NET MVC. I suppose it comes down to two questions.
1) Can I edit the class that is being used already to store the information that I need?
2) If I roll my own how can I keep things like the Authentication piece that make things so nice when trying to lock down some views using the User.IsAuthenticated method?
Another alternative I have considered is using the User class provided as is, and instead putting the other information into a separate table with the guid userid as the foreign key.
Suggestions?
Profiles are one option as #Burt says, and offers a lot of flexibility.
I had a similar need to track Employee information, but I opted to roll my own Employee class and create a relationship to a standard User. I really like how this has worked out as I can keep any Employee specific business logic separate from the User class Membership system.
Since not every User was going to be bound with an employee, this made more sense for my case. It may not for yours, but it is an alternative.
So, I have something like:
public class Employee
{
public Employee(string name) : this()
{
Name = name;
}
public virtual string Name { get; set; }
public virtual string Title { get; set; }
public virtual decimal Salary { get; set; }
public virtual decimal Hourly { get; set; }
public virtual decimal PerDiem { get; set; }
public virtual string StreetAddress { get; set; }
public virtual Guid UserId { get; set; }
public virtual MembershipUser User {
get
{
// note that I don't have a test for null in here,
// but should in a real case.
return Membership.GetUser(UserId);
}
}
}
See ASP.Net MVC Membership Starter Kit. It provides the Asp.Net MVC controllers, models, and views needed to administer users & roles. It will cut distance in half for you.
Out of the box, the starter kit gives you the following features:
List of Users
List of Roles
User
Account Info
Change Email Address
Change a User's Roles
Look into profiles that are part of the membership functionality provided by MS. They are extendable and pretty flexible.

Resources