Active Directory

M

Marc Scheuner

Being a little less familiar with accessing AD, can someone tell me the best
way to obtain an AD user record (profile). Ultimately I would like to simply
obtain the manager that has been assigned to a specific user.

You will need to bind to the user's AD object - this requires that you
understand what LDAP path names are,and how to construct those.

Something like: LDAP://yourserver01.domain.com/cn=Bob
Mixon,OU=IT,OU=Headquarters,dc=domain,dc=com

In order to be able to bind to an AD object, you'll need to add a
reference to the "System.DirectoryServices" assembly to your project,
and add a "using System.DirectoryServices" line into your code.

From there, you bind to the user by constructing a DirectoryEntry
object instance:

string ldapPath = "LDAP://yourserver01.domain.com/cn=Bob
Mixon,OU=IT,OU=Headquarters,dc=domain,dc=com";

DirectoryEntry deUser = new DirectoryEntry(ldapPath);

Once you have a "deUser" object, you can query for any valid LDAP
property, e.g. things like "givenName" (first name), "sn" (surname =
last name), "mail" (e-mail address) and so forth.

string firstName = deUser.Properties["givenName"].Value;

and so forth.

For more info, I'd suggest

* the MSDN portal for System.DirectoryServices
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/portal.asp

* Joe Kaplan and Ryan Dunn's outstanding book on S.DS programming (the
"bible" for any S.DS programmer, really)

The .NET Developer's Guide to Directory Services Programming
http://www.amazon.com/Developers-Di..._bbs_sr_1/104-3503577-8887962?ie=UTF8&s=books

* my C# ADSI object browser called "BeaverTail" (free and with source
code):
http://adsi.mvps.org/adsi/CSharp/beavertail.html

Cheers!
Marc
 
B

Bob Mixon

Hi Marc,

I really appreciate your response. I have done quite a bit of reading and
am still struggling with getting this to work. I am a seasoned developer,
just not with using Directory Services and LDAP.

Here is what I have. I have a Windows 2003 Server VM that I use for SharePoint
development efforts. In this type of "sandbox" environment, it is very common
to have everything installed on the single server. This VM is an AD DC,
running SQL Server 2005 and MOSS. I understand this won't be the same in
a "real" production environment. The server is named "w2k3" and the domain
is simply "moss".

I am first trying to simply see if an LDAP entry exist. The entry "LDAP://DC=moss"
returns a valid DirectoryService object instance. And so does "LDAP://DC=moss/CN=Users".
However, the entry "LDAP://DC=moss/CN=Bob Mixon" and "LDAP://DC=moss,CN=Bob
Mixon" both fail. The account "Bob Mixon" is valid in AD; i.e. user id bob.mixon,
name "Bob Mixon".

Ultimately all I want to do is locate a user account then retrieve that users
manager information. This can't be that difficult.

Thank you for your time! :)

Bob Mixon [Microsoft SharePoint MVP]
http://www.ShareSquared.com
http://www.ShareSquared.com/blogs/BobMixon
Being a little less familiar with accessing AD, can someone tell me
the best way to obtain an AD user record (profile). Ultimately I
would like to simply obtain the manager that has been assigned to a
specific user.
You will need to bind to the user's AD object - this requires that you
understand what LDAP path names are,and how to construct those.

Something like: LDAP://yourserver01.domain.com/cn=Bob
Mixon,OU=IT,OU=Headquarters,dc=domain,dc=com

In order to be able to bind to an AD object, you'll need to add a
reference to the "System.DirectoryServices" assembly to your project,
and add a "using System.DirectoryServices" line into your code.

From there, you bind to the user by constructing a DirectoryEntry
object instance:

string ldapPath = "LDAP://yourserver01.domain.com/cn=Bob
Mixon,OU=IT,OU=Headquarters,dc=domain,dc=com";

DirectoryEntry deUser = new DirectoryEntry(ldapPath);

Once you have a "deUser" object, you can query for any valid LDAP
property, e.g. things like "givenName" (first name), "sn" (surname =
last name), "mail" (e-mail address) and so forth.

string firstName = deUser.Properties["givenName"].Value;

and so forth.

For more info, I'd suggest

* the MSDN portal for System.DirectoryServices
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/s
ds/portal.asp
* Joe Kaplan and Ryan Dunn's outstanding book on S.DS programming (the
"bible" for any S.DS programmer, really)

The .NET Developer's Guide to Directory Services Programming

http://www.amazon.com/Developers-Directory-Programming-Microsoft-Devel
opment/dp/0321350170/sr=8-1/qid=1168695760/ref=pd_bbs_sr_1/104-3503577
-8887962?ie=UTF8&s=books

* my C# ADSI object browser called "BeaverTail" (free and with source
code):
http://adsi.mvps.org/adsi/CSharp/beavertail.html
Cheers!
Marc
 
J

Joe Kaplan

Hi Bob,

There is no way those paths you have are going to be working correctly.
LDAP distinguished names (DN) are similar to file system paths in that they
suggest the directory hierarchy, but with three key differences:
- They are listed in opposite order (most specific first instead of last
like a file system path)
- Each component in the hierarchy has a two part name called a relative
distinguished name (RDN) that is made up of the naming attribute and value.
For example, CN=someuser could be an RDN where CN is the naming attribute
and someuser is the value of CN for that object. AD uses just three naming
attributes: CN, OU and DC, although LDAP in general can be much more varied.
- The top level object in the hierarchy (called the naming context name or
domain root in some cases) may consist of more than one RDN component. For
example, you might have the NC name as DC=domain,DC=com.

As such, a typical DN for a user might be
CN=someuser,CN=Users,DC=domain,DC=com. Here, CN=someuser points to the user
object, CN=Users points to the default container in AD where users are
stored and DC=domain,DC=com points to the domain root.

Now, with an ADsPath (which is used by ADSI and System.DirectoryServices),
the path is a combo of the provider, the server (which can be optional) and
the object name. It goes like:

<provider>://<server>/<object>

In LDAP, the provider is always "LDAP" (upper case is important) unless you
are talking to the global catalog, in which it is GC. The server name is
optional and can be the DNS name of the DC, the DNS name of the domain, the
NetBIOS name of the domain or the IP address of the DC. I generally
recommend using either the DNS name of the domain or nothing (called
"serverless binding" in ADSI terms). However, when you use nothing, ADSI
uses the current security context of the thread to figure out what domain to
contact and this can get complex in web apps, so you can get unexpected
failures this way. Adding the domain name is safe. The object name is the
distinguished name of the object. As such, a valid ADsPath for the DN of
the example object above might be:

LDAP://domain.com/CN=someuser,CN=Users,DC=domain,DC=com

or

LDAP://mydc.domain.com/CN=someuser,CN=Users,DC=domain,DC=com

or

LDAP://CN=someuser,CN=Users,DC=domain,DC=com

Remember that with S.DS, the constructor doesn't actually bind the object
(it is late binding), so you'll generally get an object back when you use
the constructor. It will just fail later when you attempt to use it. This
is a little different than ADSI in VB or VBScript.

My recommendation would be to pick up Marc's browser that he wrote (good
sample code inside) or just get LDP.exe which comes with ADAM or the Windows
adminpack. I like it especially, as it is sort of the "query analyzer" for
LDAP. It kind of forces you to know what you are doing, but it also shows
you exactly what is going and and can really help you prototype your
queries.

My book (that Marc aluded to) has a bunch of other helpful stuff. You may
run into issues related to security context when you move this into
production and have everything on different boxes. It is very much like
getting SSPI auth to work with a remote SQL server. You need to understand
security context and delegation quite well, especially if you are using
impersonation and want to connect to AD as the authenticated user instead of
the app pool process identity.

LDAP can be an annoying struggle for those seeing it for the first time,
even for experienced devs like you, but it all comes together once you get a
few things down.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Bob Mixon said:
Hi Marc,

I really appreciate your response. I have done quite a bit of reading and
am still struggling with getting this to work. I am a seasoned developer,
just not with using Directory Services and LDAP.

Here is what I have. I have a Windows 2003 Server VM that I use for
SharePoint development efforts. In this type of "sandbox" environment, it
is very common to have everything installed on the single server. This VM
is an AD DC, running SQL Server 2005 and MOSS. I understand this won't be
the same in a "real" production environment. The server is named "w2k3"
and the domain is simply "moss".

I am first trying to simply see if an LDAP entry exist. The entry
"LDAP://DC=moss" returns a valid DirectoryService object instance. And so
does "LDAP://DC=moss/CN=Users". However, the entry "LDAP://DC=moss/CN=Bob
Mixon" and "LDAP://DC=moss,CN=Bob Mixon" both fail. The account "Bob
Mixon" is valid in AD; i.e. user id bob.mixon, name "Bob Mixon".

Ultimately all I want to do is locate a user account then retrieve that
users manager information. This can't be that difficult.

Thank you for your time! :)

Bob Mixon [Microsoft SharePoint MVP]
http://www.ShareSquared.com
http://www.ShareSquared.com/blogs/BobMixon
 
B

Bob Mixon

Greetings Joe,

I really appreciate all of the information. I am going to go ahead and purchase
your book. I didn't really want to have to go through all of this but I
don't see any way around it. :)

In the meantime I have a couple of additional questions. When I am specifying
the user name (CN), is it the user name or account name?

Thank you again and I will keep you posted on my progress!

Bob Mixon [Microsoft SharePoint MVP]
http://www.ShareSquared.com
http://www.ShareSquared.com/blogs/BobMixon
 
J

Joe Kaplan

The CN is the CN. :) It is not the account name, as that is stored in the
sAMAccountName attribute (the username in "domain\username"). Unfortunately
AD has a ton of naming attributes (CN, userPrincipalName, sAMAccountName,
displayName, givenName, SN, etc.), so it can be confusing.

It is often the case that CN will be the same as sAMAccountName, but that
would just be by convention. The directory doesn't enforce that.

If you have the logon name and need to find the user in the directory, you
typically have to use the DirectorySearcher to search for them with a filter
like:

(sAMAccountName=username)

I do appreciate you buying my book. Thanks. :) I'm happy to continue to
help either way, but it may save you a bunch of trouble. I'm sure Marc will
be happy to jump in as well if I give him half a chance. He knows this
stuff real well too. :)

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Bob Mixon said:
Greetings Joe,

I really appreciate all of the information. I am going to go ahead and
purchase your book. I didn't really want to have to go through all of
this but I don't see any way around it. :)

In the meantime I have a couple of additional questions. When I am
specifying the user name (CN), is it the user name or account name?

Thank you again and I will keep you posted on my progress!

Bob Mixon [Microsoft SharePoint MVP]
http://www.ShareSquared.com
http://www.ShareSquared.com/blogs/BobMixon
Hi Bob,

There is no way those paths you have are going to be working
correctly.
LDAP distinguished names (DN) are similar to file system paths in that
they
suggest the directory hierarchy, but with three key differences:
- They are listed in opposite order (most specific first instead of
last
like a file system path)
- Each component in the hierarchy has a two part name called a
relative
distinguished name (RDN) that is made up of the naming attribute and
value.
For example, CN=someuser could be an RDN where CN is the naming
attribute
and someuser is the value of CN for that object. AD uses just three
naming
attributes: CN, OU and DC, although LDAP in general can be much more
varied.
- The top level object in the hierarchy (called the naming context
name or
domain root in some cases) may consist of more than one RDN component.
For
example, you might have the NC name as DC=domain,DC=com.

As such, a typical DN for a user might be
CN=someuser,CN=Users,DC=domain,DC=com. Here, CN=someuser points to
the user object, CN=Users points to the default container in AD where
users are stored and DC=domain,DC=com points to the domain root.

Now, with an ADsPath (which is used by ADSI and
System.DirectoryServices), the path is a combo of the provider, the
server (which can be optional) and the object name. It goes like:

<provider>://<server>/<object>

In LDAP, the provider is always "LDAP" (upper case is important)
unless you are talking to the global catalog, in which it is GC. The
server name is optional and can be the DNS name of the DC, the DNS
name of the domain, the NetBIOS name of the domain or the IP address
of the DC. I generally recommend using either the DNS name of the
domain or nothing (called "serverless binding" in ADSI terms).
However, when you use nothing, ADSI uses the current security context
of the thread to figure out what domain to contact and this can get
complex in web apps, so you can get unexpected failures this way.
Adding the domain name is safe. The object name is the distinguished
name of the object. As such, a valid ADsPath for the DN of the
example object above might be:

LDAP://domain.com/CN=someuser,CN=Users,DC=domain,DC=com

or

LDAP://mydc.domain.com/CN=someuser,CN=Users,DC=domain,DC=com

or

LDAP://CN=someuser,CN=Users,DC=domain,DC=com

Remember that with S.DS, the constructor doesn't actually bind the
object (it is late binding), so you'll generally get an object back
when you use the constructor. It will just fail later when you
attempt to use it. This is a little different than ADSI in VB or
VBScript.

My recommendation would be to pick up Marc's browser that he wrote
(good sample code inside) or just get LDP.exe which comes with ADAM or
the Windows adminpack. I like it especially, as it is sort of the
"query analyzer" for LDAP. It kind of forces you to know what you are
doing, but it also shows you exactly what is going and and can really
help you prototype your queries.

My book (that Marc aluded to) has a bunch of other helpful stuff. You
may run into issues related to security context when you move this
into production and have everything on different boxes. It is very
much like getting SSPI auth to work with a remote SQL server. You
need to understand security context and delegation quite well,
especially if you are using impersonation and want to connect to AD as
the authenticated user instead of the app pool process identity.

LDAP can be an annoying struggle for those seeing it for the first
time, even for experienced devs like you, but it all comes together
once you get a few things down.

Joe K.
 
M

Marc Scheuner

In the meantime I have a couple of additional questions. When I am specifying
the user name (CN), is it the user name or account name?

The CN (common name) is really the *object* name of the AD object -
which as Joe points out really doesn't necessarily have anything to do
with your user name (first and last name), nor his (or her) account
name (as in Win NT account, "domain\user").

Confusing? Maybe - just think of it that way - you could leave you AD
object alone (it's CN), while still changing first name, last name,
account name, and a plethora of other names, too - but your OBJECT
name is still the same.

Marc
 
J

Joe Kaplan

Glad you got it working. Tools like ADSI Edit and ldp.exe can really help
with these types of issues in case you end up having to walk up to an AD you
aren't familiar with in the future. They generally know how to bootstrap
enough of the key data (such as the name of the default naming context for
the domain and its DNS name) to get you off the ground and allow you to
quickly test an operation before coding it and making you wonder whether the
problem is your actual logic or just the values you are passing in.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Bob Mixon said:
Hey Joe and Marc,

I really approciate all of your help; I did get things working. After
following all of your direction, I was still having a few problems and it
was due to my using the incorrect FQDN. My domain is simply 'moss' so I
had to use "DC=moss,DC=local"; the "DC=local" is the part I wasn't
providing.

Bob Mixon [SPS MVP]
http://www.ShareSquared.com
http://www.ShareSquared.com/blogs/BobMixon
The CN (common name) is really the *object* name of the AD object -
which as Joe points out really doesn't necessarily have anything to do
with your user name (first and last name), nor his (or her) account
name (as in Win NT account, "domain\user").

Confusing? Maybe - just think of it that way - you could leave you AD
object alone (it's CN), while still changing first name, last name,
account name, and a plethora of other names, too - but your OBJECT
name is still the same.

Marc
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top