Expand Minimize

PrincipalPermissionMode Enumeration

Sets the mode for authorization checks when using the PrincipalPermissionAttribute to control access to a method.

Namespace:  System.ServiceModel.Description
Assembly:  System.ServiceModel (in System.ServiceModel.dll)

public enum PrincipalPermissionMode

Member nameDescription
AlwaysAlways enables the user to specify a IPrincipal class for CurrentPrincipal.
CustomEnables the user to specify a custom IPrincipal class for CurrentPrincipal.
NoneCurrentPrincipal is not set.
UseAspNetRolesCurrentPrincipal is set based on the ASP.NET role provider (RoleProvider).
UseWindowsGroupsCurrentPrincipal is set based on Windows (WindowsPrincipal). If the user identity is not associated with a Windows account, anonymous Windows is used.

When applying the PrincipalPermissionAttribute to a method, this mode specifies which set of roles to use when authorizing access. By default, the attribute uses Windows groups (such as Administrator or Users) to specify the role to which the user must belong.

To set the mode programmatically, create an instance of the ServiceHost class, then find the ServiceAuthorizationBehavior in its collection of behaviors, and set the PrincipalPermissionMode to the appropriate enumeration. The following example sets the property to UseAspNetRoles.

ServiceHost myServiceHost = new ServiceHost(typeof(Calculator), baseUri);
ServiceAuthorizationBehavior myServiceBehavior =
    myServiceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
myServiceBehavior.PrincipalPermissionMode =
    PrincipalPermissionMode.UseAspNetRoles;

You can also set the behavior in configuration by adding a <serviceAuthorization> element to the <serviceBehaviors> of a configuration file, as shown in the following code.

// Only a client authenticated with a valid certificate that has the  
// specified subject name and thumbprint can call this method.
[PrincipalPermission(SecurityAction.Demand,
     Name = "CN=ReplaceWithSubjectName; 123456712345677E8E230FDE624F841B1CE9D41E")]
public double Multiply(double a, double b)
{
    return a * b;
}
<configuration>
 <system.serviceModel>
  <behaviors>
   <serviceBehaviors>
    <behavior name="myServiceBehavior">
      <serviceAuthorization principalPermissionMode="UseAspNetRoles" />
    </behavior>
   </serviceBehaviors>
  </behaviors>
 </system.serviceModel>
</configuration>

The enumeration affects how the PrincipalPermissionAttribute attribute authorizes a user when it is applied to a method. The following example applies the attribute to a method and demands that the user belong to the Users group on the computer. This code works only when the PrincipalPermissionMode is set to UseWindowsGroup (the default setting).

// Only members of the CalculatorClients group can call this method.
[PrincipalPermission(SecurityAction.Demand, Role = "Users")]
public double Add(double a, double b)
{
    return a + b;
}

UseAspNetRoles

The UseAspNetRoles value is used for all credential types. This mode enables Windows Communication Foundation (WCF) to use the ASP.NET role provider to make authorization decisions.

When the credential for a service is an X.509 certificate, you can set the Name property of the PrincipalPermissionAttribute to a string that consists of the concatenated values of the Subject field and the Thumbprint field, as shown in the following example.

ServiceHost myServiceHost = new ServiceHost(typeof(Calculator), baseUri);
ServiceAuthorizationBehavior myServiceBehavior =
    myServiceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
myServiceBehavior.PrincipalPermissionMode =
    PrincipalPermissionMode.UseAspNetRoles;
MyServiceAuthorizationManager sm = new MyServiceAuthorizationManager();
myServiceBehavior.ServiceAuthorizationManager = sm;

The concatenated string consists of the subject and thumbprint values separated by a semicolon and a space.

It is also possible for a certificate to have a Subject field set to a null string. In that case, you can set the Name property to a semicolon followed by a space and then the thumbprint, as shown in the following example.

// Only a client authenticated with a valid certificate that has the  
// specified thumbprint can call this method.
[PrincipalPermission(SecurityAction.Demand,
     Name = "; 123456712345677E8E230FDE624F841B1CE9D41E")]
public double Divide(double a, double b)
{
    return a * b;
}

If an ASP.NET role provider is present, you can also set the Role property to a role in the database. By default, the database is represented by the SqlRoleProvider. You can also set a custom role provider with the RoleProvider property of the ServiceAuthorizationBehavior class. The following code sets the role to Administrators. Note that the role provider must map the user account to that role.

[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
public string ReadFile(string fileName)
{
    // Code not shown. 
    return "Not implemented";
}

For more information about the ASP.NET Role provider, see How To: Use Role Manager in ASP.NET 2.0.

For more information about using WCF and the role provider, see How to: Use the ASP.NET Role Provider with a Service.

Custom

When the property is set to Custom, you must also provide a custom class that implements the IAuthorizationPolicy class. This class is responsible for providing the caller's IPrincipal representation inside the Properties collection. It must store the IPrincipal instance to the properties collection using the "Principal" string key, as shown in the following example.

evaluationContext.Properties["Principal"]=new CustomPrincipal(identity);

Background

The role-based security in .NET Framework enables applications to specify authorizations through code. By specifying the PrincipalPermission demand, the CurrentPrincipal must satisfy the PrincipalPermission requirement. For example, that the user must be in a specific role or group. Otherwise, the thread is not authorized to execute the code, which results in an exception. WCF provides a set of PrincipalPermissionMode selections to specify the CurrentPrincipal based on SecurityContext accordingly.

The following example shows how to specify UseAspNetRoles.

namespace TestPrincipalPermission
{
    class PrincipalPermissionModeWindows
    {

        [ServiceContract]
        interface ISecureService
        {
            [OperationContract]
            string Method1();
        }

        class SecureService : ISecureService
        {
            [PrincipalPermission(SecurityAction.Demand, Role = "everyone")]
            public string Method1()
            {
                return String.Format("Hello, \"{0}\"", Thread.CurrentPrincipal.Identity.Name);
            }
        }

        public void Run()
        {
            Uri serviceUri = new Uri(@"http://localhost:8006/Service");
            ServiceHost service = new ServiceHost(typeof(SecureService));
            service.AddServiceEndpoint(typeof(ISecureService), GetBinding(), serviceUri);
            service.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.UseAspNetRoles;
            service.Open();

            EndpointAddress sr = new EndpointAddress(
                serviceUri, EndpointIdentity.CreateUpnIdentity(WindowsIdentity.GetCurrent().Name));
            ChannelFactory<ISecureService> cf = new ChannelFactory<ISecureService>(GetBinding(), sr);
            ISecureService client = cf.CreateChannel();
            Console.WriteLine("Client received response from Method1: {0}", client.Method1());
            ((IChannel)client).Close();
            Console.ReadLine();
            service.Close();

        }

        public static Binding GetBinding()
        {
            WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message);
            binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
            return binding;
        }
    }
}

The following example shows how to specify Custom.

namespace CustomMode
{
    public class Test
    {
        public static void Main()
        {
            try
            {
                ShowPrincipalPermissionModeCustom ppwm = new ShowPrincipalPermissionModeCustom();
                ppwm.Run();

            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
                Console.ReadLine();
            }
        }
    }

    class ShowPrincipalPermissionModeCustom
    {
        [ServiceContract]
        interface ISecureService
        {
            [OperationContract]
            string Method1(string request);
        }

        [ServiceBehavior]
        class SecureService : ISecureService
        {
            [PrincipalPermission(SecurityAction.Demand, Role = "everyone")]
            public string Method1(string request)
            {
                return String.Format("Hello, \"{0}\"", Thread.CurrentPrincipal.Identity.Name);
            }
        }

        public void Run()
        {
            Uri serviceUri = new Uri(@"http://localhost:8006/Service");
            ServiceHost service = new ServiceHost(typeof(SecureService));
            service.AddServiceEndpoint(typeof(ISecureService), GetBinding(), serviceUri);
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>();
            policies.Add(new CustomAuthorizationPolicy());
            service.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly();
            service.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
            service.Open();

            EndpointAddress sr = new EndpointAddress(
                serviceUri, EndpointIdentity.CreateUpnIdentity(WindowsIdentity.GetCurrent().Name));
            ChannelFactory<ISecureService> cf = new ChannelFactory<ISecureService>(GetBinding(), sr);
            ISecureService client = cf.CreateChannel();
            Console.WriteLine("Client received response from Method1: {0}", client.Method1("hello"));
            ((IChannel)client).Close();
            Console.ReadLine();
            service.Close();            
        }

        public static Binding GetBinding()
        {
            WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message);
            binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
            return binding;
        }

        class CustomAuthorizationPolicy : IAuthorizationPolicy
        {
            string id = Guid.NewGuid().ToString();

            public string Id
            {
                get { return this.id; }
            }

            public ClaimSet Issuer
            {
                get { return ClaimSet.System; }
            }

            public bool Evaluate(EvaluationContext context, ref object state)
            {
                object obj;
                if (!context.Properties.TryGetValue("Identities", out obj))
                    return false;

                IList<IIdentity> identities = obj as IList<IIdentity>;
                if (obj == null || identities.Count <= 0)
                    return false;

                context.Properties["Principal"] = new CustomPrincipal(identities[0]);
                return true;
            }
        }

        class CustomPrincipal : IPrincipal
        {
            IIdentity identity;
            public CustomPrincipal(IIdentity identity)
            {
                this.identity = identity;
            }

            public IIdentity Identity
            {
                get { return this.identity; }
            }

            public bool IsInRole(string role)
            {
                return true;
            }
        }
    }
}

.NET Framework

Supported in: 4.5.2, 4.5.1, 4.5, 4, 3.5, 3.0

.NET Framework Client Profile

Supported in: 4, 3.5 SP1

Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows 7, Windows Vista SP2, Windows Server 2008 (Server Core Role not supported), Windows Server 2008 R2 (Server Core Role supported with SP1 or later; Itanium not supported)

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft