I hate wasting time, especially when it’s because of an obvious error that’s staring me in the face but I just can’t see it. Well, it happened today so I thought I’d make a note so it never happens again. Take the following code:
var principalContext = new PrincipalContext(ContextType.Domain, domain); var validated = principalContext.ValidateCredentials(userName, password); var userPrincipal = UserPrincipal.FindByIdentity(principalContext, userName);
My problem was that an exception was being thrown on the last line. “How is this possible?” I asked myself. “The call to ValidateCredentials worked so why the error on FindByIdentity?”
Firstly, the exception:
Exception thrown autenticating the user. System.DirectoryServices.DirectoryServicesCOMException (0x8007052E): Logon failure: unknown user name or bad password. at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at System.DirectoryServices.DirectoryEntry.Bind() at System.DirectoryServices.DirectoryEntry.get_AdsObject() at System.DirectoryServices.PropertyValueCollection.PopulateList() at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName) at System.DirectoryServices.PropertyCollection.get_Item(String propertyName) at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer() 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, String identityValue) at System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, String identityValue) at GL.AnglianWater.WIRM.Core.Membership.LdapAuthentication.Authenticate(String userName, String password, String domain, String requiredGroup)
Drilling into the exception details in Visual Studio 2010 yielded a bit more information:
ExtendedError = -2146893044 ExtendedErrorMessage = "8009030C: LdapErr: DSID-0C0904DC, comment: AcceptSecurityContext error, data 52e, v1db1"
After scratching my head for an age the solution turned out to be so obvious as to be embarrassing; simply create the PrincipleContext by passing in the username and password too:
var principalContext = new PrincipalContext(ContextType.Domain, domain, userName, password); var validated = principalContext.ValidateCredentials(userName, password); var userPrincipal = UserPrincipal.FindByIdentity(principalContext, userName);
Doh!