Strategy to guard against malicious data changes
breeze
Solution
I think you are on the right track. I've been noodling this myself and have gone down much the same path.
Let's assume you've handled authentication and there's an `IPrincipal` available. You've got yourself a custom `IIdentity` too (call it `AppIdentity`) where you can stash the `UserId` for the authenticated user.
The Web Api's base `ApiController` class makes the ambient `IPrincipal` available via its `User` property. We will leverage that in your custom Breeze Web Api controller which might begin like this:
[Authorize]
[JsonFormatter, ODataActionFilter]
public class BreezeApiController : ApiController
{
private readonly AppContextProvider _context;
public BreezeApiController() {
// pass 'User' IPrincipal to the context ctor
_context = new AppContextProvider(User);
}
...
// one of the Query action methods
[HttpGet]
public IQueryable<Foo> Foos() {
return _context.Foos
}
...
Your custom `EFContextProvider` might begin like this:
public class AppContextProvider : EFContextProvider<AppDbContext>
{
public AppContextProvider(IPrincipal user)
{
UserId = ((AppIdentity) user.Identity).UserId;
}
public int UserId { get; private set; }
...
Now you probably want to prevent UserB's entities from being seen by UserA. So instead of allowing every `Foo` to go out the door, your custom `EFContextProvider` could filter accordingly.
public DbQuery Foos
{
get
{
// Here the 'Context' is your EF DbContext
return (DbQuery) Context.Foos
.Where(f => f.UserId == UserId);
}
}
Looking back at the controller, we see that its `Foos` GET action method is oblivious to the filter ... as it should be. We want our controllers to be light and move the business logic to the custom `EFContextProvider` and its helpers.
Finally, a highly simplified, general purpose `BeforeSaveEntity` could look like this:
private bool BeforeSaveEntity(EntityInfo info)
{
var entity = info.Entity;
if (info.EntityState == EntityState.Added)
{
entity.UserId = UserId;
return true;
}
return UserId == entity.UserId || throwCannotSaveEntityForThisUser();
}
...
private bool throwCannotSaveEntityForThisUser()
{
throw new SecurityException("Unauthorized user");
}
Notice that the custom context provider on the server is responsible for setting the `UserId` of added entities. We wouldn't trust the client to do that anyway. And of course it is responsible for verifying the `UserId` of modified and deleted entities.
Hope this helps. Remember, this is only a sketch. The real deal would have greater sophistication and be refactored into helpers.
Problem
Looking for ideas to guard against malicious data changes: userA manipulating (editing or deleting) data that belongs to userB. Since we are creating entities on the client, we need to assign them (or at least some of them) to the authenticated user. For example: ``` var newItem = ds.createNewItem(); newItem.OwnerId(22); //this is the problem that I see. newItem.Name("New Item"); newItem.Description("I just changed your item!"); ... //and so on ds.saveChanges(); ``` Assuming we know the identity of the user calling `SaveChanges` on our API, how do we validate our entities (new or modified) against this user? The first thought that comes to mind is to subclass `EFContextProvider`, override `BeforeSaveEntity` and examine the entities `OwnerId` property against the identity of our user. For example: ``` if (entityInfo.Entity.GetType() == typeof(Item) && (entityInfo.EntityState == EntityState.Added || entityInfo.EntityState == EntityState.Modified) && ((Item)entityInfo.Entity).OwnerId != _currentUserId) { return false ... //and so on ``` If using this approach, does it make sense to establish `_currentUserId` in the constructor of our new `EFContextProvider` class? An ideas or perhaps a better way to approach this problem?