2

I have a client asking for an integrated authentication based solution utilizing a custom role/membership schema. My original plan was to use claims based authentication mechanism with integrated authentication. However, my initial research is not turning up a whole lot of useful information.

To the point, I have an ASP.NET (not core nor owin) WebAPI application, which has api actions used by angular SPA based (asp.net) web application. I am attempting to authorize the api calls using integrated authentication. My initial effort was focused around a custom AuthorizationAttribute and ClaimsAuthenticationManager implementation. However as I got deeper into that I started running into issues with the custom ClaimsAuthenticationManager, at this point I'm not sure that is the proper route to take.

So my question for you all is, can you at least give me some ideas of what it would take to make this happen? I don't need help with secific bits the code, just need to figure out the appropriate "stack" so to speak.

The only real requirement is WebAPI calls can be authorized, with a custom attribute passing a name of a claim to authorize on, but the claim is not in AD even though it is using windows authentication, the claims themselves would come from a database.

Thank you all in advance!

Brandon
  • 830
  • 1
  • 15
  • 35
  • 1
    Why do you need custom AuthorizationAttribute ? Usually its the other way around - you decorate your controllers with default AuthorizationAttribute & make sure your authentication procedure does set principal (HttpContext.Current.User and Thread.CurrentPrincipal). – Ondrej Svejdar Dec 06 '16 at 13:59
  • Also see https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api for reference. – Ondrej Svejdar Dec 06 '16 at 14:07
  • @OndrejSvejdar The original idea was to use a custom authorize attribute to decorate actions with the claims required to access them. The challenge comes in that although I am using windows authentication, the actual claims/roles are stored in a separate database, not in active directory. What is confusing me is was to actually use to do this in a ASP.Net WebApi2 OWIN project. Ive explored doing it in middleware as well as overriding default class functionality. I am simply not sure specifically where I need to focus my efforts. – Brandon Dec 07 '16 at 03:39

1 Answers1

2

Look at https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api.

Your scenario isn't much different:

  • you're using AD for authentication
  • you're using your db for authorization

Simply put this can be addressed by configuring web-api to use windows authentication.

<system.web>
   <authentication mode="Windows" />
</system.web>

And add your own IAuthorizationFilter to Web API pipeline, that will check current principal (should be set), and then override this principal with your own (i.e. query db - get claims, and override it with your custom claims principal by setting HttpContext.Current.User and Thread.CurrentPrincipal). For how to add filter to WebAPI pipe line check out How to add global ASP.Net Web Api Filters?

public class CustomAuthenticationFilter : IAuthenticationFilter {
  public bool AllowMultiple { get { return true; } }
  public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) {
    var windowsPrincipal = context.Principal as WindowsPrincipal;
    if (windowsPrincipal != null) {
      var name = windowsPrincipal.Identity.Name;
      // TODO: fetch claims from db (i guess based on name)
      var identity = new ClaimsIdentity(windowsPrincipal.Identity);
      identity.AddClaim(new Claim("db-crazy-claim", "db-value"));
      var claimsPrincipal = new ClaimsPrincipal(identity);
      // here is the punchline - we're replacing original windows principal 
      // with our own claims principal
      context.Principal = claimsPrincipal;
    }

    return Task.FromResult(0);
  }

  public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) {
    return Task.FromResult(0);
  }
}

public static class WebApiConfig {
  public static void Register(HttpConfiguration config) {
    config.Filters.Add(new CustomAuthenticationFilter());

    // Web API routes
    config.MapHttpAttributeRoutes();
    config.Routes.MapHttpRoute( ... );
  }
}

Also there is no need for custom authorization attribute - use default one - its understood by everyone, and makes your code more readable.

Community
  • 1
  • 1
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • I apologize for the late response. I got pulled of on something else for a few days. This was a very helpful suggestion and for that reason I will mark it as the answer. I still had to implement a custom authorize attribute to do what I needed to do, but this suggestion got my over the first hurdle. :) – Brandon Dec 13 '16 at 23:32
  • I've been thinking about this more and have another question. So I have a WebAPI endpoint that provides data, this is where the Authorize attribute lives. But the authorization server is a separate machine. I've done some auth systems using openiddict and such that use JSON web tokens to validate users, but both the client and the webapi site talk to the auth service. Would this be similar? – Brandon Dec 21 '16 at 15:19