views:

55

answers:

3

How can I implement following in ASP.NET MVC application:

  1. user opens intranet website
    • user is silently authenticated if possible
    • if NTLM authentication didn't worked out, show login form to user
    • user indicate login password and select domain from list of predefined domains
    • user is authenticated in code using AD

I know how to implement 4 and 5 but cannot find info on how to combine NTLM and forms. So that NTLM native login/password dialog is never shown - transparent authentication or nice looking login page.

How should work? Should user be asked login and password? Can her current credentials (domain username) be used without asking to enter login and password?

A: 

This article might get you pointed in the right direction. Basically you have two apps in two virtual directories under the same host name. One app uses Forms authentication, one uses Windows. The one using Windows authentication creates a valid form authentication cookie and redirects to the second virtual directory.

ASP.NET Mixed Mode Authentication

Pete Nelson
A: 

You cannot have both NTLM and FormsAuthentication in the same ASP.NET application. You will need two different applications in separate virtual directories.

Darin Dimitrov
+1  A: 

I have this exact setup in production, I setup my portal to use FormsAuth and wrote a function that takes the visitors IP to look up the user account that is logged in to that IP / PC. Using the name I find (eg. DOMAIN\user), I verify the domain matches my domain and that the user name / account is valid in my FormsAth provider using Membership.GetUser(). If this call returns a match and the user IsApproved I create a FormsAuthenticationTicket & cookie for the user. I have 400+ people on the network and this works perfect, the only computers that still login are (1. Users without accounts in my portal, 2. A few MAC/Linux users, 3. Mobile users who did not boot on the network and had Group Policy enable their Firewall to High).

The catch to this solution is that it requires impersonation of a domain admin account to query the users PC, and that you use unmanaged code netapi32.dll.

Here is the code I use (external function calls not provided, for brevity). I've tried to simplify this a bit, since have LOTS of external calls.

            string account = String.Empty;
            string domain = String.Empty;
            string user = String.Empty;


                ImpersonateUser iu = new ImpersonateUser();  //Helper that Enabled Impersonation
                if (iu.impersonateValidUser(StringHelper.GetAppSetting("DomainAccount"), StringHelper.GetAppSetting("DomainName"), StringHelper.GetEncryptedAppSetting("DomainAccountPassword")))
                {
                    NetWorkstationUserEnum nws = new NetWorkstationUserEnum(); //Wrapper for netapi32.dll (Tested on Vista, XP, Win2K, Win2K3, Win2K8)
                    string host = nws.DNSLookup(Request.UserHostAddress); // netapi32.dll requires a host name, not an IP address

                    string[] users = nws.ScanHost(host); // Gets the users/accounts logged in

                    if (nws.ScanHost(host).Length > 0)
                    {
                        string workstationaccount = string.Empty;

                        if (host.IndexOf('.') == -1)  // Pick which account to use, I have 99.9% success with this logic (only time doesn't work is when you run a interactive process as a admin e.g. Run As <process>).
                        {
                            workstationaccount = String.Format("{0}\\{1}$",StringHelper.GetAppSetting("DomainName"), host).ToUpper();
                        }
                        else
                        {
                            workstationaccount = String.Format("{0}\\{1}$", StringHelper.GetAppSetting("DomainName"), host.Substring(0, host.IndexOf('.'))).ToUpperInvariant();
                        }

                        account = users[users.Length - 1].Equals(workstationaccount) ? users[0] : users[users.Length - 1];

                        domain = account.Substring(0, account.IndexOf("\\"));
                        user = account.Substring(account.IndexOf("\\") + 1,
                                                 account.Length - account.IndexOf("\\") - 1);
                    }

                    iu.undoImpersonation(); // Disable Impersonation
                }

Now using the account we grabbed in the first function/process, we now try to verify and decide if we should show a login or auto-login the user.

                MembershipUser membershipUser = Membership.GetUser(user);

                if (membershipUser != null && membershipUser.IsApproved)
                {
                    string userRoles = string.Empty;  // Get all their roles
                    FormsAuthenticationUtil.RedirectFromLoginPage(user, userRoles, true); // Create FormsAuthTicket + Cookie + 
                }

I wrote a blog post about this a long time ago, here is a link to the wrapper for netapi32.dll and my Impersonation helper that I provided in the post Source Code Download

Zachary
thank you for your detailed response, I'm not marking it as answer yet as I feel it may have concerns with security and overall has a 'hack' feel :-)
Igor Romanov
It definately is a hack..
Zachary