Using Windows Domain accounts AND application-managed accounts

The simplest approach is to have 2 different presentation Projects only for Authentication/Authorization.

This has the advantage of leaning on existing framework and standard configuration.

From there, you decide to either

  • create an AD user for every internet user, or
  • create a DB/Internet user for every AD user.

Creating an Identity user for each AD user is easier to implement further. Then the same cookies and filters can exist in the entire app.

In that case you can either

  • use subdomain(s) for your app
  • AD Authentiction Project can have the singular purpose of Authentication / Authorization, then the Web App can represent the rest of your app.

Alternatively, If you want a truly Unified Solution, use MohammadYounes/Owin-MixedAuth

MohammadYounes/Owin-MixedAuth

Install-Package OWIN-MixedAuth

In Web.config

<location path="MixedAuth">
  <system.webServer>
    <security>
      <authentication>
        <windowsAuthentication enabled="true" />
      </authentication>
    </security>
  </system.webServer>
</location>

In in Startup.Auth.cs

app.UseMixedAuth(cookieOptions);

:

:

How it works:

The handler uses ApplyResponseChallengeAsync to confirm the request is a 401 challenge. If so, it redirects to the callback path to request authentication from IIS which is configured to query the AD.

        AuthenticationResponseChallenge challenge = Helper.LookupChallenge(
              Options.AuthenticationType, Options.AuthenticationMode);

A 401 challenge is caused by an unauthorized users attempting to use a resource that requires Authentication

The handler uses InvokeAsync to check if a request is coming from a callback path (IIS) and then calls AuthenticateCoreAsync

    protected async override System.Threading.Tasks.Task<AuthenticationTicket>
                AuthenticateCoreAsync()
    {
        AuthenticationProperties properties = UnpackStateParameter(Request.Query);

        if (properties != null)
        {
            var logonUserIdentity = Options.Provider.GetLogonUserIdentity(Context);

            if (logonUserIdentity.AuthenticationType != Options.CookieOptions.AuthenticationType
                && logonUserIdentity.IsAuthenticated)
            {
                AddCookieBackIfExists();

                ClaimsIdentity claimsIdentity = new ClaimsIdentity(
                    logonUserIdentity.Claims, Options.SignInAsAuthenticationType);

                //  ExternalLoginInfo GetExternalLoginInfo(AuthenticateResult result)
                claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier,
                  logonUserIdentity.User.Value, null, Options.AuthenticationType));

                //could grab email from AD and add it to the claims list.
                var ticket = new AuthenticationTicket(claimsIdentity, properties);

                var context = new MixedAuthAuthenticatedContext(
                   Context,
                   claimsIdentity,
                   properties,
                   Options.AccessTokenFormat.Protect(ticket));

                await Options.Provider.Authenticated(context);

                return ticket;
            }
        }
        return new AuthenticationTicket(null, properties);
    }

AuthenticateCoreAsync uses AddCookieBackIfExists to read the claims cookie created by AD and creates it’s own Claims based.

AD users are provided a Claims based Cookie identical to Web Users. AD is now like any other 3rd party authenticator (Google, FB, LinkedIN)

Leave a Comment