0

I've looked at implementing a way to maybe impersonate your AD user to secure my Web API, using my local domain AD. All the samples I've found they use basic or token authentication. or secure it using Azure AD.

I want to implement my custom authorization business logic using my local domain AD/Impersonation. All I can achieve is using BASIC authentication and the challenge always POPS UP a form to input username/password. I would like to bypass that and use my local domain + custom logic to authenticate/authorize users.

Is there a way where I can impersonate the windows user to authenticate and authorize resources in my web api?

this is what my challenge function looks like:

 void Challenge(HttpRequestMessage request, HttpResponseMessage response)
    {
        var host = request.RequestUri.DnsSafeHost;
        response.Headers.Add(WWWAuthenticateHeader, string.Format("Basic realm=\"{0}\"", host));
    }

Thanks very much!

Jerry Stratton
  • 3,287
  • 1
  • 22
  • 30
DataAnalyst1
  • 147
  • 2
  • 12

1 Answers1

1

First, you should read this:

How to get HttpClient to pass credentials along with the request?

Second (if you're doing a "one hop").

If you enable "Windows Authentication" and disable "Anonymous Authentication" (in IIS under "Authentication").......you can get at the Windows Identity.

You'll want to write a custom AuthorizeAttribute.

Here is a basic one to try out:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace MyLibrary.CustomAttributes.WebApi
{
    public class IdentityWhiteListAuthorizationAttribute : System.Web.Http.AuthorizeAttribute
    {
        public const string ErrorMessageBadIdentityContent = "IIdentity.Name was empty or IIdentity was not a WindowsIdentity. CurrentAction='{0}'";
        public const string ErrorMessageBadIdentityReasonPhrase = "IIdentity.Name was empty or IIdentity was not a WindowsIdentity.  The most likely reason is that the web service is not setup for WindowsAuthentication and/or Anonymous Authentication is enabled.";

        public const string ErrorMessageNotAuthenticated = "IIdentity.IsAuthenticated was false. '{0}'";

        public IdentityWhiteListAuthorizationAttribute()
        {
        }

        private string CurrentActionName { get; set; }

        public override void OnAuthorization(HttpActionContext actionContext)
        {
            this.CurrentActionName = actionContext.ActionDescriptor.ActionName;
            base.OnAuthorization(actionContext);
        }

        protected override bool IsAuthorized(HttpActionContext actionContext)
        {

            /* this will authenticate if the authorization-header contained a "Negotiate" windows Identity.  Note, WebApi must be running in Windows-Authentication mode (and the WebApi-web.config must be set for "<authentication mode="Windows" />") for this to work.  (the client will send the windows identity via the DefaultRequestHeaders.Authorization header */

            string currentActionName = this.CurrentActionName;
            IPrincipal httpContextCurrentUserPrinc = HttpContext.Current.User; /*  */
            IIdentity ident = httpContextCurrentUserPrinc.Identity;

            bool badIdentity = false;

            string errorMessageContent = string.Empty;
            string errorMessageReasonPhrase = string.Empty;

            if (null == ident)
            {
                badIdentity = true;
                errorMessageContent = string.Format(ErrorMessageBadIdentityContent, currentActionName);
                errorMessageReasonPhrase = ErrorMessageBadIdentityReasonPhrase;
            }

            if (!badIdentity)
            {
                /* Ensure that we have an actual userName which means windows-authentication was setup properly */
                if (string.IsNullOrEmpty(ident.Name))
                {
                    badIdentity = true;
                    errorMessageContent = string.Format(ErrorMessageBadIdentityContent, currentActionName);
                    errorMessageReasonPhrase = ErrorMessageBadIdentityReasonPhrase;
                }
            }

            if (!badIdentity)
            {
                if (!ident.IsAuthenticated)
                {
                    badIdentity = true;
                    errorMessageContent = string.Format(ErrorMessageNotAuthenticated, ident.Name);
                    errorMessageReasonPhrase = string.Format(ErrorMessageNotAuthenticated, ident.Name);
                }
            }

            if (!badIdentity)
            {
                if (ident.GetType() != typeof(WindowsIdentity))
                {
                    badIdentity = true;
                    errorMessageContent = string.Format(ErrorMessageBadIdentityContent, currentActionName);
                    errorMessageReasonPhrase = ErrorMessageBadIdentityReasonPhrase;
                }
            }

            if (badIdentity)
            {
                HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content = new StringContent(errorMessageContent),
                    ReasonPhrase = errorMessageReasonPhrase
                };
                throw new HttpResponseException(resp);
            }


            return true;



        }
    }
}

Apply that attribute to a webapi controller and/or method(s).

You could also write a DelegatingHandler...and use the same code above......

Community
  • 1
  • 1
granadaCoder
  • 26,328
  • 10
  • 113
  • 146
  • Thanks very much mate... this is very useful. What would be the benefit in using a Delegating Handler in this scenario? I want to write my custom authorization routine somewhere. Do you recommend doing it in the "IsAuthorized" event? Thanks again for your help! Cheers! – DataAnalyst1 Mar 09 '16 at 02:23
  • 1
    Delegating Handler (once added)..will affect EVERY controller/action. The attribute-way (above in my post) lets you pick and choose. The Delegating Handler runs earlier in the pipeline. If every single controller/action needs the security check.....then go with the delegating handler. – granadaCoder Mar 09 '16 at 14:11