Authorization based on assigned Permission function - c#

I have three tables
dbo.PermissionFunc, dbo.Roles, dbo.Permissions for my asp.net MVC web application.
dbo.PermissionFunc contains all the function name in my project.
dbo.Roles contains the user roles such as admin, user, subuser etc
dbo.Permissions contains the RolesId from dbo.Roles and PermissionFuncId from dbo.PermissionFunc.
I want to give authorization based on the value assigned in dbo.Permission.
Update in question:
Query using to determine if the current user has permission or not
string mail = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
var usr = _user.GetUserByMail(mail);
var permFunc = _permissionfunc.FindByName("ActionResultName");
var permission = _permission.checkIfPermitted(Convert.ToInt64(usr.Usr_Role_ID), permFunc.PermFunc_ID);//usr.Usr_Role_ID is RoleId and permFunc.PermFunc_ID is the PermissionFunctionId
if(permission != null)
{
//Permission granted
}
else
{
//Permission Rejected
}
Thanks in advance

You can create custom AuthorizationAttribute with the logic of checking your roles and permissions in it and use it for operations that requires that.
You can use mvc.filters with your implementation of IAuthorizationFilter, to filter every request. Register it in your FilterConfig
filters.Add(new MyAuthorizationAttribute());

Updated to use CustomAuthorize attribute on MVC action
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorize : AuthorizeAttribute
{
private string _action { get; set; }
public CustomAuthorize() { }
public CustomAuthorize(string action) { _action = action; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.User == null)
return false;
if (!httpContext.User.Identity.IsAuthenticated)
return false;
// HasPermission function implements looking up by user name and action
// to see if user has a role that would give them access to this action
return PermissionChecker.HasPermission(httpContext.User.Identity.Name, _action);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// handle unauthorized requests here
// return 503 error or whatever
}
}
// example of using custom attribute in MVC controller action
[HttpGet]
[CustomAuthorize("View")]
public ActionResult MyActionActualViewMethodName()
{
var result = {
id = 1,
name = ""
};
return Json(result);
}
[HttpDelete]
[CustomAuthorize("Delete")]
public ActionResult MyActionActualDeleteMethodName(int id)
{
// do delete action
return Json(true);
}
// static permission checker implementation
public static class PermissionChecker
{
static List<GenericIdNameClass> users = new List<GenericIdNameClass>() {
new GenericIdNameClass { Id = 1, Name = "John" },
new GenericIdNameClass { Id = 2, Name = "Bob" },
};
static List<GenericIdNameClass> roles = new List<GenericIdNameClass>() {
new GenericIdNameClass { Id = 10, Name = "User" },
new GenericIdNameClass { Id = 11, Name = "Admin" },
};
static List<GenericIdNameClass> actions = new List<GenericIdNameClass>() {
new GenericIdNameClass { Id = 100, Name = "View" },
new GenericIdNameClass { Id = 101, Name = "Create/Edit" },
new GenericIdNameClass { Id = 102, Name = "Delete" },
};
static List<GenericEntityRelationClass> roleActionMappings = new List<GenericEntityRelationClass>() {
new GenericEntityRelationClass{ Id1 = 10, Id2 = 100 },
new GenericEntityRelationClass{ Id1 = 11, Id2 = 100 },
new GenericEntityRelationClass{ Id1 = 11, Id2 = 101 },
new GenericEntityRelationClass{ Id1 = 11, Id2 = 102 },
};
// John only has User role, Bob has User and Admin
static List<GenericEntityRelationClass> userRoleMappings = new List<GenericEntityRelationClass>() {
new GenericEntityRelationClass{ Id1 = 1, Id2 = 10 },
new GenericEntityRelationClass{ Id1 = 2, Id2 = 10 },
new GenericEntityRelationClass{ Id1 = 2, Id2 = 11 },
};
public static bool HasPermission(string userName, string actionName)
{
var user = users.SingleOrDefault(x => x.Name == userName);
if (user == null)
return false;
var action = actions.SingleOrDefault(x => x.Name == actionName);
if (action == null)
return false;
var userRoles = userRoleMappings.Where(x => x.Id1 == user.Id).Select(x => x.Id2).ToList();
return roleActionMappings.Any(x => userRoles.Contains(x.Id1) && x.Id2 == action.Id);
}
public class GenericIdNameClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public class GenericEntityRelationClass
{
public int Id1 { get; set; }
public int Id2 { get; set; }
}
}

Alsamil,
If you have time, please read about the new way Microsoft is doing Claims-Based Authorization
And if you have even more time, I really recommend you this conference. Dominick Baier & Brock Allen are really known in the security industry and they explain how to do Authorisation in a really nice way which is related to the Claims-Based Authorization article. If I am not wrong they are the minds behind this new way of authorisation.

The answer that worked for the above question is here:
AuthorizationController
#region CustomAuthorizationAttribute
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
private PermissionRepository _permission = new PermissionRepository();
private PermissionFuncRepository _permissionFun = new PermissionFuncRepository();
// roles start
public string IdentityRoles
{
get { return _permissionName ?? String.Empty; }
set
{
_permissionName = value;
}
}
private string _permissionName;
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//do the base class AuthorizeCore first
if (httpContext.User.Identity.IsAuthenticated)
{
string RoleID = FormsAuthentication.Decrypt(httpContext.Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name.Split('|')[1];
var permisionID = _permissionFun.FindByName(_permissionName);
if(permisionID != null)
{
var permis = _permission.GetPermission().Where(a => a.Perm_PermFuncID == permisionID.PermFunc_ID && a.Perm_RollID.ToString() == RoleID).FirstOrDefault();
if (permis != null)
{
return true;
}
}
}
return false;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//if the user is not logged in use the deafult HandleUnauthorizedRequest and redirect to the login page
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
else
//if the user is logged in but is trying to access a page he/she doesn't have the right for show the access denied page
{
filterContext.Result = new RedirectResult("~/Home/AccessDenied");
}
}
}
#endregion
Foreach ActionController, I accessed these Authorization as follows:
[CustomAuthorization(IdentityRoles = "AdjustmentsView")]
public ActionResult AdjustmentIndex()
{
var adjlist = _Adj.GetAdjustmentHead();
List<AdjustmentHeadViewModel> adjustlist = new List<AdjustmentHeadViewModel>();
foreach (var item in adjlist)
{
Mapper.Initialize(cfg => cfg.CreateMap<AdjustmentHead, AdjustmentHeadViewModel>());
AdjustmentHeadViewModel entity = Mapper.Map<AdjustmentHead, AdjustmentHeadViewModel>(item);
adjustlist.Add(entity);
}
return View(adjustlist);
}

You need to create a custom AuthorizeAttribute and tag your actions with it.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class RequireFunction : AuthorizeAttribute
{
private string _function;
public RequireFunction(string func) { _function = func; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.User == null)
return false;
if (!httpContext.User.Identity.IsAuthenticated)
return false;
// modified code sample from question
string mail = httpContext.User.Identity.Name;
var user = _user.GetUserByMail(mail);
var permFunc = _permissionfunc.FindByName(_function);
var permission = _permission.checkIfPermitted(Convert.ToInt64(usr.Usr_Role_ID), permFunc.PermFunc_ID);
return permission != null;
}
}

Related

How to check phone number is unique in AspNetUsers table when using ASP.NET Web Api

I have created an Asp.Net Web Api project and used Individual user accounts.
When I am adding users to the table the default system automatically checks if the email address supplied already exists in the table, if so a bad request is thrown otherwise the user can be submitted.
How can I also check if the Phone Number is unique and hasn't already been submitted to the table?
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
**using (ApplicationDbContext db = new ApplicationDbContext())
{
var foundPhoneNumber = await db.Users.FirstOrDefaultAsync(x => x.PhoneNumber.Equals(model.PhoneNumber));
if (foundPhoneNumber != null)
{
return BadRequest("Phone number already exists");
}
}**
var user = new ApplicationUser()
{
UserName = model.Email,
Email = model.Email,
PhoneNumber = model.PhoneNumber,
FirstName = model.FirstName,
LastName = model.LastName,
MemberNumber = model.MemberNumber,
CarReg = model.CarReg
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
I have queried the database to check if there is a Phone Number with the same number. This works, but is there a better way to do this?
Modify your ApplicationUser call and add the following attributes.
public class ApplicationUser : IdentityUser
{
[MaxLength(17)]
[IsUnique]
public string PhoneNumber { get; set; }
}
You can override ValidateEntity method in ApplicationUserDbContext class, it will trigger on SaveChanges method.
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
if (entityEntry != null && entityEntry.State == EntityState.Added)
{
var errors = new List<DbValidationError>();
////User Validation
if (entityEntry.Entity is ApplicationUser user)
{
if (this.Users.Any(u => string.Equals(u.PhoneNumber, user.PhoneNumber)))
{
errors.Add(new DbValidationError("User",
string.Format($"Phonenumber {user.PhoneNumber} is already taken")));
}
}
if (errors.Any())
{
return new DbEntityValidationResult(entityEntry, errors);
}
}
return new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
}
Validation can be added via a custom ValidationAttribute that you add to the PhoneNumber property on you model. Here is a simple example:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class NotABananaAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var inputValue = value as string;
var isValid = true;
if (!string.IsNullOrEmpty(inputValue))
{
isValid = inputValue.ToUpperInvariant() != "BANANA";
}
return isValid;
}
}
And its used liked this...
public class Model
{
[NotABanana(ErrorMessage = "Bananas are not allowed.")]
public string FavoriteFruit { get; set; }
}
Example sourced from:
https://riptutorial.com/csharp/example/18486/creating-a-custom-validation-attribute

Issue with returning object from a function in asp.net MVC

i am little confused about my code:
Here is some function from my controller:
public void signIn(string userName, string userPass)
{
User user = new User();
user.getUser(userName , userPass);
if (user.userName != null)
{
Response.Redirect("/Home/Menu");
}
else
{
Response.Redirect("/Index/Index?Fail=" + "fail");
}
}
the " user.getUser" suppose to return a User object.. here is the code from my Model directory:
public class User
{
public ObjectId _id { get; set; }
public string userName { get; set; }
public string userPass { get; set; }
public User getUser(string name , string pass)
{
var client = new MongoClient("mongodb://localhost:27017");
var db = client.GetDatabase("testdb");
var coll = db.GetCollection<User>("user");
List<User> list = coll.Find(x => x.userName == name && x.userPass == pass).ToList<User>();
User uObj = new User();
uObj = list.FirstOrDefault();
return uObj;
}
}
when i am debugging the code i can see the uJob object contain values. but when the function end and i return to the controller i see that the user object contain only null values, and the condition - " if (user.userName != null)" is returning FALSE!.. instead of TRUE..
i would like to get some help. Thanks !
You have to assign it.
user = user.getUser(userName , userPass);
Either you assign the value returned by the getUser method in calling program like this
user = user.getUser(userName , userPass);
Or you change the code in Model like this
public class User
{
public ObjectId _id { get; set; }
public string userName { get; set; }
public string userPass { get; set; }
public void getUser(string name , string pass)
{
var client = new MongoClient("mongodb://localhost:27017");
var db = client.GetDatabase("testdb");
var coll = db.GetCollection<User>("user");
var user = coll.FirstOrDefault(x => x.userName == name && x.userPass == pass);
if(user != null)
{
this._id = user._id;
this.userName = user.userName;
this.userPass = user.userPass;
}
}
}
if you replace
if (user.userName != null)
with
if ( user.getUser(userName , userPass).userName != null)
wil works for you.

Get User Roles with ASP.net Identity and Web API

I am currently trying to get the given user's list of Roles and am having some trouble fitting this into the context we are using it in. I was able to get a list of all available roles with this API function earlier,
[HttpGet]
[Route("GetRoles")]
public async Task<ApiResponse<List<RoleViewModel>>> GetRoles()
{
try
{
//Get Roles
var roles = await (from r in _db.AspNetRoles
select new RoleViewModel { Id = r.Id, Name = r.Name}).ToListAsync();
return new ApiResponse<List<RoleViewModel>>{ Success = true, Result = roles };
}
catch(Exception ex)
{
return new ApiResponse<List<RoleViewModel>> { Success = false, Message = ex.Message };
}
}
But can't seem to figure out what I need to throw into this one to get a list of the roles for the user. We went with Entity Frameworks Code First from Existing Database approach and are pulling from those tables. Strangely though there is no AspNetUserRoles table since I guess it is just relating the two tables AspNetUsers and AspNetRoles. Anyway, here is the function in question,
[HttpGet]
[Route("GetUserRoles")]
public async Task<ApiResponse<List<RoleViewModel>>> GetUserRoles(string userName)
{
try
{
var userRoles = await (_db.AspNetUsers.FirstOrDefault(u => u.UserName == userName).AspNetRoles).ToListAsync();
}
catch (Exception ex)
{
return new ApiResponse<List<RoleViewModel>> { Success = false, Message = ex.Message };
}
}
The current error I am getting is that AspNetRole does not contain a definition for ToListAsync(). I think the async stuff is throwing me a little. And lastly here is the RoleViewModel for reference,
public class RoleViewModel
{
public string Id { get; set; }
[Required]
[StringLength(256)]
public string Name { get; set; }
}
And the ApiResponse class,
public class ApiResponse<TResult>
{
public bool Success { get; set; }
public string Message { get; set; }
public TResult Result { get; set; }
}
I feel like there should be a simple fix, but I just can't quite grasp what it is.
Just found the answer to my problem. The main thing I was missing was utilization of the User Manager which made things so much easier. Then I just had to fit things into the functions I had already defined. Here is the code.
[HttpGet]
[Route("GetUserRoles")]
public async Task<ApiResponse<List<RoleViewModel>>> GetUserRoles(string userName)
{
try
{
// Get the user in question
var aspUser = (from u in _db.AspNetUsers
where u.UserName == userName
select u).FirstOrDefaultAsync();
// Check if the user was found
if (aspUser == null)
{
throw new Exception("User was not found");
}
// Get the roles associated with that user
var userRoles = await UserManager.GetRolesAsync(aspUser.Result.Id.ToString());
// Setup a RoleViewModel list of roles and iterate through userRoles adding them to the list
List<RoleViewModel> roleList = new List<RoleViewModel>();
foreach (var u in userRoles)
{
var item = new RoleViewModel { Name = u };
roleList.Add(item);
}
return new ApiResponse<List<RoleViewModel>> { Success = true, Result = roleList };
}
catch (Exception ex)
{
return new ApiResponse<List<RoleViewModel>> { Success = false, Message = ex.Message };
}
}

ASP NET select object from list

I'm beginner in ASP NET and I don't know how to select object from list for example I have static data in my model:
namespace ProjectMVC.Models
{
public class Initializer
{
public List<Profile> GetProfiles()
{
var profile = new List<Profile>(){
new Profile {
Id = 2,
Name = "Henrik Crawford",
SportType = "Спортсмен",
Location = "Украина, Кременчуг"
},
new Profile {
Id = 3,
Name = "Diane McCartney",
SportType = "Спортсмен",
Location = "Украина, Кременчуг"
},
new Profile {
Id = 4,
Name = "William Jenkins",
SportType = "Спортсмен",
Location = "Украина, Кременчуг"
},
};
return profile;
}
}
And I have ajax request which send an Id of user. For this I have actionresult in controller:
namespace ProjectMVC.Controllers
{
public class HomeController : Controller
{
private readonly Initializer init = new Initializer();
public ActionResult AddUserAjax(int UserId)
{
List<Profile> SomeList = init.GetProfiles();
// here I want to select and return user from list , where UserId == Id from list in model
}
}
This should do:
var user = SomeList.FirstOrDefault(u => u.Id == UserId)
It's utilising LINQ which is very powerful for querying objects.
You can just use Where or FirstOrDefault if you want to get one user:
var user = SomeList.FirstOrDefault(u => u.Id == UserId);

Entity Framework Deep Query Many to Many

New to Entity Framework, trying to figure out some stuff. I have tables as listed below:
Users
---------
UserID
UserName
Roles
---------
RoleID
RoleName
UserRoles
---------
UserRoleID
UserID
RoleID
I am using a repository pattern. here's an example of a repository (they're all essentially the same)
public class RoleRepository : IRoleRepository
{
private AuthorizationContext context = new AuthorizationContext();
public IQueryable<Role> Roles
{
get
{
return this.context.Roles;
}
}
public bool Save(Role pRole)
{
if (pRole.RoleID == 0 || pRole.RoleID == null)
{
context.Roles.Add(pRole);
}
context.SaveChanges();
return true;
}
public bool Delete(Role pRole)
{
context.Roles.Remove(pRole);
context.SaveChanges();
return true;
}
}
Now, I want to test to see if a user (by UserName) belongs to a role (by RoleName). How can I query? I expected it to be something like this, but it doesn't work:
public bool IsUserInRole(string username, string roleName)
{
var repo = new UserRepository();
var user = repo.Users.FirstOrDefault(u => u.NetID == username && u.UserRoles.FirstOrDefault(r => r.Role.Name == roleName));
}
How can I query to see if the user belongs to the role? I would prefer to use predicates if possible.
I would use the .Any function like this:
public static bool IsUserInRole(string username, string roleName)
{
using(var roleRepository = new RoleRepository())
{
return roleRepository.Roles.Any(r => r.RoleName == roleName && r.UserRoles.Any(ur => ur.User.UserName == username));
}
}
Here is a sample Console Application:
class Program
{
static void Main(string[] args)
{
var users = new List<string> { "A", "B", "C", "D" };
var roles = new List<string> { "User", "Admin", "Superuser"};
//User A has roles: User, Admin, Superuser
Debug.Assert(IsUserInRole(users[0], roles[0]) == true);
Debug.Assert(IsUserInRole(users[0], roles[1]) == true);
Debug.Assert(IsUserInRole(users[0], roles[2]) == true);
//User B has roles: User, Admin
Debug.Assert(IsUserInRole(users[1], roles[0]) == true);
Debug.Assert(IsUserInRole(users[1], roles[1]) == true);
Debug.Assert(IsUserInRole(users[1], roles[2]) == false);
//User C has roles: User
Debug.Assert(IsUserInRole(users[2], roles[0]) == true);
Debug.Assert(IsUserInRole(users[2], roles[1]) == false);
Debug.Assert(IsUserInRole(users[2], roles[2]) == false);
//User D has no roles
Debug.Assert(IsUserInRole(users[3], roles[0]) == false);
Debug.Assert(IsUserInRole(users[3], roles[1]) == false);
Debug.Assert(IsUserInRole(users[3], roles[2]) == false);
Debugger.Break();
}
public static bool IsUserInRole(string username, string roleName)
{
using(var roleRepository = new RoleRepository())
{
return roleRepository.Roles.Any(r => r.RoleName == roleName && r.UserRoles.Any(ur => ur.User.UserName == username));
}
}
}
public interface IRoleRepository : IDisposable
{
}
public class RoleRepository : IRoleRepository
{
private Context context = new Context();
public IQueryable<Role> Roles
{
get
{
return this.context.Roles.AsQueryable<Role>();
}
}
public void Dispose()
{
//Do nothing
}
}
public class Context : IDisposable
{
public IList<User> Users { get; set; }
public IList<Role> Roles { get; set; }
public IList<UserRole> UserRoles { get; set; }
public Context()
{
//Generate Some Fake Data
Users = new List<User>();
Users.Add(new User { UserID = 1, UserName = "A" });
Users.Add(new User { UserID = 2, UserName = "B" });
Users.Add(new User { UserID = 3, UserName = "C" });
Users.Add(new User { UserID = 4, UserName = "D" });
Roles = new List<Role>();
Roles.Add(new Role { RoleID = 1, RoleName = "User" });
Roles.Add(new Role { RoleID = 2, RoleName = "Admin" });
Roles.Add(new Role { RoleID = 3, RoleName = "Superuser" });
UserRoles = new List<UserRole>();
UserRoles.Add(new UserRole(1, Users[0], Roles[0]));
UserRoles.Add(new UserRole(1, Users[0], Roles[1]));
UserRoles.Add(new UserRole(1, Users[0], Roles[2]));
UserRoles.Add(new UserRole(1, Users[1], Roles[0]));
UserRoles.Add(new UserRole(1, Users[1], Roles[1]));
UserRoles.Add(new UserRole(1, Users[2], Roles[0]));
//User A has roles: User, Admin, Superuser
//User B has roles: User, Admin
//User C has roles: User
//User D has no roles
}
public void Dispose()
{
//Do nothing
}
}
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public IList<UserRole> UserRoles { get; set; }
public User()
{
UserRoles = new List<UserRole>();
}
}
public class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
public IList<UserRole> UserRoles { get; set; }
public Role()
{
UserRoles = new List<UserRole>();
}
}
public class UserRole
{
public int UserRoleID { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
public UserRole(int id, User user, Role role)
{
UserRoleID = id;
UserId = user.UserID;
User = user;
user.UserRoles.Add(this);
RoleId = role.RoleID;
Role = role;
role.UserRoles.Add(this);
}
}
Here is the modified "IsUserInRole" API that you already created :
public bool IsUserInRole(string username, string roleName)
{
var repo = new UserRepository();
return repo.Users.Any(u => u.UserName == username && u.UserRoles.Any(userrole => userrole.Role.RoleName == roleName));
}
The problem with your API was the FirstOrDefault, which restricts the navigation properties.

Categories

Resources