An ASP.NET Blog
I work for Microsoft and help people and businesses make better use of technolgy to realize their full potential. The opinions mentioned herein are solely mine and do not reflect those of my employer.

Setting Role cookie at the Application Level in Role Based Authorization - Forms Authentication

Monday, April 25, 2005 7:42 AM
Hi,

When using Role Based Authorization, we can set the Roles of a user at the application level by specifying it in the Global.asax's Application_AuthenticateRequest method.

As soon as a user is authenticated, it will fetch his roles from the database and assign it to him so that we can use the User.IsInRole("RoleName") to check his role and perform actions based on the same.

You can find many resources on the above topic on how to set the roles. However, one disadvantage is that on every page you check the Role, the DB call is made which might affect the performance of the application.

To resolve that we can set the role cookie manually through code so that it doesnt make the DB call for every request.

The following code segment provides the code for the total operation.


In the Global.asax's code behind file, locate the following method and put the code inside as follows:-



protected void Application_AuthenticateRequest(Object sender, EventArgs e)

{

AssignRolesToUser();

}




Then place the following code segment.





private void AssignRolesToUser()

{

if (Context.Request.IsAuthenticated)

{

// Retrieve user's identity from context user

FormsIdentity ident = (FormsIdentity) Context.User.Identity;



// Retrieve roles from the authentication ticket userdata field

string[] roles = ident.Ticket.UserData.Split('|');



// If we didn't load the roles before, go to the DB

if (roles[0].Length == 0)

{

// Fetch roles from the database.

roles = FetchRoles();



// Store roles inside the Forms ticket.

FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(

ident.Ticket.Version,

ident.Ticket.Name,

ident.Ticket.IssueDate,

ident.Ticket.Expiration,

ident.Ticket.IsPersistent,

String.Join("|", roles),

ident.Ticket.CookiePath);



// Create the cookie.

HttpCookie authCookie = new HttpCookie(

FormsAuthentication.FormsCookieName,

FormsAuthentication.Encrypt(newticket));

authCookie.Path = FormsAuthentication.FormsCookiePath + "; HttpOnly; noScriptAccess";

authCookie.Secure = FormsAuthentication.RequireSSL;



if (newticket.IsPersistent)

authCookie.Expires = newticket.Expiration;



Context.Response.Cookies.Add(authCookie);

}



// Create principal and attach to user

Context.User = new System.Security.Principal.GenericPrincipal(ident, roles);

}

}







private string[] FetchRoles()

{

// Fetch roles from the database somehow.

ArrayList roleList = new ArrayList();

SqlDataReader objRdr=null;



SqlConnection objCon = new SqlConnection("Your connection string here);

SqlCommand objCmd = new SqlCommand("spRoles", objCon);

objCmd.CommandType = CommandType.StoredProcedure;

objCmd.Parameters.Add("@Username", User.Identity.Name.ToString());

try

{

objCon.Open();

objRdr = objCmd.ExecuteReader();

if(objRdr.HasRows)

{

while(objRdr.Read())

{

roleList.Add(objRdr["RoleName"].ToString());

}

}

objRdr.Close();

}

catch

{

return null;

}

finally

{

objCon.Close();

objCon.Dispose();

}

return (string[])roleList.ToArray (typeof (string));

}






The procedure spRoles will fetch the roles based on the UserName which is passed as a parameter.

The code for the procedure is as below:-



CREATE PROCEDURE spRoles

(

@Username varchar(50)

)

AS



SELECT G.Name

FROM Roles R

INNER JOIN Groups G ON

R.GroupID = G.GroupID

INNER JOIN Users U ON

R.UserID = U.UserID AND U.Username = @Username




In the above procedure I have used three sample tables Users, Groups and Roles

Users - will contain UserID, UserName and password
Groups - will contain GroupID and Name i.e. Admin, Moderator, User
Roles - will contain the UserID and their GroupID i.e. group they are assigned to.


Once you set the above Roles, thereafter in your pages, you can just use

if(Context.User.IsInRole("RoleName"))
{
// do something
}


Queries, Comments and Suggestions are welcome.

Thanks.

Feedback

# re: Setting Role cookie at the Application Level in Role Based Authorization - Forms Authentication

Correct me if I'm wrong, but doesn't this create a security problem?

Let's say you have a role called "admin" and only members of this role can access secure pages. If I edit my cookie and put "admin" in the userData section, I would gain access to the secure pages.

Now, you could encrypt the cookie which would make it far more difficult to achieve. But without verifying the cookie data with the database of roles, how can you be certain to allow the user access? Doesn't this fall under the heading of "Never trust user input"?

I'm currently working on this myself, so if I am wrong or if you have a different suggestion, I would be curious to hear it. 5/29/2008 10:18 AM | MCM

Post a comment





 

Please add 5 and 7 and type the answer here: