Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Earlier this summer I posted two tutorials on using Windows Authentication with ASP.NET: Enabling Window Authentication within an Intranet ASP.NET Web Application and Implementing Role Based Security within ASP.NET using Windows Authentication and SQL Server.  I also linked to Scott Mitchell's great ASP.NET 2.0 Security, Membership and Roles Tutorials that cover how to use Forms Authentication and the new Membership/Roles APIs in ASP.NET for Internet based web applications.

These tutorials covers how to implement authentication on your site, which is the process of identifying who an incoming user is.  They also demonstrate how to implement role based management on your site, which allows you to logically group individual users into higher-level roles or groups (for example: "admins", "friends", "subscribers", etc).  The tutorials also demonstrate how to implement authorization rules to grant or deny users/roles access to visit individual pages or URLs within a site (the roles tutorial above also demonstrates how to show/hide menu nodes based on the permissions of the incoming user).

Adding Security Authorization Rules to Business and Data Layers

When you authenticate a user within an ASP.NET application, the authenticated user's identity will be automatically flowed throughout that user's request on the server.  What this means is that you don't need to manually pass a user's identity around from method to method or class to class.  This makes it much easier to implement security authorization rules throughout your application.

One little known feature in .NET is the ability to have the CLR automatically use this identity information to authorize a user's capabilities before instantiating a class, or accessing a method/property on it.  This makes it easy to add clean security authorization rules to your business and data layers without having to write much code.

All you need to do to implement this is to use the PrincipalPermissionAttribute within the "System.Security.Permissions" namespace and decorate it on the appropriate class or member on it.  For example:

using System;
using System.Security.Permissions;

[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public class EmployeeManager
{
    [PrincipalPermission(SecurityAction.Demand, Role 
"Manager")]
    
public Employee LookupEmployee(int employeeID)
    {
       // todo
    }

    [PrincipalPermission(SecurityAction.Demand, Role 
"HR")]
    
public void AddEmployee(Employee e)
    {
       // todo
    }
}

In the above example, I have added a PrincipalPermission attribute to the "EmployeeManager" class.  By adding it I am requiring that a user must be authenticated (logged-in) before this class can be instantiated during a web request (the Authenticated=true demand enforces this).  I have also then added two additional security demands on the "LookupEmployee" and "AddEmployee" methods.  With the LookupEmployee method I am requiring that the authenticated user for the request is within the "Manager" role in order for the method to be invoked.  With the AddEmployee method I am requiring that the authenticated user for the request is within the "HR" role in order for this method to be invoked and have a new Employee added to the system.

And now if I accidentally introduce a security hole within my UI tier and have some code-path that allows a non-Manager/HR employee to cause these methods to be invoked, my business tier will automatically prevent this from happening and raise a security exception.  

The PrincipalPermissionAttribute isn't tied to any specific authentication mode.  It will work with Forms Authentication, Windows Authentication, Passport Authentication, or any custom authentication mode you want to invent.  It will also work with any Role implementation I might use (so if you build or plug-in your own Role Provider in ASP.NET it will just work).

The PrincipalPermissionAttribute type is implemented in the standard CLR mscorlib assembly that all .NET projects compile against.  So it isn't ASP.NET specific, and can be used within any application type (including Windows and Console applications).  In addition to making it more generically useful, this makes it easier to unit-test business/data libraries built with it.

Using PrincipalPermissionAttributes within Pages and Controls

The PrincipalPermissionAttribute can be used on any class within an application.  So in addition to using it within your business and data layers, you can also use it within ASP.NET pages or user-controls you author in your site as well.  For example, to enforce that your "MyPage" page can only be used by those within the "Manager" role, you could add a PrincipalPermission attribute to the code-behind of it (below done in VB):

Imports System.Security.Permissions

<PrincipalPermission(SecurityAction.Demand, Authenticated:
=True, Role:="Manager")> _
Partial Class MyPage
    
Inherits System.Web.UI.Page

End Class

More on ASP.NET Security

To learn more about ASP.NET security I'd recommend checking out my ASP.NET Security Resources list as well as my ASP.NET Tips and Tricks Page.

There are also now two dedicated books on ASP.NET 2.0 Security out there: Stefan Schackow's Professional ASP.NET 2.0 Security, Membership and Role Management book and the new Developing More Secure Microsoft ASP.NET 2.0 Applications book by Dominick Baier (who runs the great http://www.leastprivilege.com/ blog) that just got published this week:

Hope this helps,

Scott

Published Wednesday, October 04, 2006 8:50 AM by ScottGu

Comments

# Authorization Rules

Wednesday, October 04, 2006 3:02 PM by Mike Diehl's WebLog

ScottGu posted an article showing how to add authorization rules to business and data layers. In his

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Wednesday, October 04, 2006 3:50 PM by Plip
Nice trick! :-)

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Wednesday, October 04, 2006 4:29 PM by Jeff
There are so many neat things like this in the framework that I'm sure we'd all use if we knew they were there. Well done! This is cool stuff.

# Specifying Authorization Rules for the Business Logic or Data Access Layers (BLL/DAL)

Wednesday, October 04, 2006 7:48 PM by Community Blogs

In my Limiting Data Modification Functionality Based on the User (C# version) tutorial, I show how to

# Link Listing - October 4, 2006

Wednesday, October 04, 2006 10:33 PM by Christopher Steen
Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes...

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Wednesday, October 04, 2006 10:52 PM by Cesar
Excellet Tip, I was looking for a way to validate the Roles against a control inside a page, this is the solution, is excelent, thanks a lot. Cesar

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 05, 2006 2:36 AM by MichaelF
The ideea of having class and method security permissions is excellent. But i can see a major shortcoming of the PrincipalPermissionAttribute: the developer must decide on the Role which has the execution permission. A nice feature would be if the Role is replaced by a tag. Then the tags, roles and their associations could be managed from somewhere else, for example AuthorizationManager (tags <=> operations).

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 05, 2006 6:00 AM by Aaron
Scott, We really wanted to use these security features in ASP.net 1.1 app that we were writing for a large government customer. The problem was that it was a new organization and the “roles” were evolving and being re-defined and renamed on a continual basis as the org settled in. We couldn’t do anything with this because the roles in the security demands have to be hard coded in. At least as best as I could tell. It would be nice if these could be mapped to the web.config. Cheers, Aaron

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 05, 2006 9:58 AM by Rodrigo
Hi Scot I know this comment has nothing to do with your post ..but I am implementing a Custom Atlas Extender control that is basically a better Data Grid. You can see a live sample at http://www.rodrigodiniz.qsh.eu/atlasyuigrid.aspx Features: -Column resizing -Drag and drop row sorting(I have to upload this) -Tableless -Pure Ajax

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 05, 2006 10:20 AM by ScottGu

Hi Aaron,

The string values for roles should be mappable to resource strings - which would allow you to store these separately from the action code (allowing you to name the roles whatever you want).

Michael and Mike have a nice request above which is the ability to add another level of indirection, where the assertions are for capabilities and then a separate store is used to map which roles have those capabilities.

Permission stores like AZMan give you the ability to define capabilities<->roles<->user mappings like this.  In theory you could create a similar attribute to the PrincipalPermission one above that uses this store to perform those security checks.

Hope this helps,

Scott

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 05, 2006 11:03 AM by Dom
Scott, I thought this feature was limited to COM+. About the only use for COM+ that I can find is asynchronous execution. Nice to know about these features. Can I set the values in web.config, accessing them this way?

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 05, 2006 10:19 PM by Val
When a user without the access to the role specified tries to access the method, the SecurityException is thrown. How to catch that exception? If I use that attribute for a UserControl, I just would like that control not to render. However, I was not able to catch the Security Exception. Thanks.

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Friday, October 06, 2006 8:39 AM by NicoB
Scott, I tried to map the string value to a resource string but I keep getting an error when I compile the project: "An attribute argument must be a constant expression, typeof expression or array creation expression" Here's a code snippet: [System.Security.Permissions.PrincipalPermission(System.Security.Permissions.SecurityAction.Demand, Role = Resources.Resource.Role)] Please, can you give me a tip I can use to map the Role value to a resource string in order to change it without hardcoding it. Thx! NicoB.

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Friday, October 06, 2006 2:04 PM by Richard P

Workaround for dynamic role names:

Use nested groups on the MembershipProvider side.

For example, at the time of coding, you know the final name of the Managers group is going to change.  So you hard-code "DONOTUSE My Application Managers" and just make sure the final Managers group is in that group.

Obviously, this strategy won't work if your provider doesn't support nested membership.

# Code Decorating for Security

Tuesday, October 10, 2006 4:11 AM by Dan's Bloggings

In this article, Scott blogs about using decorations (code attributes) to apply security restrictions to code. There are some especially helpful comments on the blog that are worth reading too, such a ...

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Tuesday, October 10, 2006 7:26 AM by Martin
Great article, thanks! Is it possible to specify the PrincipalPermission attribute in the ASPX instead of the code-behind (e.g. in the @Page directive)? This would allow to change the security without having to recompile the application. Thanks.

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Tuesday, October 10, 2006 10:59 AM by ScottGu

Hi Nico,

I checked with a few folks on my team, and unfortunately it looks like the PrincipalPermission attribute doesn't support pulling the role-name from a resource provider like I thought. :-(

Sorry about that,

Scott

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Tuesday, October 10, 2006 11:01 AM by ScottGu

Hi Martin,

There isn't a built-in way to set this via the page directive.  However, you could use this technique to extend the page directive to allow this to be specified: http://weblogs.asp.net/scottgu/archive/2005/08/02/421405.aspx

You could then use this within your base class to check the permissions.

Alternatively, I'd recommend using the web.config authorization model if you want to store these settings separately from the application code.

Hope this helps,

Scott

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 12, 2006 5:20 PM by Jeff Gonzalez
I think you can create an instance of PermissionPrincipal instead of using the attribute if you need more flexibility. It isn't as "neat" as using the declarative form, but it still works I think. Pseudocode Example: //Assume Resources.Roles.Manager is "Manager" try { PermissionPrincipal permPrincipal = new PermissionPrincipal( User.Identity.Name, Resources.Roles.Manager); permPrincipal.Demand(); } catch (SecurityException ex) { //handle noauthZ here }

# Adding Authorization to Business Layers

Friday, October 13, 2006 7:58 AM by Technical Weblog of Eric Charran

Scott Guthrie has written a great article on adding authorization attributes and security attributes

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Sunday, October 15, 2006 5:16 PM by Johann Oosthuizen
Hi Scott, I am in a bit of a fix. I require the built-in providers because my application has personalization as a requirement. My UI tier connects to my business tier via ASP XML webservices. As far as i know there is no provider for webservices out of the box. How do I combine personalization & authentication & authroization & webservices effectively?

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Monday, October 16, 2006 1:04 AM by ScottGu

Hi Johann,

You should be able to access the Profile and Membership providers from within your web-service.  You could then authorize any code called from the web-service.

Hope this helps,

Scott

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Monday, October 16, 2006 4:17 AM by Andy Mackie
My *business* requirement is for users to be able to define their own roles, and many different roles can have access to the same operation. For ease of administration, it should also be possible to have groups of operations that can be assigned to roles. In an enterprise-wide, multi-department/multi-company environment, I must also be able to assign a user different roles for different things. Nothing should be hard-coded. I would love to use the in-built .NET security that you describe, but it doesn't provide the features I need. Windows Authorization Manager (AzMan) does, but then that doesn't integrate at all into .NET security - I have to code against the AzMan API. It seems to me that the .NET and the AzMan teams at Microsoft need to work together to integrate these two. The declarative security could then be based on whether a user has access to a specific operation (via any assigned role/scope), rather than on whether the user is a member of a specific role. Any plans on integrating AzMan operations with .NET declarative security ?

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Tuesday, October 17, 2006 5:05 AM by Dirk
Hi There, Could someone tell me how to add users to roles? Unfortuantly it is asp.net 1.1 boo-hoo

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Tuesday, October 17, 2006 10:27 AM by ScottGu

Hi Dirk,

For learning how to implement a Roles-based solution for ASP.NET 1.1, I'd recommend reviewing the "Portal Starter Kit" here: http://www.asp.net/downloads/default11.aspx?tabid=62

It includes sample code that shows how to-do this.

Hope this helps,

Scott

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Tuesday, October 17, 2006 11:19 AM by ScottGu

Hi Andy,

Yep - I definitely agree that there could be better integration with AZMan.

Here is an article that might be helpful that shows how you can use it today with ASP.NET to integrate operation checks: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000019.asp

The API code is a little messy, although you could probably create some cleaner API abstractions on top of it and have it meet your needs today.

Hope this helps,

Scott

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 19, 2006 3:09 PM by Edmund
I tried to apply this attribute to a class constructor, to allow exposing a constructor to a certain role. This failed compilation with a "Attribute 'PrincipalPermission' is not valid on this declaration type. It is valid on 'class, method' declarations only." Is there a way to apply security to constructors? Edmund

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Thursday, October 19, 2006 11:52 PM by ScottGu

Hi Edmund,

I don't believe there is a way to set it on a construtor (usually you'd just set it on the class - since the constructor is the first thing called when an object is created, and so setting it on the class level should have the same effect).

If you want to have some constructors have the permission but not others, one way to make it work would be to have an "Initialize" method that some of the secure constructors call - and then set the metadata on that method.

Hope this helps,

Scott

# Avoid using Impersonation in ASP.NET

Tuesday, October 24, 2006 5:55 AM by Ajax.NET Professional - AJAX and JSON made easy!

Scott Hanselman is writing on his blog:The MSDN Docs are very careful not to recommend using impersonation

# Impersonation in ASP.NET

Tuesday, October 31, 2006 2:53 PM by Marc Hoeppner

Wo ist der Unterschied zwischen der Einstellung des für den ASP.NET Prozess verwendeten Kontos durch

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Monday, November 06, 2006 11:42 AM by Martijn Kaag
Hi Scott, I think i have posed this before, but the method you prescribe does not work on 2.0 - this is confirmed by MS and is by design. The framework constructs a union between principal permissions which is and OR instead of the expected AND. In your example, all users that are authenticated will be given full access to your class. Please see this post where i have taken your post as an example: http://msdn.microsoft.com/newsgroups/managed/Default.aspx?query=Unexpected+behavior+PrincipalPermissionAttribute. Regards, Martijn Kaag

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Monday, December 25, 2006 3:49 AM by Prasad Khandekar

Hello,

   The approach you have mentioned does make application development simpler. However this approach may not be a good idea for services companies who are developing and maintaining applications for large number of customers. As for every authorization change (Role) the customer will have to come back to the company who has developed the application. Also this approach mau result in re-compilation of large number of code in the application upon such change.

For inhouse application however I would strongly recommend this approach.

Regards,

Prasad P. Khandekar

# re: Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes

Monday, January 22, 2007 12:38 AM by Martijn Kaag

Scott,

The code you presented does not work and opens serious security holes:

http://msdn.microsoft.com/newsgroups/managed/default.aspx?&guid=&sloc=en-us&dg=microsoft.public.dotnet.framework&p=1&tid=caff7a36-cd2f-4d55-bd05-4ca792ac01a4

Since many people seem to encouter your blog I'd suggest you either rewrite this article or at least add a warning.

Kind regards,

Martijn Kaag

ps I can be reached on my first.lastname at domain vecozo.com.

# PrincipalPermissionAttribute usage

Saturday, September 06, 2008 2:46 AM by DotNetDesign

PrincipalPermissionAttribute usage

# Adam Carr&#8217;s Blog &raquo; PrincipalPermissionAttribute usage

Friday, December 26, 2008 2:30 PM by Adam Carr’s Blog » PrincipalPermissionAttribute usage

Pingback from  Adam Carr&#8217;s Blog &raquo; PrincipalPermissionAttribute usage