Extened service behavior to check authorization

I wish WCF can provide something like this:

instead of

[PrincipalPermission(SecurityAction.Demand, Role ="Administrators")]

We can use

[PrincipalPermission(SecurityAction.Demand, RoleProvider = typeof(MyAuthorizationChecker)]

So developers won’t care if security requirement changed.

I posted before about explicitly calling

permissionSet.Demand()

right in service method, it works, but it would be nice to use service behavior attribute to make code looks cleaner.

Extending WCF service is not that hard, thanks to this post.

    public class CheckAuthorizationBehaviorAttribute : Attribute, IOperationBehavior
    {
        public string MethodName { get; set; }

        public void Validate(OperationDescription operationDescription)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.Invoker = new AuthorizationChecker(dispatchOperation.Invoker
                , MethodName);
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {

        }

        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {

        }
    }

    public class AuthorizationChecker : IOperationInvoker
    {
        private readonly IOperationInvoker _invoker;
        private readonly string _methodName;

        public AuthorizationChecker(IOperationInvoker invoker, string methodName)
        {
            _invoker = invoker;
            _methodName = methodName;
        }

        public object[] AllocateInputs()
        {
            return _invoker.AllocateInputs();
        }

        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
             Console.WriteLine("Checking permission on methodname {0}.{1}", instance.ToString(),_methodName);

            if (!.....(my authorization logic here ))
                throw new FaultException<SecurityAccessDeniedException>(new SecurityAccessDeniedException("No access"))
                ;

            string value;
            value = (string)_invoker.Invoke(instance, inputs, out outputs);
            return value;

        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            return _invoker.InvokeBegin(instance, inputs, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return _invoker.InvokeEnd(instance, out outputs, result);
        }

        public bool IsSynchronous
        {
            get { return _invoker.IsSynchronous; }
        }
    }

Then my service contract is just like this:

        [ServiceContract]
        public interface ITestService
        {
            [CheckAuthorizationBehavior(MethodName = "PingWithUserName")]
            [OperationContract]
            void Ping(string username);

I was having difficult to get the method name inside invoker, the methodname is hide in the private syncInvoker class, so I had to add the public attribute to my behavior. Later I found out this might be a better idea, because what if the method is an overload one?

Still, it would be nice to set the default method name to the one we just attached. Hope I can figure this out soon.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s