Forms Auth with AD Native Mode

G

George Durzi

I'm authentication against ActiveDirectory by implementing forms
authentication similar to this MSDN article.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT02.asp

I want to make it so that the forms authentication supports AD Native Mode.
So the user should be able to enter
(e-mail address removed) as their username, and the provide their password to
login.

I can of course do this the dirty way, which is to use a regex validator to
make sure the username is entered in the (e-mail address removed) format, then
trim the @domain.com and authenticate normally.

But the nerd in me thinks that's an unacceptable solution.

Any tips?
 
M

Michael Gaillez

George Durzi said:
I'm authentication against ActiveDirectory by implementing forms
authentication similar to this MSDN article.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT02.asp

I want to make it so that the forms authentication supports AD Native Mode.
So the user should be able to enter
(e-mail address removed) as their username, and the provide their password to
login.

I can of course do this the dirty way, which is to use a regex validator to
make sure the username is entered in the (e-mail address removed) format, then
trim the @domain.com and authenticate normally.

But the nerd in me thinks that's an unacceptable solution.

Any tips?

in that example they use the netbios domainname to logon to active directory
but if the user provides (e-mail address removed) you should be able to use
that as well in stead of "yourdomain\username". this only works with AD.

so u use DirectoryEntry entry = new DirectoryEntry(somepath,
"(e-mail address removed)", "password");

I'm doing it over here and it works fine

greets

Michael
 
G

George Durzi

Michael,
I tried that but it doesn't work. We have our AD set to use Mixed Mode,
could that be why ?
 
M

Michael Gaillez

George Durzi said:
Michael,
I tried that but it doesn't work. We have our AD set to use Mixed Mode,
could that be why ?

My test-server here is mixed-mode as well so I guess that isn't the problem.

could you show me some code to see what exactly you are doing? I would be
glad to help you out by testing it over here...

the only relevant article I could find on it so far was this (but if it is
helpfull is yet another story):

http://www.microsoft.com/technet/tr...tserver/POP3_concept_understand_authentAD.asp

greets

Michael
 
G

George Durzi

Michael,
Here's some test code, it's gonna be very similar to the code in the article
I mentioned in my first post, with some tweaks.

Here's the bulk of my LDAPAuthentication class. I excluded the GetGroups
method, and also put in comments, the values of some stuff I'm pulling out
of web.config.

#region Constructor

#region LDAPAuthentication
public LDAPAuthentication() {}
#endregion

#region LDAPAuthentication(string path)
public LDAPAuthentication(string path) { _path = path; }
#endregion

#endregion

private string _path;
private string _filterattribute;

#region bool IsAuthenticated
public bool IsAuthenticated(
string Domain,
string UserName,
string Password)
{
// Credentials should be in the form Domain\UserName
string DomainUserName = Domain + @"\" + UserName;

// Create an Active Directory object
DirectoryEntry oDE = new DirectoryEntry(
_path, // LDAP://ELRW.com/DC=ELRW,DC=com
DomainUserName, // User
Password, // Password
AuthenticationTypes.Secure); // Authentication Type

try
{
// Get the native ADSI object
Object oNativeObject = oDE.NativeObject;
// Perform query against Active Directory
DirectorySearcher oDS = new DirectorySearcher(oDE);

// Set LDAP filter string
oDS.Filter = "(SAMAccountName=" + UserName + ")";
// Set the Properties retrieved during the search
oDS.PropertiesToLoad.Add("cn");

// Execute the search and only return the first entry
SearchResult oSR = oDS.FindOne();
// Check if any search results came back
if (null == oSR) return false;

// Set _path to the path of the search results
_path = oSR.Path;
// Set _filterattribute to the properties retrieved during the search
_filterattribute = (string)oSR.Properties["cn"][0];
}
catch (Exception)
{
return false;
}

return true;
}
#endregion

Here's the method in my Login page which called the IsAuthenticated method
of LDAPAuthentication

#region LoginUser
private void LoginUser()
{
// Retrieve LDAP Connect String and Domain Name
// LDAP://ELRW.com/DC=ELRW,DC=com
string sADPath =
ConfigurationSettings.AppSettings["LDAPConnectString"].ToString();
// ELRW
string sDomain =
ConfigurationSettings.AppSettings["DomainName"].ToString();

// Instance of LdapAuthentication class
LDAPAuthentication oLdapAuth = new LDAPAuthentication(sADPath);

try
{
if (true == oLdapAuth.IsAuthenticated(sDomain, txtUserName.Value.Trim(),
txtPassword.Value.Trim()))
{
// Retrieve a list of AD Groups the User is a Member of
string sGroups = oLdapAuth.GetGroups();

// Create the User's FormsAuthenticationTicket
FormsAuthenticationTicket oAuthTicket = new FormsAuthenticationTicket(
1, // Version
txtUserName.Value.Trim(), // Name
DateTime.Now, // Date Issued
DateTime.Now.AddHours(8), // Expiration Date --> 8 Hours
true, // Persistence
sGroups); // UserData --> Group Membership

// Encrypt the FormsAuthenticationTicket
string sTicket = FormsAuthentication.Encrypt(oAuthTicket);

// Create the auth cookie for the User
HttpCookie oCookie = new
HttpCookie(FormsAuthentication.FormsCookieName, sTicket);
oCookie.Expires = DateTime.Now.AddHours(8);

// Add the cookie to the collection
Response.Cookies.Add(oCookie);

// Create User Sessions
CreateUserSessions(txtUserName.Value.Trim());

// Redirect the User

Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUserName.Value.Trim(
), false));
}
else
{
divLoginError.Visible = true;
lblLogin.Text = "* Sorry, you entered incorrect login credentials,
please try again. *";
}
}
catch (Exception ex)
{
throw (ex);
}
}
#endregion


When I was testing trying to authenticate with mixed mode, I removed the
code that was adding the domain + "\" to my username.
I stuck a regex validator on my login screen to make sure the username came
in the format (e-mail address removed),

so, the new DirectoryEntry line woulda looked like this:

DirectoryEntry oDE = new DirectoryEntry(
LDAP://ELRW.com/DC=ELRW,DC=com,
(e-mail address removed)
"mypassword",
AuthenticationTypes.Secure);

Thanks for your help!!
 
M

Michael Gaillez

just some small extra question. could you tell me where the code throws an
exception in this routine in the case you use (e-mail address removed)? because I
see that you use samaccountname to filter and that won't work if you assign
(e-mail address removed) to that as well... If you get past the Object
oNativeObject =oDE.NativeObject; line then authentication works...

greets

Michael
try
{
// Get the native ADSI object
Object oNativeObject = oDE.NativeObject;
// Perform query against Active Directory
DirectorySearcher oDS = new DirectorySearcher(oDE);

// Set LDAP filter string
oDS.Filter = "(SAMAccountName=" + UserName + ")";
// Set the Properties retrieved during the search
oDS.PropertiesToLoad.Add("cn");

// Execute the search and only return the first entry
SearchResult oSR = oDS.FindOne();
// Check if any search results came back
if (null == oSR) return false;

// Set _path to the path of the search results
_path = oSR.Path;
// Set _filterattribute to the properties retrieved during the search
_filterattribute = (string)oSR.Properties["cn"][0];
}
catch (Exception)
{
return false;
}

return true;
}
#endregion
 
G

George Durzi

Michael,
At this time, my code only handles a username and automatically prefixes
domain\ to it. When testing mixed mode authentication, I disabled that in
code. I would obviously add some sort of validation to make sure the
username is entered as (e-mail address removed). So I'm not throwing any
exceptions based on the formatting of the username entered.

If I modify my code to allow (e-mail address removed), and NOT automatically
prefix the username with domain\ and I go into debug mode, I get as far as

and return false, coz no results were found. Should I not be using
SAMAccountName if I want to use mixed mode?

Thanks again Michael


Michael Gaillez said:
just some small extra question. could you tell me where the code throws an
exception in this routine in the case you use (e-mail address removed)? because I
see that you use samaccountname to filter and that won't work if you assign
(e-mail address removed) to that as well... If you get past the Object
oNativeObject =oDE.NativeObject; line then authentication works...

greets

Michael
try
{
// Get the native ADSI object
Object oNativeObject = oDE.NativeObject;
// Perform query against Active Directory
DirectorySearcher oDS = new DirectorySearcher(oDE);

// Set LDAP filter string
oDS.Filter = "(SAMAccountName=" + UserName + ")";
// Set the Properties retrieved during the search
oDS.PropertiesToLoad.Add("cn");

// Execute the search and only return the first entry
SearchResult oSR = oDS.FindOne();
// Check if any search results came back
if (null == oSR) return false;

// Set _path to the path of the search results
_path = oSR.Path;
// Set _filterattribute to the properties retrieved during the search
_filterattribute = (string)oSR.Properties["cn"][0];
}
catch (Exception)
{
return false;
}

return true;
}
#endregion
 
M

Michael Gaillez

George Durzi said:
Michael,
At this time, my code only handles a username and automatically prefixes
domain\ to it. When testing mixed mode authentication, I disabled that in
code. I would obviously add some sort of validation to make sure the
username is entered as (e-mail address removed). So I'm not throwing any
exceptions based on the formatting of the username entered.

If I modify my code to allow (e-mail address removed), and NOT automatically
prefix the username with domain\ and I go into debug mode, I get as far as


and return false, coz no results were found. Should I not be using
SAMAccountName if I want to use mixed mode?

It's what I thought. It is like that. the following line throws an exception
if you don't have correct security credentials.

Object oNativeObject = oDE.NativeObject;

Since it doesn't throw an exception it means that your credentials are
correct and you get authenticated.

Then the samaccountname must simple be username without the @domain added to
it. Otherwise it will indeed not return any results. I suggest you simply
split the (e-mail address removed) string and only provide the first part before
@ to the samaccountname (something like this)

String[] UserNameArray;
UserNameArray = UserName.Split("@".ToCharArray());

oDS.Filter = "(SAMAccountName=" + UserNameArray[0] + ")";


greets

Michael
 
G

George Durzi

Thanks Michael,
At least now I have a working solution. Like you said, I must be getting
authenticated properly if no Exception is being thrown at the
oDE.NativeObject line.

I'll find out if this works 100% when we switch away from Mixed mode to all
Native mode.

Thanks for your help!

Michael Gaillez said:
George Durzi said:
Michael,
At this time, my code only handles a username and automatically prefixes
domain\ to it. When testing mixed mode authentication, I disabled that in
code. I would obviously add some sort of validation to make sure the
username is entered as (e-mail address removed). So I'm not throwing any
exceptions based on the formatting of the username entered.

If I modify my code to allow (e-mail address removed), and NOT automatically
prefix the username with domain\ and I go into debug mode, I get as far as


and return false, coz no results were found. Should I not be using
SAMAccountName if I want to use mixed mode?

It's what I thought. It is like that. the following line throws an exception
if you don't have correct security credentials.

Object oNativeObject = oDE.NativeObject;

Since it doesn't throw an exception it means that your credentials are
correct and you get authenticated.

Then the samaccountname must simple be username without the @domain added to
it. Otherwise it will indeed not return any results. I suggest you simply
split the (e-mail address removed) string and only provide the first part before
@ to the samaccountname (something like this)

String[] UserNameArray;
UserNameArray = UserName.Split("@".ToCharArray());

oDS.Filter = "(SAMAccountName=" + UserNameArray[0] + ")";


greets

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top