Field Level Security Enhancement

Tips submitted by PHPMaker users
Post Reply
sticcino
User
Posts: 1043

Field Level Security Enhancement

Post by sticcino »

have a project where we need field level security (read-only/hidden) at the field level for a form being displayed whether it is ADD/EDIT/VIEW etc...

this would get hairy if you had to manually specify logic on every form to either hide or make a field read only based on a user or group level, along with new fields/forms/changes etc it would be a nightmare.

Say hello to Casbin Library and thank you to DBField.php file/class.

you will need the Casbin authorization library from casbin.org - you can easily add it you your phpMaker project via composer packages (casbin/casbin). Make sure you understand and read the Casbin docs on how to utilize the library, it is quiet flexible and this example is only one way to utilize it.

you will need to create your own custom extension to replace the DBField.php file with the modified version. See the phpMaker help on how to create your own extension so you can upload the new DBField.php file

in the DBField.php file:

add:
public $e ;
To the class variables

change the function setVisibility() in DBfield.php as follows:

public function setVisibility()
{
global $Security, $Page;

$this->e = new Enforcer("config/model.conf", "config/policy.csv");

if($this->e == null) { // fails safe if something goes astray with the Auth Library
$this->Visible = Container($this->TableVar)->getFieldVisibility($this->Param);
return;
}

// GROUP OVERRIDE: hidden attribute is the inverse - all flds visible unless implicit hidden flag - hidden
// readonly attribute is normal - all fields writeable unless implicit readonly flag - readonly
//
// USERID OVERRIDE: visible attribute is not inversed for users: visible flag overrides group visibility flag
// write attribute is not inversed for users: write flag overrides group readonly flag
//
// Order of precedence: GROUP LEVEL - USERID overrides
//

// GROUP OVERRIDE
//
$this->Visible = (1 ^ $this->e->enforce("$Security->CurrentUserLevel", "$Page->PageObjName", "$this->Param", "hidden"));
$this->ReadOnly = $this->e->enforce("$Security->CurrentUserLevel", "$Page->PageObjName", "$this->Param", "readonly");

// USERID OVERRIDE Order of precedence visible - hidden : write - readonly
// there should not be both flags for a user at the same time, hence the readonly/hidden are read after the visible/write flags
// incase there was a mistake
//
$hasNamedVisiblePolicy = $this->e->hasNamedPolicy("p", CurrentUserID(), "$Page->PageObjName", "$this->Param", "visible");
if($hasNamedVisiblePolicy) {
$this->Visible = true;
}
$hasNamedHiddenPolicy = $this->e->hasNamedPolicy("p", CurrentUserID(), "$Page->PageObjName", "$this->Param", "hidden");
if($hasNamedHiddenPolicy) {
$this->Visible = false;
}
$hasNamedWritePolicy = $this->e->hasNamedPolicy("p", CurrentUserID(), "$Page->PageObjName", "$this->Param", "write");
if($hasNamedWritePolicy) {
$this->ReadOnly = false;
}
$hasNamedReadOnlyPolicy = $this->e->hasNamedPolicy("p", CurrentUserID(), "$Page->PageObjName", "$this->Param", "readonly");
if($hasNamedReadOnlyPolicy) {
$this->ReadOnly = true;
}
}

I created a folder under my root site and called it config and have my files located there.. ($this-> = new Enforcer("config/model.conf", "config/policy.csv"))

in the Casbin model.conf (or whatever you named it) file change the policy definition as follows:

[policy_definition]
p = sub, dom, obj, act

In the Casbin Polcy File, add your permissions as shown on this example: (you don't need to add "p, GROUPID, PAGEOBJNAME, FIELDNAME, FLAG" -- its only for illustration)

p, GROUPID, PAGEOBJNAME, FIELDNAME, FLAG (options: hidden/readonly)
p, 511, AnfRequestsEdit, AnfEmployeeLastDayWorked, readonly
p, 511, AnfRequestsEdit, AnfEmployeeSecondShiftMissed, hidden

Translation:
when the AnfRequestsEdit form is loaded and AnfEmployeeLastDayWorked is encountered make it READONLY for SECURITY GROUP 511
when the AnfRequestsEdit form is loaded and AnfEmployeeSecondShiftMissed is encountered HIDE IT for SECURITY GROUP 511

now to override for a particular user:

p, USERID, PAGEOBJNAME, FIELDNAME, FLAG (options: visible/hidden | write/readonly)
p, 100, AnfRequestsEdit, AnfEmployeeFirstShiftMissed, visible
p, 343, AnfRequestsEdit, AnfEmployeeFirstShiftMissed, write

Translation:
when the AnfRequestsEdit form is loaded and AnfEmployeeSecondShiftMissed is encountered HIDE IT for USERID 100
when the AnfRequestsEdit form is loaded and AnfEmployeeSecondShiftMissed is encountered make it WRITABLE for USERID 343

seems to be working so far. working different scenarios for the USER ID override, don't think there is a simpler way to do it, I think we need to check both scenarios (visible/hidden and write/readonly)

a permissions editor would probably be nice that ties into the userid/groups of the app, so you can see/manage the objects easier.

I had $this->e = new Enforcer("config/model.conf", "config/policy.csv"); at the construct level, but after testing found that all the list boxes were failing, couldn't isolate why, so it was moved to the function level

let me know if you come up with any enhancements or fixes to the logic

enjoy.

Post Reply