How to: Create a Custom Principal Identity

The PrincipalPermissionAttribute is a declarative means of controlling access to service methods. When using this attribute, the PrincipalPermissionMode enumeration specifies the mode for performing authorization checks. When this mode is set to Custom, it enables the user to specify a custom IPrincipal class returned by the CurrentPrincipal property. This topic illustrates the scenario when Custom is used in combination with a custom authorization policy and a custom principal.

For more information about using the PrincipalPermissionAttribute, see How to: Restrict Access with the PrincipalPermissionAttribute Class.

Example

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;
            }
        }
    }
}
Namespace CustomMode
	Public Class Test
		Public Shared Sub Main()
			Try
				Dim ppwm As New ShowPrincipalPermissionModeCustom()
				ppwm.Run()

			Catch exc As Exception
				Console.WriteLine("Error: {0}", exc.Message)
				Console.ReadLine()
			End Try
		End Sub
	End Class

	Friend Class ShowPrincipalPermissionModeCustom
		<ServiceContract> _
		Private Interface ISecureService
			<OperationContract> _
			Function Method1(ByVal request As String) As String
		End Interface

		<ServiceBehavior> _
		Private Class SecureService
			Implements ISecureService
            <PrincipalPermission(SecurityAction.Demand, Role:="everyone")> _
            Public Function Method1(ByVal request As String) As String Implements ISecureService.Method1
                Return String.Format("Hello, ""{0}""", Thread.CurrentPrincipal.Identity.Name)
            End Function
		End Class

		Public Sub Run()
			Dim serviceUri As New Uri("http://localhost:8006/Service")
			Dim service As New ServiceHost(GetType(SecureService))
			service.AddServiceEndpoint(GetType(ISecureService), GetBinding(), serviceUri)
			Dim policies As New List(Of IAuthorizationPolicy)()
			policies.Add(New CustomAuthorizationPolicy())
			service.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly()
			service.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom
			service.Open()

			Dim sr As New EndpointAddress(serviceUri, EndpointIdentity.CreateUpnIdentity(WindowsIdentity.GetCurrent().Name))
			Dim cf As New ChannelFactory(Of ISecureService)(GetBinding(), sr)
			Dim client As ISecureService = cf.CreateChannel()
			Console.WriteLine("Client received response from Method1: {0}", client.Method1("hello"))
			CType(client, IChannel).Close()
			Console.ReadLine()
			service.Close()
		End Sub

		Public Shared Function GetBinding() As Binding
			Dim binding As New WSHttpBinding(SecurityMode.Message)
			binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows
			Return binding
		End Function

		Private Class CustomAuthorizationPolicy
			Implements IAuthorizationPolicy
			Private id_Renamed As String = Guid.NewGuid().ToString()

			Public ReadOnly Property Id() As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id
				Get
					Return Me.id_Renamed
				End Get
			End Property

			Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer
				Get
					Return ClaimSet.System
				End Get
			End Property

			Public Function Evaluate(ByVal context As EvaluationContext, ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate
                Dim obj As Object = Nothing
				If (Not context.Properties.TryGetValue("Identities", obj)) Then
					Return False
				End If

				Dim identities As IList(Of IIdentity) = TryCast(obj, IList(Of IIdentity))
				If obj Is Nothing OrElse identities.Count <= 0 Then
					Return False
				End If

				context.Properties("Principal") = New CustomPrincipal(identities(0))
				Return True
			End Function
		End Class

		Private Class CustomPrincipal
			Implements IPrincipal
			Private identity_Renamed As IIdentity
			Public Sub New(ByVal identity As IIdentity)
				Me.identity_Renamed = identity
			End Sub

			Public ReadOnly Property Identity() As IIdentity Implements IPrincipal.Identity
				Get
					Return Me.identity_Renamed
				End Get
			End Property

			Public Function IsInRole(ByVal role As String) As Boolean Implements IPrincipal.IsInRole
				Return True
			End Function
		End Class
	End Class
End Namespace

Compiling the Code

References to the following namespaces are needed to compile the code:

See Also

PrincipalPermissionMode
PrincipalPermissionMode
PrincipalPermissionAttribute
How to: Use the ASP.NET Role Provider with a Service
How to: Restrict Access with the PrincipalPermissionAttribute Class