Introduction
Security in web applications is something necessary nowadays; especially because everyday attacks are in increase. But in this article, we are not going to discuss the authentication of a web application, we are going to discuss a simple and powerful way for authorization instead.
Background
In the Web Application Security Model, there are two essential terms in use: Authentication and Authorization; it's very necessary to differentiate between the two.
Authorization is the mechanism in which systems securely identify users to know who the user really is and if the user is whom he is claiming he is.
Authentication is the mechanism in which systems determine what level of access an authenticated user should have to secured resources in the system. And this includes: accessing resources and performing operations.
This article focuses on authorization. As there are a lot of ways for authorization (we are not going to discuss them in this article), we are going to discuss one of them in this article, which is using .NET Attributes.
Using the code
A .NET attribute is a class that can be used on the header of another class, method, delegate, property, etc ... and it should be inheriting from the class System.Attribute
. We will create our own attribute as follows:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Method, AllowMultiple = false)]
public class PrivilegedObjectAttribute : System.Attribute
{
private string m_PrivilegeCode;
public string PrivilegeCode
{
get { return m_PrivilegeCode; }
set { m_PrivilegeCode = value; }
}
public PrivilegedObjectAttribute(string privilegeCode)
{
m_PrivilegeCode = privilegeCode;
}
}
This attribute class will be used with classes and methods. Surely, you can identify more of these if you want, but for the purposes of this sample, we will have just these two.
The AllowMultiple
property indicates whether we can use more than one attribute on each class or method, we will be using only one privilege for each class or method.
Note that we have a simple privilege object which will only have the privilege code attribute as a string, which we will use.
Next, we will use the BasePage
class for pages and BaseUserControl
for User Controls. BasePage
inherits from the System.Web.UI.Page
class, and each page in the application we want to apply the privileges to should inherit from the BasePage
class. This is for code reuse and so that the same code will handle the authorization of all pages.
The most important thing in the BasePage
is the OnInit
method; we will override this method to include our authorization code, and the BasePage
will look something like this:
public class BasePage : Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
int userID = SecurityHelper.UserID;
string pagePrivilegeCode = SecurityHelper.GetPrivilegeCode(this);
if (!string.IsNullOrEmpty(pagePrivilegeCode))
{
bool authorized =
SecurityHelper.UserHasThePrivilege(userID, pagePrivilegeCode);
SecurityHelper.RaiseAuthorizationDescision(this, authorized);
}
}
}
Now, once a user needs authorization, when asking for a page in the application, he will enter the base page of that page first, and there he will be asked for authorization information. This is done in the OnInit
life cycle of the page.
Now to apply a privilege on a certain page, for example, the HumanResources.aspx page, the code-behind of the page will look something like this:
[PrivilegedObject ("PRV_HUMANRESOURCES")]
public partial class HumanResources : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
Note the usage of the PrivilegedObject
attribute. It takes a string as a parameter, which will indicate the privilege of the page. Of course, you can use an enum instead of a string, for example. And, note that each page has its own privilege and only one privilege. Authenticated users should have these privileges stored in the database, for example, so when adding a new page with a new privilege, you have to add that privilege to the database as well so that admin users can map that privilege to normal users.
To summarize, the Authorization mechanism by .NET happens as follows:
- Get the authenticated User ID (to get his privileges later)
- Get the current page privilege
- Return a value of whether the current user has the privilege
- Raise the authorization decision, which is taken by specifying the authorization object (a page) and the authorization result (authorized or not)
The RaiseAuthorizationDecision
method either makes the current page accessible or not. If the user is not authorized, then you can redirect the user to the AccessDenied
page:
public static void RaiseAuthorizationDescision(object authorizationObject, bool authorized)
{
if (!authorized)
{
if (authorizationObject is Page)
{
Page currentPage = authorizationObject as Page;
currentPage.Response.Redirect("AccessDenied.aspx?BackUrl=" +
currentPage.Server.UrlEncode(currentPage.Request.UrlReferrer.PathAndQuery));
}
else if (authorizationObject is UserControl)
{
UserControl currentControl = authorizationObject as UserControl;
}
}
}
In the AccessDenied
page, there will be a link to redirect the user back to the page he was in before his authorization was declined:
public partial class AccessDenied : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnBackUrl_Click(object sender, EventArgs e)
{
string backUrl=this.Request.QueryString ["BackUrl"];
this.Response.Redirect(backUrl);
}
}
The same concept almost applies for User Controls. The main difference is the action taken when the user is not authorized. You probably want to make the User Control invisible for the user on that page, or do whatever you think is appropriate for your application.
Points of interest
There are a few points you should take care of when implementing this model of authorization:
- Non-privileged pages: if you add a page that inherits from the
BasePage
class but you did not apply the PrivilegedObject
attribute to it, then you have two options: either make that page accessible by default or non-accessable by default, for me, I think I will treat it to be accessable by default - Static pages and dynamic Pages: in this example, we talked so far about static pages, or static page functions in which the page only does a specific operation, or view, or something like that, instead of dynamic pages in which the contents of a page will vary dynamically depending on some kind of business logic - in this case, the privileged page will control all the operations in the page, so you have to figure out some way to control it depending on your business in that page, or use User Controls to grant dynamic privileges.
Summary
This authorization model is just one of a lot of other authorization models that exist or that you could think of, but I think there is some kind of simplicity and clarity in using this model. Definitely, you could add and enhance this model to suit your business. I have used this model and I have simplified this foe the purposes of this article.