Active Directory Using Form Auth and Windows Auth

流过昼夜 提交于 2020-01-17 04:41:11

问题


I have an ASP.Net Application. The requirement is to implement Form Authentication using ADFS. If the user is accessing the WebSite from within the Domain(the same Domain as the Active Directoris), then the Form Authentication should be performed. i.e. Using the User's Windows logged in email Id, we should check if the user exists in the Active Directory or not. If the user exists, then the Website is made accessible to the user. If the user is not found on the basis of his/her email id, then the user is asked his/her UserName and Password, and to select one of the Two Active Directories on which the user should be searched. (PN: There are two Active Directories. One Default for using with-in the Domain.)

If the User is accessing the Website from outside the Domain, then the user is always asked his/her UserName and Password, and to select one of the two Active Directories to which the User Belongs.

So, there is one URL to access the Website from with in the Domain, and one to access from Outside the Domain.

And I need help to accomplish this task. The project is in Dot.Net, using Framework 3.5 on ASP.Net and C#.

Help with code solution highly appreciated.


回答1:


I have done this. The basic idea is that your main form of authentication is Forms. However you make your default login page use Windows authentication. If the Windows authentication succeeds, then you create the Forms ticket and proceed. If not, then you display the login page.

The only caveat is that since Windows authentication always sends a 401 response to the browser (challenging it for Windows credentials), then non-Domain users will always get a credentials pop-up that they will have to click Cancel on.

I used MVC in my project. My Windows login page is /Login/Windows and my manual login page is /Login.

Here are the relevant areas of my web.config:

<system.web>
  <authentication mode="Forms">
    <forms loginUrl="~/Login/Windows" defaultUrl="~/" name=".MVCFORMSAUTH" protection="All" timeout="2880" slidingExpiration="true" />
  </authentication>
<system.web>

<location path="Login">
  <system.web>
    <authorization>
      <allow users="?" />
      <allow users="*" />
    </authorization>
  </system.web>
</location>
<location path="Login/Windows">
  <system.webServer>
    <security>
      <authentication>
        <windowsAuthentication enabled="true" />
        <anonymousAuthentication enabled="false" />
      </authentication>
    </security>
    <httpErrors errorMode="Detailed" />
  </system.webServer>
  <system.web>
    <authorization>
      <allow users="?" />
    </authorization>
  </system.web>
</location>

Here is my LoginController:

[RoutePrefix("Login")]
public class LoginController : Controller {

    [Route("")]
    public ActionResult Login() {
        //Clear previous credentials
        if (Request.IsAuthenticated) {
            FormsAuthentication.SignOut();
            Session.RemoveAll();
            Session.Clear();
            Session.Abandon();
        }
        return View();
    }

    [Route("")]
    [HttpPost]
    public ActionResult TryLogin(string username, string password) {
        //Verify username and password however you need to

        FormsAuthentication.RedirectFromLoginPage(username, true);
        return null;
    }

    [Route("Windows")]
    public ActionResult Windows() {
        var principal = Thread.CurrentPrincipal;
        if (principal == null || !principal.Identity.IsAuthenticated) {
            //Windows authentication failed
            return Redirect(Url.Action("Login", "Login") + "?" + Request.QueryString);
        }

        //User is validated, so let's set the authentication cookie
        FormsAuthentication.RedirectFromLoginPage(principal.Identity.Name, true);
        return null;
    }
}

Your Login View will just be a normal username / password form that does a POST to /Login.

At this point, you have a /Login page that people can manually go to to login. You also have a /Login/Windows page that is the default login page that people are automatically redirected to. But if Windows login fails, it'll display a generic 401 error page.

The key to making this seamless is using your Login view as your custom 401 error page. I did that by highjacking the response content in Application_EndRequest using the ViewRenderer class written by Rick Strahl.

Global.asax.cs:

protected void Application_EndRequest(object sender, EventArgs e) {
    if (Response.StatusCode != 401 || !Request.Url.ToString().Contains("Login/Windows")) return;

    //If Windows authentication failed, inject the forms login page as the response content
    Response.ClearContent();
    var r = new ViewRenderer();
    Response.Write(r.RenderViewToString("~/Views/Login/Login.cshtml"));
}

Another caveat I've found is that this doesn't work in IIS Express (although it's been a version or two since I last tried). I have it setup in IIS and point the debugger at that.




回答2:


There is an OOTB solution that may work for you.

Use a ADFS WAP as well and set up split-brain DNS.

Internal users (inside the domain) get the DNS of the ADFS box. The default is Windows auth. (IWA)

External users (outside the domain) get the DNS of the ADFS WAP box. The default is FBA.



来源:https://stackoverflow.com/questions/43206333/active-directory-using-form-auth-and-windows-auth

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!