WebDevelopersJournal.comTips on Web Page Design, HTML and Graphics
SITE SEARCH
Newsletters
HTML (M-F) Text (M,TH)



Jobs at webdeveloper.com

Resources By Subject
Technical
Graphical
Authoring
Business
WDJ resources
Archive

internet.com

internet.commerce
  • Partner With Us
















Developer Channel


Find a web host with:
CGI Access DB Support Telnet Access
NT Servers UNIX Servers



Semi-automatic?

JavaScript
JavaScript Helper:
Meet Paige Turner, the least geeky geek we've ever come across.

Variables and Operators Explained:
First of a three part guide to JavaScript basics.

Controlling Forms:
Enhance your HTML forms with a touch of JS.

DHTML:
Forget how it works, let's see some in action!


A Solution to the User Privilege Challenge

by Al Hetzel

Simplifying the mechanism for who can see what.

Perhaps the greatest challenge in the development arena is security, particularly as applications grow in size and complexity. Defining user access privileges for an application with a small number of users is straightforward. But as new groups of users are added, it can become messy. The company I work for, KPMG LLP, faced this challenge. Here are the solutions we considered and details of the solution we finally used. Ours is an ASP system, but many of the principles can be applied to other set-ups as well.
September 20, 2000

The following HTML code snippet is a very simplified example that I will be using throughout this article.

<a href="create.htm">Create Order</a><br>
<a href="edit.htm">Edit Order</a><br>
<a href="delete.htm">Delete Order</a><br>
<a href="report.htm">Run Reports</a><br>

This snippet shows four links. Each link represents a different section of an application.

Groups

The original application used groups to determine who can see what link, since not all users need access to all applications. The groups were assigned based on the login name of the user who logged in. Most users were normal users (userGroup="Users"). The remaining few were administrators (userGroup="Admin").

All users were allowed to create or edit orders, but only the administrators were allowed to delete an order or run a report. A simple if..then statement in the ASP code allowed this easily. If the user was in the "Admin" group, then the last two links were shown. Otherwise, they were not.

<a href="create.htm">Create Order</a><br>
<a href="edit.htm">Edit Order</a><br>
<%if userGroup="Admin" then%>
<a href="delete.htm">Delete Order</a><br>
<a href="report.htm">Run Reports</a><br>
<%end if%>

This worked very well for a single company (called Company 1). However, as new companies were added, difficulties were encountered. Each company had their own set of requirements that had to be incorporated into the code. We could have given each company a separate page, but this would have led to maintenance problems.

For the purpose of this example, I will add 2 more companies.

Company 2 has three user types. First, there is the DataEntry user who can create, edit, or delete orders but cannot run any reports. Second, there is the Management user who can run reports but cannot create, edit, or delete orders. Third, there is the SuperUser who can do anything.

Company 3 has two user types. First, there is the DataEntry user who can create orders only. Second, there is the Reps user who can edit or delete orders but cannot create them. Company 3 does not want any reports.

These two companies requirements were added to the code, which then looked like this.

<% if ( company="1" ) or _
( company="2" and userGroup="DataEntry" ) or _
( company="2" and userGroup="SuperUser" ) or _
( company="3" and userGroup="DataEntry" ) then %>
<a href="create.htm">Create Order</a><br>
<% end if %>

<% if ( company="1" ) or _
( company="2" and userGroup="DataEntry" ) or _
( company="2" and userGroup="SuperUser" ) or _
( company="3" and userGroup="Reps" ) then %>
<a href="edit.htm">Edit Order</a><br>
<% end if %>

<% if ( company="1" and userGroup="Admin" ) or _
( company="2" and userGroup="DataEntry" ) or _
( company="2" and userGroup="SuperUser" ) or _
( company="3" and userGroup="Reps" ) then %>
<a href="delete.htm">Delete Order</a><br>
<% end if %>

<% if ( company="1" and userGroup="Admin") or _
( company="2" and userGroup="Management" ) then %>
<a href="report.htm">Run Reports</a><br>
<%end if%>

This simple example is not so simple any more. Any additional companies will only compound the problem.

Privileges

What we needed was a way to let each user have exactly the access that they needed. Also, we wanted to make sure that it was scalable. Once a page was done, we wanted it to stay done regardless of how many other companies were added. We did this by using privileges.

Privileges are just a handy way to identify a single type of action. If the user can create an order, they get the CreateOrder privilege that will allow this. If they can edit an order, they get the EditOrder privilege, and so forth.

The question now is where and how to store the privileges. For readability, we used Boolean values as the privilege. This would allow us to write the if..then statements like statement. (If the user can create an order, then do this, else do something else.) The where was more difficult.

Boolean Array

A standard Boolean array was the first thought. Each privilege would have its own place in the array. That privilege would be set to either true or false depending on the user. The code would look like the following.

<% if ( bPrivileges(1) ) then %>
<a href="create.htm">Create Order</a><br>
<% end if %>

<% if ( bPrivileges(2) ) then %>
<a href="edit.htm">Edit Order</a><br>
<% end if %>

<% if ( bPrivileges(3) ) then %>
<a href="delete.htm">Delete Order</a><br>
<% end if %>

<% if ( bPrivileges(4) ) then %>
<a href="report.htm">Run Reports</a><br>
<%end if%>

Advantages. All of the privileges are stored in a single object that would let all of the privileges be removed immediately when the user logs out.

Disadvantages. The array has numbered elements. The CreateOrder privilege is number 1, the EditOrder privilege is number 2, and so forth. If the order ever changed or if privileges were ever added or removed, the entire security system would have to be updated. The code is not readable at all and would require severe commenting just to be usable.

The disadvantages outweighed the advantages so we decided against using this solution.

Session Variables

The second solution suggested was to create a session variable for each privilege and then assign true to each privilege that the user has. Since session variables only affect the user that creates them, this seems to be a pretty good solution. The code would look like the following.

<% if ( session("CreateOrder") ) then %>
<a href="create.htm">Create Order</a><br>
<% end if %>

<% if ( session("EditOrder") ) then %>
<a href="edit.htm">Edit Order</a><br>
<% end if %>

<% if ( session("DeleteOrder") ) then %>
<a href="delete.htm">Delete Order</a><br>
<% end if %>

<% if ( session("RunReports") ) then %>
<a href="report.htm">Run Reports</a><br>
<%end if%>

Advantages. This code is very readable with it being possible to determine at a glance what each privilege is and what it does. Adding new or deleting old privileges would not affect the code at all since they are called by name and not number.

Disadvantages. Each session variable is separate in memory from all of the others. Therefore clean up of the variables becomes the major problem. When the user logs out, it is possible that one or more of the variables do not get removed as they should.

Again, the disadvantages outweighed the advantages so this solution was rejected. We did notice that the advantages of this method were listed as the disadvantages of the previous method and vice versa. What we needed was some way to combine the two methods.

Dictionary Objects

The dictionary object would do just that. A dictionary object is an associative array so it stores the values by name rather than by number. That makes it very readable and eliminates the problem with numbering. Also, since it is a single object, it is much easier to control than multiple objects. The code using a dictionary object looks like the following.

<% if ( session("userPrivileges").Item("CreateOrder") ) then %>
<a href="create.htm">Create Order</a><br>
<% end if %>

<% if ( session("userPrivileges").Item("EditOrder") ) then %>
<a href="edit.htm">Edit Order</a><br>
<% end if %>

<% if ( session("userPrivileges").Item("DeleteOrder") ) then %>
<a href="delete.htm">Delete Order</a><br>
<% end if %>

<% if ( session("userPrivileges").Item("RunReports") ) then %>
<a href="report.htm">Run Reports</a><br>
<%end if%>

We found no major disadvantages to using a dictionary object and adopted this method.

Assignment Methods

Now that we had chosen a method for storing the privileges, we needed some way to populate the dictionary object. We chose to use a database table that matched the privileges with the user. See the code snippet below.

<%
set conn = getDBConnection()

sSql = "select privilege from user_privilege where user = '" & userName & "' )"

set rsPrivileges = conn.Execute( sSql )

do until rsPrivileges.EOF
session("userPrivileges").Add cStr( rsPrivileges(0) ), true
rsPrivileges.MoveNext
loop
%>

The user_privilege table holds all of the privileges that the user is able to see. Those privileges are loaded in using a recordset and then added to the dictionary object. Since the table only holds the privileges that the user has, they are all added as true. An interesting quirk of the dictionary object is that if an item is checked that is not there, it adds it as its default value. The default value for a Boolean is false.

There are other ways to accomplish loading the privileges without using a database. All of the privileges could be stored in an application variable with either session or application variables determining what a particular user can do. Also, the privileges could be stored on the client machine as cookies. We prefer database driven techniques, and that is why we chose the solution above.

Possible Uses

In this article, I have only discussed how to use privileges to limit various links. They can also be used for such things as determining program flow, altering functionality and completely changing the look and feel of the web site depending on the user logging in. Below are several situations that we found privileges to be of particular use.

We have a list of reports. Some of the reports can only be seen by particular companies. Other reports can only be seen by particular users within the companies. We assign privileges to each of the reports and then only give each user the privileges (and thereby the reports) they need.

Several parts of the application function differently depending on the user that is logged in. For instance, a regular user might go to the user maintenance page and only be able to update their own record. An administrator user would go to the same page and see a list of users that they are able to change. This is controlled exclusively with privileges.

We have a demo application that is used as a preview to our main application. While this application shows all of the same features as our main one, pressing any of the buttons will only show a page with the description of the functionality that would have been available if this was not just a demo. The demo is nothing more than our main application being accessed by a user with no privileges.

These are just a few of the uses. With a little bit of imagination, there are a lot more possibilities.

Al Hetzel is an Oracle DBA/Web Developer in Dallas, Texas for KPMG LLP.
Suits PonytailsPropheadsContact WDJDiscussWeb AudioSearch

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers