M
Mike Hofer
BACKGROUND: We've designed a Website for a client that will be
deployed across multiple physical locations. The site will be hosted
from a corporate NOC, and administered by the IT group there.
The site's end-users tend to fill each others' roles on a pretty
frequent basis. Their permissions in the system have to be extremely
flexible. We initially wanted to use role-based security, defining
concrete roles, but when we realized how these folks worked, we
realized that that simply wouldn't work. Joe would one day be out
sick and Mary would sit in his desk and do his work for him. This
happens a *lot* in this particular company, and she would have to be
able to acquire his permissions. (Not very secure, but that's what
they want.)
As a result of this, we opted to skip the roles in the code (because
they couldn't really be concretely defined), and check for the
existence of *permissions* on the user. This check occurs on each page.
We don't really look for what roles the user is in; instead, we check
to see if he has a specific permission. If he has it, access is
granted; otherwise, he's presented with the Access Denied page. (The
menu system, a custom control, prevents the users from accessing these
pages in the first place, but the pages contain fail-safe code to
prevent the users from hard-coding the URLs as well.)
PROBLEM: The IT group has recently demanded that the system implement
role-based security. This has fairly stumped us. They want to be able
to create roles in the system, apply permissions to the role, and then
place the users in the role. The system should then check to see if the
user is in the role.
The problem here, as I see it, is that the roles are then *dynamic*,
and the role-based security in .NET isn't really dynamic in nature.
When you design a Web page, you kind of have an idea of what roles you
want to access it. For instance, assume you have a form that allows you
to fill out payroll forms. Generally speaking, you only want
individuals in the PayrollEmployees role to access that page, and
that's something you know before the site is designed and deployed.
So you can write code like this:
If Not user.IsInRole("PayrollEmployees") Then
Response.Redirect("~/AccessDenied.aspx")
End If
But how do you do this when you don't know the names of the roles
beforehand?
HYPOTHESIS: Bear in mind that this stuff all has to be done within our
application's interface, and that we need to be able to manage the
permissions within the database. The application has a lookup table
with the permissions in it. We could create a series of tables like
this:
+--------------------+
| Role |
+--------------------+
| ID (int) (PK) |
| Name (varchar[255])|
+--------------------+
+-------------------------+
| RolePermission |
+-------------------------+
| RoleID (int) (FK) | <-- Foreign key into Role table
| PermissionID (int) (FK) | <-- Foreign key into Permission table
+-------------------------+
+-------------------+
| UserRole |
+-------------------+
| UserID (int) (FK) | <-- Foreign key into User table
| RoleID (int) (FK) | <-- Foreign key into Role table
+-------------------+
The code is currently liberally sprinkled with calls to a method
(User.HasPermission), which takes a permission as an argument. This
method invokes a stored procedure which makes the determination. The
stored procedure can be rewritten to first get all the roles that have
the permission, and then determine whether or not the user is a member
of any of those roles. If the user is a member of any of those roles,
the method returns True.
QUESTION: Is this a viable solution? Is there a more efficient way to
do it that won't involve a major rewrite of the system? How would you
folks do this?
deployed across multiple physical locations. The site will be hosted
from a corporate NOC, and administered by the IT group there.
The site's end-users tend to fill each others' roles on a pretty
frequent basis. Their permissions in the system have to be extremely
flexible. We initially wanted to use role-based security, defining
concrete roles, but when we realized how these folks worked, we
realized that that simply wouldn't work. Joe would one day be out
sick and Mary would sit in his desk and do his work for him. This
happens a *lot* in this particular company, and she would have to be
able to acquire his permissions. (Not very secure, but that's what
they want.)
As a result of this, we opted to skip the roles in the code (because
they couldn't really be concretely defined), and check for the
existence of *permissions* on the user. This check occurs on each page.
We don't really look for what roles the user is in; instead, we check
to see if he has a specific permission. If he has it, access is
granted; otherwise, he's presented with the Access Denied page. (The
menu system, a custom control, prevents the users from accessing these
pages in the first place, but the pages contain fail-safe code to
prevent the users from hard-coding the URLs as well.)
PROBLEM: The IT group has recently demanded that the system implement
role-based security. This has fairly stumped us. They want to be able
to create roles in the system, apply permissions to the role, and then
place the users in the role. The system should then check to see if the
user is in the role.
The problem here, as I see it, is that the roles are then *dynamic*,
and the role-based security in .NET isn't really dynamic in nature.
When you design a Web page, you kind of have an idea of what roles you
want to access it. For instance, assume you have a form that allows you
to fill out payroll forms. Generally speaking, you only want
individuals in the PayrollEmployees role to access that page, and
that's something you know before the site is designed and deployed.
So you can write code like this:
If Not user.IsInRole("PayrollEmployees") Then
Response.Redirect("~/AccessDenied.aspx")
End If
But how do you do this when you don't know the names of the roles
beforehand?
HYPOTHESIS: Bear in mind that this stuff all has to be done within our
application's interface, and that we need to be able to manage the
permissions within the database. The application has a lookup table
with the permissions in it. We could create a series of tables like
this:
+--------------------+
| Role |
+--------------------+
| ID (int) (PK) |
| Name (varchar[255])|
+--------------------+
+-------------------------+
| RolePermission |
+-------------------------+
| RoleID (int) (FK) | <-- Foreign key into Role table
| PermissionID (int) (FK) | <-- Foreign key into Permission table
+-------------------------+
+-------------------+
| UserRole |
+-------------------+
| UserID (int) (FK) | <-- Foreign key into User table
| RoleID (int) (FK) | <-- Foreign key into Role table
+-------------------+
The code is currently liberally sprinkled with calls to a method
(User.HasPermission), which takes a permission as an argument. This
method invokes a stored procedure which makes the determination. The
stored procedure can be rewritten to first get all the roles that have
the permission, and then determine whether or not the user is a member
of any of those roles. If the user is a member of any of those roles,
the method returns True.
QUESTION: Is this a viable solution? Is there a more efficient way to
do it that won't involve a major rewrite of the system? How would you
folks do this?