Support for "Built-In" objects

Support for "Built-In" objects

Old forum URL: forums.lhotka.net/forums/t/834.aspx


SonOfPirate posted on Monday, August 07, 2006

I am throwing this out there in the hopes of getting some feedback with ideas/suggestions on how best to implement, enforce and protect some "built-in" objects in our framework.

For an example, we want to build-in an "Administrators" group/role into our framework so that it will always be available for every application and cannot be modified by users when configuring security on an application basis.  In other words, we can guarantee that this role has the access we want, etc.  We will also have a built-in "Administrator" user that is a member of this role where we can control the password so that we are guaranteed access for support concerns.  This is all analagous to what Windows does.

The question is how to best implement this into the framework?

Our initial stab at this was to create an AdministratorsGroup object that inherits our Group class and hard-defines the appropriate property values.  It also marks itself as read-only.  We have a SecurityManager (pseudo-factory) class that exposes the application's users and groups through its Users and Groups static properties (respectively). When the GroupCollection class initializes, we add a new instance of the AdministratorsGroup to the collection.

That works great but then we had to start dealing with all of the operations that can be done with the collection: Add, Clear, Insert, Remove, etc. this has become daunting as we have to override just about every property and method in our collection to prevent users from changing them or removing them or adding a new object with the same name, etc.  Plus, if the app is data-driven and we allow the client application to assign new users to this group, how do we enforce a foreign key relationship to an object that exists only in code?

See where I'm going with this?

Any thoughts on how to accomplish what we are after?

We've already done a similar thing in a couple of other areas of our framework but in those cases we are not dealing with data-driven objects and we allow the applications to remove the built-in objects if we want to override the behavior.  Plus, those objects are not user (on-the-fly) configurable as our security model is.

Your ideas/suggestions are appreciated.

RockfordLhotka replied on Monday, August 07, 2006

Maybe you could just have a BuiltIn column in your roles table in the database. If this is true, then any object loaded based on that data would set itself to read-only, and would refuse to delete the data, etc?

During app install you'd have a special program that runs to pre-initialize the data table with your built-in roles, but only that special program would ever set the BuiltIn flag to true, so no other roles would ever have that flag.

SonOfPirate replied on Monday, August 07, 2006

I'd thought of the idea of having the built-in objects always marked as New so that they would always be added to the database if they didn't exist when changes were applied.  We already have logic in our sprocs to pre-check for the existance of the primary key field (Guid) when we attempt to insert an object and defer to an Update if it already exists.  So, the combination of these two things would address the foreign key issue.  But...

The reason we want to build these object into the framework is because we can't trust the database as the 'source' for the objects.  We develop many applications that are deployed on remote/client networks that are vulnerable to the prying hands of...well, whomever is allowed accesses to their systems.  Because of this, we have to account for the fact that there is no guarantee that changes to the application's data were made through the application's interface.  So, if we only pre-initialize the data on install, and later someone who didn't know any better was 'cleaning house' or something and deleted our objects from the database, we would need some way of restoring those objects.  Which, the above method does allow us to do - but only if an object is changed and applied to the database.

We have about a dozen different thoughts flying around on this end covering a range of "what ifs" and "how tos".  I'm hoping that someone may have crossed this before and can share their approach to help me sort through these ideas.

The big issues as I see them are:

1. Making it so the objects can't be altered through application code (either modified or removed) and duplicates cannot be created by client code.  So far, the best approach we've have is to override all of the methods in our base collection to block such functions from occurring.  Total pain in the...

2. Addressing the data storage concerns where the object is automatically created in the database if missing so that foreign key references are valid.  Then there's the added twist that once it's in the database, we have to block the data access methods from creating the object out of the database and to use the coded instance.  This is because the hard-coded object is 'golden' whereas the database version could have been modified by someone playing with Query Analyzer or Enterprise Manager (for instance).

At the core of our logic is that our compiled code, the framework, is secure and not vulnerable to intentional or inadvertant changes whereas our data store, whatever that may be, is open, accessible and subject to changes outside of our control.  When designing our applications, we always lead with the assumption that the database is an unstable and unreliable source and equip our types with fail-safe measures to account for that.  This is part of that process.  Our goal, in this portion, is to ensure a reliable way for users and our support personnel to gain access and control of the application even when undesirable changes have been made to the database (like someone blowing away the Users table!).

One line of thought (that I don't prefer) is to eliminate enforcement of the foreign key constraints in the database so that these objects never have to exist in the database.  That would eliminate the data access issues but, as I said, I don't like this idea because FK constraints are a powerful tool to enforce data integrity.  So, that brings me back to trying to figure out a happy medium that does what we want without having to make unwanted sacrifices in the exchange.

Hopefully that puts things in a little more perspective.  I appreciate the feedback.

ajj3085 replied on Monday, August 07, 2006

SonOfPirate:
We develop many applications that are deployed on remote/client networks that are vulnerable to the prying hands of...well, whomever is allowed accesses to their systems.  Because of this, we have to account for the fact that there is no guarantee that changes to the application's data were made through the application's interface.


If this is the case, then there's not a whole lot you can do about this problem.  Once people access and change your database from outside your application, you really don't have any control over that anymore.  I would say don't worry about it.  If someone pokes into the database, and a role which your application assumes to be there isn't, have the application throw an exception when it tries to find your role / user.

Make it clear to your clients that they aren't to modify the data outside of your system, and if they do and something breaks, you'll be happy to help them, but only for a fee.  Alternately, let them know which rows of data they shouldn't modify, if they feel they must modify some data.

Andy


Jurjen replied on Tuesday, August 08, 2006

SonOfPirate,

Assuming you always have access to the database, I think I would make some sort of SQL script, this script would check to see if the user(s)/role(s) used for support are in place, if not it will insert them, it could also remove any users in the Administrators group not belonging there.  You could even decide to execute this script (StoredProc) every time the app starts, making sure that any 'polution' introduced by your users is removed.

Jurjen.

SonOfPirate replied on Tuesday, August 08, 2006

Yea, it would be great if we could make demands on our customers to not touch things and it is certainly reasonable to follow a "buyer beware" approach to breakage, but this is as much for us as it is used to keep things running smoothly.  We sell commercial software and with it comes support.  A large segment of our market is manufacturing/industrial oriented and they have certain expectations about the support they receive.  In order to compete, we have to play ball by many of their rules - or at least on par with what our competitors offer.  With that comes the need to be able to address issues quickly including recovering applications from something catastrophic like someone manually messing with the contents of the database (it happens, geez, don't get me started on the crazy crap we've seen!)

As part of this, my support personnel need a reliable, guaranteed way to access the system for support tasks.  This is where the concept of a built-in user and role applies.  If we allow the client ANY opportunity to remove those items, we lock ourselves out of our own software.

We are extending this to a common set of "built-in" users and roles that we would be incorporating into every application anyway: Administrator/Administrators.  This way the customer is also guaranteed access regardless of what their personnel do to that application out on the shop floor.

Again, this is analogous to Windows, so our expectation was that there'd be more experience in this area.  The biggest difference from Windows is, of course, that the database is accessible in our case and your average Windows user isn't getting into the OS's security.

At this point, what we are considering doing is building-in a "safety check" in our data portal fetch method for our collection class that checks to see that our built-in objects are retrieved from the database with any other objects.  If they are not, the built-in objects are added to the collection, marking them as new.  Presumably, our FK constraint in the DB has made it so any changes to the records in the database have been cascaded to any referencing items, so integrity is maintained (and if they removed the FK constraint, then we won't have any problems as the reference will be restored once we re-write the record back into the table with the same uniqueidentifer).

As such, if we find the items are not in the collection retrieved from the database, we can add the built-in items back into the collection where they will be re-applied to the database with the next set of changes.  This allows us to eliminate additional classes for these objects and handle these objects within the confines of our collection class(es).

Make sense?

ajj3085 replied on Tuesday, August 08, 2006

SonOfPirate:
Yea, it would be great if we could make demands on our customers to not touch things and it is certainly reasonable to follow a "buyer beware" approach to breakage, but this is as much for us as it is used to keep things running smoothly.  We sell commercial software and with it comes support.


I certainly hear where you are coming from.  FWIW, most products exclude from warranty support if any modifications are done by the user.

SonOfPirate:
A large segment of our market is manufacturing/industrial oriented and they have certain expectations about the support they receive.  In order to compete, we have to play ball by many of their rules - or at least on par with what our competitors offer.  With that comes the need to be able to address issues quickly including recovering applications from something catastrophic like someone manually messing with the contents of the database (it happens, geez, don't get me started on the crazy crap we've seen!)


Sounds like a tough industry in which to be.  I worked at a company that built custom solutions for clients; we did encounter most of these problems with one of them.  At once point, the company decided to no longer accept business from this client.  It was tough, since it was a larger client, but they felt that's the only course of action that made sense.  In our case, it was because not only was the customer breaking things, they were expecting us to fix it for free.  In general, they were a pretty unreasonable company.

If your entire market is like that, well.. that's a problem, but not impossible to solve.  I assume you have some loyal customers.   What you need are sales people who can 'manage the customer' very well.  Bucking the trend may work for you, since your system should be more reliable (because the customer has less chance to mess it up) that your competitors.  I was suprised; our company also started pushing back against unreasonable expectations.  To my suprise, customers seemed to actually like that aspect.  We didn't just say no of course, we offered a better alternative to what they wanted to do.  I'm no longer with the company (left for some personal reasons) but from what I hear they are doing well.

SonOfPirate:
As part of this, my support personnel need a reliable, guaranteed way to access the system for support tasks.  This is where the concept of a built-in user and role applies.  If we allow the client ANY opportunity to remove those items, we lock ourselves out of our own software.

Yes, I agree you need to be able to access the application.  How do your support people get in?  Do they use a client's workstation?  Their own laptop (from your company)?  If its the latter, perhaps code can skip any authentication and grant full access if the domain is your companies (and the laptop is a 'support' laptop).  Perhaps even better, have your application look for a USB dongle of some kind, that grants admin access.

SonOfPirate:
We are extending this to a common set of "built-in" users and roles that we would be incorporating into every application anyway: Administrator/Administrators.  This way the customer is also guaranteed access regardless of what their personnel do to that application out on the shop floor.

Again, this is analogous to Windows, so our expectation was that there'd be more experience in this area.  The biggest difference from Windows is, of course, that the database is accessible in our case and your average Windows user isn't getting into the OS's security.

This is a good way to go, if you must always have certain groups.  FWIW though, Windows suffers the same problems as your application.  You can boot off a Linux Cd, change the administrator password, and unlock the account, then reboot into Windows.  This will cause windows to see a 'problem' with the filesystem, but if you tell it not to do anything, you're in.  Obviously, if you can do this, you can delete the expected accounts.  I'm not sure Windows would behave that well in that situation either.

SonOfPirate:
At this point, what we are considering doing is building-in a "safety check" in our data portal fetch method for our collection class that checks to see that our built-in objects are retrieved from the database with any other objects.  If they are not, the built-in objects are added to the collection, marking them as new.  Presumably, our FK constraint in the DB has made it so any changes to the records in the database have been cascaded to any referencing items, so integrity is maintained (and if they removed the FK constraint, then we won't have any problems as the reference will be restored once we re-write the record back into the table with the same uniqueidentifer).

As such, if we find the items are not in the collection retrieved from the database, we can add the built-in items back into the collection where they will be re-applied to the database with the next set of changes.  This allows us to eliminate additional classes for these objects and handle these objects within the confines of our collection class(es).

Probably a better idea is to build a seperate tool which connects to the db, and scans system data, with the option to fix things.  This way you can fix the problems with the database, and don't need to code anything special to get into your application.  

The only potential problem is that I'm not sure there's any guarantee that the collection will be saved (well, I suppose you could  make sure).

Just remember though, this isn't just a security problem.  Any data may be compromised at which point reports that don't check the data will give invalid results.  This is a more subtle problem, and your customers may blame you.  Even your application may behave oddly or crash, if they do something extreme like change the schema.  You have to validate data from the db, which usually is not a requirement (I would hope, anyway).

Good luck.
Andy

SonOfPirate replied on Tuesday, August 08, 2006

Andy,

I agree completely.  As I said, this effort is as much, if not more, for us than for the customers and I certainly do agree that there is a line we can and do draw in regards to support.  With mfg customers (esp. the Big-3!), there are many hands involved from a user standpoint and a system failure costs big bucks so the heat is really on you to make corrections fast.  Having a 'backdoor' for our support personnel side-steps the hassles of having to locate the person who knows the passwords or waiting for IT to come down or any of the several dozens issues we've ran into over the years.  You put a computer in front of a user and they will play, that's the rule of thumb.  So, having this 'backdoor' is more to facilitate support than anything.  Whether we are getting paid to be there or not is a whole 'nother issue!

I like the idea of the dongle.  Definitely something to look into.  My initial thought, however, is that this is an authentication tool to identify the user but that user still has to be 'mapped' to the roles and rights within the application.  So, in that regard, it isn't really any different than integrated Windows authentication.  In other words, we still need some way of indicating that user 'x' is in such-and-such role with these rights for our authorization rules to grant access.  We already have an interface under development for RF ID badges and would assume that a security fob or dongle would follow the same suit as this.  In that case we treat the user's information the same as we do with Windows (single-sign-on) authentication and consider the user authenticated but still have to determine what roles/rights that user has to the application.

BTW - we connect in a variety of ways depending on the type of access and connectivity available.  Our preferred method is via Remote Desktop connection or other remoting tool, but that is rarely an option and more times than not, it requires someone be on site (because the first thing these guys do when budgets get tight is remove as much of the networking as they can without compromising the systems).  Some of the network topologies we've had to endure are amazing!

I understand the idea of doing a system scan on startup or with a separate utility, but am trying to simplify this from a usage standpoint to a) eliminate as many phone calls as possible from customers; b) encapsulate the logic as much as possible; and, c) reduce the work for my developers.  Because these objects are built into our framework, a "recovery" utility would only be able to address framework-level components.  We would either have to extend this utility for every application to add application-specific components or develop a second utility for each.  Either way, we've just added to the development efforts required for each application.  Plus, initiating the utility would require either service intervention or a walk-through with the customer on the phone.  I'd rather have the "fail-safe" built in along with the objects so that all of this becomes transparent to my developers and users.

Obviously, this is still a work in progress, but I think we are getting closer.  Thanks for the input.  It is appreciated.

ajj3085 replied on Tuesday, August 08, 2006

SonOfPirate:
I like the idea of the dongle.  Definitely something to look into.  My initial thought, however, is that this is an authentication tool to identify the user but that user still has to be 'mapped' to the roles and rights within the application.  So, in that regard, it isn't really any different than integrated Windows authentication.  In other words, we still need some way of indicating that user 'x' is in such-and-such role with these rights for our authorization rules to grant access.  We already have an interface under development for RF ID badges and would assume that a security fob or dongle would follow the same suit as this.  In that case we treat the user's information the same as we do with Windows (single-sign-on) authentication and consider the user authenticated but still have to determine what roles/rights that user has to the application.


I was thinking along different lines with regards to the dongle idea.  The security checks in my mind would be similar to:

public bool void CanLoad() {
     IPrincipal prin;

     prin = ApplicationContext.User;

     return prin.IsInRole( "Administrators" ) || Dongle.IsPresent;
}

So you wouldn't check just the roles of the user, you'd also check if there was this dongle present.  The drawback to this method is that you'd have to remember to do this in every security check and make the change to all the existing code. 

The advantage though is that you're not relying on an untrustable source to do your authenciation when things go wrong.

SonOfPirate:
BTW - we connect in a variety of ways depending on the type of access and connectivity available.  Our preferred method is via Remote Desktop connection or other remoting tool, but that is rarely an option and more times than not, it requires someone be on site (because the first thing these guys do when budgets get tight is remove as much of the networking as they can without compromising the systems).  Some of the network topologies we've had to endure are amazing!

Hmm, the dongle approach may not work for you in this case. 

SonOfPirate:
I understand the idea of doing a system scan on startup or with a separate utility, but am trying to simplify this from a usage standpoint to a) eliminate as many phone calls as possible from customers;

You could do that by raising support costs.  Wink [;)]  Sorry, I don't have any serious advice in this regard.

SonOfPirate:
b) encapsulate the logic as much as possible;

This is certainly good.  Perhaps the best bet is to approach this as another use case.  Build objects custom to handling these problems.  Of course that doesn't help you if the problem is getting into the system.  Sad [:(]

SonOfPirate:
and, c) reduce the work for my developers.  Because these objects are built into our framework, a "recovery" utility would only be able to address framework-level components.  We would either have to extend this utility for every application to add application-specific components or develop a second utility for each. 

One approach is to have a main program, that always performs common tasks, and than can load modules based on the system chosen to work with.  These modules would be classes implementing an interface (could be as simple as an Execute method, and each class knows how to check for an fix a particular problem). 

SonOfPirate:
Either way, we've just added to the development efforts required for each application.  Plus, initiating the utility would require either service intervention or a walk-through with the customer on the phone.  I'd rather have the "fail-safe" built in along with the objects so that all of this becomes transparent to my developers and users.

Initial development time could be large; maintence hopefully much much lower as your tool matures.  I'm curious though.. it sounds like you want to enable the users to fix things themselves.  Assumnig they can get into the system, how will they know how to fix the problems?  If this needs to be documented or explained by one of your people, could you not explain / document the tool instead? 

At any rate, I hope I've thrown some ideas out there you may not have considered.. sorry I couldn't be of more help though.

I hope you'll keep us updated on your solution, if you don't mind.  I'd be curious to know what you come up with.

Andy

Copyright (c) Marimer LLC