In the part where the requirements were listed there was another set that defines some business rules applied to the set of entities that are accessible to a user. Remember, Sales Representatives can edit only their own Order instances, while Sales Managers can edit both their own orders as well as orders of stuff from their Sales Department and so on.
Let me recall the matrix:
So, we should have an option to restrict the set of Customers and Orders visible for Sales Representative & Sales Manager roles. These requirements are more like full-fledged business rules applied to the entire set of Customers & Orders than just a security issue, thus they rarely can be implemented in terms of ACL model.
Having Permission<T> class we can add there a property that will hold an IQueryable<T> object that will be used to describe the entire set of entities of type T that is accessible to a role that contains the permission.
Here is the definition of the Permission<T> class:
public class Permission<T> : Permission where T : class, IEntity { public Func<SecurityContext, IQueryable<T>> Query { get; protected set; } ... public Permission(bool canWrite) : base(typeof(T), canWrite) { // If not set explicitly, all entities are accessible by default Query = context => context.Session.Query.All<T>(); } public Permission(bool canWrite, Func<SecurityContext, IQueryable<T>> query) : base(typeof(T), canWrite) { Query = query; } }
Having such an option, we can use it to explicitly define the accessibility-related business rules. Let's start with Sale Representative. This role restricts access to Order entities to those that are created by particular sales representative. So we have to define a rule that will build an IQueryable<Order> and register it properly. Here is how:
public class SalesRepresentativeRole : EmployeeRole { private static IQueryable<Order> GetOrdersQuery(SecurityContext context) { // Sales representative role has access to its own orders only return context.Session.Query.All<Order>() .Where(o => o.Employee == context.User); } public SalesRepresentativeRole() { RegisterPermission(new OrderPermission(canWrite:true, canApprove:false, GetOrdersQuery)); } }
I won't focus on SecurityContext for now, The only thing that we should know about it is that it contains a Session and a User.
Note that we use Func<SecurityContext, IQueryable<T>> because we need to dynamically resolve the IQueryable<T> depending on the security context, currently active session, etc.
Using the same technique we can define restrictions for Sales Manager role:
public class SalesManagerRole : SalesRepresentativeRole { private static IQueryable<Order> GetOrdersQuery(SecurityContext context) { // Sales manager role has access to its own orders as well as to orders of his department return context.Session.Query.All<Order>() .Where( o => o.Employee == context.User || o.Employee.In( context.Session.Query.All<Employee>().Where(e => e.ReportsTo == context.User))); } public SalesManagerRole() { // Sales manager can do sale orders approval, in addition RegisterPermission(new OrderPermission(canWrite:true, canApprove:true, GetOrdersQuery)); } }
Note that actually we don't need ACLs or something artificial for defining the restrictions. Imagine a database with thousands and billions of entities and every single one must have one or more records that store entity's owner & all users that should have access to it. That's not an option. Pure business objects from the domain model and their relationships are enough for business rules of almost arbitrary complexity.
Now let's define business rules for Sales Representative & Sales Manager roles for accessing Customer objects. There is a rule that says that both of them should deal only with those customers that are from their local region. In this sample there are 2 sales departments, one is located in London, another is in Seattle. Thus, I split all customers into 2 groups: customers from the Old World & customers from the New World. The first group is served by the London sales department, the second one is by the Seattle one.
To simplify things I added a helper class that contains 2 groups of countries:
public static class WellKnown { public static IList<string> NewWorldCountries; public static IList<string> OldWorldCountries; static WellKnown() { NewWorldCountries = new List<string>() { "Argentina", "Australia", "Brazil", "Canada", "Mexico", "USA", "Venezuela" }; OldWorldCountries = new List<string>() { "Austria", "Belgium", "Denmark", "Finland", "France", "Germany", "Ireland", "Italy", "Japan", "Netherlands", "Norway", "Poland", "Portugal", "Singapore", "Spain", "Sweden", "Switzerland", "UK" }; } }
Having that done, I can describe the customers-related business rule as follow:
public class SalesRepresentativeRole : EmployeeRole { private static IQueryable<Customer> GetCustomersQuery(SecurityContext context) { // Sales representative role has access to local customers only var employee = (Employee)context.User; if (employee.Address.Country.In(WellKnown.NewWorldCountries)) return context.Session.Query.All<Customer>() .Where(c => c.Address.Country.In(WellKnown.NewWorldCountries)); else return context.Session.Query.All<Customer>() .Where(c => c.Address.Country.In(WellKnown.OldWorldCountries)); } public SalesRepresentativeRole() { // Sales representative can see and edit customers RegisterPermission(new Permission<Customer>(canWrite:true, GetCustomersQuery)); } }
Is't that good? As the role structure is hierarchical, this business rule is automatically inherited by all descendants of Sale Representative role, if not overridden. This means that there is no need to duplicate it in Sales Manager role. However, as Sales President role shouldn't have such a restriction we properly override that permission:
public class SalesPresidentRole : SalesManagerRole { public SalesPresidentRole() { // Overriding the inherited permission with restriction, so this role will have access to all customers RegisterPermission(new Permission<Customer>()); ... } }
That's all for today. In the next part I'll describe the SecurityContext class and related stuff in details.
Big note for all:
The security concept I'm talking about is a prototype. Its purpose is to find out the better way to implement the security in DataObjects.Net. The only way I can see this can be done right is to criticize & discuss the thing before it is implemented and released. I know that the most of DataObjects.Net users are mature and experienced developers that have numerous properly built applications that have their own security systems. Therefore, I'm hoping that it will be better to join our efforts and make the security system that will perfectly fit our needs.
For now, I would like to specially thank Vlad Klekovkin for his critics of the prototype. Vlad also shared a concept of his own security system built on top of DataObjects.Net.
Thanks a lot, Vlad!
For now what this prototype has, is enough for me. Maybe when it will go to some "alpha" testing of it, it will shows some fails of it (hope not). Good work as always :-)
ReplyDeleteThanks, Peter.
ReplyDeleteA corresponding sample is being developed to play with the security concept.
Good work Dmitri! This style of security is very new to me and it will be nice to run it.
ReplyDeleteI like to develop with extensibility in mind and i can see this approach fitting into a dynamic discovery model.
:)
Thanks, Malisa!
ReplyDeleteThe extensibility is one of the important things that should be taken into account while developing such models. That is why I'm asking for critics and ready to discuss any alternative approache.
Very nice! This will fit in our needs. Do you also support the concept of completely disabling the security system?
ReplyDeleteThanks, Marco!
ReplyDeleteYes, I'm going to write about this a bit later, may be in the next post where the SecurityContext notion will be introduced.
And maybe some "ImpersonateAs..." as we does in our security system. Where we can in some situation impersonate as "System" or another "user" (this user is defined by some "token").
ReplyDeleteGood suggestion Peter!
ReplyDeleteDmitri: What do you think about such "impersonations" ?
ReplyDeleteImpersonation itself is a quite useful concept. However, it has sense in inflexible and restrictive security models mostly. I'm hoping to avoid such a special operation as "impersonation" in DataObjects.Net security. Let's see.
ReplyDeleteOk, maybe such "impersonation" can be done as 3rd party solution :-)
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteAny progress on the implementation?
ReplyDeleteHello Marco,
ReplyDeleteRight now the team is focused on the Firebird & MySQL providers. Both of them will be included into the 4.5 Beta 1 and I'm hoping to publish the beta this week. After having this done, we will switch back to the security.
I was at a party in SF that had free estimate First Security Service protection, I felt much more comfortable having them there. I'm definitely going to use them next time I throw an event at our office!
ReplyDeleteWaooow!!! Magnificent blogs, this is what I wanted to search. Thanks buddykaty landscapers
ReplyDeleteKeep it up!! You have done the nice job having provided the latest information.divorce lawyers houston tx
ReplyDeleteWell, it’s a nice one, I have been looking for. Thanks for sharing such informative stuff.Lender
ReplyDeleteNobody can reject the info you have given in the blogs, this is actually a great work.
ReplyDeleteBank
Your way to enlighten everything on this blog is actually pleasant, everyone manage to efficiently be familiar with it, Thanks a great deal.
ReplyDelete55printing
This is one of the most important blogs that I have seen, keep it up!
ReplyDeletetop lawyers
Well, it’s a nice one, I have been looking for. Thanks for sharing such informative stuff.
ReplyDeleteloans for bad credit with monthly payments
I will prefer this blog because it has much more informative stuff.
ReplyDeletecambridge digital marketing agency
What Is A Proxy? And the Use
ReplyDeleteMyBlogger Club
Guest Posting Site
Best Guest Blogging Site
Guest Blogger
Guest Blogging Site
Awesome blog with detail Information. Thank you for sharing such a nice blog.
ReplyDeletestop avast servicet
cancel avg subscription
canon support code b203
my mail app keeps crashing
rdk 03003
how to fix error 550 email
aol mail download for pc
mcafee renew
roadrunner webmail problems
sonar protection
Wow, thanks to share this informative blog.
ReplyDeleteHOW TO CREATE ETSY & FACEBOOK BANNERS USING FOTOR FOR FREE
Boarding School in Dehradun
ReplyDeletebest Residential School in Dehradun
Boarding schools for girls in India
Best Boarding School in India
best boarding school for girls in India
B.Tech College in Dehradun
Private College in Dehradun
9 Career advantages to Do an MBA Degree
dehradun Engineering College
Best College in Dehradun
as well as an ongoing investment commitment. For most people, that ongoing commitment is a full 360 months long - a long time! TwentyMilliseconds.com loans
ReplyDeleteAwesome post. Thanks for sharing.
ReplyDelete5 Ways to Optimize Your Rankings
emberjs
ReplyDeleteinsidesalescareers
theartcareerproject
adtechdaily
ethereumworldnews
Nice Blog. Thanks for sharing with us. Such amzing information.
ReplyDelete3 Essential Tips For a Startup
Interpages
Guest Blogger
Guest Blogging Site
Guest Posting Site
Guest Blogging Website
trepup
ReplyDeletep-tweets
vbscan
caliberforums
tinhte
vbscan
ReplyDeleteinstagram
caliberforums
tinhte
unitymix
Really Awesome post. I like this post.
ReplyDeleteGuest Blogging for Your Business
choralnet
ReplyDeletehyperspaces
chevereto
gameworld
imfl.sci
Very nice article.
ReplyDeleteTips to Keep your Kids Safe Online
Really great, I appreciate your work.
ReplyDeleteHow Local SEO Help Your Business
getmonero
ReplyDeletemaisoncarlos
cyprus
linktr
coffeejobs
gamedevmarket
peeranswer
minecraftcommand
ivrpa
participez
radiocut
ReplyDeletecouponness
sydt
esljobslounge
lostwolverhampton
politjobs
ReplyDeletebikemap
tribe
waffle360
coders
I found such huge numbers of intriguing stuff with regards to your blog particularly its dialog. Extremely its incredible article. Keep it up. creating a business plan
ReplyDeleteThis post is really astounding one! I was delighted to read this, very much useful. Many thanks Feel free to visit my website. bed bugs
ReplyDelete