Access Control with Bit Masks
Join the DZone community and get the full member experience.
Join For FreeHere is a little theory about Bitwise Operators:
Example | Name | Result |
---|---|---|
$a & $b | And | Bits that are set in both $a and $b are set. |
$a | $b | Or (inclusive or) | Bits that are set in either $a or $b are set. |
$a ^ $b | Xor (exclusive or) | Bits that are set in $a or $b but not both are set. |
~ $a | Not | Bits that are set in $a are not set, and vice versa. |
$a << $b | Shift left | Shift the bits of $a $b steps to the left (each step means “multiply by two”) |
$a >> $b | Shift right | Shift the bits of $a $b steps to the right (each step means “divide by two”) |
Live Demo
download in package
Now – download the source files and lets start coding !
Step 1. HTML
Our demo uses 3 html template files:
main_page.html
<!DOCTYPE html> <html lang="en" > <head> <title>Access Control with Bit Masks</title> <link href="css/main.css" rel="stylesheet" type="text/css" /> </head> <body> <header> <h2>Access Control with Bit Masks</h2> <a href="http://www.script-tutorials.com/access-control-with-bit-masks/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a> </header> <div class="container"> {form} </div> </body> </html>
This is a very easy layout, isn’t it?. Next template file:
login_form.html
<div class="column"> <h3>Access control demonstration</h3> <p>You can use next usernames "User", "Writer", "Moderator" and "Admin" and password "password" to login in system. Each of them have own set of possibilities.</p> </div> <div class="column"> <form class="login_form" action="index.php" method="post"> <h3>Log In</h3> <label>Username:</label><input type="text" name="username"> <label>Password:</label><input type="password" name="password"> <input type="submit" name="LogIn" value="Login"> </form> </div>
Another one easy template for the login form. Next template file:
logout_form.html
<div class="column"> <h3>Hello {name}</h3> <h3>Your bit mask:</h3> <div>{bit_mask}</div> <h3>Your possibilities:</h3> <div>{possibilities}</div> </div> <div class="column"> <a href="index.php?logout">Log Out</a> </div>
This is a template where we will display the user's possibilities and link to the logout.
Step 2. CSS
css/main.css
This file contains several styles of our page layout, no need to publish it today.
Step 3. PHP
Now, let's review our main functionality:
index.php
<?php // define bit mask for access rights define('CAN_READ', 1 << 0); // 000001 define('CAN_CREATE', 1 << 1); // 000010 define('CAN_EDIT_OWN', 1 << 2); // 000100 define('CAN_DELETE_OWN', 1 << 3); // 001000 define('CAN_EDIT_ANY', 1 << 4); // 010000 define('CAN_DELETE_ANY', 1 << 5); // 100000 // login system init and generation code $oSimpleAccessSystem = new SimpleAccessSystem(); $sLoginForm = $oSimpleAccessSystem->getLoginBox(); echo strtr(file_get_contents('main_page.html'), array('{form}' => $sLoginForm)); // class SimpleAccessSystem class SimpleAccessSystem { // variables var $aMembers; // Existed members array // constructor function SimpleAccessSystem() { session_start(); // different sets of permissions $sUserPerm = CAN_READ; $sWriterPerm = CAN_READ | CAN_CREATE | CAN_EDIT_OWN | CAN_DELETE_OWN; $sModeratorPerm = CAN_READ | CAN_EDIT_ANY | CAN_DELETE_ANY; $sAdminPerm = CAN_READ | CAN_CREATE | CAN_EDIT_OWN | CAN_DELETE_OWN | CAN_EDIT_ANY | CAN_DELETE_ANY; /* hash = sha1(md5('password') . 'testing'); */ $this->aMembers = array( 'User' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sUserPerm), 'Writer' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sWriterPerm), 'Moderator' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sModeratorPerm), 'Admin' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sAdminPerm) ); } // get login box function function getLoginBox() { if (isset($_GET['logout'])) { // logout processing if (isset($_SESSION['member_name']) && isset($_SESSION['member_pass'])) $this->performLogout(); } if ($_POST && $_POST['username'] && $_POST['password']) { // login processing if ($this->checkLogin($_POST['username'], $_POST['password'], false)) { // successful login $this->performLogin($_POST['username'], $_POST['password']); header( "Location:{$_SERVER['REQUEST_URI']}" ); exit; } else { // wrong login ob_start(); // get template of Login form require_once('login_form.html'); $sLoginForm = ob_get_clean(); return $sLoginForm . '<h2>Username or Password is incorrect</h2>'; } } else { // in case if we already logged (on refresh page): if (isset($_SESSION['member_name']) && $_SESSION['member_name'] && $_SESSION['member_pass']) { if ($this->checkLogin($_SESSION['member_name'], $_SESSION['member_pass'])) { $sRule = $this->aMembers[$_SESSION['member_name']]['rule']; $sPermissions = ''; $sPermissions .= $this->isCanRead($sRule); $sPermissions .= $this->isCanCreate($sRule); $sPermissions .= $this->isCanEdit($sRule); $sPermissions .= $this->isCanEditAny($sRule); $sPermissions .= $this->isCanDelete($sRule); $sPermissions .= $this->isCanDeleteAny($sRule); ob_start(); // get template of Logout form require_once('logout_form.html'); $sLogoutForm = ob_get_clean(); $sLogoutForm = str_replace('{name}', $_SESSION['member_name'], $sLogoutForm); $sLogoutForm = str_replace('{bit_mask}', $sRule, $sLogoutForm); $sLogoutForm = str_replace('{possibilities}', $sPermissions, $sLogoutForm); return $sLogoutForm; } } // otherwise - draw login form ob_start(); require_once('login_form.html'); $sLoginForm = ob_get_clean(); return $sLoginForm; } } // check functions function isCanRead($sRule) { return ($sRule & CAN_READ) ? 'You can Read<br />' : ''; } function isCanCreate($sRule) { return ($sRule & CAN_CREATE) ? 'You can Create<br />' : ''; } function isCanEdit($sRule) { return ($sRule & CAN_EDIT_OWN) ? 'You can Edit<br />' : ''; } function isCanEditAny($sRule) { return ($sRule & CAN_EDIT_ANY) ? 'You can Edit anything<br />' : ''; } function isCanDelete($sRule) { return ($sRule & CAN_DELETE_OWN) ? 'You can Delete<br />' : ''; } function isCanDeleteAny($sRule) { return ($sRule & CAN_DELETE_ANY) ? 'You can Delete anything<br />' : ''; } // perform login function performLogin($sName, $sPass) { $this->performLogout(); $sSalt = $this->aMembers[$sName]['salt']; $sPass = sha1(md5($sPass) . $sSalt); $_SESSION['member_name'] = $sName; $_SESSION['member_pass'] = $sPass; } // perform logout function performLogout() { unset($_SESSION['member_name']); unset($_SESSION['member_pass']); } // check login function checkLogin($sName, $sPass, $isHash = true) { if (isset($this->aMembers[$sName])) { if (! $isHash) { $sSalt = $this->aMembers[$sName]['salt']; $sPass = sha1(md5($sPass) . $sSalt); } return ($sPass == $this->aMembers[$sName]['hash']); } return false; } }
First, we define the constants for access rights (bit mask). Further, when we enumerate users on the system – we grant them different sets of rights (using the logical operator | or). Keep in mind that I am not forcing you to keep users in the same array, in your case, your users can easily be in the database. And, in this case, you can grant them their right in the database itself. Further, I have added extra check functions, so that we can understand if the user can perform a certain action.
In such functions we use the logical operator & (and). Most of these checks use a single bit check. If you want to do multiple check, for example – let's create a function to check if the member can read and create. Then this function will looks like this:
function isCanReadCreate($sRule) { return ($sRule & (CAN_READ | CAN_CREATE)); }
This function will return True or False.
Live Demo
download in archive
Conclusion
I hope that it was interesting for you to remember how bitwise and logical operands work. If you have any good ideas you would like to share, be sure to write us as well. Good luck!
Source: http://www.script-tutorials.com/access-control-with-bit-masks/
Opinions expressed by DZone contributors are their own.
Comments