- Home
- LLBLGen Pro
- Architecture
Architecture for authorization and/or auditing
Joined: 15-Oct-2004
An architecture I have been banging in my head for the last two days is one modeled after LLBL's validation. LLBL's documentation categories validation into 3 types; Field, Entity and multiEntity. It seemed that Authorization can also be categoriezed into the same 3 categories. Where applying the latter two seems natural at the BL layer, the problem arizes in implementing the field security.
Steeling a page from LLBL's design, I thought of doing the following:
1- Define IAuthorizer/AuthorizerBase classes that exposes OnBeforePropertySet/OnBeforePropertyGet/OnBeforeSave/OnBeforeDelete
2- Add an (Authorizer) property to each entity (by using the CommonBaseClass template)
3- Extend the adapter class in my BL to override the Save/Delete entities actions and inspect if the entity in question has an IAuthorizer property and accordingly call its appropiate Onxx method.
This architecure can also be applied for Auditing where an entity can have an (Auditor) property. The real problem with this architecture is the place to house the IAuthorizer/AuthorizerBase classes which I only found 2 possibilities:
1- LLBL's support lib DLL which is something I always make a point to avoid (unless FRANS decides to give us some sort of hooks to inject our logic in a call-back approach)
2- In the BL, Extend each DAL entity class that requires the Authorizer/Auditor property(s) to add the property(s) in each entity and then define the IAuthorizer/AuthorizerBase classes in the BL assembly itself. I find extending 100 DAL entities in the BL to be an over-kill and hope to find a better approach.
I see this architecture (modeled after LLBL's validation) as felxible and natural. I just wish I can resolve the issue of where to find a home for the IAuthorizer/AuthorizerBase classes in a pracical way.
Joined: 14-Jul-2006
I'm also thinking about the problem of Authorization validation, and Entity modification audit; in near future we will need this functionality on our project I also think I can use CommonBaseClass template to get these functionality, but for the moment I have not tried this template.
I'm not sure I understand the problem...
If the question is "where to check for field get/set" maybe you can override GetCurrentFieldValue/SetNewFieldValue in CommonBaseClass, so that if there is an instance of IAuthorizer, this instanbce can validate the access to each single field.
Another problem can be how to instantiate the proper IAuthorizer for each entity. For this maybe that you can create an object (in the LLBLGen generated library) with a shared property that point to a IAuthorizerFactory. Now in the CommonBaseClass you can add code to istantiate the IAuthorizer.
Joined: 15-Oct-2004
Max wrote:
If the question is "where to check for field get/set" maybe you can override GetCurrentFieldValue/SetNewFieldValue in CommonBaseClass, so that if there is an instance of IAuthorizer, this instanbce can validate the access to each single field.
I did not know that CommonBaseClass exposes GetCurrentFieldValue/SetNewFieldValue. If these two methods are fired BEFORE the fact then indeed property authorization can be checked in these two methods.
Max wrote:
Another problem can be how to instantiate the proper IAuthorizer for each entity. For this maybe that you can create an object (in the LLBLGen generated library) with a shared property that point to a IAuthorizerFactory. Now in the CommonBaseClass you can add code to instantiate the IAuthorizer.
Well.. I am looking at it from the same view point as the VALIDATION architecture in LLBL2.0. The UI developer can choose to instantiate (or ignore) an instance of the entity's validation class and assign it to the entity's Validaotr property. Whatever the case is, when the entity is passed back to the BL; the BL would check that the entity has a proper validator property and issue a VALIDATE call on the entity.
In similar fashion the UI developer can choose to instantiate an instance of the entity's Authorizer class (or ignore to do so). When the entity is passed back to the BL, the BL must check if the entity has a proper AUTHORIZER property and call the AUTHORIZE method on the entity.
The nice thing about this model is that though it is flexible it does NOT sacrifice data integrity and/or security becuase the BL should never trust that the UI in that perspictive.
Jessynoo wrote:
I guess partial classes may give you a help there, or you may play with templates and the two classes adapter scenario.
I usually look at the DAL and BL layers as two distinct and separate layers. The problem with injecting logic into the partial classes of entities is it would scatter some of the BL's logic into the DAL layer. Thats why though LLBL2.0 offers two alternatives for validation; I always prefer to use a validator class in the BL than putting the validation logic in an entity's partial class.
This works in tandem with the miss-trust relation between the UI and BL. As long as the BL ALWAYS does its job of validating and/or authorizing we are always assured data validity.
Joined: 14-Jul-2006
omar wrote:
Max wrote:
If the question is "where to check for field get/set" maybe you can override GetCurrentFieldValue/SetNewFieldValue in CommonBaseClass, so that if there is an instance of IAuthorizer, this instanbce can validate the access to each single field.
I did not know that CommonBaseClass exposes GetCurrentFieldValue/SetNewFieldValue. If these two methods are fired BEFORE the fact then indeed property authorization can be checked in these two methods.
I didn't tried the CommonBaseClass, but from my understanding: CommonBaseClass inherits from EntityBase2 and YourEntityClass inherits from CommonBaseClass
If this is true, EntityBase2 expose Public Overridable Function SetNewFieldValue(ByVal fieldIndex As Integer, ByVal value As Object) As Boolean
so you can override this property in CommonBaseClass.
But looking at EntityBase2 , I see that GetCurrentFieldValue is not overridable
Max
Joined: 15-Oct-2004
Indeed, LLBL's DLL has an overridable (PreProcessValueToSet) that is perfectly suited for checking a proprty's authorization security BEFORE the fact. My problem is that LLBL's DLL does not expose an overridable (PreProcessValueToGet).
I hope FRANS conisders adding a no-op method in LLBL's DLL for the PreGET as he did for the PreSET...
how about it FRANS, any chance of doing that???
Joined: 17-Aug-2003
The preprocess method for setters is to allow a preprocessing right before the value is set, some scenario's require that.
I haven't followed the complete thread, but the core request is to have some sort of tap-in code for field access?
Joined: 14-Jul-2006
Otis wrote:
The preprocess method for setters is to allow a preprocessing right before the value is set, some scenario's require that.
I haven't followed the complete thread, but the core request is to have some sort of tap-in code for field access?
A similar feature will be very useful in our project. In short time we will need to add low-level field access control.
Each user can have different access authorization, so *) User A can view and edit all fields *) User B can view all fields, but can only edit some fields *) User C can only view some fields
The access right of each user are of different type: *) Business Procedure authorization *) Table (entity) global authorization *) Single field authorization
The user's authorization are loaded once at program start, so our LLBLGen Entity can check if the current user has the required authorization to do the stuff it's trying to do.
If the user doesn’t have access to the "Password" column, no matter what it can do in the application... even if the application has some bug the user will never be able to view/edit the password column.
Thanks, Max
Joined: 15-Jul-2005
Max wrote:
If the user doesn’t have access to the "Password" column, no matter what it can do in the application... even if the application has some bug the user will never be able to view/edit the password column.
This is a thorny issue. To play devils advocate - if you are trying to prevent unauthorized access to data, and you feel that the risks associated with applying this logic only in the UI are inadequate, then I could argue the best place for "backup" security is at the database itself. i.e. In the case that there is a bug in the UI or its security is compromised somehow, wouldn't you want to put that kind of security in the database? e.g. create views for different user groups, or some other column-level security scheme.
Joined: 15-Oct-2004
Otis wrote:
The preprocess method for setters is to allow a preprocessing right before the value is set, some scenario's require that.
I haven't followed the complete thread, but the core request is to have some sort of tap-in code for field access?
Yes FRANS. What the others and myself are asking for a tap-in code (BEFORE the fact) for the fields access just as the PreProcessValueToSet() is called inside LLBL before the value is SET
Also, I would appreciate if you at least read the frist post in this thread and tell me what you think about what I am proposing for the Authorization/Auditing architecture modeled after LLBL's Validation architecture??
Joined: 14-Jul-2006
Chester wrote:
Max wrote:
If the user doesn’t have access to the "Password" column, no matter what it can do in the application... even if the application has some bug the user will never be able to view/edit the password column.
This is a thorny issue. To play devils advocate - if you are trying to prevent unauthorized access to data, and you feel that the risks associated with applying this logic only in the UI are inadequate, then I could argue the best place for "backup" security is at the database itself. i.e. In the case that there is a bug in the UI or its security is compromised somehow, wouldn't you want to put that kind of security in the database? e.g. create views for different user groups, or some other column-level security scheme.
This is hard, because we need to support 2 database, SQL Server (for big customers) and Access (little customers). Access is limited about security managemente, ad is different and less manegable respect to sql server. So we are tring to maintain the minimum possible complexity on the DB level, and put the majority of check and validation on the Software-DAL level (LLBLGen Poweres ) that will run on any DB. So we will have a DB that describe the access authorization of users, this DB can be access or sql server, ora any other db, no matter... our software will run fine on any db with the same access authorization logic and granularity.
Joined: 14-Jul-2006
Otis wrote:
Ok, so tap-in code for field access so you can cancel / deny field access?
I could add that, however what about: int value = (int)myEntity.Fields[index].CurrentValue;
?
mmmh.... I see that CurrentValue use
Public Function get_CurrentValue() As Object
Return Me._currentValue
End Function
adding tap-in code here my slow down things when not needed... Maybe that the tap-in code can be generated by an optional template?
The result code can be something like:
Public Function get_CurrentValue() As Object
if ContainingEntity.Authorizer isnot nothing then
if ContainingEntity.Authorizer.ReadField(me.fieldIndex) then
Return Me._currentValue
else
throw new exception("Field access not allowed")
endif
else
Return Me._currentValue
endif
End Function
But looking at the EntityField2 class, I was not able to find some reference to the containig entity... so I don't know if this approach is possible.
I'm also thinking about the dynamiclist/typedlist: a similar approach probably will not deny access to the data trough dynamic/typed list.
I'm not sure that this is the right aproach to the problem...
Max
Joined: 26-Jul-2006
We had to solve this problem too. While it is not even remotely the cleanest approach, I implemented it in the BL through a custom template that generates my foundation for the BL. Our security model is extremely granular as others indicated. While what I have works, it is not really an OO implementation.
I really like the idea in the first post. I could see that an IAuthorizer class that was tied into everything that happens to an Entity (inc. prop gets/sets) and could check against the Authorizer asking if it can do the requested action would be just...awesome. We/I simply did not have time to look deeper into that clean of an implementation.
Ironically, now that the BL security model is in place and working, the amount of time developing the BL template for that and the highly granular generic security classes probablly would have been enough to just tie into the DAL in the first place as is suggested.
I'd like to hear more if you get something elegant in place.
Joined: 17-Aug-2003
What Max illustrates is also what I ran into when I thought about adding something like this in the development phase of v2.0: it's simply easy to circumvent it. But it's also easy to do that no matter what through reflection of course.
I think there are two different types of security: 1) protect the data against shortcuts taken by dumb developers (so code has to be secure so it's protected against the developer who uses it) 2) make sure the code doesn't contain bugs so users can accidently set/get fields they're not supposed to set/get
ad. 1: I think this is a thing which can't be achieved, you can always find a way to set/write/get data from an object. Either by reflection or by other means. If you don't trust your developers, you might consider firing them.
ad. 2: This is the situation which might need extra 'set and forget' code or at least hooks which allow you to add code which is triggered when such a situation occurs.
The topic is about authorization AND auditing, however these aren't the same. Authorization is BEFORE the act and auditing is AFTER the act. Authorization is active, auditing is passive.
For auditing, we have already the eventhandlers and On.. methods in place which are called at various times during the entity lifecycle. As these are called after the act, it's not really something useful to use for authorization which has to be able to deny access.
There's still a problem though. If the developer does some things like setting the Fields property to a new set of fields, overwriting a field object on a given index, writing CurrentValue via reflection etc., is that really something that should be trapped by this code? I think that's not even possible. However BECAUSE it's not done, would it make the other code insecure? I'm not sure... The thing is that I'm not convinced that security checks on data should be done INSIDE the entity, as it then also has to know the ACL's for access. So it should signal outside code that something happend and outside code should then report back (by the Cancel property of the event args) if the entity code should proceed or not.
Joined: 15-Oct-2004
Otis wrote:
The topic is about authorization AND auditing, however these aren't the same. Authorization is BEFORE the act and auditing is AFTER the act. Authorization is active, auditing is passive.
For auditing, we have already the eventhandlers and On.. methods in place which are called at various times during the entity lifecycle. As these are called after the act, it's not really something useful to use for authorization which has to be able to deny access.
I agree with AUDITING handled by the various entity events and I see that as an easier way to audit concerned entities.
The "property authorization" issue as you explained is an active process that needs to react to SET/GET inside each property. Since such authorization rules are just like business rules, they are meant to assure data-integrity and assist the UI with adhering to these rules. Writing security in a way that miss-trusts the developer is counter-effective because among other things Reflection is the master key for all .NET assemblies!!
Still, it would be nice if a property's authorization logic is checked irrespective of how the property is SET/GET (through an Entity's property or through an Entity's Fields items). That said, I would be very happy to have my code to only tap the fields' SET/GET.
Otis wrote:
The thing is that I'm not convinced that security checks on data should be done INSIDE the entity, as it then also has to know the ACL's for access. So it should signal outside code that something happened and outside code should then report back (by the Cancel property of the event args) if the entity code should proceed or not.
That's why I wanted an architecture similar to the VALIDATOR architecture. An entity can optionally have an AUTHORIZER property. LLBL's logic for SET/GET can check for the authorizer's AuthorizeGetField method and cancels the GET if the method returns a FALSE (just like the ValidateField in the Validator Class).
Joined: 15-Oct-2004
Otis wrote:
Ok, so tap-in code for field access so you can cancel / deny field access?
I could add that, however what about: int value = (int)myEntity.Fields[index].CurrentValue;
?
If the EntityFields2 class had a reference to its containing entity, then the EntityFields2.Item(index) SET/GET could call into the containing entity's AUTHORIZER.AuthorizeFieldSET/GET. The same AUTHORIZER call also can be made in each entity's property SET/GET...
Joined: 17-Aug-2003
A reference back from the fields to the entity is a bit of a problem, as the fields object has to be usable as a DTO, and once set to an entity it will drag along that entity as well, which isn't what I want.
Properties get/set code always calls into entity methods, so it should be possible to add methods to that which raise events or call into On... methods and which are cancelable.
Joined: 14-Jul-2006
Otis wrote:
A reference back from the fields to the entity is a bit of a problem, as the fields object has to be usable as a DTO, and once set to an entity it will drag along that entity as well, which isn't what I want.
What's a DTO?
Otis wrote:
Properties get/set code always calls into entity methods, so it should be possible to add methods to that which raise events or call into On... methods and which are cancelable.
Thinking on the IAuthorizer object, we can have IAuthorizer.OnBeforeFieldGet(FieldIndex as integer, Cancel as boolean) IAuthorizer.OnBeforeFieldSet(FieldIndex as integer, Cancel as boolean)
maybe even (but this seem more an IAuditing interface that an IAuthirizer ) IAuthorizer.OnAfterFieldGet(FieldIndex as integer) IAuthorizer.OnAfterFieldSet(FieldIndex as integer)
and the entity can call the IAuthorizer in GetCurrentFieldValue(ByVal fieldIndex As Integer) SetNewFieldValue(ByVal fieldIndex As Integer, ByVal value As Object, ByVal fireChangeEvent As Boolean)
This works for field access trough Entity method. But will not work for Entity.Fields("MySeecretField").CurrentValue Will not work because field don't have a reference to the entity, so they can't get a reference to the IAuthorizer instance. Maybe that the field object can hold a reference to the IAuthorizer object? This way even the field can call the IAuthorizer method on get/set of CurrentValue and DbValue property.
But: If we can monitor field access of type Entity.Fields("MySeecretField").CurrentValue thanks to the reference to IAuthorizer in the field object; how can we monitor data access in Typedlist/Dynamiclist? maybe we didn't have the entity, so we need to directly create field, and set the field.IAuthorizer to the proper IAuthorizer instance?
Thanks, Max
Joined: 15-Oct-2004
Max wrote:
Otis wrote:
A reference back from the fields to the entity is a bit of a problem, as the fields object has to be usable as a DTO, and once set to an entity it will drag along that entity as well, which isn't what I want.
What's a DTO?
DTO => Data Transfer Objects. The concept is to have objects that are designed to be data reservoirs and be transferred between the different tiers of the system.
Otis wrote:
Properties get/set code always calls into entity methods, so it should be possible to add methods to that which raise events or call into On... methods and which are cancelable.
Max wrote:
Thinking on the IAuthorizer object, we can have IAuthorizer.OnBeforeFieldGet(FieldIndex as integer, Cancel as boolean) IAuthorizer.OnBeforeFieldSet(FieldIndex as integer, Cancel as boolean)
I defined those two methods in my IAuthorize interface as follows:
Sub AuthorizeSetField(involvedEntity As IEntityCore, fieldIndex As Integer, Cancel as boolean)
Sub AuthorizeGetField(involvedEntity As IEntityCore, fieldIndex As Integer, Cancel as boolean)
Max wrote:
maybe even (but this seem more an IAuditing interface that an IAuthirizer ) IAuthorizer.OnAfterFieldGet(FieldIndex as integer) IAuthorizer.OnAfterFieldSet(FieldIndex as integer)
I am more inclined to FRANS's view on that Auditing is a passive action that can be handled in the different events raised by the entity.
Max wrote:
and the entity can call the IAuthorizer in GetCurrentFieldValue(ByVal fieldIndex As Integer) SetNewFieldValue(ByVal fieldIndex As Integer, ByVal value As Object, ByVal fireChangeEvent As Boolean)
As long as those calls are done before the fact, then this should work fine...
Max wrote:
This works for field access trough Entity method. But will not work for Entity.Fields("MySeecretField").CurrentValue Will not work because field don't have a reference to the entity, so they can't get a reference to the IAuthorizer instance. Maybe that the field object can hold a reference to the IAuthorizer object?
This way even the field can call the IAuthorizer method on get/set of CurrentValue and DbValue property.
But: If we can monitor field access of type Entity.Fields("MySeecretField").CurrentValue thanks to the reference to IAuthorizer in the field object; how can we monitor data access in Typedlist/Dynamiclist? maybe we didn't have the entity, so we need to directly create field, and set the field.IAuthorizer to the proper IAuthorizer instance?
Thanks, Max
If I understand you right, you are suggesting to have the FIELD object itself have a reference for the IAUTHORIZE object. This seems to solve the problem nicely but I hope it does not have side-effects that prohibit its use (like we had with the fields getting a reference for the containing entity)