Active Directory Services: PrincipalContext — What

2019-01-16 09:57发布

问题:

I'm currently trying to authenticate via Active Directory Services using the PrincipalContext class. I would like to have my application authenticate to the Domain using Sealed and SSL contexts. In order to do this, I have to use the following constructor of PrincipalContext (link to MSDN page):

public PrincipalContext(
    ContextType contextType,
    string name,
    string container,
    ContextOptions options
)

Specifically, I'm using the constructor as so:

PrincipalContext domainContext = new PrincipalContext(
    ContextType.Domain, 
    domain, 
    container, 
    ContextOptions.Sealing | ContextOptions.SecureSocketLayer);

MSDN says about "container":

The container on the store to use as the root of the context. All queries are performed under this root, and all inserts are performed into this container. For Domain and ApplicationDirectory context types, this parameter is the distinguished name (DN) of a container object.

What is the DN of a container object? How do I find out what my container object is? Can I query the Active Directory (or LDAP) server for this?

回答1:

Well, I managed to figure out the issue:

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,domain);

domainContext.ValidateCredentials(userName, password, 
    ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);

By specifying the ContextOptions in the ValidateCredentials method (instead of in the constructor), this allowed me to avoid having to specify a DN for a container object.

UPDATE:

Although I should clarify that after further experimentation, I found that any queries derived from this PrincipalContext object takes place UN-encrypted.

Apparently, when the ContextOptions are set in ValidateCredentials, those options are only used for that specific call of ValidateCredentials. But here's where it gets strange...

So, I wanted to have my queries to the AD server take place encrypted as well. Example query:

UserPrincipal p = UserPrincipal.FindByIdentity(
    domainContext, IdentityType.SamAccountName, userName);
var groups = p.GetGroups();
foreach (GroupPrincipal g in groups) { /* do something */ }

The above code gets a list of all the Groups that the user belongs to, but it happens in the clear (unencrypted). So after much fiddling, I discovered that the DN never needs to be set.

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,domain,
    null,ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);

I found that I could set the container object (DN) to null. And this works fine. Setting it to an empty string ("") results in an exception of some unknown type, so don't think you can give it an empty string.

And here's the weird part. You'd think that setting the SecureSocketLayer option in the PrincipalContext would mean that you don't have to explicitly set it when you use VerifyCredentials. But I found that if I didn't set it in the VerifyCredentials part, the authentication would fail, but the queries (like in the example to the Groups) still takes place encrypted.

Maybe I just don't fully understand AD authentication and queries yet, but that seems like odd behavior to me.