Revision: 2659
https://sourceforge.net/p/mrbs/code/2659/
Author: jberanek
Date: 2013-01-25 18:54:20 +0000 (Fri, 25 Jan 2013)
Log Message:
-----------
Added Diego Zuccato's initial patch which adds preliminary ACL support.
Modified Paths:
--------------
mrbs/branches/acl_devel/web/Themes/default/header.inc
mrbs/branches/acl_devel/web/admin.php
mrbs/branches/acl_devel/web/del_entry_ajax.php
mrbs/branches/acl_devel/web/edit_area_room.php
mrbs/branches/acl_devel/web/edit_entry.php
mrbs/branches/acl_devel/web/edit_entry_handler.php
mrbs/branches/acl_devel/web/js/admin.js.php
mrbs/branches/acl_devel/web/js/edit_entry.js.php
mrbs/branches/acl_devel/web/js/multiple.js.php
mrbs/branches/acl_devel/web/js/report.js.php
mrbs/branches/acl_devel/web/js/resizable.js.php
mrbs/branches/acl_devel/web/mrbs_auth.inc
mrbs/branches/acl_devel/web/pending.php
mrbs/branches/acl_devel/web/report.php
mrbs/branches/acl_devel/web/search.php
mrbs/branches/acl_devel/web/systemdefaults.inc.php
mrbs/branches/acl_devel/web/view_entry.php
Added Paths:
-----------
mrbs/branches/acl_devel/web/ECAPS.php
Added: mrbs/branches/acl_devel/web/ECAPS.php
===================================================================
--- mrbs/branches/acl_devel/web/ECAPS.php (rev 0)
+++ mrbs/branches/acl_devel/web/ECAPS.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -0,0 +1,167 @@
+<?php
+
+/**
+ * ACL management class
+ *
+ * Contributed by Diego Zuccato <[email protected]>
+ */
+/*
+ * From mail sent to the ML:
+ * > Basically, any group of controls should be
+ * > protected by three caps: "create/delete", "access(read)" and
"edit(write)".
+ * > Caps sets can be represented by strings (so requiring only the addition
+ * > of a "caps varchar" column to users table and "acl varchar" to
+ * > areas/rooms tables) and can leverage current method to override strings
+ * > with lists of options (making it more user-friendly).
+ * >
+ * > A good way to represent caps could be a list of comma-separed words, and
+ * > a good way to represent an ACL could be a set of 3 (extended: a cap
+ * > could be prefixed by a '-' to indicate that it must *not* be set) caps
+ * > sets separed by pipes. More formally:
+ * > LETNUM := 'a'..'z' | 'A'..'Z' | '0'..'9' | '_'
+ * > CAP := LETNUM | LETNUM CAP
+ * > CAPS := '' | CAP | CAP ',' CAPS
+ * > ECAP := CAP | '-' CAP
+ * > ECAPS := '' | ECAP | ECAP ',' ECAPS
+ * > ACL := ECAPS '|' ECAPS' '|' ECAPS
+ * Actually I modified this last, to represent full CRUD set, so
+ * ACL := ECAPS '|' ECAPS '|' ECAPS '|' ECAPS
+ * (caps respectively for Create, Read, Update and Delete)
+ *
+ * Extension: caps and ACLs can include levels! cap[=lev][,cap=lev]*
+ * A cap w/o level is equal to a cap with level=0.
+ * An acl is verified iif:
+ * - the checked caps set is a superset of acl's caps
+ * - every cap in acl's set have a level <= the corresponding compared cap
level
+ *
+ * For example, given an ACL of "level=2,-disabled":
+ * - "level=5,disabled" is rejected ('disabled' is set)
+ * - "level=1,admin" is rejected (1 < 2)
+ * - "level=2,foo=3,bar=0" is accepted ('foo' and 'bar' aren't in ACL, but
it's OK)
+ * - "foo=100,bar=abc" is rejected (missing required 'level')
+*/
+
+define('ALPHA1', "abcdefghijklmnopqrstuvwxyz");
+define('ALPHA2', "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+define('NUMBERS', "0123456789");
+define('LETNUM', ALPHA1.ALPHA2.NUMBERS."_");
+
+class ECAPS {
+ // Accept an array (one extended capability per *key* -- value is the
level) or a string
+ // (packed extended capabilities. Duplicated capabilities are overwritten
and only the
+ // last one remains)
+ public function __construct($ecaps) {
+ if(is_array($ecaps)) {
+ // Sanitize input array:
+ // - remove illegal keys (not valid caps)
+ // - make sure values are positive integers
+ foreach($ecaps as $k => $v) {
+ $t=$this->parse_ecap("$k=$v", TRUE);
+ if(FALSE===$t || $t['key']!=$k) { // invalid cap or different
key: discard
+ unset($ecaps[$k]);
+ } else {
+ $ecaps[$k]=$t['val']; // sanitize value
+ }
+ }
+ } else if(is_string($ecaps)) {
+ $ecaps=$this->parse_ecaps_string($ecaps, true);
+ } else { // Ops! Don't know what to do, so I leave caps empty
+ trigger_error("Bad caps constructor parameter -- leaving caps
empty!", E_USER_WARNING);
+ return;
+ }
+ foreach($ecaps as $cap => $v) {
+ if(substr($cap, 0, 1) == '-') {
+ $this->neg_caps[substr($cap, 1)]=$v;
+ } else {
+ $this->pos_caps[$cap]=$v;
+ }
+ }
+
+ $this->pcaps=count($this->pos_caps); // Useless to count every time
it's needed to verify a CAPS set
+
+ $tst=array_intersect(array_keys($this->pos_caps),
array_keys($this->neg_caps));
+ if(count($tst)) {
+ trigger_error("Never-satisfiable CAPS: pos and neg caps overlap for
". implode(",",$tst), E_USER_WARNING);
+ }
+ }
+
+ // Gets a capability set and returns if the CAPs allows access (TRUE) or
not (FALSE)
+ public function test($cap) {
+ if(is_array($cap)) $caparr=$cap;
+ else if(is_string($cap)) $caparr=$this->parse_ecaps_string($cap);
+ else return FALSE;
+
+ $pos=count(array_intersect(array_keys($this->pos_caps),
array_keys($caparr)));
+ $neg=count(array_intersect(array_keys($this->neg_caps),
array_keys($caparr)));
+
+ // There must be *NO* negatives and *ALL* positives
+ $rv=($neg==0)&&($pos==$this->pcaps);
+
+ if($rv) { // Time to check levels!
+ foreach($this->pos_caps as $cap => $lev) {
+ if($caparr[$cap]<$lev) {
+ $rv=FALSE;
+ break; // bail out: at least one level too low!
+ }
+ }
+ }
+
+ return $rv;
+ }
+
+ public function __toString() {
+ $tmp=$this->pos_caps;
+ foreach($this->neg_caps as $ncap => $nval) {
+ $tmp["-".$ncap]=$nval;
+ }
+ $out="";
+ foreach($tmp as $k => $v) {
+ $out .= ($out==""?"":",")."$k=$v";
+ }
+ return $out;
+ }
+
+ //************************
+ private function parse_ecaps_string($caps, $allow_neg=FALSE) {
+ $tcaps = array();
+ $tmp=explode(",", $caps);
+ foreach($tmp as $tok) { // Probably this can be optimized
+ if(""==$tok) continue;
+
+ $t=$this->parse_ecap($tok, $allow_neg);
+ if(is_array($t)) {
+ $tcaps[$t['key']] = $t['val'];
+ }
+ }
+ return $tcaps;
+ }
+
+ // Gets a single ecap string and returns an array:
+ // 'key' => ecap name
+ // 'val' => ecap value
+ // Returns FALSE if the capability is invalid
+ private function parse_ecap($tok, $allow_neg) {
+ $rv=array();
+
+ $start=0;
+ if($tok[0]=='-' && $allow_neg) { // *Possibly* a neg cap
+ $start=1; // Skip the initial '-'
+ }
+ $kl=strspn($tok, LETNUM, $start);
+ if($kl) { // at least one valid char as key
+ $kl+=$start;
+ $rv['key'] = substr($tok, 0, $kl);
+ $rv['val'] = 0;
+ if(strlen($tok)>$kl && "="==$tok[$kl]) {
+ // value present
+ $rv['val'] = (int)substr($tok, $kl+1, strspn($tok, NUMBERS,
$kl+1));
+ }
+ } else { // Invalid key ==> invalid cap (no name and val)
+ $rv=FALSE;
+ }
+
+ return $rv;
+ }
+
+ private $pos_caps=array(), $neg_caps=array(), $pcaps=0;
+}
Property changes on: mrbs/branches/acl_devel/web/ECAPS.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: mrbs/branches/acl_devel/web/Themes/default/header.inc
===================================================================
--- mrbs/branches/acl_devel/web/Themes/default/header.inc 2013-01-25
18:46:36 UTC (rev 2658)
+++ mrbs/branches/acl_devel/web/Themes/default/header.inc 2013-01-25
18:54:20 UTC (rev 2659)
@@ -20,7 +20,7 @@
$page = basename($PHP_SELF, ".php");
$user = getUserName();
- $is_admin = (authGetUserLevel($user) >= $max_level);
+ $is_admin = getAuthorised($sys_caps['admin']);
// Need to set the timezone before we can use date()
get_area_settings($area);
@@ -152,7 +152,7 @@
// (if there are any enabled areas where we require bookings to be
approved)
$approval_somewhere = some_area('approval_enabled', TRUE);
- if ($approval_somewhere && (authGetUserLevel($user) >= 1))
+ if ($approval_somewhere && getAuthorised($sys_caps['regular']))
{
$sql_approval_enabled = some_area_predicate('approval_enabled');
// Find out how many bookings are awaiting approval
Modified: mrbs/branches/acl_devel/web/admin.php
===================================================================
--- mrbs/branches/acl_devel/web/admin.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/admin.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -34,8 +34,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$required_level = (isset($max_level) ? $max_level : 2);
-$is_admin = (authGetUserLevel($user) >= $required_level);
+$is_admin = getAuthorised($sys_caps['admin']);
print_header($day, $month, $year, isset($area) ? $area : "", isset($room) ?
$room : "");
Modified: mrbs/branches/acl_devel/web/del_entry_ajax.php
===================================================================
--- mrbs/branches/acl_devel/web/del_entry_ajax.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/del_entry_ajax.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -29,8 +29,7 @@
// Check that the user has the highest level of admin rights
$user = getUserName();
-$level = authGetUserLevel($user);
-if ($level < $max_level)
+if (!getAuthorised($sys_caps['admin']))
{
exit;
}
Modified: mrbs/branches/acl_devel/web/edit_area_room.php
===================================================================
--- mrbs/branches/acl_devel/web/edit_area_room.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/edit_area_room.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -214,8 +214,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$required_level = (isset($max_level) ? $max_level : 2);
-$is_admin = (authGetUserLevel($user) >= $required_level);
+$is_admin = getAuthorised($sys_caps['admin']);
// Done changing area or room information?
if (isset($change_done))
Modified: mrbs/branches/acl_devel/web/edit_entry.php
===================================================================
--- mrbs/branches/acl_devel/web/edit_entry.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/edit_entry.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -592,7 +592,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= 2);
+$is_admin = getAuthorised($sys_caps['admin']);
// You're only allowed to make repeat bookings if you're an admin
// or else if $auth['only_admin_can_book_repeat'] is not set
$repeats_allowed = $is_admin || empty($auth['only_admin_can_book_repeat']);
Modified: mrbs/branches/acl_devel/web/edit_entry_handler.php
===================================================================
--- mrbs/branches/acl_devel/web/edit_entry_handler.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/edit_entry_handler.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -12,7 +12,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= 2);
+$is_admin = getAuthorised($sys_caps['admin']);
Modified: mrbs/branches/acl_devel/web/js/admin.js.php
===================================================================
--- mrbs/branches/acl_devel/web/js/admin.js.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/js/admin.js.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -13,7 +13,7 @@
}
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= $max_level);
+$is_admin = getAuthorised($sys_caps['admin']);
//
=================================================================================
Modified: mrbs/branches/acl_devel/web/js/edit_entry.js.php
===================================================================
--- mrbs/branches/acl_devel/web/js/edit_entry.js.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/js/edit_entry.js.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -13,7 +13,7 @@
}
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= $max_level);
+$is_admin = getAuthorised($sys_caps['admin']);
// Function to display the secondary repeat type fieldset appropriate
Modified: mrbs/branches/acl_devel/web/js/multiple.js.php
===================================================================
--- mrbs/branches/acl_devel/web/js/multiple.js.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/js/multiple.js.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -13,7 +13,7 @@
}
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= $max_level);
+$is_admin = getAuthorised($sys_caps['admin']);
//
=================================================================================
Modified: mrbs/branches/acl_devel/web/js/report.js.php
===================================================================
--- mrbs/branches/acl_devel/web/js/report.js.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/js/report.js.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -13,7 +13,7 @@
}
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= $max_level);
+$is_admin = getAuthorised($sys_caps['admin']);
Modified: mrbs/branches/acl_devel/web/js/resizable.js.php
===================================================================
--- mrbs/branches/acl_devel/web/js/resizable.js.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/js/resizable.js.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -13,7 +13,7 @@
}
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= $max_level);
+$is_admin = getAuthorised($sys_caps['admin']);
// function to reverse a collection of jQuery objects
Modified: mrbs/branches/acl_devel/web/mrbs_auth.inc
===================================================================
--- mrbs/branches/acl_devel/web/mrbs_auth.inc 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/mrbs_auth.inc 2013-01-25 18:54:20 UTC (rev
2659)
@@ -1,6 +1,9 @@
<?php
// $Id$
+// include ACL basic infrastructure
+require_once 'ECAPS.php';
+
// include the authentification wrappers
require_once "auth/auth_$auth[type].inc";
@@ -47,17 +50,17 @@
*
* Check to see if the current user has a certain level of rights
*
- * $level - The access level required
+ * $acl - The access control list to satisfy to access the page
*
* Returns:
* 0 - The user does not have the required access
* non-zero - The user has the required access
*/
-function getAuthorised($level)
+function getAuthorised($acl)
{
- // If the minimum level is zero (or not set) then they are
+ // If the acl is empty (or not set) then they are
// authorised, whoever they are
- if (empty($level))
+ if (empty($acl))
{
return TRUE;
}
@@ -70,7 +73,8 @@
return 0;
}
- return authGetUserLevel($user) >= $level;
+ $req=new ECAPS($acl);
+ return $req->test(authGetUserCaps($user));
}
/* checkAuthorised()
@@ -84,26 +88,47 @@
*/
function checkAuthorised()
{
- global $page_level, $max_level;
+ global $page_level, $page_acl, $max_level, $sys_caps;
global $day, $month, $year, $area, $room;
global $PHP_SELF;
-
+
+ $acl="";
+
+ $pagename=basename($PHP_SELF);
// Get the minimum authorisation level for this page
- if (isset($page_level[basename($PHP_SELF)]))
+ if (isset($page_acl[$pagename]))
{
- $required_level = $page_level[basename($PHP_SELF)];
+ $acl=$page_acl[$pagename];
}
- elseif (isset($max_level))
- {
- $required_level = $max_level;
+ else {
+ if (isset($page_level[$pagename]))
+ {
+ // Need to map page level to an ACL
+ if($page_level[$pagename]) {
+
$acl=($page_level[$pagename]>1)?$sys_caps['admin']:$sys_caps['regular'];
+ } else {
+ $acl=""; // Always allowed
+ }
+ }
+ else
+ {
+ $acl=$sys_caps['admin'];
+ }
}
- else
+
+ // Add to ACL area-/room- specific constraints
+ if (is_array($acl))
{
- $required_level = 2;
+ $newacl="";
+ if (isset($acl["a$area"]))
+ $newacl.=$acl["a$area"];
+ if (isset($acl["r$room"]))
+ $newacl.=$acl["r$room"];
+ $acl=$newacl;
}
-
+
// Check that the user has this level
- if (!getAuthorised($required_level))
+ if (!getAuthorised($acl))
{
// If we dont know the right date then use today's
if (!isset($day) or !isset($month) or !isset($year))
@@ -190,15 +215,15 @@
*/
function auth_can_edit_user($user, $target)
{
- global $min_user_editing_level;
-
+ global $sys_caps;
+
// Always allowed to modify your own stuff
if(strcasecmp($user, $target) == 0)
{
return 1;
}
- if(authGetUserLevel($user) >= $min_user_editing_level)
+ if(getAuthorised($sys_caps['edit_users']))
{
return 1;
}
@@ -220,6 +245,8 @@
// the room; otherwise FALSE
function auth_book_admin($user, $room)
{
- return (authGetUserLevel($user) >= 2);
+ global $sys_caps;
+
+ return getAuthorised($sys_caps['admin']);
}
?>
Modified: mrbs/branches/acl_devel/web/pending.php
===================================================================
--- mrbs/branches/acl_devel/web/pending.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/pending.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -196,7 +196,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= 2);
+$is_admin = getAuthorised($sys_caps['admin']);
print_header($day, $month, $year, $area, isset($room) ? $room : "");
Modified: mrbs/branches/acl_devel/web/report.php
===================================================================
--- mrbs/branches/acl_devel/web/report.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/report.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -1083,8 +1083,7 @@
checkAuthorised();
// Also need to know whether they have admin rights
$user = getUserName();
- $user_level = authGetUserLevel($user);
- $is_admin = ($user_level >= 2);
+ $is_admin = getAuthorised($sys_caps['admin']);
}
// If we're running in CLI mode we're passing the parameters in from the
command line
Modified: mrbs/branches/acl_devel/web/search.php
===================================================================
--- mrbs/branches/acl_devel/web/search.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/search.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -127,7 +127,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$is_admin = (isset($user) && authGetUserLevel($user)>=2) ;
+$is_admin = (isset($user) && getAuthorised($sys_caps['admin'])) ;
// Set up for Ajax. We need to know whether we're capable of dealing with
Ajax
// requests, which will only be if (a) the browser is using DataTables and (b)
Modified: mrbs/branches/acl_devel/web/systemdefaults.inc.php
===================================================================
--- mrbs/branches/acl_devel/web/systemdefaults.inc.php 2013-01-25 18:46:36 UTC
(rev 2658)
+++ mrbs/branches/acl_devel/web/systemdefaults.inc.php 2013-01-25 18:54:20 UTC
(rev 2659)
@@ -1083,4 +1083,14 @@
// Default description for new bookings
$default_description = "";
+/****************
+ * Capabilities *
+ ***************/
+
+$sys_caps['admin']='level=2';
+$sys_caps['regular']='level=1';
+// Note that if you change $min_user_editing_level in config.inc.php, you have
to
+// redefine the edit_users element!!!
+$sys_caps['edit_users']="level=$min_user_editing_level";
+
?>
Modified: mrbs/branches/acl_devel/web/view_entry.php
===================================================================
--- mrbs/branches/acl_devel/web/view_entry.php 2013-01-25 18:46:36 UTC (rev
2658)
+++ mrbs/branches/acl_devel/web/view_entry.php 2013-01-25 18:54:20 UTC (rev
2659)
@@ -115,7 +115,7 @@
// Also need to know whether they have admin rights
$user = getUserName();
-$is_admin = (authGetUserLevel($user) >= 2);
+$is_admin = getAuthorised($sys_caps['admin']);
// You're only allowed to make repeat bookings if you're an admin
// or else if $auth['only_admin_can_book_repeat'] is not set
$repeats_allowed = $is_admin || empty($auth['only_admin_can_book_repeat']);
------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. ON SALE this month only -- learn more at:
http://p.sf.net/sfu/learnnow-d2d
_______________________________________________
Mrbs-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mrbs-commits