Note that there are some explanatory texts on larger screens.

plurals
  1. POASP.MVC best security practices for control access to Entities
    primarykey
    data
    text
    <p>Let we have system with following entities:</p> <pre><code>public class Doctor { public int ID { get; set; } public int DepartmentID { get; set; } public string Name { get; set; } public ICollection&lt;Recipe&gt; Recipes { get; set; } } public class Patient { public int ID { get; set; } public string Name { get; set; } public ICollection&lt;Recipe&gt; Recipes { get; set; } } public class Recipe { public int ID { get; set; } public int DoctorID { get; set; } public int PatientID { get; set; } public Doctor Doctor { get; set; } public Patient Patient { get; set; } public ICollection&lt;RecipeDetails&gt; Details { get; set; } } public class RecipeDetails { public int ID { get; set; } public Guid SomeGuid { get; set; } public double SomeValue { get; set; } } </code></pre> <p>Also we have requirements:</p> <ul> <li>Doctor should be able to edit his recipes</li> <li>Doctor should be able to see only recipes from doctors within his department</li> <li>Doctor should be able to perform search by available recipes</li> <li>Doctor should be able to generate reports by available recipes details</li> </ul> <p>For now I've implemented following security check:</p> <pre><code>public void ValidateAccess(Doctor doctor, Recipe aRecipe, EntityAction action) { if (action == EntityAction.Modify &amp;&amp; doctor.ID == aRecipe.Doctor.ID) return; if (action == EntityAction.Read &amp;&amp; doctor.DepartmentID == aRecipe.Doctor.DepartmentID) return throw new SecurityException(); } </code></pre> <p>That works perfect for simple methods when i have receipe entity, I can easy validate access by caling this method at the begining of my logic method.</p> <p>But now I have problem, this solution won't work for search and reporting when I don't have exact entity but have some statistics on them.</p> <p>Lets imagine that I want to generate report for patients with name "aName" that have receipes with component "someGuid", I will have some query with 2 criterias :</p> <pre><code>var res = RecipeRepository.Query(r =&gt; aName.Contains(r.Patient.Name)).SelectMany(r =&gt; r.Details).Where(d =&gt; d.SomeGuid == someGuid).Sum(d =&gt; d.SomeValue); </code></pre> <p>This query is not correct, it will display statistics for all recipes, including those which should be hidden. To fix that, we should add our access condition to our query: </p> <pre><code>currentDoctor.DepartmentID == r.Doctor.DepartmentID </code></pre> <p>So now I have query:</p> <pre><code>var res = RecipeRepository.Query(r =&gt; aName.Contains(r.Patient.Name) &amp;&amp; currentDoctor.DepartmentID == r.Doctor.DepartmentID).SelectMany(r =&gt; r.Details).Where(d =&gt; d.SomeGuid == someGuid).Sum(d =&gt; d.SomeValue); </code></pre> <p>The problem is that I should add this part to each query in the system that makes any calculations on receipes.</p> <p>UPDATE (2012-11-12):</p> <p>First example is very simple, and can be solved as StuartLC mentioned in his post. But we have more complex reports in our system. For example - show all patients, that had component someGuid in their recipes. Now our query starts with another repository, so we can't apply private or protected methods from RecipeRepository. Here is sample query:</p> <pre><code>var res = PatientRepository.Query(p =&gt; p.Name.Contains(aName) &amp;&amp; p.Recipes.Any(r =&gt; r.Details.Any(d =&gt; d.SomeGuid == someGuid))); </code></pre> <p>In this case we still need to add our filter directly into query:</p> <pre><code>var res = PatientRepository.Query(p =&gt; p.Name.Contains(aName) &amp;&amp; p.Recipes.Any(r =&gt; currentDoctor.DepartmentID == r.Doctor.DepartmentID &amp;&amp; r.Details.Any(d =&gt; d.SomeGuid == someGuid))); </code></pre> <p>END UPDATE.</p> <p>What pattern or practice could be applied to make this solution easier and prevent copy-pasting expression to each query? I'll appreciate your answers and advices.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload