I need help with implementing validation logic for users. I need to check whether the password entered by the user matches the passwordhash inside a SQL Server user table.
The big question for me is, where do I implement this validation logic?
You can see my user implementation below:
public class User : BaseEntity
{
public virtual string Username { get; set; }
public virtual string Hash { get; set; }
public virtual string Salt { get; set; }
}
public interface IUserTasks
{
List<User> GetAll();
User Get(int id);
User CreateOrUpdate(User user);
void Delete(int id);
bool Validate(string username, string password);
}
public class UserTasks : IUserTasks
{
private readonly IRepository<User> _userRepository;
private readonly IValidateHashQuery _validateHashQuery;
public UserTasks(IRepository<User> userRepository, IValidateHashQuery validateHashQuery)
{
_userRepository = userRepository;
_validateHashQuery = validateHashQuery;
}
public List<User> GetAll()
{
return _userRepository.GetAll().ToList();
}
public User Get(int id)
{
return _userRepository.Get(id);
}
public User CreateOrUpdate(User user)
{
return _userRepository.SaveOrUpdate(user);
}
public void Delete(int id)
{
var entity = _userRepository.Get(id);
if(entity != null)
{
_userRepository.Delete(entity);
}
}
public bool Validate(string username, string password)
{
return _userRepository.PerformQuery(_validateHashQuery) != null ? true : false;
}
}
Do need to implement the validation logic inside the Task implementation or do I need to create a new query object inside my domain and use it in my Task implementation?
I really need help with this, looking forward to your replies!
Rob
Its an age old argument and one I've fought with myself before.
Take Sharp arch's lead. They solve these problems with attributes check out their DomainSignatureAttrribute, for solving an object's persistence uniquness.
For me, this is domain logic. Tasks are for orchestrating one or more events in a request.
I'd inject a repository interface into your core object and do the checking there:
public User(IUserRepsoitory userRepository)
{
this.userRepsoitory = userRepository;
}
public void IsValid()
{
return userRepository.IsPsswordValid(this);
}
I dont see how this breaks any rules. This generally isnt recommended.
AFAIK the IRepository.PerformQuery(IQuery query) has been removed from latest build of SA, in favor of using Enhanced query object.
public class ValidateHashQuery : IValidateHashQuery
{
public bool Validate(string username, string password)
{
ISession nhSession = NHibernateSession.Current;
// you now have your session and run your query however you like
}
}
public class UserTasks : IUserTasks
{
private readonly IRepository<User> _userRepository;
private readonly IValidateHashQuery _validateHashQuery;
public UserTasks(IRepository<User> userRepository, IValidateHashQuery validateHashQuery)
{
_userRepository = userRepository;
_validateHashQuery = validateHashQuery;
}
public List<User> GetAll()
{
return _userRepository.GetAll().ToList();
}
public User Get(int id)
{
return _userRepository.Get(id);
}
public User CreateOrUpdate(User user)
{
return _userRepository.SaveOrUpdate(user);
}
public void Delete(int id)
{
var entity = _userRepository.Get(id);
if(entity != null)
{
_userRepository.Delete(entity);
}
}
public bool Validate(string username, string password)
{
return _validateHashQuery.Validate(username, password);
}
}
But looking at your user tasks, it doesn't seem to be doing anything other than calling the repository, not sure what value that brings why not just use the repository directly?
Same goes for the validate query, you could add that dependency to your controller and call the user validation query directly from there, and set cookie/session according to result.
Then before performing a task that requires a user to be logged in, you check for that cookie (Ideally some attribute on the action [Autherise]). Depending on your scenario you might want to have that authorisation in the task itself.
Related
I am trying to implement a Policy that is quite granular level.
The idea is like in the image.
Each entity has always the One-To-Many relation with the entity on the right.
One Institution can have many Courses, each Course can have many Subjects, each Subject can have many Syllabus, etc...
There are 3 Roles: Administrator, Contributor, Viewer
If you have a Role in one of the top entities this role will be propagated to the rest bellow.
E.g: If you are an Administrator of Course you are administrator of Subject, Syllabus, etc...
If you are Contributor of one of the Syllabus you will be Contributor for bellow Lessons and Videos of this Syllabus.
I have tried to solve it using Custom Policies:
Adding a requirement like below:
public class AdministratorRequirement : IAuthorizationRequirement
{
public int UserId { get; private set; }
public EntityType EntityType { get; private set; }
public int EntityId { get; private set; }
public AdministratorRequirement(int userId, EntityType entityType, int entityId)
{
UserId = userId;
EntityType = entityType;
EntityId = entityId;
}
}
And adding the Policy Handler as bellow:
public class AdministratorHandler : AuthorizationHandler<AdministratorRequirement>
{
public IRolesRepository RolesRepository {get;set;}
public AdministratorHandler(IRolesRepository rolesRepository)
{
RolesRepository = rolesRepository;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdministratorRequirement requirement)
{
// Save User object to access claims
bool isAdministrator = RolesRepository.CheckUserRole(requirement.UserId, requirement.EntityType, requirement.EntityId, "Administrator");
if (isAdministrator)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
The problem is that I would like to define variable requirement on the Startup class:
options.AddPolicy("CourseAdministrator",
policy => policy
.Requirements
.Add(
new AdministratorRequirement(
/*userId - should be variable*/ 0,
EntityType.Course,
/*int entityId - should be variable*/ 0))
And use it on something like
[Authorize(/*pass some parameters in here like user Id and course Id*/)]
[HttpPost]
[Route("create")]
public async Task<IActionResult> CreateCourse([FromBody] Course course)
{
//Or call the policy handler programatically in here.
CleanCacheOnUpdateCourse();
return Ok(await Services.CreateCourse(course, EmauaUser));
}
Do you know if there is such a solution?
For Policy, you need to pass the satic variable.
If you want to check the permission dynamically, you could implement your own IAuthorizationFilter like
custom IAuthorizationFilter
public class CustomAuthorize : IAuthorizationFilter
{
private readonly int _input;
public CustomAuthorize(int input)
{
_input = input;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//custom validation rule
if (_input == 1)
{
context.Result = new ForbidResult();
}
}
}
Custom CustomAuthorizeAttribute
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
public CustomAuthorizeAttribute(int input) : base(typeof(CustomAuthorize))
{
Arguments = new object[] { input };
}
}
Use
[CustomAuthorizeAttribute(1)]
public IActionResult About()
There are many questions about custom authentication in ASP.NET, but none of them answers how to fully integrate it with ASP.NET mechanics.
I want to make a web application for system which already exists and have users.
Let's create new ASP.NET MVC project. I choose "No authentication" to make it from scratch (because I need to read from custom tables, custom hashing function etc, so I'll go this way).
I'll use IIdentity and IPrincipal interfaces to carry logged in user in HttpContext.
public class Identity : IIdentity
{
public Identity(string name)
{
Name = name;
IsAuthenticated = true;
}
public string Name { get; private set; }
public string AuthenticationType { get; set; }
public bool IsAuthenticated { get; set; }
}
public class Principal : IPrincipal
{
public Principal(string email)
{
Identity = new Identity(email);
}
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
return false;
}
}
I'll create SessionsController which will create and destroy Session. Session will contain Id of logged in user.
public class UserManager
{
public bool Authenticate(WorkerDTO user, string password)
{
using (var context = new DatabaseContext())
{
var user = context.Users.SingleOrDefault(w => w.Email == user.Email);
if (user != null)
{
// compute SHA512 of password with salt
var hash = Hash(user.Password);
if (user.HashPassword == hash)
return true;
}
return false;
}
}
}
public class SessionsController : Controller
{
private IDatabaseManager _dbManager;
private UserManager _userManager;
public SessionsController(IDatabaseManager dbManager, UserManager userManager)
{
_dbManager = dbManager;
_userManager = userManager;
}
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(UserLoginViewModel model)
{
var user = _dbManager.Give(new WorkerByEmail(model.Email));
if(user != null && _userManager.Authenticate(user, model.Password))
{
// create session
Session["UserId"] = worker.Id;
// assign User property
User = new Principal(worker.Email);
return RedirectToAction("Index", "Home");
}
return RedirectToAction("New");
}
public ActionResult Logout()
{
Session.Remove("UserId");
User = null;
return View();
}
}
Application won't remember that User = new Principal(worker.Email);.
So, if I want to make use of sessions, I want to tell my ASP.NET application that User behind UserId carried by session (probably a cookie) each request is the logged in user. In Global.asax I have available events with reasonable names:
AuthenticateRequest
PostAuthenticateRequest.
Unfortunately, Session is unavailable in these events.
How to make use of ASP.NET in my application? Maybe Session isn't the way to go?
Should I create new IPrincipal object and attach to User prop each request?
And why User property isn't null at start? Should I set it to null on logout?
What is the best way of passing user information if items in database are assigned to specific users and no user can get access to data which isn't his? I have two ideas, but I don't know if any of them is correct.
First idea I don't like, because it requires to pass user name every time I want to get any data from repository:
public class Repository : IRepository
{
private DbContext dbContext = new DbContext();
public IEnumerable<Item> GetItems(string userName)
{
return dbContext.Items.Where(i => i.UserName == userName);
}
}
Second is injecting user name and it looks more natural to me, because I can use repository like there was no user authentication, but I have no idea if it's safe and if it's ASP.NET MVC style:
public class Repository : IRepository
{
private DbContext dbContext = new DbContext();
private string userName;
public Repository(string userName)
{
this.userName = userName;
}
public IEnumerable<Item> Items
{
get { return dbContext.Items.Where(i => i.UserName == userName); }
}
}
// In NinjectDependencyResolver.cs:
public void AddBindings()
{
kernel.Bind<IRepository>().To<Repository>().WithConstructorArgument(HttpContext.Current.User.Identity.Name);
}
I don't know if it's good to use HttpContext class somewhere else than controller or view.
These are very simple examples and I didn't compile them, but I hope there's no mistakes and you know what I mean. Of course UserName should be part of another table with users, but I made it as simple as I could.
public ItemsController : Controller {
private readonly IItemsService _service;
public ItemsController(IItemsService service) {
_service = service;
}
public ActionResult Index(){
return View("Index", _service.GetItemsForUser(HttpContext.Current.User.Identity.Name));
}
}
your service would look like this
public class ItemsService : IItemsService {
private readonly IItemsRepository _repository;
public ItemsService(IItemsRepository repository) {
_repository = repository;
}
public IEnumerable<Item> GetItemsForUser(string username) {
return _repository.GetItems(username);
}
}
and you repo
public ItemsRepository : IItemsRepository, IRepository {
private DbContext dbContext = new DbContext();
public ItemsRepository() {
}
public IEnumerable<Item> GetItems(string username) {
return _context.Items.Where(i => i.username == username).ToList();
}
}
or something similar to this structure. I have used interfaces because I assume the use of inversion of control.
Hi I have table employee with some fields
to validate fields I have created two layers
Service layer
Employee repository
Employee repository code is
namespace MvcApplication2.Models
{
public interface IEmployeeMainTableRepository
{
bool CreateEmployee(EMP_MAIN_TBL EmployeeToCreate);
IEnumerable<EMP_MAIN_TBL> ListEmployees();
}
public class EmployeeRepository : MvcApplication2.Models.IEmployeeMainTableRepository
{
private EMPLOYEE_SYSTEMEntities _entities = new EMPLOYEE_SYSTEMEntities();
public IEnumerable<EMP_MAIN_TBL> ListEmployees()
{
return _entities.EMP_MAIN_TBL.ToList();
}
public bool CreateEmployee(EMP_MAIN_TBL EmployeeToCreate)
{
try
{
// _entities.AddToEMP_MAIN_TBL(productToCreate);
_entities.SaveChanges();
return true;
}
catch
{
return false;
}
}
}
And service layer contains
public interface IEmployeeService
{
bool CreateEmployee(EMP_MAIN_TBL EmployeeToCreate);
System.Collections.Generic.IEnumerable<EMP_MAIN_TBL> ListEmployees();
}
public class EmployeeService : MvcApplication2.Models.IEmployeeService
{
private IValidationDictionary _validatonDictionary;
private IEmployeeMainTableRepository _repository;
public EmployeeService(IValidationDictionary validationDictionary, IEmployeeMainTableRepository repository)
{
_validatonDictionary = validationDictionary;
_repository = repository;
}
protected bool ValidateEmployee(EMP_MAIN_TBL employeeToValidate)
{
if (employeeToValidate.EMP_NM == null)
_validatonDictionary.AddError("EMP_NM", "Name is required.");
if (employeeToValidate.PLCE_OF_BRTH == null)
_validatonDictionary.AddError("PLCE_OF_BRTH", "Place of birth is required.");
return _validatonDictionary.IsValid;
}
public IEnumerable<EMP_MAIN_TBL> ListEmployees()
{
return _repository.ListEmployees();
}
public bool CreateEmployee(EMP_MAIN_TBL EmployeeToCreate)
{
// Validation logic
if (!ValidateEmployee(EmployeeToCreate))
return false;
// Database logic
try
{
_repository.CreateEmployee(EmployeeToCreate);
}
catch
{
return false;
}
return true;
}
and I have created two more classes to add validation messages
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
bool IsValid { get; }
}
And
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
#endregion
}
finally employee controllers contains below structure
public class EmployeeController : Controller
{
private IEmployeeService _service;
public EmployeeController()
{
_service = new EmployeeService(new ModelStateWrapper(this.ModelState), new EmployeeRepository());
}
public EmployeeController(IEmployeeService service)
{
_service = service;
}
public ActionResult Index()
{
return View(_service.ListEmployees());
}
//
// GET: /Product/Create
public ActionResult Create()
{
return View(new EMP_MAIN_TBL());
}
//
// POST: /Product/Create
[AcceptVerbs(HttpVerbs.Post)]
[HttpPost]
public ActionResult Create([Bind(Exclude = "EMP_ID")] EMP_MAIN_TBL employeeToCreate)
{
if (!_service.CreateEmployee(employeeToCreate))
return View();
return RedirectToAction("Index");
}
}
}
and my view looks like this
My question is above code working fine for server side validation
but how do I achieve validation on client side using above same code
please
Since you are already validating on the service side you could return the ModelStateDictionary instead of the bool, you could then check that it is valid on the client side.
But this won't help when it comes to checking that the whole service method has finished, so you could create a new type that returns say a bool and the ModelStateDictionary.
Another approach is to use Fault Exceptions. You can create your own fault exception that would get thrown when the model state is not valid. This Model State Fault could contain your ModelStateDictionary.
So from that you have three options.
Change the return type to the ModelStateDictionary.
Create a new return type to return a result and a ModelStateDictionary.
Use Fault Exceptions that occur when the Model State isn't valid.
Personally I would use the third approach, as you can then still use your original return type, and then just need to catch the Fault like you would an Exception. Here is an example and also MSDN
I'm using NHibernate on a custom membership provider in a MVC3 application. Whenever I try to login though, I get the exception:
Session is closed!
Object name: 'ISession'
The code in the membership provider looks like this:
ContractRepository repository;
public string UserDescription { get; set; }
public CustomSqlMembershipProvider() {
this.repository = new ContractRepository(ProviderPortal.Persistance.NHibernateSessionStorage.RetrieveSession());
}
public override bool ValidateUser(string username, string password) {
var user = repository.GetContractForUser(username);
if (user == null)
return false;
else {
UserDescription = user.Description;
return true; //TODO: come back and add user validation.
}
}
And here is the retrieve session methods:
public static ISession RetrieveSession() {
HttpContext context = HttpContext.Current;
if (!context.Items.Contains(CURRENT_SESSION_KEY)) OpenCurrent();
var session = context.Items[CURRENT_SESSION_KEY] as ISession;
return session;
}
private static void OpenCurrent() {
ISession session = NHibernateConfiguration.CreateAndOpenSession();
HttpContext context = HttpContext.Current;
context.Items[CURRENT_SESSION_KEY] = session;
}
This is where the exception is happening:
public Contract GetContractForUser(string UserName) {
return (Contract)session.CreateCriteria(typeof(Contract))
.Add(Restrictions.Eq("Login", int.Parse(UserName))).UniqueResult();
}
Somewhere between the CustomSqlMembershipProvider constructor being called, and the ValidateUser method being called, the session is being closed. Any ideas? My other Controllers are injected with an open session via DI, but this one is giving me the hardest time.
Do you get this one consistently or on and off?
We were getting this using Spring.net for our DI and using OpenSessionInView
We had to add the following http module to change the storage options for the current thread.
public class SpringThreadStorageModule : IHttpModule
{
static SpringThreadStorageModule()
{
LogicalThreadContext.SetStorage(new HybridContextStorage());
}
#region IHttpModule Members
public void Dispose()
{
// do nothing
}
public void Init(HttpApplication context)
{
// we just need the staic init block.
}
#endregion
}