I am using Breeze.js, AngularJS, Web API and EF6 in a project which has 3 main security roles. Lets say High Level, Medium Level, and Low Level. In these examples I have Person, Company, LowLevelSecret, MediumLevelSecret, HighLevelSecret entities.
Security Problem 1: In the first example I want to be able to secure access to the entities as a whole. All security roles (low level, medium level and high level) should be able to access the Person entities. Only the users with a matching role level or higher should be able to access the secret entities which hold privileged information.
For example I might have.
class Person {
public int Id { get; set; }
public string Name { get; set; }
public LowLevelSecret LowLevelSecret { get; set; }
public MediumLevelSecret MediumLevelSecret { get; set; }
public HighLevelSecret HighLevelSecret { get; set; }
}
Where LowLevelSecret, MediumLevelSecret and HighLevelSecret would look something like this:
class LowLevelSecret {
public int Id { get; set; }
public string Secret { get; set; }
}
class MediumLevelSecret {
public int Id { get; set; }
public string Secret { get; set; }
}
class HighLevelSecret {
public int Id { get; set; }
public string Secret { get; set; }
}
I have a controller which an IQueryable per type for Person and Company:
class BreezeController : ApiController {
[HttpGet]
public string Metadata()
{
return _repository.Metadata;
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
var result = _repository.SaveChanges(saveBundle);
return result;
}
[HttpGet]
public IQueryable<Person> People()
{
return _repository.People;
}
[HttpGet]
public IQueryable<Company> Companies()
{
return _repository.Companies;
}
}
I can't use an AuthorizeAttribute on the secret entities, they are not listed in the controller - I use expand on the breeze query client side to pull them in. My concern is that anyone could write their own client side code and use the expand function of breeze to first query for an entity they are allowed to access then expand it to other entities they should not be able to access.
I could override the expand depth on each controller action:
[HttpGet]
[BreezeQueryable(MaxExpansionDepth = 0)]
public IQueryable<Person> People()
{
return _repository.People;
}
This seems a little bit cumbersome and prone to error. Is there a better way to protect what gets sent to the client?
Security Problem 2 Say I have a Company entity as follows:
public Company {
// low level, medium level and high level access required
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
// medium level, high level access only - NOT low level
public string DirectorsName { get; set; }
public string DirectorsEmail { get; set; }
// high level access only - NOT low level, medium level
public string Profit { get; set; }
public string Turnover { get; set; }
}
How do I restrict access as described so that different user roles can access different parts of the same Company entity. I could write a projection query to only get the bits I want, but there is nothing to stop a user from writing their own query for the whole entity. I assume the key here may be to use different DTO's for each access level? How can this work so that it can all get pieced back together when saving etc. so it knows which entity to update.
Security Problem 3 The SaveChanges method in the controller accepts a change bundle. There does not appear to be anything to stop a user with lower level access from submitting changes to entities which they should not be able to change. Even if the normal client code does not allow this, they could simply write their own or create it manually and submit.
I believe the preferred solution to this is to override the BeforeSavingEntity method and inspect the changes to ensure they are acceptable for the users role? Is the only way to ensure security to manually inspect for changes to every medium or high level property and compare the users role? Is there a good scalable pattern which can be used to perform these checks and other business logic on a large number of entities. I can't find any good real world examples of how to properly enforce these kinds of business rules in a larger project scenario.
Thanks for all your help and suggestions,