hizperion Absent Member.
Absent Member.
4709 views

LDAP service and user authentication C#

I'm quite new to using LDAP for authentication I was given few parameters from security group to be implemented in the authentication script.

Service Account ID: myappsldapadmin 
UID: myappsldapadmin
Password: P@ssw0rd
DN: cn=myappsldapadmin,ou=serviceAccount,o=MyCompany

Groups Name: myapps
DN: cn=myapps,ou=groups,o=data
Query/Filter:
member=*


and this is what i have successful done to authenticate with the server:

try
{
//Authenticate the username and password
using (ldapConnection)
{
//Pass in the network creds, and the domain.
NetworkCredential networkCredential = new NetworkCredential(authUser, authPass);
//Since we're using unsecured port 389, set to false. If using port 636 over SSL, set this to true.
ldapConnection.SessionOptions.SecureSocketLayer = false;
ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
//To force NTLM\Kerberos use AuthType.Negotiate, for non-TLS and unsecured, use AuthType.Basic
ldapConnection.AuthType = System.DirectoryServices.Protocols.AuthType.Basic;
ldapConnection.Bind(networkCredential);
}
}
catch (Exception ex)
{
Response.Write("<br>Error ldapQuery:" + ex);
}


How do I go about getting users information after they supply their username and password?

This is what I got so far but it returns object does not exist. I didn't even know how to supply the password.

string username = Login1.UserName.ToUpper();
string password = Login1.Password;
string userDN = "cn=myapps,ou=groups,o=data"

System.DirectoryServices.Protocols.SearchRequest request =
new System.DirectoryServices.Protocols.SearchRequest(
username, //specified name
"cn="+username+","+userDN, //search filter
System.DirectoryServices.Protocols.SearchScope.Subtree, //scope
new string[] {"dn","cn"} //attributes
);


System.DirectoryServices.Protocols.SearchResponse response = (System.DirectoryServices.Protocols.SearchResponse)ldapConnection.SendRequest(request);

if(response.Entries.Count == 1)
{
System.DirectoryServices.Protocols.SearchResultEntry entry = response.Entries[0];
Response.Write("<br>Query: "+entry.DistinguishedName);
}
else
Response.Write("<br>Query: Result not found");


This is my attempt using Compare which doesn't seem to work either

	
LdapConnection conn = new LdapConnection();
try
{
// connect to the server
conn.Connect(serverIp, serverPort);

// authenticate to the server
conn.Bind(authUser, authPass);

LdapAttribute attr = new LdapAttribute("password", "mypassword");
bool correct = conn.Compare(cn="+username+","+userDN, attr);

Response.Write(correct?"<br>The password is correct.":"The password is incorrect.\n");

// disconnect with the server
conn.Disconnect();
}
catch (LdapException ex)
{
if (ex.ResultCode == LdapException.NO_SUCH_OBJECT)
{
Response.Write("<br>Error: No such entry");
}
else if (ex.ResultCode == LdapException.NO_SUCH_ATTRIBUTE)
{
Response.Write("<br>Error: No such attribute");
}
else
{
Response.Write("<br>Error: " + ex.ToString());
}
}
Labels (1)
0 Likes
5 Replies
Knowledge Partner
Knowledge Partner

Re: LDAP service and user authentication C#

On 10/22/2017 10:44 PM, hizperion wrote:
>
> I'm quite new to using LDAP for authentication I was given few
> parameters from security group to be implemented in the authentication
> script.


Welcome to the forum; LDAP is wonderful.

It may help if we find out which LDAP provider you are using on the
backend. e.g. eDirectory, OpenLDAP, Apache DS, etc.

> Code:
> --------------------
> Service Account ID: myappsldapadmin
> UID: myappsldapadmin
> Password: P@ssw0rd
> DN: cn=myappsldapadmin,ou=serviceAccount,o=MyCompany
>
> Groups Name: myapps
> DN: cn=myapps,ou=groups,o=data
> Query/Filter:
> member=*
> --------------------


I presume that really is a group object, but then you are using it below
more like a container which may be part of the problem with actually
finding your results after successfully binding to LDAP.

If you have not done so before, download Apache Directory Studio which is
a free and awesome LDAP client that lets you view/modify/whatever very
easily/graphically so you can better understand the structure without
necessarily coding to make it work from the start.

> and this is what i have successful done to authenticate with the
> server:
>
> Code:
> --------------------
> try
> {
> //Authenticate the username and password
> using (ldapConnection)
> {
> //Pass in the network creds, and the domain.
> NetworkCredential networkCredential = new NetworkCredential(authUser, authPass);
> //Since we're using unsecured port 389, set to false. If using port 636 over SSL, set this to true.
> ldapConnection.SessionOptions.SecureSocketLayer = false;
> ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
> //To force NTLM\Kerberos use AuthType.Negotiate, for non-TLS and unsecured, use AuthType.Basic
> ldapConnection.AuthType = System.DirectoryServices.Protocols.AuthType.Basic;
> ldapConnection.Bind(networkCredential);
> }
> }
> catch (Exception ex)
> {
> Response.Write("<br>Error ldapQuery:" + ex);
> }
> --------------------


Is there a reason you would use TCP 389, or is this just for testing until
you get things working? Either enabling StartTLS over 389 or using TCP
636 from the start is highly recommended for security reasons.

> How do I go about getting users information after they supply their
> username and password?
>
> This is what I got so far but it returns object does not exist. I didn't
> even know how to supply the password.


If you have not already done so, you may want to look at the LDAP SDK in
C# to see if the examples there can help you skip past common issues:

https://www.novell.com/documentation/developer/ldapcsharp/cnet/data/bovtz77.html

> Code:
> --------------------
> string username = Login1.UserName.ToUpper();
> string password = Login1.Password;
> string userDN = "cn=myapps,ou=groups,o=data"
>
> System.DirectoryServices.Protocols.SearchRequest request =
> new System.DirectoryServices.Protocols.SearchRequest(
> username, //specified name
> "cn="+username+","+userDN, //search filter
> System.DirectoryServices.Protocols.SearchScope.Subtree, //scope
> new string[] {"dn","cn"} //attributes
> );
>
>
> System.DirectoryServices.Protocols.SearchResponse response = (System.DirectoryServices.Protocols.SearchResponse)ldapConnection.SendRequest(request);
>
> if(response.Entries.Count == 1)
> {
> System.DirectoryServices.Protocols.SearchResultEntry entry = response.Entries[0];
> Response.Write("<br>Query: "+entry.DistinguishedName);
> }
> else
> Response.Write("<br>Query: Result not found");
> --------------------


With this last section of code I see a few things that do not make sense
to me in a generic LDAP sense. The first argument to the SearchRequest
object is just 'username' which is not normal; you probably need to
specify a connection, or a search base, or an LDAP filter for searching.
The connection is the one you setup in your previous example. Your search
base could be either zero-length string, or some container which holds
the sought object (e.g. o=data) directly or as a parent of a container
which holds that object. The scope for a valid search should be something
like Subtree, which you already have.

In your code example you have a line marked as search filter, but that is
actually, probably, a search base. If you know the DN of the object
(because all objects are in one container and you are given the username
within that container) then you can specify that full DN as the base,
leave the filter blank (or use the 'objectClass=*' default), set the scope
to Base (because there is no reason to waste resources on a subtree search
when you know exactly where the sought object is), and you should be fine
with getting a single result.

Also, your attribute list has one attribute and then the DN; asking for
the 'dn' as an attribute is redundant; every entry returned has a DN even
if you ask for no attribute (with the pseudo-attribute '1.1') so asking
for 'dn' is a common mistake made by programmers who are not LDAP gurus.

Finally, your code checking for the response count behaves correctly if
one entry is returned, but the 'else' branch is probably wrong, at least
until you change your scope to Base and make the other changes listed
above. The reason is that it is not uncommon for LDAP environments to
have multiple objects with the same CN; as a result, you should probably,
if ever doing a subtree search (which implies you do not know the full DN
of the object yet), that you have conditions for zero entries returned
(your 'else' branch now satisfies this) as well as code for more-than one
entry with an appropriate message.

Give it a shot and post back your code/results/etc. and we'll do what we
can to get you going.

--
Good luck.

If you find this post helpful and are logged into the web interface,
show your appreciation and click on the star below.

If you want to send me a private message, please let me know in the
forum as I do not use the web interface often.
hizperion Absent Member.
Absent Member.

Re: LDAP service and user authentication C#

Welcome to the forum; LDAP is wonderful.

It may help if we find out which LDAP provider you are using on the
backend. e.g. eDirectory, OpenLDAP, Apache DS, etc.

Thank you for your time replying!
The LDAP we're using is eDirectory
The specifications documents led me to this forums (Novell)

I presume that really is a group object, but then you are using it below
more like a container which may be part of the problem with actually
finding your results after successfully binding to LDAP.

If you have not done so before, download Apache Directory Studio which is
a free and awesome LDAP client that lets you view/modify/whatever very
easily/graphically so you can better understand the structure without
necessarily coding to make it work from the start.

great, i'm trying this Apache Directory Studio right now


Is there a reason you would use TCP 389, or is this just for testing until
you get things working? Either enabling StartTLS over 389 or using TCP
636 from the start is highly recommended for security reasons.

Yeah.. about this, the webpage we are discussing about is hosted on an old windows server, we are unable to install the SSL cert provided by the vendors. TCP 389 was opened specifically for this and few other systems for internal use. The system already pointing to an old LDAP server before, but it was using the simplest authentication method (bind using user's account, then retrieve attributes), also using TCP 389.

If you have not already done so, you may want to look at the LDAP SDK in
C# to see if the examples there can help you skip past common issues:

https://www.novell.com/documentation/developer/ldapcsharp/cnet/data/bovtz77.html

I actually went through this URL earlier, but unable to find ways to first bind to the service then authenticate and retrieve results. Best I can find inside was using Compare in my last example in first post.

With this last section of code I see a few things that do not make sense
to me in a generic LDAP sense. The first argument to the SearchRequest
object is just 'username' which is not normal; you probably need to
specify a connection, or a search base, or an LDAP filter for searching.
The connection is the one you setup in your previous example. Your search
base could be either zero-length string, or some container which holds
the sought object (e.g. o=data) directly or as a parent of a container
which holds that object. The scope for a valid search should be something
like Subtree, which you already have.

In your code example you have a line marked as search filter, but that is
actually, probably, a search base. If you know the DN of the object
(because all objects are in one container and you are given the username
within that container) then you can specify that full DN as the base,
leave the filter blank (or use the 'objectClass=*' default), set the scope
to Base (because there is no reason to waste resources on a subtree search
when you know exactly where the sought object is), and you should be fine
with getting a single result.

Thanks, this is what I was trying to understand. I tried all sorts of combinations but unable to get a proper response.
Could you give me an example how a complete specified name would look like when user provide their username and password?

Also, your attribute list has one attribute and then the DN; asking for
the 'dn' as an attribute is redundant; every entry returned has a DN even
if you ask for no attribute (with the pseudo-attribute '1.1') so asking
for 'dn' is a common mistake made by programmers who are not LDAP gurus.

Sorry about this, I was just testing out to get a response first. There are a lot of other attributes that we area able to get from the LDAP (givenName, jobGrade, mail etc)



Finally, your code checking for the response count behaves correctly if
one entry is returned, but the 'else' branch is probably wrong, at least
until you change your scope to Base and make the other changes listed
above. The reason is that it is not uncommon for LDAP environments to
have multiple objects with the same CN; as a result, you should probably,
if ever doing a subtree search (which implies you do not know the full DN
of the object yet), that you have conditions for zero entries returned
(your 'else' branch now satisfies this) as well as code for more-than one
entry with an appropriate message.

Understood, this also just for temporary testing.
0 Likes
hizperion Absent Member.
Absent Member.

Re: LDAP service and user authentication C#

ab;2468548 wrote:
I presume that really is a group object, but then you are using it below
more like a container which may be part of the problem with actually
finding your results after successfully binding to LDAP.

If you have not done so before, download Apache Directory Studio which is
a free and awesome LDAP client that lets you view/modify/whatever very
easily/graphically so you can better understand the structure without
necessarily coding to make it work from the start.

I managed to at least authenticate user password after using Apache Directory Studio and understands how queries work
I guess the rest would be easy

Nothing much wrong with my codes, I just confused about the DN
I'm using the Compare method and changed from "cn=userId000,ou=serviceAccount,o=Company" to "cn=userId000,ou=users,o=data" and it worked now!

Thanks a lot!
0 Likes
Knowledge Partner
Knowledge Partner

Re: LDAP service and user authentication C#

On 10/24/2017 12:44 AM, hizperion wrote:
>
> ab;2468548 Wrote:
>> I presume that really is a group object, but then you are using it below
>> more like a container which may be part of the problem with actually
>> finding your results after successfully binding to LDAP.
>>
>> If you have not done so before, download Apache Directory Studio which
>> is
>> a free and awesome LDAP client that lets you view/modify/whatever very
>> easily/graphically so you can better understand the structure without
>> necessarily coding to make it work from the start.

> I managed to at least authenticate user password after using Apache
> Directory Studio and understands how queries work
> I guess the rest would be easy
>
> Nothing much wrong with my codes, I just confused about the DN
> I'm using the Compare method and changed from
> "cn=userId000,ou=serviceAccount,o=Company" to
> "cn=userId000,ou=users,o=data" and it worked now!


Thank-you for reporting back your results as they may help others doing
similar things in the future.

I suppose as a last comment a few basic concepts may help somebody new to
LDAP:

First, a DN is the way to absolutely identify one object, e.g. a user, in
a directory. DNs look like cn=username,ou=context,o=goes,dc=here or
something like that. They can be pretty short (cn=manager) or really long
(much longer than above) but levels of the hierarchy are always
comma-delimited, and within each level you always have a naming attribute,
equal sign, and the name, e.g. cn = manager.

There are other ways to uniquely identify objects in a directory, but DN
is the one that everybody knows/uses/assumes by default. If you are
familiar with relational databases, a DN is kind of like a
schema/table/primary-key combination which, if you know that, you can find
any single row anywhere in a relational database.

Using a compare for authentication works as long as you know the DN and
password, but you could also do a bind directly as the authenticating user
rather than using an administrative user to compare the userPassword
against the specified value. One benefit in doing this is performance
(one operation instead of two or three) as well as security. On the
security side, you do not need to enable users to see other users'
passwords, and you also get benefits (in eDirectory at least) of intruder
detection, such as if a user tries to guess another user's password over
and over through your application.

Let us know if you have any other hangups and we'll do what we can to help
you.

--
Good luck.

If you find this post helpful and are logged into the web interface,
show your appreciation and click on the star below.

If you want to send me a private message, please let me know in the
forum as I do not use the web interface often.
0 Likes
hizperion Absent Member.
Absent Member.

Re: LDAP service and user authentication C#

First, a DN is the way to absolutely identify one object, e.g. a user, in
a directory. DNs look like cn=username,ou=context,o=goes,dc=here or
something like that. They can be pretty short (cn=manager) or really long
(much longer than above) but levels of the hierarchy are always
comma-delimited, and within each level you always have a naming attribute,
equal sign, and the name, e.g. cn = manager.

There are other ways to uniquely identify objects in a directory, but DN
is the one that everybody knows/uses/assumes by default. If you are
familiar with relational databases, a DN is kind of like a
schema/table/primary-key combination which, if you know that, you can find
any single row anywhere in a relational database.

yes.. that makes sense now
thanks for the explanation

Using a compare for authentication works as long as you know the DN and
password, but you could also do a bind directly as the authenticating user
rather than using an administrative user to compare the userPassword
against the specified value. One benefit in doing this is performance
(one operation instead of two or three) as well as security. On the
security side, you do not need to enable users to see other users'
passwords, and you also get benefits (in eDirectory at least) of intruder
detection, such as if a user tries to guess another user's password over
and over through your application.

the vendors requires us to first check whether user is allowed to access the apps (it's part of the requirements)
but i will try to play around the codes again for science

till we meet again!
0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.