Architecture for authorization and/or auditing

Posts   
 
    
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 04-Sep-2006 14:34:00   

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.

Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 04-Sep-2006 16:02:14   

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 simple_smile 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.

Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 04-Sep-2006 16:06:00   

Hi,

I guess partial classes may give you a help there, or you may play with templates and the two classes adapter scenario.

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 05-Sep-2006 13:01:05   

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.

Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 05-Sep-2006 14:30:26   

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 disappointed

Max

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 05-Sep-2006 15:08:20   

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???flushed

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 06-Sep-2006 15:39:19   

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?

Frans Bouma | Lead developer LLBLGen Pro
Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 08-Sep-2006 15:36:06   

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

Chester
Support Team
Posts: 223
Joined: 15-Jul-2005
# Posted on: 10-Sep-2006 00:07:35   

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.

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 10-Sep-2006 13:20:09   

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??

Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 11-Sep-2006 09:33:46   

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 sunglasses ) 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.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 11-Sep-2006 10:15:27   

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;

?

Frans Bouma | Lead developer LLBLGen Pro
Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 11-Sep-2006 12:13:08   

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... disappointed 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. disappointed

I'm not sure that this is the right aproach to the problem...

Max

MatthewM
User
Posts: 78
Joined: 26-Jul-2006
# Posted on: 11-Sep-2006 22:03:44   

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.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 12-Sep-2006 10:47:56   

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.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 12-Sep-2006 15:34:01   

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).

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 13-Sep-2006 08:12:34   

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...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 13-Sep-2006 10:42:52   

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.

Frans Bouma | Lead developer LLBLGen Pro
Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 13-Sep-2006 12:53:16   

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 simple_smile ) 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

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 14-Sep-2006 09:12:49   

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 simple_smile ) 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)

Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 22-Sep-2006 09:55:49   

Otis, will some feature like IAuthorize/Field_level_access_control be implemented in LLBLGen future release?

Thanks, Max

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 22-Sep-2006 11:41:24   

It's on the todolist, but many points are on the todo list, so it's not decided yet which version will get this feature.

Frans Bouma | Lead developer LLBLGen Pro
Max avatar
Max
User
Posts: 221
Joined: 14-Jul-2006
# Posted on: 22-Sep-2006 11:55:06   

Otis wrote:

It's on the todolist, but many points are on the todo list, so it's not decided yet which version will get this feature.

Thanks.