• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1242
  • Last Modified:

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.
0
shanemay
Asked:
shanemay
  • 5
  • 4
1 Solution
 
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
 
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
NFR key for Veeam Agent for Linux

Veeam is happy to provide a free NFR license for one year.  It allows for the non‑production use and valid for five workstations and two servers. Veeam Agent for Linux is a simple backup tool for your Linux installations, both on‑premises and in the public cloud.

 
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
 
AshleighGreenCommented:
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
 
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

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now