Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClaimsAuthenticationManager.Authenticate never gets called

I want to add some additional claims to a Principal during authentication. I am trying to implement a custom ClaimsAuthenticationManager in my MVC 4.5 project which uses Windows Authentication:

namespace Project.Infrastructure
{
    public class ClaimsTransformer : ClaimsAuthenticationManager
    {
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
            {
                ((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(new Claim(ClaimTypes.Role, "Admin"));
            }

            return incomingPrincipal;
        }
    }
}

I have the web.config set up to use my custom class:

<configSections>
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</configSections>

and

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="Project.Infrastructure.ClaimsTransformer, [AssemblyName]" />
    </identityConfiguration>
</system.identityModel>

But the Authenticate method never gets called. Am I missing something?

like image 540
newmanth Avatar asked Jul 24 '15 19:07

newmanth


1 Answers

The missing step is that you need to add an HTTP Module to kick all of this off.

So, you need a class that looks like this:

public class MyClaimsAuthenticationModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
    }

    public void Dispose()
    {
        // Nothing to dispose, method required by IHttpModule
    }

    void Context_PostAuthenticateRequest(object sender, EventArgs e)
    {
        var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
        if (transformer != null)
        {
            var context = ((HttpApplication)sender).Context;
            var principal = context.User as ClaimsPrincipal;
            var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, principal);

            context.User = transformedPrincipal;
            Thread.CurrentPrincipal = transformedPrincipal;
        }
    }
}

This will pick up the transformer you specified in the web.config and call authenticate on it, then attach the returned principal to the HttpContext and the current thread.

You will also need something like the following in your web.config:

<system.webServer>
  <modules>
    <add name="MyClaimsAuthenticationModule" type="MyApplication.MyHttpModels.MyClaimsAuthenticationModule, MyApplicationAssembly" />
  </modules>
</system.webServer>

Update

You can, of course, put the code from the method Context_PostAuthenticationRequest in the PostAuthenticateRequest handler in your Global.asax.cs class file. However, I prefer to keep the responsibilities of the classes small so I go for an implementation of IHttpModule so that the module does its thing and it is obvious what that is, and it is separate from other things that may be happening at various stages of the pipeline.

If your Global.asax.cs file is small then there is no problem with putting the code there. It should still work. However, you are mixing responsibilities in the class and it could get unwieldy in the future.

like image 170
Colin Mackay Avatar answered Oct 20 '22 01:10

Colin Mackay