I have an ASP.NET WebApi service that requires http basic authentication (this is for a demonstration, not for production, so that's the reason for basic authentication and not something more secure). The service runs fine with visual studio IIS express server and authentication happens through a custom HTTP module.
It fails and continues to popup a login screen when I deploy the site to the hosting server. I verified with Fiddler that the request is being sent and the credentials are being sent. But it keeps responding with a 401 unauthorized response. It appears that the request credentials are somehow being lost in the time it takes to get from the client to the server. I have spent many, many hours trying to diagnose this and the .NET authentication with Web API and IIS seems very confusing. Please help!!
Outgoing request from Fiddler shows:
GET mywebsiteaddress HTTP/1.1
Host: my website address
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: /
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Basic YmJvbm5ldDE4Om9jdG9iZXIxNw==
X-Requested-With: XMLHttpRequest
Referer: mysite
Connection: keep-alive
Here are the relevant pieces of my config (I can post more if necessary):
<modules>
<add name="BasicAuthHttpModule" type="ITMService.Modules.BasicAuthHttpModule"/>
</modules>
<httpModules>
<add name="BasicAuthHttpModule" type="ITMService.Modules.BasicAuthHttpModule"/>
</httpModules>
<authentication mode="Windows"/>
My custom http module (also working fine in testing from visual studio). This was mostly taken from the example on asp.net :
namespace ITMService.Modules
{
public class BasicAuthHttpModule : IHttpModule
{
private const string Realm = "www.mysite.net";
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnApplicationAuthenticateRequest;
context.EndRequest += OnApplicationEndRequest;
}
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
Log.LogIt("current principal: " + principal.Identity.Name);
}
}
private static bool CheckPassword(string username, string password)
{
string passHash = AuthUser.GetUserPassword(username);
if (PasswordHash.ValidatePassword(password, passHash))
{
return true;
}
else
{
return false;
}
}
private static bool AuthenticateUser(string credentials)
{
bool validated = false;
try
{
var encoding = Encoding.GetEncoding("iso-8859-1");
credentials = encoding.GetString(Convert.FromBase64String(credentials));
int separator = credentials.IndexOf(':');
string name = credentials.Substring(0, separator);
string password = credentials.Substring(separator + 1);
validated = CheckPassword(name, password);
if (validated)
{
var identity = new GenericIdentity(name);
SetPrincipal(new GenericPrincipal(identity, null));
}
}
catch (FormatException)
{
// Credentials were not formatted correctly.
validated = false;
Log.LogIt("not validated");
}
return validated;
}
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("basic",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
AuthenticateUser(authHeaderVal.Parameter);
}
}
}
// If the request was unauthorized, add the WWW-Authenticate header
// to the response.
private static void OnApplicationEndRequest(object sender, EventArgs e)
{
var response = HttpContext.Current.Response;
if (response.StatusCode == 401)
{
response.Headers.Add("WWW-Authenticate",
string.Format("Basic realm=\"{0}\"", Realm));
}
}
public void Dispose()
{
}
}
}
My IIS server is hosted and running .NET 4 in integrated pipeline mode. I disabled forms authentication and disabled impersonation. I enabled basic authentication and anonymous authentication methods on the server.
I've read countless forum responses and posts about this and nothing has lead me to a clear answer.
I see two www-Authenticate response headers. I believe your HTTP module is adding one and IIS is adding one. Ensure all kinds of authentication are disabled in IIS, like so. My guess is that you have basic authentication enabled in IIS.