.netcastle-windsorowinkatanaowin-security

Registering OWIN IAuthenticationManager using Castle Windsor


Since IAuthenticationManager implementation can be retrieved from OWIN context, but Castle Windsor's component registration must be done before resolving components, how can I register IAuthenticationManager as component to get injected anywhere?

AFAIK, I should use Component.For<IAuthenticationManager>().UsingFactoryMethod(...), but since I'm using OWIN/Katana, something like HttpContext.Current.GetOwinContext() won't work (and if it would work, I would hate to add a dependency to System.Web for this...).

What's the solution for this right now?


Solution

  • Temporal (or definitive) solution...

    This is how I've managed to solve the issue.

    First of all, I've implemented a simple OWIN middleware:

    public sealed class WindsorMiddleware : OwinMiddleware
    {
        public WindsorMiddleware(OwinMiddleware next) : base(next)
        {
        }
    
        public override async Task Invoke(IOwinContext context)
        {
            CallContext.LogicalSetData("owinContext", context);
    
            await Next.Invoke(context);
    
            CallContext.FreeNamedDataSlot("owinContext");
        }
    }
    

    And I've configured IAuthenticationManager using ComponentRegistration<T>.UseFactoryMethod so I've implemented an extension method like this:

    public static ComponentRegistration<TService> UseOwinComponentFactoryMethod<TService>(this ComponentRegistration<TService> registration)
        where TService : class
    {
        return registration.UsingFactoryMethod
        (
            (kernel, componentModel, creationContext) =>
            {
                IOwinContext owinContext = CallContext.LogicalGetData("owinContext") as IOwinContext;
    
                Contract.Assert(owinContext != null);
    
                if (creationContext.RequestedType == typeof(IAuthenticationManager))
                {
                    return (TService)owinContext.Authentication;
                }
                else
                {
                    throw new NotSupportedException();
                }
            },
            managedExternally: true
        );
    }
    

    Finally, I've registered IAuthenticationManager this way:

    Component.For<IAuthenticationManager>().UseOwinComponentFactoryMethod().LifestyleTransient()
    

    It smells...

    BTW, I'm not self-convinced about the reliability of this solution since this should work unless you try to resolve components in another thread than the request one.

    Sadly, it should be a lot of situations where this solution can fail. If your code implements non-blocking I/O, I expect to try to inject IAuthenticationManager from another thread from the one that set "owinContext" in the CallContext...

    I'll still look forward for other answers while I find a better and more elegant solution.