9

The following posts show how to setup the web.config for a site using Mixed Mode Authentication. IIS7 Mixed Mode Authentication and How to allow mixed-mode authentication in IIS 7.0.

I've got my site setup and working locally (on my developer machine). However, when I run it locally on the server I get 401.2 - Login failed due to server configuration error.

Anyone know how I'm supposed to configure the server, Default Web Site, and My Site?

Edit: Here are the settings in my web.config, including the loginUrl from the Forms authentication node.

    <location path="~/Account/WinLogin.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
        <allow users="*"/>
      </authorization>
    </system.web>
    <system.webServer>
      <security>
        <authentication>
          <anonymousAuthentication enabled="false"/>
          <windowsAuthentication enabled="true"/>
        </authentication>
      </security>
    </system.webServer>
  </location>
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/WinLogin.aspx" timeout="60"/>
    </authentication>
    <authorization>
      <deny users="?"/>
    </authorization>
Community
  • 1
  • 1
Rich
  • 1,895
  • 3
  • 26
  • 35

1 Answers1

11

Let's start with server roles configuration (this is under server manager, roles, IIS)

You're gonna want to make sure that the windows auth and anonymous auth sections are enabled/installed, and also the forms auth (which presumably you already have). After those are installed/configured, you'll need to define the following stuff:

In your Web.Config you're going to want to have the following sections defined:

<configuration>
  <system.web>
  <authentication mode="Forms">
      <forms cookieless="UseDeviceProfile" defaultUrl="~/Default.aspx" enableCrossAppRedirects="true" loginUrl="~/WindowsLogin.aspx" name=".ASPXAUTH" path="/" protection="All" requireSSL="false" slidingExpiration="true" timeout="10080"/>
    </authentication>
    <authorization>
        <deny users="?"/>
    </authorization>
  </system.web>
  <location path="Login.aspx">
      <system.web>
          <authorization>
              <allow users="?"/>
          </authorization>
      </system.web>
      <system.webServer>
          <security>
              <authentication>
                  <anonymousAuthentication enabled="true"/>
                  <windowsAuthentication enabled="false"/>
              </authentication>
          </security>
      </system.webServer>
  </location>
  <location path="WindowsLogin.aspx">
      <system.web>
          <authorization>
              <deny users="?"/>
              <allow users="*"/>
          </authorization>
      </system.web>
      <system.webServer>
          <security>
              <authentication>
                  <anonymousAuthentication enabled="false"/>
                  <windowsAuthentication enabled="true"/>
              </authentication>
          </security>
      </system.webServer>
  </location>
</configuration>

Then you'll need two files:

Login.aspx (this does forms auth)
WindowsLogin.aspx (this does Windows auth)

LOGIN does forms, right, so that's just bog standard ASP.NET forms auth It's WindowsLogin that does the magic (and here's that file)

using System;
using System.Web;
using System.Web.Security;
using App_Code.Biz;

public partial class WindowsLogin : System.Web.UI.Page {
    protected string UserIsInRoles = string.Empty;
    private static readonly BAL _mBAL = new BAL();
    protected void Page_Load(object sender, EventArgs e) {
        string redirectUrl = Request["returnurl"] ?? "~/default.aspx";
        string username = Request.ServerVariables["LOGON_USER"];
        try {
            if ( Roles.GetRolesForUser( username ).Length < 1 )
                Roles.AddUserToRole( username, Global.defaultRole );
            int status;
            _mBAL.aspnet_Membership_CreateUser( username, out status );
        } catch ( Exception ex ) {
            ErrHandler.WriteXML( ex );
        }

        /* Test to see if the user is in any roles */
        if ( Roles.GetRolesForUser( username ).Length < 1 ) {
            UserIsInRoles = "<br />" + username + "You are not in any rules. This must be your first visit to our site!<br /> Adding you to the " + Global.defaultRole + " role now!";

        } else {
            UserIsInRoles = "You are in the following roles: ";
            string[] roles = Roles.GetRolesForUser( username );
            foreach ( string role in roles )
                UserIsInRoles += role + ", ";
            UserIsInRoles = UserIsInRoles.Remove( UserIsInRoles.Length - 2 ) + "!";

            if ( Login( username, String.Join( ",", roles ) ) )
                Response.Redirect( redirectUrl );
        }

        //we shouldn't get here, so if we do, redirect back to a page they can use.
        if ( Page.IsPostBack ) {
            if ( Response.StatusCode == 401 )
                Response.Redirect( "~/Login.aspx" );

        }
    }

    private bool Login(string strUser, string strRole) {
        if ( strRole != null ) {
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
               1,                            // version
               strUser,                      // user name
               DateTime.Now,                 // create time
               DateTime.Now.AddYears(1),     // expire time
               false,                        // persistent
               strRole );                     // user data
            string strEncryptedTicket = FormsAuthentication.Encrypt( ticket );
            HttpCookie cookie = new HttpCookie( FormsAuthentication.FormsCookieName, strEncryptedTicket );
            Context.Response.Cookies.Add( cookie );
            return true;
        }
        return false;
    }
}

After all this, you might get a config error for section locked at a parent level. Lock is either by default (overrideModeDefault="Deny") or set explicitly by a location tag ... and if so, then the fastest way to fix that is to open C:\Windows\System32\inetsrv\config\applicationHost.config and edit the following block:

<configSections>
  <sectionGroup name="system.webServer">
    <sectionGroup name="security">
      <sectionGroup name="authentication">
        <section name="anonymousAuthentication" overrideModeDefault="Allow">
        <section name="windowsAuthentication" overrideModeDefault="Allow">
      </sectionGroup>
    </sectionGroup>
  </sectionGroup>
</configSections>

Also see the chat log: https://chat.stackoverflow.com/rooms/5/conversation/configuring-iis7-and-mixed-mode-authentication-in-asp-net

Community
  • 1
  • 1
jcolebrand
  • 15,889
  • 12
  • 75
  • 121
  • This played out exactly as you described, including the Lock error at the very end. I'm worried about the implications of your suggested "fix". Am I opening up some vulnerabilities or potential problems by overriding the default behavior this way? It feels kinda like a hack. This is so old...I wonder if there's a better way now? – ctb Mar 12 '14 at 17:05
  • Microsoft denies it by default as a security measure. Everything in editing the IIS metabase by default feels like a hack. There's probably some UI function to let you change that but I can't be arsed to find out where it is. – jcolebrand Mar 12 '14 at 18:52
  • Depends on which one you want to come first – jcolebrand Apr 28 '17 at 13:07
  • if (page.ispostback) seems to be always false because there is no button or server side action in this page. right? – Niloofar May 08 '17 at 09:52
  • if ( Page.IsPostBack ) seems to be always false because there is no button or server side action in the "WindowsLogin.aspx page. In which case are you expecting this to be true? – Niloofar May 08 '17 at 15:05
  • I'm confused. What issue are you referencing @Niloofar ... are you responding to someone's comment on this page, or are you asking a question? – jcolebrand May 08 '17 at 15:18
  • Are you asking "how can they get to `if ( Page.IsPostBack )` if there is no button for them to click? The answer is "tricky users not visiting the page in a browser but using APIs." – jcolebrand May 08 '17 at 15:19
  • in IIS do I need to have windows authentication, form authentication and anonymous authentication enabled? I get an error there that challenge based and login redirect based auth can not be used simultaneously – Niloofar May 16 '17 at 21:28
  • @Niloofar are you trying to do all three? What specifically are you trying to do? If you are trying to do what I did, yes, you need all three enabled. I'm confused tho by the "challenge based and login redirect based auth can not be used" ... what are you trying to do? Maybe you should create a new question? – jcolebrand May 16 '17 at 23:05
  • Please make a new question so we can approach this with fresh eyes, link back to this one. Or, let's create a chat room. What timezone are you in? A new question would be easier. Please have as complete a minimal working set as you can. – jcolebrand May 17 '17 at 15:00
  • apparently in IIS authentication settings , anonymous must be disabled otherwise forms authentication does not work – Niloofar May 24 '17 at 19:27
  • yes thats the web.config file but in IIS settings only Forms authentication should be enabled. The rest should be disabled. – Niloofar May 26 '17 at 07:19