I have an ASP.NET Web API 2 application that uses Windows Authentication for all the controllers. I have a need now for some controllers to use Basic Authentication.
I know it is not possible to enable both Anonymous and Windows Authentications, but is it possible to enable Windows Authentication for some controllers and Basic Authentication for some others?
UPDATE: Implemented a filter as shown on the article EdSF shared
Here is what I have so far:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class BasicAuthenticationFilter : AuthorizationFilterAttribute
{
private bool _active = true;
private const string ValidUsername = @"Test";
private const string ValidPassword = @"T3st";
public BasicAuthenticationFilter()
{
}
public BasicAuthenticationFilter(bool active)
{
_active = active;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
if (_active)
{
var identity = ParseAuthorizationHeader(actionContext);
if (identity == null)
{
Challenge(actionContext);
return;
}
if (!OnAuthorizeUser(identity.Name, identity.Password, actionContext))
{
Challenge(actionContext);
return;
}
var principal = new GenericPrincipal(identity, null);
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
base.OnAuthorization(actionContext);
}
}
protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
{
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password) ||
!username.Equals(ValidUsername) || !password.Equals(ValidPassword))
{
return false;
}
return true;
}
protected virtual BasicAuthenticationIdentity ParseAuthorizationHeader(HttpActionContext actionContext)
{
string authHeader = null;
var auth = actionContext.Request.Headers.Authorization;
if (auth != null && auth.Scheme == "Basic")
{
authHeader = auth.Parameter;
}
if (string.IsNullOrEmpty(authHeader)) return null;
authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));
var tokens = authHeader.Split(':');
if (tokens.Length < 2) return null;
return new BasicAuthenticationIdentity(tokens[0], tokens[1]);
}
private void Challenge(HttpActionContext actionContext)
{
var host = actionContext.Request.RequestUri.DnsSafeHost;
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
}
}
BasicAuthenticationIdentity Class:
public class BasicAuthenticationIdentity : GenericIdentity
{
public BasicAuthenticationIdentity(string name, string password)
: base(name, "Basic")
{
Password = password;
}
public string Password { get; set; }
}
Also, decorated my controller with the Basic Authentication Filter:
[BasicAuthenticationFilter]
[RoutePrefix("api/BasicAuth")]
public class BasicAuthController : ApiController
{
//[BasicAuthenticationFilter]
[HttpGet]
public IHttpActionResult TestBasicAuth()
{
return Ok("success");
}
}
When I make a call to api/BasicAuth from Fiddler I got back 401, but it only returns the following challenges:
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
At this point Fiddler tries it again but this time instead of passing Basic Authorization Scheme, it passes Negotiate. This one fails also.
Then, when Fiddler finally tries the third time, my filter actually gets the request, but since authorization scheme is Negotiate instead of Basic, my filter returns Unauthorized also.
Is there a way to force the controller to just use the BasicAuthenticationFilter?
Thanks in advance