Need some 'strategic thinking' advice on security??

Hi Folks - looking for a bit of advice on the design (redesign really) of our security structure. Currently we have:

Security tables

Master (holding client names and databases anyone from that client can attach to, and forms they have access too) This is the most open of the security tables and allows us to add new client companies and define what they can and cant do.

User (holding users and databases the particular user can attach to, also what forms they have access to and if they are editable etc.) this is linked to the Master db so even if the user has more verbose privileges they become limited by the Client privileges.

The problem with this set-up (and the reason we want to move away from it) is that in order to manage editable rights etc we have to use solution model on forms before they are touched in order to change the onLoad onShow events for the particular user. This is both slow at start-up and very messy to keep up to date. Same for the security tables - as the solution changes we need to modify the security tables.

The simple Security built into Servoy would be much easier to manage, because we can define rights to groups at design time and let Servoy take care of access right down to specific buttons etc.

However the stumbling block is that we need both a custom log-in form and also the ability to still have a Master Db with Client names.

I am not sure how we can alter the Servoy security tables (if we could we could then add master data columns - even though there will be somewhat of duplication of data - manageable).

Our solution uses separate db’s for each client but we will soon have multiple clients connecting to the same solution. If it colours your thoughts on this we will be moving to the web client as soon as we can.

Any suggestions will be gladly received.

TIA Cheers Ian

I, too, would be interested in any suggestions regarding a hybrid security system.

Servoy’s built-in security is fine for a few groups, a few basic form settings, and maybe an organization or two. And only if you don’t need a whole lot of flexibility to adjust things at runtime. Anything beyond that and you’re writing your own UI’s, code and possibly your own tables to manage things in a much more powerful and flexible way.

Servoy’s internal security tables and associated methods are there for the developer to build their own UI’s to manage things the “Servoy” way. This approach is solid and ties in with various design-time screens. Issues come into play when coordinating with your own data tables (hybrid approach) and when you need more flexibility than what Servoy gives you. For example:

Kahuna:
The simple Security built into Servoy would be much easier to manage, because we can define rights to groups at design time and let Servoy take care of access right down to specific buttons etc.

Servoy’s design-time element level security is not-so-simple anymore if your rules need to change based on what record the user is on. (IE, ‘my’ records I can edit but John Doe’s records I can only view.) And what about giving a power user run-time control?

After doing a few security schemes back in the day via Servoy’s (and hybrid) approach we finally decided to supercede Servoy’s system completely. So all our own tables: organizations, groups, users, logins, logging, etc. Then on login we push everyone through a couple of basic Servoy group and user records.

Our “strategic thinking” is groups define what people can see and do (typical). Logins are assigned to one or more groups. User tables (default supplied or from a CRM or Active Directory, etc) can be attached to our login records.

Security is in four tiers:

1- what views can be accessed (navigation).
2- what records can be accessed. filter by organization and further filter by group level rules.
3- what actions can be run. each workflow form can expose rules (via form variable object).
4- form element states. what shows up and editable or not.

1 and 2 can be managed entirely by UI (meta data). In addition to the UI component (actions registered by forms assigned to groups), 3 and 4 require code at the form level (usually onLoad and onRecordSelection events) to setup and manage state. We provide an API to make this easy. Example:

function REC_on_select() {
	
	// editing control
	if (globals.SUTRA.security.workflow.allowed('employee edit')) {
		TOGGLE_elements(true)
	}
	else {
		TOGGLE_elements(false)
	}
	
	// status field
	var superStatus = ''
	
	if (flag_status) {
		superStatus += 'INACTIVE '
	}
	
	// status label	
	elements.lbl_super_status.text = 'User: ' + globals.SUTRA.security.getUser().staff.name

}

If needed, we will pull the above code out and create a UI for that particular client module to manage form level elements at runtime. We specifically do this on a case-by-case basis instead of in our core security module because of the plethora of customizations each situation can entail.

The key to making all this work is a layout manager that can be driven by security, the concept that forms publish their access rules, an API to make coding against simple, a four tier approach to keep complexity down, and the UI screens to manage everything at runtime. I think these same concepts apply for a hybrid system – but having to hook into Servoy’s security system just makes it harder to build in my opinion.

The end result is that any application can be run by this security system. Wonder why our Sutra CMS doesn’t have security built-in? Because it is a set of modules that is meant to be plugged into this setup. Same security UI for Sutra CMS and any other modules/solutions it is working along-side. Module portability requires that security be abstracted.

None of the things you bring up are a problem for us. And we run in web client now (even provide a login widget for websites). Want to save a buttload of work? :) http://demo.data-sutra.com

Thanks for that feedback David - very instructive and it sounds very much like what we already have - but I guess we missed a point because out system is really complex and too detailed to maintain easily.

Where you mentioned handling element access in the onLoad event - are you talking about having some solution model code that changes the onLoad event before the form actually loads (that is what we are doing currently)?

So where elements or even forms need to be read-only for a certain group - we run solution model code to modify the basic onLoad code. My understanding is that after the onload is run we cant set/reset the access factors of the form or elements???

Appreciate your feedback.

Ian

Kahuna:
I guess we missed a point because out system is really complex and too detailed to maintain easily.

Success in this area depends on your UI for managing meta data and how you’ve designed the access points to other moving parts of an application. A security module is a big deal and is easy to leave parts incomplete, hacked in the fast way, cut corners here and there, etc. We even thought Servoy got their security framework wrong (not a well layered design, bad UI, tried to tackle too much, required additional programmer customization to integrate = overly complex) when we saw a webinar on it several years ago. So not an easy thing to accomplish.

Kahuna:
Where you mentioned handling element access in the onLoad event - are you talking about having some solution model code that changes the onLoad event before the form actually loads (that is what we are doing currently)?

So where elements or even forms need to be read-only for a certain group - we run solution model code to modify the basic onLoad code. My understanding is that after the onload is run we cant set/reset the access factors of the form or elements???

Solution Model is overkill. Just use a combination of element runtime properties — editable, transparency, visible, and enabled. Set these for various elements depending on privileges on the form onLoad and onRecordSelection events. The goal is to ensure a user only sees and does what they’re allowed to do on that form.

I have seen cases where developers move stuff around on a form based on logged in user and this does require Solution Model. We never do this and instead opt for designing workflows and UI’s such that we don’t have to resort to overly complex shenanigans like this. Not needed and just makes maintaining a solution a lot harder.

In your case specifically, I would submit that using Solution Model to modify onLoad code would fall into the “complex shenanigans” category if it were to get code reviewed by us… :)

Some sample code on how we set elements on onLoad and onRecordSelection events:

function TOGGLE_elements(state) {
	var formOne = 'CRM_0F_employee'
	
	var fields = [
				'fld_email',
				'fld_gender',
				'fld_job_title',
				'fld_name_first',
				'fld_name_last',
				'fld_name_middle',
				'fld_name_salutation'
			]
	
	var nonFields = [
				'fld_date_birth',
				'fld_date_hire',
				'fld_ssn',
				'fld_gender'
			]
	
	var formFour = 'CRM_0F_employee_1L_employee_contact'
	
	var fourFields = [
				'fld_email',
				'fld_relation',
				'fld_name_first',
				'fld_name_last'
			]
	
	var formFive = 'CRM_0F_employee_1F__tax'
	
	var fiveFields = [
				'fld_tax_eeo_class',
				'fld_tax_exemptions',
				'fld_tax_filing_status',
				'fld_tax_marital_status',
				'fld_tax_withholding',
				'fld_tax_work_status'
			]
	
	//turn things on if off
	if (state) {
	//form one
		for (var i = 0; i < fields.length; i++) {
			forms[formOne].elements[fields[i]].editable = true
			forms[formOne].elements[fields[i]].transparent = true
		}
		for (var i = 0; i < nonFields.length; i++) {
			forms[formOne].elements[nonFields[i]].visible = true
			forms[formOne].elements[nonFields[i] + '__noedit'].visible = false
		}
		
	//form two
		forms.CRM_0F_employee_1L_phone.elements.btn_phone_type.visible = true
		forms.CRM_0F_employee_1L_phone.elements.lbl_phone_type.enabled = true
		forms.CRM_0F_employee_1L_phone.elements.btn_primary.enabled = true
		forms.CRM_0F_employee_1L_phone.elements.fld_phone_number.visible = true
		forms.CRM_0F_employee_1L_phone.elements.fld_phone_number__noedit.visible = false
		forms.CRM_0F_employee_1L_phone.elements.btn_delete.enabled = true
		
	//form three
		forms.CRM_0F_employee_1L_address.elements.btn_actions.visible = true
		
	//form four
		for (var i = 0; i < fourFields.length; i++) {
			forms[formFour].elements[fourFields[i]].editable = true
//			forms[formFour].elements[fourFields[i]].transparent = true
		}
		forms.CRM_0F_employee_1L_employee_contact.elements.btn_delete.visible = true
		
	//form five
		for (var i = 0; i < fiveFields.length; i++) {
			forms[formFive].elements[fiveFields[i]].editable = true
			forms[formFive].elements[fiveFields[i]].transparent = true
		}
	}
	//turn things off
	else {
	//form one
		for (var i = 0; i < fields.length; i++) {
			forms[formOne].elements[fields[i]].editable = false
			forms[formOne].elements[fields[i]].transparent = false
		}
		for (var i = 0; i < nonFields.length; i++) {
			forms[formOne].elements[nonFields[i]].visible = false
			forms[formOne].elements[nonFields[i] + '__noedit'].visible = true
		}
		
	//form two
		forms.CRM_0F_employee_1L_phone.elements.btn_phone_type.visible = false
		forms.CRM_0F_employee_1L_phone.elements.lbl_phone_type.enabled = false
		forms.CRM_0F_employee_1L_phone.elements.btn_primary.enabled = false
		forms.CRM_0F_employee_1L_phone.elements.fld_phone_number.visible = false
		forms.CRM_0F_employee_1L_phone.elements.fld_phone_number__noedit.visible = true
		forms.CRM_0F_employee_1L_phone.elements.btn_delete.enabled = false
		
	//form three
		forms.CRM_0F_employee_1L_address.elements.btn_actions.visible = false
		
	//form four
		for (var i = 0; i < fourFields.length; i++) {
			forms[formFour].elements[fourFields[i]].editable = false
//			forms[formFour].elements[fourFields[i]].transparent = false
		}
		forms.CRM_0F_employee_1L_employee_contact.elements.btn_delete.visible = false
		
	//form five
		for (var i = 0; i < fiveFields.length; i++) {
			forms[formFive].elements[fiveFields[i]].editable = false
			forms[formFive].elements[fiveFields[i]].transparent = false
		}
	}
}

Note that it does exactly what the design-time security tab of a form does. Except all in one place for an entire view of forms. Easy to maintain.

Better yet, this method can easily be upgraded with a UI to set the meta data the method uses (variable definitions at the top) for runtime control.