4

Typically, you can get the service instance from the OperationContext like this:

OperationContext.Current.InstanceContext.GetServiceInstance()

However, when you're in an IAuthorizationPolicy, InstanceContext is null. Is there another way to get the instance of the service when hosted in IIS?

Community
  • 1
  • 1
zimdanen
  • 5,508
  • 7
  • 44
  • 89
  • From my observations of `IAuthorizationPolicy` and `ServiceAuthorizationManager`, the instance of the service is **not created** until **after you grant access** to the user by returning true during the call to `ServiceAuthorizationManager.CheckAccess`. Considering that `CheckAccess` calls `CheckAccessCore` and ultimately `IAuthorizationPolicy.Evaluate` I'm not sure what you ask is possible, at least for a `PerSession` service –  Sep 09 '14 at 01:29
  • @MickyDuncan: Thanks; I was afraid that would be the case. Is there a reference that shows that flow of events, by chance? – zimdanen Sep 09 '14 at 12:43
  • There is a nice article [here](http://pfelix.wordpress.com/2008/08/06/the-serviceauthorizationmanager-class-in-wcf/) –  Sep 09 '14 at 13:00
  • @MickyDuncan: Thanks, but that article doesn't seem to place the authorization within the context of the service lifecycle. – zimdanen Sep 09 '14 at 15:25

2 Answers2

7

In an IAuthorizationPolicy.Evaluate() OperationContext.Current.InstanceContext is not always null.

Starting with Carlos Figueira’s WCF Extensibility test program which prints to the command line a message each time a WCF extension is called. I added a custom IAuthorizationPolicy. The output and program are below.

The output shows that

  1. IAuthorizationPolicy.Evaluate() Is called after the service instance is created
  2. OperationContext.Current.InstanceContext is not null in IAuthorizationPolicy.Evaluate()

The test program is self hosted using BasicHttpBinding. It’s very possible that in other hosting environments IAuthorizationPolicy.Evaluate() does not have access to the service instance, but it is at least theoretically possible.

Why would you do this?

From an architecture point of view an IAuthorizationPolicy should be dealing with claims. The application should be consuming the claims on the ClaimsPrinciple. To have an IAuthorizationPolicy tightly coupled to a particular service breaks the very intentional separation of concerns in the Window Identity architecture. In other words, I think this is a bad idea.

Test Program

This is a windows command line program all in one file.

using System;
using System.Globalization;
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading;
using System.Collections.Generic;

namespace WcfRuntime
{
    class MyDispatchMessageInspector : IDispatchMessageInspector
    {
        public MyDispatchMessageInspector()
        {
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }
    }

    class MyDispatchMessageFormatter : IDispatchMessageFormatter
    {
        IDispatchMessageFormatter inner;
        public MyDispatchMessageFormatter(IDispatchMessageFormatter inner)
        {
            this.inner = inner;
        }

        public void DeserializeRequest(Message message, object[] parameters)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            this.inner.DeserializeRequest(message, parameters);
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.SerializeReply(messageVersion, parameters, result);
        }
    }

    class MyClientMessageInspector : IClientMessageInspector
    {
        public MyClientMessageInspector()
        {
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return null;
        }
    }

    class MyClientMessageFormatter : IClientMessageFormatter
    {
        IClientMessageFormatter inner;
        public MyClientMessageFormatter(IClientMessageFormatter inner)
        {
            this.inner = inner;
        }

        public object DeserializeReply(Message message, object[] parameters)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.DeserializeReply(message, parameters);
        }

        public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.SerializeRequest(messageVersion, parameters);
        }
    }

    class MyDispatchOperationSelector : IDispatchOperationSelector
    {
        public string SelectOperation(ref Message message)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            string action = message.Headers.Action;
            string method = action.Substring(action.LastIndexOf('/') + 1);
            return method;
        }
    }

    class MyParameterInspector : IParameterInspector
    {
        ConsoleColor consoleColor;
        bool isServer;
        public MyParameterInspector(bool isServer)
        {
            this.isServer = isServer;
            this.consoleColor = isServer ? ConsoleColor.Cyan : ConsoleColor.Yellow;
        }

        public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
        {
            ColorConsole.WriteLine(this.consoleColor, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }

        public object BeforeCall(string operationName, object[] inputs)
        {
            ColorConsole.WriteLine(this.consoleColor, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return null;
        }
    }

    class MyCallContextInitializer : ICallContextInitializer
    {
        public void AfterInvoke(object correlationState)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }

        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return null;
        }
    }

    class MyOperationInvoker : IOperationInvoker
    {
        IOperationInvoker inner;
        public MyOperationInvoker(IOperationInvoker inner)
        {
            this.inner = inner;
        }

        public object[] AllocateInputs()
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.AllocateInputs();
        }

        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.Invoke(instance, inputs, out outputs);
        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.InvokeBegin(instance, inputs, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.InvokeEnd(instance, out outputs, result);
        }

        public bool IsSynchronous
        {
            get
            {
                ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
                return this.inner.IsSynchronous;
            }
        }
    }

    class MyInstanceProvider : IInstanceProvider
    {
        Type serviceType;
        public MyInstanceProvider(Type serviceType)
        {
            this.serviceType = serviceType;
        }

        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return Activator.CreateInstance(this.serviceType);
        }

        public object GetInstance(InstanceContext instanceContext)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return Activator.CreateInstance(this.serviceType);
        }

        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }
    }

    class MyInstanceContextProvider : IInstanceContextProvider
    {
        IInstanceContextProvider inner;
        public MyInstanceContextProvider(IInstanceContextProvider inner)
        {
            this.inner = inner;
        }

        public InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.GetExistingInstanceContext(message, channel);
        }

        public void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            this.inner.InitializeInstanceContext(instanceContext, message, channel);
        }

        public bool IsIdle(InstanceContext instanceContext)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return this.inner.IsIdle(instanceContext);
        }

        public void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            this.inner.NotifyIdle(callback, instanceContext);
        }
    }

    class MyInstanceContextInitializer : IInstanceContextInitializer
    {
        public void Initialize(InstanceContext instanceContext, Message message)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }
    }

    class MyChannelInitializer : IChannelInitializer
    {
        ConsoleColor consoleColor;
        public MyChannelInitializer(bool isServer)
        {
            this.consoleColor = isServer ? ConsoleColor.Cyan : ConsoleColor.Yellow;
        }
        public void Initialize(IClientChannel channel)
        {
            ColorConsole.WriteLine(this.consoleColor, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }
    }

    class MyClientOperationSelector : IClientOperationSelector
    {
        public bool AreParametersRequiredForSelection
        {
            get
            {
                ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
                return false;
            }
        }

        public string SelectOperation(MethodBase method, object[] parameters)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return method.Name;
        }
    }

    class MyInteractiveChannelInitializer : IInteractiveChannelInitializer
    {
        public IAsyncResult BeginDisplayInitializationUI(IClientChannel channel, AsyncCallback callback, object state)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            Action act = new Action(this.DoNothing);
            return act.BeginInvoke(callback, state);
        }

        public void EndDisplayInitializationUI(IAsyncResult result)
        {
            ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
        }

        private void DoNothing() { }
    }

    class MyErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            return error is ArgumentException;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
            MessageFault messageFault = MessageFault.CreateFault(new FaultCode("FaultCode"), new FaultReason(error.Message));
            fault = Message.CreateMessage(version, messageFault, "FaultAction");
        }
    }

    public class MyAuthorizationPolicy : IAuthorizationPolicy
    {
        string id;
        public MyAuthorizationPolicy()
        {
            id = Guid.NewGuid().ToString();
        }

        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            ColorConsole.WriteLine(ConsoleColor.Green, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));

            if (OperationContext.Current.InstanceContext != null)
            {
                var instance = (Service)OperationContext.Current.InstanceContext.GetServiceInstance();
                ColorConsole.WriteLine(ConsoleColor.Green, "Got the service instance. Name={0}", instance.Name);
            }
            else
            {
                ColorConsole.WriteLine(ConsoleColor.Green, "OperationContext.Current.InstanceContext is null");
            }

            // Return true, indicating that this method does not need to be called again.
            return true;
        }

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

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

    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        int Add(int x, int y);
        [OperationContract(IsOneWay = true)]
        void Process(string text);
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class Service : ITest
    {
        public Service() { ColorConsole.WriteLine(ConsoleColor.Green, "Created Service Instance"); }

        public string Name { get { return "MyService instance 1234"; } }

        public int Add(int x, int y)
        {
            ColorConsole.WriteLine(ConsoleColor.Green, "In service operation '{0}'", MethodBase.GetCurrentMethod().Name);

            if (x == 0 && y == 0)
            {
                throw new ArgumentException("This will cause IErrorHandler to be called");
            }
            else
            {
                return x + y;
            }
        }

        public void Process(string text)
        {
            ColorConsole.WriteLine(ConsoleColor.Green, "In service operation '{0}'", MethodBase.GetCurrentMethod().Name);
        }
    }

    class MyBehavior : IOperationBehavior, IContractBehavior
    {
        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
            clientOperation.Formatter = new MyClientMessageFormatter(clientOperation.Formatter);
            clientOperation.ParameterInspectors.Add(new MyParameterInspector(false));
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.CallContextInitializers.Add(new MyCallContextInitializer());
            dispatchOperation.Formatter = new MyDispatchMessageFormatter(dispatchOperation.Formatter);
            dispatchOperation.Invoker = new MyOperationInvoker(dispatchOperation.Invoker);
            dispatchOperation.ParameterInspectors.Add(new MyParameterInspector(true));
        }

        public void Validate(OperationDescription operationDescription)
        {
        }

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.ChannelInitializers.Add(new MyChannelInitializer(false));
            clientRuntime.InteractiveChannelInitializers.Add(new MyInteractiveChannelInitializer());
            clientRuntime.MessageInspectors.Add(new MyClientMessageInspector());
            clientRuntime.OperationSelector = new MyClientOperationSelector();
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            dispatchRuntime.ChannelDispatcher.ChannelInitializers.Add(new MyChannelInitializer(true));
            dispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(new MyErrorHandler());
            dispatchRuntime.InstanceContextInitializers.Add(new MyInstanceContextInitializer());
            dispatchRuntime.InstanceContextProvider = new MyInstanceContextProvider(dispatchRuntime.InstanceContextProvider);
            dispatchRuntime.InstanceProvider = new MyInstanceProvider(dispatchRuntime.ChannelDispatcher.Host.Description.ServiceType);
            dispatchRuntime.MessageInspectors.Add(new MyDispatchMessageInspector());
            dispatchRuntime.OperationSelector = new MyDispatchOperationSelector();
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }
    }

    static class ColorConsole
    {
        static object syncRoot = new object();

        public static void WriteLine(ConsoleColor color, string text, params object[] args)
        {
            if (args != null && args.Length > 0)
            {
                text = string.Format(CultureInfo.InvariantCulture, text, args);
            }

            lock (syncRoot)
            {
                Console.ForegroundColor = color;
                Console.WriteLine("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture), text);
                Console.ResetColor();
            }

            Thread.Sleep(50);
        }

        public static void WriteLine(string text, params object[] args)
        {
            Console.WriteLine(text, args);
        }

        public static void WriteLine(object obj)
        {
            Console.WriteLine(obj);
        }
    }

    static class ReflectionUtil
    {
        public static string GetMethodSignature(MethodBase method)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(method.Name);
            sb.Append("(");
            ParameterInfo[] parameters = method.GetParameters();
            for (int i = 0; i < parameters.Length; i++)
            {
                if (i > 0) sb.Append(", ");
                sb.Append(parameters[i].ParameterType.Name);
            }
            sb.Append(")");
            return sb.ToString();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            using (ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)))
            {
                ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
                endpoint.Contract.Behaviors.Add(new MyBehavior());
                foreach (OperationDescription operation in endpoint.Contract.Operations)
                {
                    operation.Behaviors.Add(new MyBehavior());
                }

                var polices = new List<IAuthorizationPolicy>();
                polices.Add(new MyAuthorizationPolicy());
                host.Authorization.ExternalAuthorizationPolicies = polices.AsReadOnly();

                host.Open();
                ColorConsole.WriteLine("Host opened");

                using (ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress)))
                {
                    factory.Endpoint.Contract.Behaviors.Add(new MyBehavior());
                    foreach (OperationDescription operation in factory.Endpoint.Contract.Operations)
                    {
                        operation.Behaviors.Add(new MyBehavior());
                    }

                    ITest proxy = factory.CreateChannel();
                    ColorConsole.WriteLine("Calling operation");
                    ColorConsole.WriteLine(proxy.Add(3, 4));

                    //ColorConsole.WriteLine("Called operation, calling it again, this time it the service will throw");
                    //try
                    //{
                    //    ColorConsole.WriteLine(proxy.Add(0, 0));
                    //}
                    //catch (Exception e)
                    //{
                    //    ColorConsole.WriteLine(ConsoleColor.Red, "{0}: {1}", e.GetType().Name, e.Message);
                    //}

                    //ColorConsole.WriteLine("Now calling an OneWay operation");
                    //proxy.Process("hello");

                    ((IClientChannel)proxy).Close();
                }
            }

            ColorConsole.WriteLine("Done");
        }
    }
}

Program Output

Look for the ---->.

[12:33:04.218] MyOperationInvoker.get_IsSynchronous()
[12:33:04.269] MyOperationInvoker.get_IsSynchronous()
Host opened
[12:33:04.322] MyChannelInitializer.Initialize(IClientChannel)
Calling operation
[12:33:04.373] MyClientOperationSelector.get_AreParametersRequiredForSelection()
[12:33:04.424] MyClientOperationSelector.SelectOperation(MethodBase, Object[])
[12:33:04.474] MyParameterInspector.BeforeCall(String, Object[])
[12:33:04.524] MyClientMessageFormatter.SerializeRequest(MessageVersion, Object[])
[12:33:04.574] MyClientMessageInspector.BeforeSendRequest(Message&, IClientChannel)
[12:33:04.632] MyInteractiveChannelInitializer.BeginDisplayInitializationUI(IClientChannel, AsyncCallback, Object)
[12:33:04.684] MyInteractiveChannelInitializer.EndDisplayInitializationUI(IAsyncResult)
[12:33:04.788] MyChannelInitializer.Initialize(IClientChannel)
[12:33:04.838] MyInstanceContextProvider.GetExistingInstanceContext(Message, IContextChannel)
[12:33:04.888] MyDispatchOperationSelector.SelectOperation(Message&)
[12:33:04.939] MyInstanceContextProvider.InitializeInstanceContext(InstanceContext, Message, IContextChannel)
[12:33:04.990] MyInstanceContextInitializer.Initialize(InstanceContext, Message)
[12:33:05.040] MyDispatchMessageInspector.AfterReceiveRequest(Message&, IClientChannel, InstanceContext)
[12:33:05.091] MyInstanceProvider.GetInstance(InstanceContext, Message)
[12:33:05.142] Created Service Instance
[12:33:05.192] MyCallContextInitializer.BeforeInvoke(InstanceContext, IClientChannel, Message)
[12:33:05.242] MyOperationInvoker.AllocateInputs()
[12:33:05.293] MyDispatchMessageFormatter.DeserializeRequest(Message, Object[])
[12:33:05.344] MyParameterInspector.BeforeCall(String, Object[])
[12:33:05.394] MyAuthorizationPolicy.Evaluate(EvaluationContext, Object&)
---->[12:33:05.445] Got the service instance. Name=MyService instance 1234
[12:33:05.495] MyOperationInvoker.Invoke(Object, Object[], Object[]&)
[12:33:05.547] In service operation 'Add'
[12:33:05.597] MyParameterInspector.AfterCall(String, Object[], Object, Object)
[12:33:05.648] MyDispatchMessageFormatter.SerializeReply(MessageVersion, Object[], Object)
[12:33:05.698] MyCallContextInitializer.AfterInvoke(Object)
[12:33:05.748] MyDispatchMessageInspector.BeforeSendReply(Message&, Object)
[12:33:05.803] MyInstanceContextProvider.IsIdle(InstanceContext)
[12:33:05.804] MyClientMessageInspector.AfterReceiveReply(Message&, Object)
[12:33:05.854] MyInstanceProvider.ReleaseInstance(InstanceContext, Object)
[12:33:05.855] MyClientMessageFormatter.DeserializeReply(Message, Object[])
[12:33:05.905] MyParameterInspector.AfterCall(String, Object[], Object, Object)
ErnieL
  • 5,773
  • 1
  • 23
  • 27
  • 1
    That's pretty impressive. Does it still work without custom instance provider? –  Sep 10 '14 at 03:21
  • It doesn't tightly couple the policy to the service, because all I want to check for is whether the service implements an interface that is defined in a component that is used by almost all of the code in our organization. The specific service doesn't matter to the policy. Also, echoing Micky's question - is there a way to get it without replacing everything? This is an IIS-hosted service. – zimdanen Sep 10 '14 at 11:55
  • It works fine if you only use the `IAuthorizationPolicy`. The behaviors, instance provider, etc. were just to address the comment on order of execution and whether the service instance was created yet. To test just comment out anything to do with `MyBehavior` from the `Main()` method. – ErnieL Sep 11 '14 at 05:26
  • Is there any way to get the service when hosting in IIS? – zimdanen Sep 11 '14 at 14:52
1

IAuthorizationPolicy implements evaluate which in turn provides a context.

From microsoft

public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
    bool bRet = false;
    CustomAuthState customstate = null;

    // If state is null, then this method has not been called before, so  
    // set up a custom state. 
    if (state == null)
    {
        customstate = new CustomAuthState();
        state = customstate;
    }
    else
        customstate = (CustomAuthState)state;

    Console.WriteLine("Inside MyAuthorizationPolicy::Evaluate");

    // If claims have not been added yet... 
    if (!customstate.ClaimsAdded)
    {
        // Create an empty list of Claims.
        IList<Claim> claims = new List<Claim>();

        // Iterate through each of the claim sets in the evaluation context. 
        foreach (ClaimSet cs in evaluationContext.ClaimSets)
            // Look for Name claims in the current claim set. 
            foreach (Claim c in cs.FindClaims(ClaimTypes.Name, Rights.PossessProperty))
                // Get the list of operations the given username is allowed to call. 
                foreach (string s in GetAllowedOpList(c.Resource.ToString()))
                {
                    // Add claims to the list.
                    claims.Add(new Claim("http://example.org/claims/allowedoperation", s, Rights.PossessProperty));
                    Console.WriteLine("Claim added {0}", s);
                }

        // Add claims to the evaluation context.
        evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer,claims));

        // Record that claims have been added.
        customstate.ClaimsAdded = true;

        // Return true, which indicates this need not be called again.
        bRet = true;
    }
    else
    {
        // This point should not be reached, but just in case...
        bRet = true;
    }


    return bRet;
}

See for example http://msdn.microsoft.com/en-us/library/ms729794(v=vs.110).aspx

Getting the name of the current assembly using reflection

Assembly SampleAssembly;
// Instantiate a target object.
Int32 Integer1 = new Int32();
Type Type1;
// Set the Type instance to the target class type.
Type1 = Integer1.GetType();
// Instantiate an Assembly class to the assembly housing the Integer type.  
SampleAssembly = Assembly.GetAssembly(Integer1.GetType());
// Display the name of the assembly currently executing
Console.WriteLine("GetExecutingAssembly=" + Assembly.GetExecutingAssembly().FullName);
AstroCB
  • 12,337
  • 20
  • 57
  • 73
Mike Beeler
  • 4,081
  • 2
  • 29
  • 44
  • Mike - Is there a way to get the service instance using `evaluationContext`? – zimdanen Sep 04 '14 at 16:17
  • The context has to do with security context, it would not be invoked directly consider an attribute on a service method like [PrincipalPermission(SecurityAction.Demand, Role = "ADMIN")] public void TheMethod() and the custom interface is bound to the service with a custom behavior in the service.config file { ... } – Mike Beeler Sep 04 '14 at 18:29
  • I don't.. understand how that's related. – zimdanen Sep 04 '14 at 18:37
  • To clarify, you cannot access operation context instance within iauthorization policy. – Mike Beeler Sep 04 '14 at 18:51
  • Well, I can get the Channel and the RequestContext and other things; it just seems to be the InstanceContext that's missing. Are you saying there is no way to access the service for which authorization is being done? – zimdanen Sep 04 '14 at 18:58
  • Please review the following for a better understanding of the authorization pipeline for a WCF service, if you still think that a service instance is the only solution, perhaps more info about the problem you are trying to solve would help http://milestone.topics.it/2011/12/wcf-iauthorizationpolicy_02.html – Mike Beeler Sep 06 '14 at 23:37
  • Mike - I have all of the authorization working, but my service advertises its name for our health framework. I want to get that name for when I send to my authorization service in order to provide the stack of applications through which the request has traveled, for our logging purposes. The reason that getting the service instance is the only solution is because the service instance is the only one that definitively knows that name, since it owns it. – zimdanen Sep 08 '14 at 12:44
  • Since this can be built using attributes one of the attributes passed in could be the name of the service, I don't really see another solution other than maybe using reflection on the current thread to get the currently loaded assembly – Mike Beeler Sep 08 '14 at 13:26
  • This answer in no way attempts to address the OP's question of _"Is there another way to get the instance of the service [in an IAuthorizationPolicy implementation] ?"_ EvaluationContext is **not** the same as the _instance context_. **Two different assemblies** for one thing –  Sep 09 '14 at 00:35
  • 1
    Really in what way? The op does not want to use attributes which could be one way to pass the service name reflection is another, if you have a better idea please contribute – Mike Beeler Sep 09 '14 at 00:38
  • Since each service controls its own name, this name can be dynamic if the service chooses - I don't want to dictate to the service **how** it implements the interface that exposes the name; as long as it implements the interface, the name is there, and I want to get it if possible. – zimdanen Sep 09 '14 at 00:49
  • 1
    @MikeBeeler Incorrect. Your "answer" is nothing more than an implementation of IAuthorizationPolicy. _"pass the service name"_ - where exactly does the OP state he wishes this information? –  Sep 09 '14 at 01:33
  • In reality the real issue is authorization logging which can be achieved in a different way http://msdn.microsoft.com/en-us/library/ms734737(v=vs.110).aspx – Mike Beeler Sep 10 '14 at 03:57
  • 1
    This is more a context-passing issue than an authorization-logging issue. – zimdanen Sep 10 '14 at 11:50