1

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?

Community
  • 1
  • 1
Alfred Wallace
  • 1,741
  • 1
  • 14
  • 32
  • Note: this question has be re-written following some constructive feedback I received... – Alfred Wallace May 04 '16 at 18:35
  • I've added a related question here: http://stackoverflow.com/questions/43224779/usecookieauthentication-looping-issue-with-basic-authentication. When LoginPath is commented out to implement BasicAuthentication, if I then try to access an unauthorised page (after basic authentication) I now get redirected to an Error 401 page as opposed to the LoginPath logic of redirecting me to my login page. I'm basically trying to redirect to my login page upon a 401 error, instead of an error 401 page..... – Captain_Planet Apr 05 '17 at 07:40

1 Answers1

0

Per OWIN Authentication with IIS Basic Authentication, the following line in Startup.Auth.cs must be deleted to avoid starting an infinite login loop:

LoginPath = new PathString("/Account/Login"),

It is the only way for Cookie Authentication and Basic Authentication to work simultaneously in MVC - no further setup required in IIS. Once a user has been authenticated via Basic Authentication, users who have logged in remain successfully logged in across the site.

Community
  • 1
  • 1
Alfred Wallace
  • 1,741
  • 1
  • 14
  • 32