Allow domain name\username on asp login form.

I have created a log in form that authenticates against LDAP and the sAMAccountName, however, I would also like the form to work if they enter their information as domainName\userName.  Currently, if they enter it that way it will not authenticate them.  

Thank you for any feedback or advice.
shanemayAsked:
Who is Participating?
 
AshleighGreenConnect With a Mentor Commented:
Sure, here is some code that should help out:

I'm ripping it straight out of my working project, so a few ends might not be there, let me know if you need more clarification.

groups are passed a a string delimeterd by a '|'. I think my code returns their names as is, if you want it more windows authentication like you may with to add domain\ to the start of the group names. If you don't care what their windows groups are then you can skip this step.

Note, the windows groups code uses tokengroups which is a property on a user which stores the SID of all their groups, including nested. This code will therefore return all groups, including nested group membership.
LDAP Authentication Code:
strDomain = FQDN i.e. mydomain.local or myforest.mydomain.com etc
_path = String.Format("LDAP://{0}", "DC=" + strDomain.Replace(".", ",DC="));
public bool IsAuthenticated(string domain, string username, string pwd)
		{
			string domainAndUsername = domain + @"\" + username;
			DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
 
			try
			{	
				//Bind to the native AdsObject to force authentication.			
				object obj = entry.NativeObject;
 
				DirectorySearcher search = new DirectorySearcher(entry);
 
				search.Filter = "(SAMAccountName=" + username + ")";
				search.PropertiesToLoad.Add("cn");
				SearchResult result = search.FindOne();
 
				if(null == result)
				{
					return false;
				}
 
				//Update the new path to the user in the directory.
				_path = result.Path;
				_filterAttribute = (string)result.Properties["cn"][0];
			}
			catch (Exception ex)
			{
				throw new Exception("Error authenticating user. " + ex.Message);
			}
 
			return true;
		}
 
Next you probably want to get the domain groups
		public string GetGroups(string strLogin)
		{
#if DEBUG
			HttpContext.Current.Response.Write("<br/>Get Groups, Login: " + strLogin);
#endif
			string qry = String.Format("(&(objectCategory=person)(objectClass=user)(sAMAccountName=" + strLogin + "))");
			//string[] columns = new string[] { "sAMAccountName", "objectGuid", "givenName", "sn", "mail" };
			string[] columns = new string[] { "adspath" };
			string path = _path;
			DirectoryEntry deParent = new DirectoryEntry(path);
			//deParent.Username = Config.Settings.UserName;
			//deParent.Password = Config.Settings.Password;
			deParent.AuthenticationType = AuthenticationTypes.Secure;
 
			DirectorySearcher ds = new DirectorySearcher(deParent, qry, columns);
			ds.PageSize = 1000;
			StringBuilder groupNames = new StringBuilder();
			int equalsIndex, commaIndex;
 
			using (deParent)
			{
#if DEBUG
				HttpContext.Current.Response.Write("<br/>LDAP Search about to run.");
#endif
				using (SearchResultCollection src = ds.FindAll())
				{
#if DEBUG
										HttpContext.Current.Response.Write("<br/>LDAP Search returned results: " + src.Count.ToString());
#endif
					foreach (SearchResult sr in src)
					{
						
#if DEBUG
						HttpContext.Current.Response.Write("<br/>Load Object Domain: " + path);
#endif
						DirectoryEntry deDomain = new DirectoryEntry(path);
						deDomain.AuthenticationType = AuthenticationTypes.Secure;
#if DEBUG
						HttpContext.Current.Response.Write("<br/>Load Object User: " + sr.Properties["adspath"][0].ToString());
#endif
						DirectoryEntry deUser = new DirectoryEntry(sr.Properties["adspath"][0].ToString());
						deUser.AuthenticationType = AuthenticationTypes.Secure;
						ArrayList Group = GetSecurityGroups(deUser, deDomain);
#if DEBUG
						HttpContext.Current.Response.Write("<br/>Groups Found: " + Group.Count);
#endif
						foreach(string s in Group)
						{
#if DEBUG
							HttpContext.Current.Response.Write("<br/>Processing Group: " + s);
#endif
							equalsIndex = s.IndexOf("=", 1);
							commaIndex = s.IndexOf(",", 1);
							if (-1 == equalsIndex)
							{
								return null;
							}
							groupNames.Append(s.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
							groupNames.Append("|");
						}
					}
					
				}
			}
			return groupNames.ToString();
		}
 
void Application_AuthenticateRequest( Object s, EventArgs e )
		{
			string cookieName = FormsAuthentication.FormsCookieName;
			HttpCookie authCookie = Context.Request.Cookies[cookieName];
 
			if (null == authCookie)
			{
				//There is no authentication cookie.
				return;
			}
			FormsAuthenticationTicket authTicket = null;
			try
			{
				authTicket = FormsAuthentication.Decrypt(authCookie.Value);
			}
			catch 
			{
				//Write the exception to the Event Log.
				return;
			}
			if (null == authTicket)
			{
				//Cookie failed to decrypt.
				return;
			}
			//When the ticket was created, the UserData property was assigned a
			//pipe-delimited string of group names.
			string[] groups = authTicket.UserData.Split(new char[] { '|' });
 
			//Create an Identity.
			GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
			//This principal flows throughout the request.
			GenericPrincipal principal = new GenericPrincipal(id, groups);
 
			
			Context.User = principal;
					
		}
 
		private string BuildFilterOctetString(byte[] bytes)
		{
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < bytes.Length; i++)
			{
				sb.AppendFormat("\\{0}", bytes[i].ToString("X2"));
			}
			return sb.ToString();
		}
 
On the login page to create the authentication ticket:
			bool isCookiePersistent = true;
			FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, txtLogin.Text, DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups);
 
			//Encrypt the ticket.
			string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
 
			//Create a cookie, and then add the encrypted ticket to the cookie as data.
			HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
 
			if (true == isCookiePersistent)
				authCookie.Expires = authTicket.Expiration;
 
			//Add the cookie to the outgoing cookies collection.
			Response.Cookies.Add(authCookie);
 
						//You can redirect now.
			string redirectUrl = FormsAuthentication.GetRedirectUrl(txtLogin.Text, false);
 
In the global.asax.cs to keep the ticket going
void Application_AuthenticateRequest( Object s, EventArgs e )
		{
			string cookieName = FormsAuthentication.FormsCookieName;
			HttpCookie authCookie = Context.Request.Cookies[cookieName];
 
			if (null == authCookie)
			{
				//There is no authentication cookie.
				return;
			}
			FormsAuthenticationTicket authTicket = null;
			try
			{
				authTicket = FormsAuthentication.Decrypt(authCookie.Value);
			}
			catch 
			{
				//Write the exception to the Event Log.
				return;
			}
			if (null == authTicket)
			{
				//Cookie failed to decrypt.
				return;
			}
			//When the ticket was created, the UserData property was assigned a
			//pipe-delimited string of group names.
			string[] groups = authTicket.UserData.Split(new char[] { '|' });
 
			//Create an Identity.
			GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
			//This principal flows throughout the request.
			GenericPrincipal principal = new GenericPrincipal(id, groups);
 
			
			Context.User = principal;
					
		}

Open in new window

0
 
AshleighGreenCommented:
A \ cannot exist in a username.

You should therefore be able to do a split on the \
i.e.
string[] DomainUsername = txtUserName.Text.Split('\\');
You can then do a switch on the Domain
string LDAPAddress;
switch(DomainUsername[0])
{
     case "MyDomain1":
           LDAPAddress = "...........";
           break;
     case "MyDomain2":
           LDAPAddress = "...........";
           break;
       //And so on
}

From then on it's the same as your current code.

Is that what you are looking for? I have an application that allows users to authenticate against multiple domains, though this is done through a dropdownlist. If this is not your question please explain it in more details and I should be able to help you out.

Regards,
-Ashleigh
0
 
AshleighGreenCommented:
Hey,

Sorry, just to add to the above. If DomainUsername.Length == 1 then you know they only provided their username and can skip the domain stuff.
0
Improve Your Query Performance Tuning

In this FREE six-day email course, you'll learn from Janis Griffin, Database Performance Evangelist. She'll teach 12 steps that you can use to optimize your queries as much as possible and see measurable results in your work. Get started today!

 
shanemayAuthor Commented:
Thank, I think your solution would work fine if I coded the form, however, I am using the <asp:Login> control and I am not sure how to override its functionality or if I should scrap it and write it on my own.  

Thank you for the response and feedback.
0
 
AshleighGreenCommented:
Ah, I see.

I'm not particularly familiar with that control as I usually write it myself. A few possibilities.

1. Create a custom control that inherits from it. Override the login event and modify the username/domain details then just call the base method and let it run as per usual.

2. Create your own username/password/login etc control that only manipulates the username/password/login of a hidden <asp:login> control then programmatically triggers the login event on that control.

3. Write it from scratch.

I think each of these has it's advantages and that's probably the path I'd look at taking. Potentially 1 or 2 could be quicker. Depending on what you want to do 3 may be more future proof if you think you will need to make further modifications in the future.

If you need some LDAP code for 3 I can pull some up, but not until tonight (morning where I am now).
0
 
shanemayAuthor Commented:
Thank you for the options, I think I will look into number 1, because much of the <asp:login> control is dictated by the web config file.  Again, I appreciate the feedback.  I will leave another message based on what I find tomorrow morning, (night where I am now).

Again, thank you.  
0
 
shanemayAuthor Commented:
I have not had any luck with overriding the <asp:login>.  Maybe writing from scratch is what I need.  Can you point me in the right direction.  Thanks.
0
 
shanemayAuthor Commented:
Thank you for the code sample, this looks like excatly what I need.  I will put this in place over the weekend and respond back on Monday.  

Again, Thank you.
0
 
shanemayAuthor Commented:
Thank you, this is exactly what I need.  I appreciate your time and feedback.  
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.