Secure your Services Declaratively (PrincipalPermission)

Ever written a WCF Service and wondered what the best way to secure it was?  Should you use SLL? (yes).  What about authorization?  Should you pass login names and passwords to each and every method?  Should you create some kind of custom/proprietary token based system?

Or, is there a better, more standard, more secure way of doing it?  Turns out, there is.  All of the “solutions” listed above should be avoided (except, of course, for SLL encryption over the wire… You should do that).

The solution is with declarative security.  In other words, you don’t have to code anything.  You just sprinkle your class and/or your methods in your WCF service with attributes and .NET will take care of everything else for you.

Here’s how:

Suppose you have the following WCF service:

Code Snippet

  1. namespace MyCompany.MyLib.Services.Implementation.UserStuff
  2. {
  3.     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
  4.     [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
  5.     public class MyLibServiceType : MyCompany.MyLib.Services.Interfaces.UserStuff.IMyLibServiceType
  6.     {
  7.         public bool DoesAccountExist(string DomainName, string LogInName)
  8.         {
  9.             return CustomUserType.DoesAccountExist(DomainName, LogInName);
  10.         }
  11.     }
  12. }

It’s a simple WCF Service that has one method “DoesAccountExist”, which takes two parameters for a user’s domain name and a login name.  As-is, this service is unsecured.  Anyone on the network can call it, and if this is in the DMZ, then anyone in the world can call it.  hackers would love this.  They can query for common domain names and login names and should be able to correctly guess a few.  Plus, you don’t want unnecessary calls going into it anyway.

You need to secure this.  This solution assumes this WCF service is on your company’s intranet, and is not exposed on the public internet (there’s a different solution for that).

Add the “PrincipalPermission” attribute to your DoesAccountExist method, like this:

Code Snippet

  1. [PrincipalPermission(SecurityAction.Demand, Role=“UserStuff_Callers”)]
  2. public bool DoesAccountExist(string DomainName, string LogInName)
  3. {
  4.     return CustomUserType.DoesAccountExist(DomainName, LogInName);
  5. }

The PrincipalPermission attribute specifies that the credentials of the caller should be examined before allowing this method to be executed.  The Role specifies an Active Directory group that the caller must belong to.  If the caller’s credentials are NOT in the specified Active Directory group (“UserStuff_Callers” in this example), then the method won’t even run.  Instead, a security exception will be thrown with “Access Denied” in the message.

Alternatively, you can apply the PrincipalPermission attribute at the class level, instead of at a method level.  This way, not even an instance of the class can be made unless the security specified passes.

This capability is build all the way down into .NET’s CLR.

This is not a WCF feature.  It’s a .NET feature.  You can use this on ANY of your classes, properties, or methods.

Leave a Reply