Re: SetPassword access denied
- From: "Joe Kaplan" <joseph.e.kaplan@xxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Thu, 19 Feb 2009 15:08:37 -0600
Glad you have the book. Sorry it did not magically solve this problem for you. We tried. :) We rewrote ch 8 3 times before we shipped and I still think we could have explained some of this stuff a little better. It is a difficult topic to nail perfectly.
That said, I think one thing worth pointing out is that in both cases here, your code is supplying credentials to the DirectoryEntry constructor. In that case, the identity of the current thread (established either via impersonation or using the process token without impersonation) is NOT the account that is used for performing remote activities in the directory.
Basically, you should either impersonate and use default credentials OR not impersonate and supply credentials directly to the DirectoryEntry. I don't quite get why you need to supply fixed credentials for just the pwd set either. It really should work consistently.
I'm also a big fan of using the SDS.P-based LDAP password changer from ch 10 and using SSPI auth with signing and sealing enabled as the default mechanism for doing pwd changes. Using this approach avoids all the confusion that can come from calling SetPassword and also allows you to bypass the need for SSL. You can still use SSL if you want and it is available, but you don't have to. This will work cleanly with impersonation as well.
Of course, this requires some recode, but I think it is overall more sustainable. For high scale situations, you can also pool LDAP connections on a "per OU admin" basis if needed.
If you set any other auth flags and don't set "Secure", you WILL be doing simple bind. That is usually a bad idea. I recommend always doing secure bind to AD, even if you are also using SSL.
If you are using a fixed DC, ServerBind gives you a little perf increase. As per the book, I'd suggest not using the IP address as that breaks Kerb auth. If impersonation is possible, DNS resolution ought to be working too. :) I can understand having to use a fixed DC if your system can't tolerate the possibility of "jumping" to another DC (dirsync, logical inconsistency due to replication lag, etc.).
I hope that gives you some ideas. I still can't quite tell what is wrong though.
--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
"systinte5" <systinte5@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message news:8BC21C53-B173-4278-8B35-595A33E1204B@xxxxxxxxxxxxxxxx
Hi Joe,
Sorry that I did not post the code snippet. Can you critique on the way we
create the DirectoryEntry object in the non-secure ldap (port 389)? Per your
book, you recommend on page 91 (Recommendations for AuthenticationTypes), it
is better to use both SECURE and SERVERBIND (because we specify full IP
address of DC in the LDAP path). We are not doing that when going to port
389. Also we use the OUAdmin credential both to impersonate (because we do a
lot of other stuff after setting password that requires that we be running as
the OUAdmin) and in the ActiveDirectory constructor. All of this works in a
number of locations. We are having the access denied error just in this
client location, so we are not entirely sure if it is the code or some other
permissions.
try
{
using (new Impersonator(userSA, domainSA, passwordSA))
{
message = "Before DirectoryEntry For " + info;
if (port == "636")
newUser = new DirectoryEntry(path, domainSA + @"\" + userSA,
passwordSA, AuthenticationTypes.SecureSocketsLayer);
else
newUser = new DirectoryEntry(path, domainSA + @"\" + userSA,
passwordSA);// no authenticationtype used)
//Ensure that the password is set
message = "Before pwdLastSet For " + info;
newUser.Properties["pwdLastSet"].Value = 0; // this does not
crash - newUser is not null
message = "Before SetPassword For " + info;
newUser.Invoke("SetPassword", new object[] { userPassword }); //
this crashes - the catch block sends back the message string to caller and it
shows Before SetPassword For ..... and inner exception is E_ACCESSDENIED with
0x80070005
Thanks.
--------
"systinte5" wrote:
Thanks Joe. I am a proud owner of your (and Ryan Dunn) book "The .NET
Developer's Guide to Directory Services Programming". The reason, we
impersonate is because depending on the OU, there may be a different OU
administrator who is delegated admin rights on that OU. This made it
flexible. The service itself is a .NET remoting server and runs with minimal
rights.
Thanks again.
------
"Joe Kaplan" wrote:
> It really should work the same way if the same credentials are being > used to
> contact the directory.
>
> One thing you could do in your code for debug purposes would be to call
> WindowsIdentity.GetCurrent() and dump out the identity groups info > somewhere
> right before the SetPassword method is called. This will help ensure > that
> you are really running with the identity and thus the permissions you > think
> you are.
>
> I still can't think of a reason why the permissions would be lower > though if
> the same account logged in interactively on the same box can execute > the
> same steps.
>
> SetPassword under the hood attempts to reset the password either by > LDAP,
> Kerberos or NetUserSetInfo, depending on what options are available. > The
> authorization policy is always applied by the DC based on the identity > of
> the user who executed the LDAP bind. Note that if you did the bind > before
> you started impersonation, that could potentially cause weird things to
> happen. Maybe showing a snip of code would be possible?
>
> I also wonder why you impersonate in code rather than having the > service
> execute as the privileged user directly? Either should be possible but
> impersonation causes you to have to store the plaintext credentials of > the
> privileged user somewhere instead of just letting the service control
> manager take care of that.
>
> -- > Joe Kaplan-MS MVP Directory Services Programming
> Co-author of "The .NET Developer's Guide to Directory Services > Programming"
> http://www.directoryprogramming.net
> "systinte5" <systinte5@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
> news:01BA1584-7663-4D85-99F8-D3461FFCF3EF@xxxxxxxxxxxxxxxx
> > .NET 2.0 c# code running as a service (no, it does not use the system
> > account). The service impersonates an OUAdmin account in order to > > create a
> > user account in that OU. We are able to create an account through the
> > software. However when SetPassword() is invoked, it encounters > > 0x80070005
> > E_ACCESSDENIED. The impersonated account is just a domain user > > account
> > that
> > has been delegated administrative control of the OU. The account is > > also a
> > member of the local machine built-in Administrators group. The funny > > thing
> > is, if we manually login using the impersonated account, we are able > > to
> > create new accounts n that OU and set the initial password and set > > the
> > change
> > password at next logon. The access denied only occurs when doen in
> > software,
> > that too only at certain client locations. Most places we have tested > > the
> > code, it works fine. How can we diagnose the problem? I keep > > thinking, it
> > is
> > not the code, rather COM permissions issue (because 0x80070005 is a > > COM
> > error)? When manually creating the account and setting the password, > > I am
> > sure Microsoft is not doing this using the same interfaces we > > developers
> > are
> > using?
> >
> > Thanks for any assistance.
>
>
.
- References:
- SetPassword access denied
- From: systinte5
- Re: SetPassword access denied
- From: Joe Kaplan
- Re: SetPassword access denied
- From: systinte5
- Re: SetPassword access denied
- From: systinte5
- SetPassword access denied
- Prev by Date: Re: active directory project
- Next by Date: Re: AD: Windows 2000 to Windows 2008 how to proceed
- Previous by thread: Re: SetPassword access denied
- Next by thread: Domain Error
- Index(es):
Relevant Pages
|