For beta testing, I would like to use Basic Authentication (or Digest) but I am unable to combine the Cookie Authentication provided by default in MVC with Basic Authentication.
Following Dead simple ASP.NET MVC 5 password protection? (and older posts such as link1 and link2), I set up an action filter in FilterConfig.cs
:
GlobalFilters.Filters.Add(new BasicAuthenticationAttribute("myUsername", "myPassword"));
However, the result is an infinite login loop:
http://localhost:52200/account/login?ReturnUrl=%2Faccount%2Flogin%3FReturnUrl%3D%252Faccount%252Flogin%253FReturnUrl%253D%25252Faccount%25252Flogin%25253FReturnUrl%25253D%2525252Faccount%2525252Flogin%2525253FReturnUrl%2525253D%252525252Faccount%252525252Flogin%252525253FReturnUrl%252525253D%25252525252Faccount%25252525252Flogin%25252525253FReturnUrl%25252525253D%2525252525252Faccount%2525252525252Flogin%2525252525253FReturnUrl%2525252525253D%252525252525252Faccount%252525252525252Flogin%252525252525253FReturnUrl%252525252525253D%25252525252525252Faccount%25252525252525252Flogin%25252525252525253FReturnUrl%25252525252525253D%2525252525252525252F
The project has Anonymous Authentication
Enabled and Windows Authentication
Disabled. The BasicAuthentication filter is as follows:
using System;
using System.Web;
using System.Web.Mvc;
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
public string BasicRealm { get; set; }
protected string Username { get; set; }
protected string Password { get; set; }
public BasicAuthenticationAttribute(string username, string password)
{
Username = username;
Password = password;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
if (!string.IsNullOrEmpty(auth))
{
var cred = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
if (user.Name == Username && user.Pass == Password)
{
return;
}
else
{
throw new HttpException(403, "Forbidden"); // For Elmah
}
}
var res = filterContext.HttpContext.Response; // The 4 lines below cause the login redirect
res.StatusCode = 401;
res.AddHeader("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", BasicRealm ?? "MyProject"));
res.End();
}
}
My understanding is that upon triggering the http 401, UseCookieAuthentication
in Startup.Auth.cs
redirects to login, which in turns calls BasicAuthentication, thus starting the loop until the browser throws an error. This is the default UseCookieAuthentication
:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
Many posts indicate that web.config
needs to modified (Owin
, formsAuthentication
, etc.) I won't cite them here because there seems to be no commonly accepted answer.
Would a temporary password-protected index
be wiser / preferable for beta testing?