We are building a MVC API + Entity project, right now we are creating our log layer, we wanna log every single entity that we add, alter or delete, however we need to log the user id that is performing the action as well, the id is provided with the Header [Authorization].
Our log is performed as the action previous to the database action, because of that we would need to add the user id to every method signature on all layers until the DAL.
After researching a bit on the internet, looking at Global Variables, HTTPContext, etc, we did not find any solution that did not "harm" the project layers, any ideias ? How should we proceed ?
You could use DI to inject the current user into whatever DAL classes need it. For example, I use Ninject to do this so I don't need to have the user id as a parameter on every update function:
kernel.Bind<IPrincipal>().ToMethod(c => HttpContext.Current.User);
Then in whatever classes in the app need it:
[Inject]
public IPrincipal CurrentUser { get; set; }
Related
I have been implementing Jhipster at my work and loving it. I was asked to implement a security validation that one user should not be allowed to edit the entity created by other user. For this I need two things:
First, in all entities, add a ManytoOne relation with User entity.
In Backend put a validation in controller while updating the entity to check if current logged in user is same as what is stored in DB. In front end also same logic to show/hide edit button.
I have done a POC for this and it works but is little ugly, check the code:
public ResponseEntity<Entry> updateEntry(#RequestBody Entry entry) throws URISyntaxException {
log.debug("REST request to update Entry : {}", entry);
if (entry.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}
//here is my logic
Optional<Entry> entry_db = entryRepository.findOneWithEagerRelationships(entry.getId());
if(!entry_db.get().getUser().getId().equals(userService.getUserWithAuthorities().get().getId())) {
//throw someexception
}
//
Entry result = entryRepository.save(entry);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, entry.getId().toString()))
.body(result);
}
Is there any better or OOTB way of doing this??? may be something in spring security i am not aware of??
Thanks for help!!
This is a job for Spring Security Expression-Based Access Control, in particular you could annotate your method with #PreFilter and a custom PermissionEvaluator you would implement with similar logic as in your POC. The PermissionEvaluator could be generic and applied to several entity types if you define an Owned interface that models the ownership with a method like User getOwner() and that all your entity classes would implement.
See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-access
The annotated method should be in a service rather than in a resource controller.
Also, UserService alone will not help you in finding the current authenticated user, you should use JHipster's SecurityUtils first and then ÙserService if you need more data about it.
I am developing an MVC app to serve multiple domains - each is a branch of a larger company.
A LocalBranch class stores details such as phone, address, email, location coordinates etc.
I want to create a single instance of this class per http request and have it available throughout the application - from within controllers, views, some helper classes and other code.
Is there a recommended way of doing this?
Right now I have it as a property on a BaseController and use ViewBagto pass it to views. But I would prefer it strongly typed in Views if possible.
I don't want to put it in an application variable, because we need to serve different values to different domains.
I would rather avoid a session variable if possible because we might scale up to use multiple servers in the future, and I've heard this doesn't play well with sessions.
Please feel free to update tags / title if you think there is a clearer way of expressing what I'm after. Thank you.
The best way to maintain your state in a web application per request is simply use the HttpContext class.
You need to store your state(LocalBranch) as an Item in the HttpContext:
HttpContext.Current.Items.Add("LocalBranch", GetLocalBranch());
You can fetch the Item all across your application like this:
LocalBranch branch = HttpContext.Current.Items["LocalBranch"] as LocalBranch;
The Items property is simply a key value Dictionary. The value is an object. You will have to check for nulls and this is really similar to the Session object you know. The main difference is the scope. The HttpContext is a dot net object that has a lifetime of an http request.
Now using the HttpContext the way I've shown you is the simplest way to do it.
You can go two steps forward and use a framework called Unity and add a lifetime to your objects.
Unity does much more and the lifetime management is just one gem.
You can create a custom HttpContext lifetime that generates objects per request. Something like this.
And them all you need to do is:
1.Register you LocalBranch class with the HttpContext lifetime.
2.Add a static Current property which will use the Unity container and resolve the correct instance of LocalBranch.
3.Use it something like this: LocalBranch.Current
BTW, you can use Unity's dependency injection for injecting objects into controllers and other modules. That's a better practice then just using the static Current property.
You kind of have two questions here. The first is "How do I create a single instance of this class per HttpRequest?" The second is "How do I make this available to strongly typed views?"
The first has pretty much been answered by #amir-popovich to use dependency injection. However, FWIW I would probably use Ninject instead of Unity (just preference, really) and I would probably implement it differently. I would not use HttpContext, and simply build a service (which is instanciated using Ninject's OnePerHttpRequest Module, passing the domain as an argument to get the proper values).
Then, in order to add these LocalBranch values to your strongly typed View Model, you can first create a base view model which holds this type:
public class BaseViewModel
{
public LocalBranch Branch {get;set;}
}
Then, make all of your current view models inherit this base type
public MyViewModel : BaseViewModel
{
public string SomeValue {get;set;}
}
Then in your controller, it is easy enough to add these values from the service you created from the first step
public ActionResult SomeAction()
{
var vm = new MyViewModel();
vm.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
//do other stuff
return View(vm);
}
However, that gets pretty tedious to add that to each controller action, so you can instead create a Result Filter to add it for you:
public class LocalBranchResultFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
//This method gets invoked before the ActionResult is executed.
filterContext.Controller.ViewData.Model.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
}
}
Now, you can just decorate your Controller and/or Actions with the filter (you could even set it in the Global Filters if you want).
You can embed the child actions into your layout or a view. You can even cache its output so you don't keep re-querying the database.
controller
[ChildActionOnly]
[OutputCache(Duration=500, VaryByParam="*")]
public ActionResult Info()
{
var localBranch = db.GetLocalBranch();
return PartialView("_Info", localBranch);
}
_Info view
This bit will get inserted into your other views
#model LocalBranch
<span>#Model.address</span>
<span>#Model.phone</span>
Use in _Layout or other view
<p>lorem ipsum...</p>
#Html.Action("Info")
In my MVC application I have Player and Coach objects, and a user can be one or the other. I also have Team objects and what I want to know is how I prevent a user who is in a list of Players or is the Coach of a Team gaining access to a route like /Teams/Details/2 where 2 is the id of a team other than that which he/she is part of.
Thanks in advance!
Since you want to restrict an id that they aren't a part of, this seems like a situation where you can Inherit from the AuthorizeAttribute and provide your implementation for AuthorizeCore
Your implementation could check their role/team id and decide what to do / redirect.
public class TeamAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return UserIsInTeam(httpContext); //whatever code you are using to check if the team id is right
}
}
You can now apply it like any other attribute.
[TeamAuthorize]
The very simplest solution would be to change the URLs from using IDs to random GUIDs. You would almost eliminate the chance of someone guessing another valid value. Of course, this is not secure by definition (mostly because someone could get the other URL from history or another source), but in some scenarios this is enough.
A better solution is to create a new attribute based on IActionFilter interface that implements OnActionExecuting method and checks the ID by using this.ControllerContext.HttpContext.User.Identity.Name and this.RouteData.Values["id"]. You will then apply this attribute to your controller methods.
In our current system we implemented row level security in controller methods by just adding the code that verifies the user permissions as the first line in each method. The checking code is the same as with the attribute and it requires the same amount of code to add. This approach has one additional benefit - it is easier to implement scenarios like where a coach would be able to see the details of other teams but not modify them (we have one action and view for both reading and updating depending on permissions).
You would also use the last approach if you need to go to the database to check the permissions and you are using IoC frameworks such as Ninject with constructor based injection - since you will not have access to those values in the attribute.
I am building an applicaiton using asp.net mvc3. I added two layers to this project, repository and service layer. some of my code, I am not sure which layer I should put them in.
on my register page, to create an account, I only ask user to enter their email and password, its using UserRegisterViewModel. before I add it to the database, my user table need more info.
I need to create an User entity from the UserRegisterViewModel:
user.ip= "1.1.1.1";
user.createddate="11/11/1911";
....
so above code, where should I put them? webui, repoistory or service layer.
I would add the 'CreatedDate' in the constructor of your 'User' entity, and add the IP address in the controller that receives the ViewModel object.
I case you didn't know: you can map ViewModels to Entities using AutoMapper.
You can only get the IP address from the request so you have 'get' it there in the Action
Something like this
[HttpPost]
public ActionResult Login(UserRegisterViewModel model) {
if(ModelState.IsValid) {
SaveLogonToAudit(model.Username);
}
return View(model);
}
private void SaveLogonToAudit(string username) {
var user = new UserAccount(username, Request.Browser.Browser, Request.Browser.Type, Request.UserHostAddress);
user.Save();
}
The User entity could live in another layer, your UserRegisterViewModel will live in the MVC UI layer. It's perfectly normal to have a ViewModel that represents the data in your view and a completely separate class in another layer that represents your User entity. That's good design. Your User entity can be in the ServiceLayer and have business rules associated to it. That class will then call into your repository layer to save its data.
I agree with Leon Cullens, the CreateDate should live in the User entity, that's why you don't see me setting it. The User entity should handle it's own CRUD actions that call into your RepositoryLayer. Set the CreateDate in the ctor or better yet, have a base class that has CreateDate, CreatedBy, LastUpdateDate, LastUpdatedBy that the User will use internally.
Let's suppose I don't want to use Membership and want to restrict user's access with ActionFilter.
I know I can create a filter/attribute and override the OnActionExecuting method and further I can put this attribute in a ActionResult.
And let's assume that I have a table named 'tbUsers', it has also an int field named 'certificate' and depending on this 'certificate' value, an user can access an ActionResult or not.
But, how can I, in a OnActionExecuting mehod, check this user's 'certificate' value and grant his access or redirect to a 'NotAllowed.aspx' page?
Thanks!!!
I would not do it this way. I would implement an IAuthorizationFilter. Authorization filters run before all action filters.
For example, suppose you later put an OutputCache attribute on the action method and it happens to run before your authentication filter. That would be bad! If the content is cached, the authentication filter would never run and people would see cached sensitive data.
The ActionExecutingContext has the HttpContext which would include the current User object. You can use this to get the User. You can also use it to access the Session if you wanted to store the information in the Session. You could also put it in an encrypted cookie and access those through the Request.Cookies on the context. You'd want to think about the security implications of that, though I don't see it as being more problematic than the auth cookie.
Checking it against the database and maintaining testability on your filter is a little more tricky. What I've done is to provide two constructors for each filter class. One provides a database factory that will create my data context. I use this in testing and supply a mock database factory that produces a mock or fake database. The normal, parameterless constructor calls the previous constructor with a null factory. When this happens the other constructor creates a new instance of the default factory.
private IDatabaseFactory Factory { get; set; }
public MyFilter( IDatabaseFactory factory )
{
this.Factory = factory ?? new DefaultDatabaseFactory();
}
public MyFilter() : this(null) { }