Solved

User permission help with bitwise in php.

Posted on 2010-09-22
20
515 Views
Last Modified: 2013-12-12
Hi,

I am trying to create a user permission system, and have decided that using a bitwise system is probably my best answer. I have thought through the process that will need to happen when a user tries to enter a page however need some help on the if statement bit.

What will happen as you can see from the code below is that when a user goes to the page, the usergroup they are apart of will be checked for its 'level' and that in turn will be checked against the page access level in a separate table.

What i need to happen is, say the level required to see the page addUser was set at 4 anybody with the level of 4 or above (so 8) (or mods and admins) would be allowed access and anybody on 2 (guests) wouldn't.

I will attach an image of the sort of tables i envisage and the code i have got so far and would appreciate any help on this matter.

Thanks, Alex

Table Idea
function permissions() {

// $page will be located on the actuall page im securing and read something like   $page = 'addUser';

$guest = 2
$mod = 4
$admin = 8

$user = $_COOKIE['username'];

$query = "SELECT * FROM user WHERE username='$user' LIMIT 1";

$result = mysql_query($query) or trigger_error("SQL", E_USER_ERROR);
$value = mysql_fetch_array($result);
$usergroup = $value['usergroup'];


$query2 = "SELECT * FROM usergroup WHERE usergroup='$usergroup' LIMIT 1";

$result2 = mysql_query($query2) or trigger_error("SQL", E_USER_ERROR);
$value2 = mysql_fetch_array($result2);
$level = $value2['level'];


$query3 = "SELECT * FROM page WHERE page='$page' LIMIT 1"; // Links to page im securing

$result3 = mysql_query($query3) or trigger_error("SQL", E_USER_ERROR);
$value3 = mysql_fetch_array($result3);
$pagelevel = $value3['level'];

// NEED HELP HERE CREATING THE IF STATEMENT USING BITWISE

if($level & $pagelevel) > 0 { // I KNOW THE IF STATEMENT IS WRONG FOR WHAT I NEED -->  // IF USERGROUP LEVEL IS THE SAME VALUE OR HIGHER THAN WHAT THE PAGE DEMANDS THEN SHOW THEM ELSE REDIRECT TO A YOU NEED THESE PERMISSIONS PAGE.

//THEN SHOW THE PAGE

} else {

header("Location:permissions.php");

}

Open in new window

0
Comment
Question by:echocpt
  • 10
  • 10
20 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33733348
I have an article here at EE that may be helpful to you in understanding the login / logout processes.
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_2391-PHP-login-logout-and-easy-access-control.html

You might extend the table 'userTable' to contain columns for the permissions.  Set up one column for each type of permission you wish to grant.  Zero or one.

For each of your pages, set up a corresponding array of permission requirements, or you could add the permission requirements right into the page code.

At the time of page access, compare the page requirements to the user permissions.  If all of the page requirements are met or exceeded, load the page.

I would recommend that you NOT use any kind of math or bitwise operation to implement this.  It gets very difficult to change permissions with that kind of structure.  OTOH, if you can read the user permissions and page permission requirements in clear text, it is very easy to understand and implement your intent.

You might extend the access_control() function described in the article to implement the permissions levels.

HTH, and good luck with it, ~Ray
0
 

Author Comment

by:echocpt
ID: 33733490
Hi,

Thanks for the reply, i like your suggestion of assigning more columns in the table, however if i did it this way could you explain this: would an admin have 1 in all 3 permission columns or just a 1 in the admin column, and mods a 1 in user and mod column and then users just a 1 in user column?

Also you say that it would be hard to change permissions but i can't see how as it is all just values in the page table. All i would do is change say addPage to 8 from 4 and it would be fine.

Also having looked on google it seems most people recommend using bitwise to achieve this, although you say it's harder (and i don't not believe you as you lead the experts in this zone :P) is it possible and i can't understand why apart from changing permissions it would be hard?

Thanks Alex

P.S Sorry i always seem to disagree, i'm more curious to know why you choose one other another.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33734016
"Hard" is a relative term.  I like to think of code and data structures that are so easy to understand that I waste no time trying to figure the meaning.  So I am a big fan of meaningful class, method, and variable names.  If it's hard to understand the meaning of the code or data, it wastes my time.

Regarding this:
would an admin have 1 in all 3 permission columns or just a 1 in the admin column, and mods a 1 in user and mod column and then users just a 1 in user column?

The simple answer would be even more general.  The permissions would be applied atomically.  So you could have an admin who was NOT a user, if you wanted to do something like that.  Where would this make sense?  If you have two or more classes of users, an admin in one of the classes might also be a user for that class, but not for the other class.  Access control has a way of getting "interesting" as you start to combine permissions - that is why I favor low-level, atomic permissions.

One construct I have used in the past is a multi-tier access control strategy.  Building on the article posted above, I wrote three methods: access_control(), admin_access_control(), and owner_access_control().  This made it possible for me to protect a script with one or two lines of code - whatever made sense for the security I needed.  If any of the methods returned FALSE, the page was disallowed.  Easy!

0
 

Author Comment

by:echocpt
ID: 33734139
Thanks for the info.

I will most likely look at what you are talking about in the future as it seems sensible and i like the idea but i will need to rework/re-design the system. However for the moment i feel like i should stick with what i'v started on and try to get it working before confusing myself more.

With the code attached i'm currently being redirect no matter what level, and i believe this is because of the if statement. Can you see anything wrong with it and why it won't allow the correct user to access the page?

Thanks Alex
function permissions() {

// $page will be located on the actuall page im securing and read something like   $page = 'addUser';

$user = $_COOKIE['username'];

$query = "SELECT * FROM user WHERE username='$user' LIMIT 1";

$result = mysql_query($query) or trigger_error("SQL", E_USER_ERROR);
$value = mysql_fetch_array($result);
$usergroup = $value['usergroup'];


$query2 = "SELECT * FROM usergroup WHERE usergroup='$usergroup' LIMIT 1";

$result2 = mysql_query($query2) or trigger_error("SQL", E_USER_ERROR);
$value2 = mysql_fetch_array($result2);
$level = $value2['value'];


$query3 = "SELECT * FROM page_permissions WHERE page='deleteUser' LIMIT 1"; // Links to page im securing

$result3 = mysql_query($query3) or trigger_error("SQL", E_USER_ERROR);
$value3 = mysql_fetch_array($result3);
$pagelevel = $value3['value'];

// NEED HELP HERE CREATING THE IF STATEMENT USING BITWISE

if( ($level <= $pagelevel) ) { // I KNOW THE IF STATEMENT IS WRONG FOR WHAT I NEED -->  // IF USERGROUP LEVEL IS THE SAME VALUE OR HIGHER THAN WHAT THE PAGE DEMANDS THEN SHOW THEM ELSE REDIRECT TO A YOU NEED THESE PERMISSIONS PAGE.

header("Location:../../system/login/permission.php");


} else {
//THEN SHOW THE PAGE
echo"you made the cut";

}
}

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33734274
OK, I'll look in a bit.  Did you read the article I linked above?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33734443
This is obviously untested code, but it might be what I would do if I had to start from the permissions function.

I would not have a function that redirected - I think I would want to see that in the code that called the function.  You might want to redirect different kinds of clients to different addresses.

What will you do if the COOKIE is not set?  Maybe you want to test for that.

One other thought... This kind of thing about user permissions is frequently found "baked in" with many frameworks.  You might consider looking at Zend, CodeIgniter, etc., as a way to reduce the time it takes you to develop your application.

best of luck with it, ~Ray
function permissions($page='deleteUser') 

{

    // PREPARE THE DATA FOR USE IN A QUERY

    $page = mysql_real_escape_string($page);



    // PREPARE THE EXTERNAL DATA FOR USE IN A QUERY

    if (empty($_COOKIE["username"])) return FALSE;

    $user = mysql_real_escape_string($_COOKIE['username']);



    // RELY ON COOKIE DATA ONLY?

    $query  = "SELECT usergroup FROM user WHERE username='$user' LIMIT 1";

    $result = mysql_query($query) or trigger_error("SQL", E_USER_ERROR);

    $value  = mysql_fetch_assoc($result);

    $usergroup = mysql_real-escape_string($value['usergroup']);



    // GET PERMISSIONS FOR THE USER GROUP

    $query2  = "SELECT value FROM usergroup WHERE usergroup='$usergroup' LIMIT 1";

    $result2 = mysql_query($query2) or trigger_error("SQL", E_USER_ERROR);

    $value2  = mysql_fetch_assoc($result2);

    $userlevel = $value2['value'];



    // GET PERMISSION REQUIREMENTS FOR THE PAGE

    $query3  = "SELECT value FROM page_permissions WHERE page='$page' LIMIT 1"; // Links to page im securing

    $result3 = mysql_query($query3) or trigger_error("SQL", E_USER_ERROR);

    $value3  = mysql_fetch_array($result3);

    $pagelevel = $value3['value'];





    // IF THE USER IS GREATER OR EQUAL TO THE PAGE REQUIREMENT

    if( ($userlevel >= $pagelevel) ) return TRUE;

    return FALSE;

}



// USE CASE - REDIRECT IF THE PERMISSIONS LEVEL IS INADEQUATE

if (!permissions()) 

{

    header("Location:../../system/login/permission.php");

    exit;

}





// THEN SHOW THE PAGE

echo "you made the cut";

Open in new window

0
 

Author Comment

by:echocpt
ID: 33735000
Hi, thanks for looking over. In answer to your first question about the link, yes i did read it and will move my system from cookies to sessions and probably look at something like it in the future.

I have tried your code however am finding that when i try and access the login form it tries to redirect to the permissions page, which in turn tries to redirect to the login page because no one is signed in until it times out. Any ideas as to why?

also where you have inserted $page = deleteUser at the top, i was using a variable on the page i was securing called $page = 'deleteUser' and wanting the function to pick that up and use it so then on each different page i could just change it so it read $page = 'addUser' etc...

Any help?

Thanks Alex
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33735138
Regarding this, "I have tried your code however am finding that when i try and access the login form it tries to redirect to the permissions page, which in turn tries to redirect to the login page because no one is signed in until it times out. Any ideas as to why?"

To quote from the article, "Perhaps it should go without saying, but I'll say it anyway: do not use the access_control() function in your login script, or else your code may cause a loop on the server!"

Why would there be any permissions associated with the login page?  That does not make sense.

Regarding this, "function permissions($page='deleteUser')" - that notation establishes a default value for the $page variable in the function.  These are equivalent statements:

$x = permissions('deleteUser');
$x = permissions();

If you write code like this, it will use the argument in the function call -- 'foo' -- for the value of $page.
$x = permissions('foo');

Let me suggest a good book that can help you get a grip on this and many other things in PHP.  It's got great examples and a downloadable code library so you can copy and paste.  Very readable.  Now in its fourth edition.  A cornerstone of my professional library since version One.
http://www.sitepoint.com/books/phpmysql4/

Best regards, ~Ray
0
 

Author Comment

by:echocpt
ID: 33735745
Hi, the code on the login script isn't access control but checks to see if a cookie is already active. I have removed this anyway but am still experiencing the same problem. I belive it is to do with this bit:


// USE CASE - REDIRECT IF THE PERMISSIONS LEVEL IS INADEQUATE
if (!permissions())
{
    header("Location:../../system/login/permission.php");
    exit;
}


// THEN SHOW THE PAGE
echo "you made the cut";


being outside of the function but within a global functions script. I will include my files if it is any help.

I will purchase the book tonight and make sure i go through it thoroughly.

Thanks Alex
global-functions.php
index.php
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33738179
Yes, you would want to include the call to the permissions() function in your page scripts that you seek to protect.  It would not be part of a global script unless you wanted to protect all the pages that call the global script.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:echocpt
ID: 33764149
After discussion i have decided to follow the tutorial link provided in your first post and am now using sessions and the access control function.

However if possible could you explain how i could implement my permission access into the access control function. I have now made it so that the table username has 3 columns, admin, mod and user and these are either a yes (1) or no (0). However when i try and make it so that if admin != 1 then don't show else do it doesn't seem to work and still allow anyone access. I will include the code im using below. If we can get this sorted i will be more than happy to award points to yourself.

Thanks Alex
function access_control($test=FALSE)
{		
	
		$username = $_SESSION["ID_ADDO_SITE"];
		
		$query = "SELECT * FROM user WHERE username='$username' LIMIT 1";
		$result = mysql_query($query) or trigger_error("SQL", E_USER_ERROR);
		$fetch = mysql_fetch_array($result);
		
		$usergroup = $fetch['usergroup_id'];
		
		$query2 = "SELECT * FROM usergroup WHERE id='$usergroup' LIMIT 1";
		$result2 = mysql_query($query2) or trigger_error("SQL", E_USER_ERROR);
		$fetch2 = mysql_fetch_array($result2);

		$administrator = $fetch2['administrator'];
		$moderator = $fetch2['moderator'];
		$user = $fetch2['user'];
		
 		if ($administrator != '1') {
			 header("Location:../../system/login/permissions.php"); 
 		} else { 
		//show
		}
		}
	
    // IF THE uid IS ALREADY SET, THE CLIENT IS ALREADY LOGGED IN
    if (isset($_SESSION["ID_ADDO_SITE"])) return TRUE;
    
    // IF THIS IS A TEST-ONLY, RETURN FALSE INSTEAD OF PROCESSING THE LOGIN
    if ($test) return FALSE;
    
    // STORE THE CLIENT'S ENTRY PAGE AND GET VARIABLE STRING IN THE SESSION
    $_SESSION["entry_uri"] = $_SERVER["REQUEST_URI"];
    
    // REDIRECT TO THE LOGIN PAGE
    header("Location: ../../system/login/");
    exit;
}

Open in new window

0
 

Author Comment

by:echocpt
ID: 33764154
Sorry there should only be 1 } after //show. But that makes no difference to it working correctly when removed.
Thanks Alex
0
 

Author Comment

by:echocpt
ID: 33764169
How weird. I just re-uploaded and it seems to work fine now. However i suppose what i could ask is, is my code the best way to do what i'm trying to?

Thanks Alex
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33764564
Regarding "the best way" -- it's almost never what our code does.  We do what works for us, given the circumstances.  One of the circumstances here is the structure of the data base tables.  I would design the tables differently.  All of the user permission information would be in the users table, so I only had ONE PLACE to look for user permission information.

Then you could select the users row and store that entire row in one field of the session array.  In the article I wrote about access control, I selected and stored only the "uid" field.  It would be easy to expand on that a little bit.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33764641
Separate note regarding this:

Sorry there should only be 1 } after //show. But that makes no difference to it working correctly when removed.

One of the most important things about successful programming is writing clear and easy-to-understand code.  As a result, coding standards have evolved that help us become better programmers.  One of these is the use of standard indents and aligned control structures.  If the curly brackets line up vertically on the page, we are much less likely to make mistakes.  Same holds true for the equivalence statements and the assignment statements.  Same holds true for meaningful variable names.

Example: Here is a function written without coding standards.  Just read it over and figure out how to make a modification.
function rc($ou, $tu, $x, $y, $q=75){

if(!$o=imagecreatefromjpeg($ou))return FALSE;

list($o_w,$o_h)=getimagesize($ou);

$xr=$x;$yr=$y;if($o_w>$o_h){

$y_r=$y/$o_h;$xr=(int)round($o_w*$y_r);}else{$x_r=$x/$o_w;$yr=(int)round($o_h

* $x_r);

}if($xr<$x){

$y_r=$x/$xr;$yr=(int)round($y*$y_r);$xr=$x;

}

$t=imagecreatetruecolor($xr,$yr);if(!imagecopyresampled($t,$o,0,0,0,0,$xr,$yr,$o_w,$o_h))return FALSE;$f=imagecreatetruecolor($x, $y);$xo 

= 0;$yo = 0;if($x<$xr)$xo=(int)round(($xr-$x)/2) else $yo=(int)round(($yr-$y)/2);

if(!imagecopy($f, $t, 0,0, $xo, $yo, $xr, $yr))return FALSE;if(!imagejpeg($f,$tu,$q))

return FALSE;return TRUE;

}

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33764650
Here is the same function written with comments, coding standards and meaningful variable names.

It's not just a matter of style

;-)

~Ray
function resize_and_crop($original_image_url, $thumb_image_url, $thumb_w, $thumb_h, $quality=75)

{

    // ACQUIRE THE ORIGINAL IMAGE: http://us3.php.net/manual/en/function.imagecreatefromjpeg.php

    $original = imagecreatefromjpeg($original_image_url);

    if (!$original) return FALSE;



    // GET ORIGINAL IMAGE DIMENSIONS

    list($original_w, $original_h) = getimagesize($original_image_url);



    // RESIZE IMAGE AND PRESERVE PROPORTIONS KEEPING AS MUCH OF THE IMAGE AS POSSIBLE

    $thumb_w_resize = $thumb_w;

    $thumb_h_resize = $thumb_h;

    if ($original_w > $original_h)

    {

        $thumb_h_ratio  = $thumb_h / $original_h;

        $thumb_w_resize = (int)round($original_w * $thumb_h_ratio);

    }

    else

    {

        $thumb_w_ratio  = $thumb_w / $original_w;

        $thumb_h_resize = (int)round($original_h * $thumb_w_ratio);

    }

    if ($thumb_w_resize < $thumb_w)

    {

        $thumb_h_ratio  = $thumb_w / $thumb_w_resize;

        $thumb_h_resize = (int)round($thumb_h * $thumb_h_ratio);

        $thumb_w_resize = $thumb_w;

    }



    // CREATE THE PROPORTIONAL IMAGE RESOURCE

    $thumb = imagecreatetruecolor($thumb_w_resize, $thumb_h_resize);

    if (!imagecopyresampled($thumb, $original, 0,0,0,0, $thumb_w_resize, $thumb_h_resize, $original_w, $original_h)) return FALSE;



    // ACTIVATE THIS TO STORE THE INTERMEDIATE IMAGE

    // imagejpeg($thumb, 'RAY_temp_' . $thumb_w_resize . 'x' . $thumb_h_resize . '.jpg', 100);



    // CREATE THE CENTERED CROPPED IMAGE TO THE SPECIFIED DIMENSIONS

    $final = imagecreatetruecolor($thumb_w, $thumb_h);



    $thumb_w_offset = 0;

    $thumb_h_offset = 0;

    if ($thumb_w < $thumb_w_resize)

    {

        $thumb_w_offset = (int)round(($thumb_w_resize - $thumb_w) / 2);

    }

    else

    {

        $thumb_h_offset = (int)round(($thumb_h_resize - $thumb_h) / 2);

    }



    if (!imagecopy($final, $thumb, 0,0, $thumb_w_offset, $thumb_h_offset, $thumb_w_resize, $thumb_h_resize)) return FALSE;



    // STORE THE FINAL IMAGE - WILL OVERWRITE $thumb_image_url

    if (!imagejpeg($final, $thumb_image_url, $quality)) return FALSE;

    return TRUE;

}

Open in new window

0
 

Author Comment

by:echocpt
ID: 33764687
Hi, I understand why you would put it in the user table however by having it in the usergroup surely it allows you to change a lot of users at a time if needed and not just one at a time.

I have also completely confused myself on how i can do what i first asked. I like your access_control and that works well but how can i go about making each page open to different usergroups etc.
I don't know if i'm not explaining properly what i want to you, but maybe im best explaining with an example.


Lets say that i run an article website and i want all users in the usergroup: "admin" to be allowed permissions to add, edit and delete articles from the database table, however i have another usergroup: "mods" that i only want to be allowed to add and edit articles. How could i possibly allow this to happen bearing in mind that any pages that the mod can access the admin must be able to access but any pages admin can access mods can't?


I don't know if you feel we are going in circles but i'm just confused on the best way to do this? Is it possible to show me an example of how you would allow an admin to add usergroups and assign them different permissions to view different pages on a small scale?

Thanks & Sorry, Alex
0
 

Author Comment

by:echocpt
ID: 33764697
P.S. Just saw your other two posts, and i agree, much easier to understand. The problem of that extra bracket was because i'd copied it from a previous function that contained a while loop that i then changed to a variable and just forgot to remove the bracket before posting, but i will be sure to look over my code to make it a lot more meaningful.

Thanks Alex
0
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 33764882
"an example of how you would allow an admin to add usergroups and assign them different permissions to view different pages on a small scale?"

That would probably cover a chapter of any book on PHP.  I just don't have time to write it all out now.  Please buy this book.  It will help you a lot, I promise:
http://www.sitepoint.com/books/phpmysql4/

The general design pattern is this:

Each user row in the data base has one column for each permission.  The column contains a 1 for allocated permissions, and a zero for denied permissions.

The access control functions test the page requirements against the user permissions.  If the page has a 1 and the user has a zero, the page is not available.

Most frameworks implement a permission-based scheme.  You might find it easier to use a framework instead of writing this yourself.  It's kind of like reinventing a concept that has been done to death in computer science.

best of luck with the project (and buy that book), ~Ray

0
 

Author Closing Comment

by:echocpt
ID: 33802205
Good sum up, will loom further into this. Good knowledge and useful information.
Thanks Alex
0

Featured Post

Easy Project Management (No User Manual Required)

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This article will explain how to display the first page of your Microsoft Word documents (e.g. .doc, .docx, etc...) as images in a web page programatically. I have scoured the web on a way to do this unsuccessfully. The goal is to produce something …
Deprecated and Headed for the Dustbin By now, you have probably heard that some PHP features, while convenient, can also cause PHP security problems.  This article discusses one of those, called register_globals.  It is a thing you do not want.  …
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now