Re: Changing domain user password
- From: "Harry Devine" <hdevine@xxxxxxxxxxxxxxxx>
- Date: Thu, 22 Dec 2005 13:28:21 -0500
We plan on upgrading our servers to Win2K3 early next year, so maybe I'll
put this off until then and get it working. I did upgrade the Framework to
2.0 in the mean time. How would I go about adding the machine account for
Kerberos Delegation?
Thanks,
Harry
"Joe Kaplan (MVP - ADSI)" <joseph.e.kaplan@xxxxxxxxxxxxxxxxxxxxxxxx> wrote
in message news:elN7cEyBGHA.4076@xxxxxxxxxxxxxxxxxxxxxxx
> Ok. In this case, you really want to be using the ChangePassword method,
> not SetPassword. SetPassword is for administrative resets.
> ChangePassword is generally only performed by a user on their own account
> and requires the current and new password.
>
> ChangePassword can be a little tricky to get working on Win2K, especially
> if your domain controller does not have an SSL certificate installed.
> They don't by default, so someone would have needed to do this.
>
> You will have trouble using Ryan's Impersonation class on Win2K server
> though as an account must have the "act as part of the operating system"
> privilege to call the LogonUser function he is using, and only SYSTEM has
> that by default. You really should not be running your processModel as
> SYSTEM. It is a very bad security practice! The problem you may be
> having right now might relate to this.
>
> As such, you probably want to consider doing regular impersonation
> combined with Kerberos delegation. Kerberos delegation is an AD feature
> that allows you to specify specific accounts that may log on to another
> service on the network using the credentials the user originally supplied
> to them. In this case, the web server would be logging in to AD on behalf
> of the user who authenticated with the web site.
>
> You would configure the app to use integrated auth in IIS (no anonymous),
> configure ASP.NET for Windows auth and <identity impersonate="true"/> and
> configure the machine account for the web server for Kerberos Delegation
> in AD.
>
> The code for doing the change would be similar, except that you would not
> do programmatic impersonation and would invoke "ChangePassword", passing
> in both the old and the new password.
>
> You also want to be using SSL to protect this website since you are
> dealing in plain text credentials. You don't want this traffic getting
> sniffed on the wire!
>
> Regarding the .NET Framework version, I definitely think you should be
> using the 1.1 Framework minimum and possibly the 2.0 one. It is released
> now and there is no good reason not to use it here. It has some nice bug
> fixes and new features for System.DirectoryServices. The new features you
> don't need, but the fixes are nice.
>
> Your options get considerably better if you can upgrade your web server to
> 2003 SP1. Some of the limitations and difficulties go away and 2003 is
> overall a much better web server platform in general.
>
> HTH,
>
> Joe K.
>
> "Harry Devine" <hdevine@xxxxxxxxxxxxxxxx> wrote in message
> news:e30ZkVxBGHA.516@xxxxxxxxxxxxxxxxxxxxxxx
>>I wanted to allow a user to change their password to something else, so
>>maybe I've been confusing myself here. Our server is Win2K, and I was
>>changing the processModel section due to some info I found on the 'Net. I
>>can put it back to it's original form. Would you recommend upgrading to
>>the .NET framework 2.0 as well?
>>
>> Basically, I'm looking for an example of allowing a user to hit the site,
>> enter their current password, and then enter a new one, using ASP.NET and
>> System.Directory services.
>>
>> Sorry for the confusion, and thanks again for any help.
>> Harry
>>
>> "Joe Kaplan (MVP - ADSI)" <joseph.e.kaplan@xxxxxxxxxxxxxxxxxxxxxxxx>
>> wrote in message news:%23znXXqwBGHA.1144@xxxxxxxxxxxxxxxxxxxxxxx
>>>I thought you were doing password changes, not resets. There are
>>>actually important differences on how that is approached.
>>>
>>> It sounds like this is running on Win2K or XP, right? That's why you
>>> are editing the processModel section.
>>>
>>> It also looks like you are using the 1.0 version of the .NET Framework.
>>> Any reason for that? 1.1 or 2.0 would be preferred. The 1.0.3300.0
>>> version for System.DirectoryServices points to the 1.0 framework.
>>>
>>> If you have changed the process model account, there is no reason to
>>> also impersonate the same account in code. The process account will be
>>> running as the admin user. However, this is generally not considered a
>>> good practice, especially if other apps may be running on the same
>>> server as they will all run under this administrative account and have
>>> more privileges than they should.
>>>
>>> Can you also show the exact line where this is crashing? If they page
>>> displays, it seems like there should be some indication of what the
>>> problem was on the postback.
>>>
>>> Joe K.
>>>
>>> "Harry Devine" <hdevine@xxxxxxxxxxxxxxxx> wrote in message
>>> news:eZ8u$cvBGHA.3604@xxxxxxxxxxxxxxxxxxxxxxx
>>>> I'm reasonably sure ASP.NET is working (the .aspx page that I'm putting
>>>> below comes up), but this is my first try at programming anything in
>>>> it, so take that for what it's worth. I'm including the code for the
>>>> reset.aspx file and web.config. The only change that I made to
>>>> machine.config was to change the username and password under the
>>>> processModel section to be my domain admin account (I found that
>>>> suggestion somewhere on the Web while researching the error).
>>>>
>>>> Thanks for any help,
>>>> Harry
>>>>
>>>> reset.aspx:
>>>> <%@ Assembly Name="System.DirectoryServices, Version=1.0.3300.0,
>>>> Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"%>
>>>> <%@ Assembly Name="Dunnry.Security" %>
>>>>
>>>> <%@ Import Namespace="System.DirectoryServices" %>
>>>> <%@ Import Namespace="Dunnry.Security" %>
>>>>
>>>> <HTML>
>>>> <script language="C#" runat="server">
>>>>
>>>> void Page_Load(Object Src, EventArgs E ) {
>>>> if(!Page.IsPostBack)
>>>> {
>>>>
>>>> }
>>>> }
>>>>
>>>> private void ResetPassword(object sender, EventArgs e)
>>>> {
>>>> //for impersonation
>>>> string username = "AdminUser";
>>>> string password = "adminpwd";
>>>> string domain = "domain";
>>>>
>>>> Impersonate i = new
>>>> Impersonate(LogonProvider.LOGON32_PROVIDER_WINNT50);
>>>> i.ImpersonateUser(username, domain, password);
>>>>
>>>> string ldapPath = LDAP://dc=mydomain,dc=com;
>>>> DirectoryEntry de = new DirectoryEntry(ldapPath);
>>>> de.AuthenticationType = AuthenticationTypes.Secure;
>>>> string qry =
>>>> String.Format("(&(objectClass=user)(objectCategory=person)(sAMAccountName={0}))",
>>>> txtUsername.Text);
>>>>
>>>> DirectorySearcher ds = new DirectorySearcher(de,qry);
>>>> SearchResult sr = ds.FindOne();
>>>>
>>>> if(sr==null)
>>>> {
>>>> lblMessage.Text = "User not found";
>>>> return;
>>>> }
>>>>
>>>> try
>>>> {
>>>> DirectoryEntry user = sr.GetDirectoryEntry();
>>>> user.AuthenticationType = AuthenticationTypes.Secure;
>>>> user.Invoke("SetPassword", new object[]{txtPassword.Text});
>>>> lblMessage.Text = "Success <br>";
>>>> }
>>>> catch(Exception ex)
>>>> {
>>>> //throw ex;
>>>> lblMessage.Text = "Failure: " + ex.Message;
>>>> if(ex.InnerException != null)
>>>> lblMessage.Text += "<br>" + ex.InnerException.Message;
>>>> }
>>>> finally
>>>> {
>>>> de.Close();
>>>> i.UndoImpersonation();
>>>> }
>>>> }
>>>> </script>
>>>>
>>>> <body>
>>>> <form runat="server">
>>>> UserName: <asp:textbox id="txtUsername" runat="server"/><br>
>>>> New Password: <asp:textbox id="txtPassword" runat="server"/><br>
>>>> <asp:button id="btnReset" runat="server" Text="Reset"
>>>> OnClick="ResetPassword" /><br>
>>>> <asp:label id="lblMessage" runat="server"/><br><br>
>>>> I am running as: <%=Context.User.Identity.Name %><br>
>>>> My process is running as:
>>>> <%=System.Security.Principal.WindowsIdentity.GetCurrent().Name %>
>>>> </form>
>>>> </body>
>>>> </HTML>
>>>>
>>>>
>>>> web.config:
>>>>
>>>> <?xml version="1.0" encoding="utf-8" ?>
>>>> <configuration>
>>>> <system.web>
>>>> <compilation debug="true"/>
>>>> <authentication mode="Windows" />
>>>> <!--<authorization>
>>>> <deny users="?" />
>>>> </authorization>-->
>>>> </system.web>
>>>>
>>>> <!-- Secure the .aspx page using web.config
>>>> <location path="reset.aspx">
>>>> <system.web>
>>>> <authorization>
>>>> <allow roles="DOMAIN\AdminUser" />
>>>> <deny users="*" />
>>>> </authorization>
>>>> </system.web>
>>>> </location> -->
>>>> </configuration>
>>>>
>>>> processModel section of machine.config:
>>>> <processModel
>>>> enable="true"
>>>> timeout="Infinite"
>>>> idleTimeout="Infinite"
>>>> shutdownTimeout="0:00:05"
>>>> requestLimit="Infinite"
>>>> requestQueueLimit="5000"
>>>> restartQueueLimit="10"
>>>> memoryLimit="60"
>>>> webGarden="false"
>>>> cpuMask="0xffffffff"
>>>> userName="domain\adminuser"
>>>> password="adminpwd"
>>>> logLevel="Errors"
>>>> clientConnectedCheck="0:00:05"
>>>> comAuthenticationLevel="Connect"
>>>> comImpersonationLevel="Impersonate"
>>>> responseDeadlockInterval="00:03:00"
>>>> maxWorkerThreads="20"
>>>> maxIoThreads="20"
>>>> />
>>>>
>>>>
>>>> "Joe Kaplan (MVP - ADSI)" <joseph.e.kaplan@xxxxxxxxxxxxxxxxxxxxxxxx>
>>>> wrote in message news:e%235SZFnBGHA.1864@xxxxxxxxxxxxxxxxxxxxxxx
>>>>> The crux of doing this in a web page is simply to create a
>>>>> DirectoryEntry object that is bound to the user's object in AD and
>>>>> invoking the ChangePassword ADSI method. Impersonation may or may not
>>>>> be needed as you need to prompt for the old password anyway, so it
>>>>> doesn't really hurt to simply use those credentials in your
>>>>> DirectoryEntry constructor.
>>>>>
>>>>> The error you are getting sounds like it is unrelated to an
>>>>> DirectoryServices programming stuff though. Are you sure ASP.NET is
>>>>> working in general?
>>>>>
>>>>> Note also that Ryan and I have book coming out that covers this stuff
>>>>> in detail, but it won't be available for a few more months now.
>>>>>
>>>>> Posting an example of the code you are using would be a great start.
>>>>>
>>>>> Joe K.
>>>>>
>>>>> "Harry Devine" <hdevine@xxxxxxxxxxxxxxxx> wrote in message
>>>>> news:%23FysvCmBGHA.1008@xxxxxxxxxxxxxxxxxxxxxxx
>>>>>> I've been searching around for an answer to this question, but
>>>>>> haven't gotten too far. I'm fairly new to ASP.NET, so I'm not sure
>>>>>> how to setup machine.config and web.config properly.
>>>>>>
>>>>>> What I want to be able to do is allow a domain user to change their
>>>>>> password in the AD via a webpage. We have several users with domain
>>>>>> accounts, but they do not actually login to our domain as they are
>>>>>> spread out all over the country. I have a VBS script that notifies
>>>>>> them when their password is due to expire, starting 10 days out.
>>>>>>
>>>>>> Since these users are not local to where my domain controller
>>>>>> resides, they have to call me or email me to have their password
>>>>>> reset. I found an example written by Ryan Dunn using an Impersonate
>>>>>> function that he wrote (www.dunnry.com), but I keep getting an error
>>>>>> stating: "Parser Error Message: The XML file
>>>>>> c:\winnt\microsoft.net\framework\v1.1.4322\Config\machine.config
>>>>>> could not be loaded. Either a required impersonation level was not
>>>>>> provided, or the provided impersonation level is invalid. "
>>>>>>
>>>>>> This seems like, to me, a fundamental type of function to do, but
>>>>>> info on how to do it is all over the place. Does anyone have any
>>>>>> good ideas or steps on how to accomplish this?
>>>>>>
>>>>>> Thanks for any help,
>>>>>> Harry
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
>
.
- Follow-Ups:
- Re: Changing domain user password
- From: Joe Kaplan \(MVP - ADSI\)
- Re: Changing domain user password
- References:
- Changing domain user password
- From: Harry Devine
- Re: Changing domain user password
- From: Joe Kaplan \(MVP - ADSI\)
- Re: Changing domain user password
- From: Harry Devine
- Re: Changing domain user password
- From: Joe Kaplan \(MVP - ADSI\)
- Re: Changing domain user password
- From: Harry Devine
- Re: Changing domain user password
- From: Joe Kaplan \(MVP - ADSI\)
- Changing domain user password
- Prev by Date: Re: Changing domain user password
- Next by Date: Re: Changing domain user password
- Previous by thread: Re: Changing domain user password
- Next by thread: Re: Changing domain user password
- Index(es):