I am currently aiming to implement a read-only role provider for an ASP.NET application based on domain security groups using the utilities in the System.DirectoryServices.AccountManagement
assembly. I have the following piece of code which works fine on my development domain, but fails in the deployment environment:
Using myContext As New PrincipalContext(ContextType.Domain, Nothing, "DC=My,DC=Controller", accountName, accountPassword)
Try
Dim p As UserPrincipal = UserPrincipal.FindByIdentity(myContext, IdentityType.SamAccountName, userName)
Dim groups = p.GetAuthorizationGroups()
For Each g In groups
Debug.WriteLine("Found security group: " & g.DisplayName & vbNewLine)
Next
Catch ex As Exception
Debug.WriteLine("Encountered an exception: " & vbNewLine & ex.ToString())
End Try
End Using
The exception stack trace returns as follows:
System.DirectoryServices.AccountManagement.PrincipalOperationException: There is no such object on the server. ---> System.DirectoryServices.DirectoryServicesCOMException (0x80072030): There is no such object on the server. at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at System.DirectoryServices.DirectoryEntry.Bind() at System.DirectoryServices.DirectoryEntry.get_SchemaEntry() at System.DirectoryServices.AccountManagement.ADStoreCtx.IsContainer(DirectoryEntry de) at System.DirectoryServices.AccountManagement.ADStoreCtx..ctor(DirectoryEntry ctxBase, Boolean ownCtxBase, String username, String password, ContextOptions options) at System.DirectoryServices.AccountManagement.PrincipalContext.CreateContextFromDirectoryEntry(DirectoryEntry entry) at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit() --- End of inner exception stack trace --- at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit() at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit() at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize() at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx() at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate) at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, IdentityType identityType, String identityValue) at System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, IdentityType identityType, String identityValue)
I know the obvious "gotcha" here is to be certain the object actually, well... exists on the server. However, I can confirm without a doubt that no matter which account's SAM Account Name I use, I receive the same result from the call. Additionally, Microsoft's ActiveDirectoryMembershipProvider
has no trouble authenticating against the same SAM Account Name and I am able to find the object using that information with the DirectorySearcher
class. The only differences I can identify between the development network and deployment is that the deployment environment's DC is a Windows Server 2003 box, whereas locally I am developing with a Windows Server 2008 DC. What might I be overlooking?
For some reason, the problem lay in the path to the domain controller. Describing the path as DC=box123,DC=dom
did not work, but using the path box123.dom
did. Can't say why, and it's not a behavior I can duplicate on the local domain, but that resolved the issue.
EDIT:
Upon further investigation, the construction DC=box123,DC=dom
when pared down to DC=dom
functioned correctly as well. I don't understand the dynamics of the addressing, but I was able to determine the trouble by displaying the path to a sample user using a DirectorySearcher object, which revealed the path to my user to be: LDAP://box123.dom/CN=username/CN=Users/DC=dom
I know this is a relatively old question, but I thought our solution might help someone else down the line. We encountered the same issue in the customer's live environment. Initially we couldn't replicate the issue in our test environment, but then we discovered it only happened when accessing the site under https. Through a lot of trial and error plus a support call to Microsoft, I started playing around with the call to create the principal context. Initially, the object instantiation was coded as
using (var pc = new PrincipalContext(ContextType.Domain, <serverUri>, <ldapDomain>, <username>, <userpass>))
The full constructor can take one additional parameter
using (var pc = new PrincipalContext(ContextType.Domain, <serverUri>, <ldapDomain>, ContextOptions.Negotiate, <username>, <userpass>))
Once the ContextOption
was specified (and in our case, it had to be Negotiate
), the call to UserPrincipal.FindByIdentity
worked as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With