Reputation: 3675
I have an MVC5 Application working with forms authentication against AD. I would like to have the ability to use windows authentication if the user is already signed into AD on their machine and if not go to forms authentication where they can enter their AD credentials.
Is there a relatively straight forward way to handle this without writing a custom membership class? And if so how? Any help would be appreciated. I have seen several posts about not mixing the types of authentication but I don't use any local authentication. It is all against AD. Is this still not supported?
Upvotes: 0
Views: 842
Reputation: 456
It's not technically supported by IIS (if that's what you're using), but you can enable both forms and windows authentication.
In whatever controller you are using in the "loginUrl" of your forms authentication settings (in your Web.config) you can check the headers to determine if the user is logged in, for instance:
Given this setting
<forms loginUrl="~/Login">
You can do this:
public class LoginController: Controller
{
public ActionResult Index()
{
string windowsUserName = Request.ServerVariables["LOGON_USER"];
if (!string.IsNullOrEmpty(windowsUserName))
{
Regex regex = new Regex(@"(^\w+)\\", RegexOptions.IgnoreCase);
string userName = regex.Replace(windowsUserName, string.Empty);
// validate the user name against ad here
FormsAuthentication.SetAuthCookie(userName, false);
this.RedirectToAction("Index", "Home");
}
else
{
// if the user isn't signed in with AD credentials you can send an
// "unauthorized" http code and the browser (excluding Firefox)
// will try to send credentials (if available).
// you will have to manage staying out of a redirect loop
// many options here: set and check a cookie, session, headers, etc.
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
}
}
}
When I had to do this for a particular app, I also checked the requests host address (to make sure it was on the same domain as the server, otherwise I didn't even bother:
IPAddress address = null;
if (IPAddress.TryParse(Request.UserHostAddress, out address))
{
if (IPAddress.IsLoopback(address))
{
address = Dns.GetHostAddresses(Dns.GetHostName()).FirstOrDefault(ip => !IPAddress.IsLoopback(ip));
if (address == null)
return View();
}
IPHostEntry entry = Dns.GetHostEntry(address);
bool isPartOfDomain = false;
foreach (IPAddress hostEntryAddress in entry.AddressList)
{
if (String.Equals(address.ToString(), hostEntryAddress.ToString()))
{
string domain = "Your Domain Here"; // or get it from your configuration settings / db / etc
using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domain))
{
string computerName = entry.HostName.Replace("." + domain, string.Empty);
using (ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(domainContext, computerName))
if (computer != null)
{
isPartOfDomain = true;
break;
}
}
}
}
}
I usually check against a Domain PrincipalContext to verify the user name.
DirectoryEntry entry;
string domain = "Your Domain Here",
userName = "Some User Name";
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
{
using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, userName))
{
if (principal != null && (entry = (DirectoryEntry)principal.GetUnderlyingObject()) != null)
{
string userPrincipalName = principal.UserPrincipalName ?? principal.Name;
userPrincipalName = userPrincipalName.Substring(0, (userPrincipalName.Contains("@") ? userPrincipalName.IndexOf("@") : userPrincipalName.IndexOf(" ")));
bool isValid = string.Equals(userName, userPrincipalName);
}
}
}
Upvotes: 1