Webbased Active Directory / Federated user password and recovery tool

Intro

A while ago i wrote a simple tool which allows users to reset their expired password  (an IISADMPWD replacment). The tool was created because at the time Office 365 did not have the ability to let federated users change their password. I have noticed that i was not the only one who had to deal with this problem, the tool was downloaded a number of times and i got some positive feedback. The tool was still very limited, if a user forgot his password, he still had to contact someone from IT to reset his password. Because remembering a password is one of the hardest things to do, resetting passwords for users took up to much of our time. This is why i build a new version of the tool which allows users to recover their account through a reset link sent to an alternative e-mail address. On this page you can find how to install, customize and download the tool. You can see it as a self-service portal for users.

How does it work

Using the Webbased Active Directory / Federated user password and recovery tool is very simple. When you navigate to the address where you installed it, you will see the following page:
Webbased Active Directory / Federated user password and recovery tool
Here you can login using your Active directory account. When successful you will see the self-service portal:

Webbased Active Directory / Federated user password and recovery tool

Here you can change your password, or the recovery e-mail address. When you try to login with an account that has an expired password, you can change your password immediately.

Webbased Active Directory / Federated user password and recovery tool
When the user does not have a recovery e-mail address set, an additional field will appear. You can make this e-mail field mandatory by a setting. If you have forgotten your password, it is possible to send a recovery link to an alternative e-mail address, if you supplied a recovery e-mail address earlier, ofcourse.
Webbased Active Directory / Federated user password and recovery tool
Webbased Active Directory / Federated user password and recovery tool

If you click on the link, you will land on the Change page, and set a new password. All the labels, notifications en texts can be customized.

Requirements
  • A Microsoft Windows Server
  • IIS
  • .net 4.0
  • Microsoft SQL 2008 Server or higher
  • Some knowledge of IIS websites and application pools
  • Some knowledge of Active Directory
  • Some knowledge of SQL
  • Some knowledge of log4net if desired
  • I strongly recommend that you secure the tool with HTTPS.

Any version of SQL server will do. You can use the free express editions if you like. IIS must be .net 4.0 capable. In this howto i used Microsoft Windows Server 2012 R2, .NET 4.5 and Microsoft SQL server 2012 Express.

Installation – Active Directory user

The first thing you need to do is create an Active Directory user which has permissions to change passwords. I strongly recommend that you create/use a seperate OU for your users set the correct permissions on that OU. Create an Active Directory user called (for example) PasswordChanger . Give the user a very long and strong password, and store this password somewhere safe, you will need it later.

  • Right-click the OU where your users are stored and click properties
  • Open the tab Security and click Advanced
  • Click add and select the user you created earlier.
  • Permissions should apply to: Descendant User objects.
  • Check the following permissions:
    Permissions: Allowed to authenticate
    Permissions: Change password
    Permissions: Reset password
    Properties: Write pwdLastSet
    Properties: Write userAccountControl
    Properties: Write lockoutTime
  • OK all the windows to apply the permissions.

That’s it for active directory configuration, the permissions should look like the following screenshot:
Webbased Active Directory / Federated user password and recovery tool

Installation – SQL database

The tool uses a SQL database to store session information, logging and recovery e-mail addresses. I have included a SQL script to create this database. The steps you need to follow are:

  • Open up SQL Management Studio and connect to your server.
  • Open db.sql and edit the file before executing. There are 3 variables to change
  • @pwcUsername: This is the SQL user created by the script, this user will have full permissions on the new database. (remember this user, you will need it later)
  • @pwcPassword: The password for the SQL user, i recommend you use a password generator for this password. (remember/store this password, you will need it later)
  • @pwcDatabaseName: The name of the SQL database that will be created. (remember the name, you will need it later)

Then execute the script and the database is created!

Installation – IIS

To make the Webbased Active Directory / Federated user password and recovery tool work in IIS we have to create an IIS application pool and site. First we are going to create the application pool.

  • Start Internet Information Services (IIS) Manager.
  • Right click on Application Pools and choose Add Application Pool…
  • Choose a name and copy settings from the screenshot. Click OK to continue
    Webbased Active Directory / Federated user password and recovery tool
  • The application pool is created. Right click it and click on Advanced Settings…
  • In the section Process Model, change Identity to ApplicationPoolIdentity
  • Change Load User Profile to false

The next step is to create the site or application. Before doing this, extract the files to you webserver directory. For instance: C:\inetpub\wwwroot\Password

  • Right click Default Website Site and click on Add Application…
  • Choose an Alias, the Application pool you just created and point it to the path where you extracted the files. Click OK to continue. The following screenshot is an example:
    Webbased Active Directory / Federated user password and recovery tool

Configuration of IIS is now completed. The Webbased Active Directory / Federated user password and recovery tool should be accessible via http://<server ip>/Password

Configuration – setup page

The final step to make the tool work is to navigate to the setup page and fill in some parameters. The setup page is accessible via http://<server ip>/Password/setup/setup.aspx. The page looks like this:

Webbased Active Directory / Federated user password and recovery tool

I will explain every setting you can configure in this page. The setup page has little validation, so check your input.

  • Active Directory Domain: Your domain name, you can find this domain name when you start Active Directory Users and Computers (Second level)
  • Search tring: Where the tool should look for your users. You can limit the search string to a specific OU by adding OU=UserOU. To find out the Search string for your OU you can right click the OU in Active Directory Users and Computers and click properties. Then open the tab Attribute Editor and look for the setting distinguishedName.
  • Active Directory user: This is the username of the Active Directory user you created earlier. This user has the permission to change passwords.
  • Active Directory password: The password of the Active Directory user
  • Password expires in days: Here you can specify your password expiration policy setting. This is used to check if a users password is expired.
  • Resetkey timeout: The time in minutes that the resetlink sent via the recovery e-mail is valid.
  • Force users to set Reset e-mail address: If this is set, you can force an user to set a recovery e-mail address. Otherwise this is not mandatory while the user changes his password.
  • Display user passwords in logging: If this is set, user passwords are logged in plain text to log4net. If you log to your database this means passwords are stored in plain text which is not recommended.
  • Session timeout: The time in minutes before a session expires.
  • SMTP server: SMTP server used to send recovery e-mail
  • SMTP server port: TCP port on which the SMTP server operates.
  • From address: From what e-mail address the recovery e-mail should originate
  • Blacklisted domains: A comma seperated list of domains which are not allowed in the alternative e-mail address. For example: if the Active Directory user account gives access to a @contoso.com e-mail address, you can blacklist the contoso.com domain. Because if a user is locked out, he cannot access his @contoso.com e-mail to click the recovery link. This would make the tool very useless.
  • Database settings: Fill in SQL connection info.

Finally click Save to save the settings. Now you can test if you can login using a active directory account, if everything works as it should be, please remember to delete or secure the setup page.

Configuration – log4net

I have build in log4net support, and included configuration examples in web.config. To enable them you have to un-comment line 5 and line 41 t/m 107. You also have to change the connection string on line 61. The db.sql script also creates the logging table, so you can log to your SQL server. For more config examples you can take a look at this page.

Customization, Language’s 

The Webbased Active Directory / Federated user password and recovery tool uses resx for localization and modifying labels and notifications in the tool. You can also change the layout by modifying style.css. To change the language file you need a simple free tool called Resx Editor written by someone called joannes, if you don’t want to use a tool you also can use a text editor. There are 2 languages included (you can find them in de App_GlobalResources folder):

  • GlobalResources.resx: Default language file if a language specific file cannot be found. Language is english. This file also contains comments.
  • GlobalResources.nl.resx: Dutch language file.

If you want to add a language, copy the GlobalResources.resx and rename it to GlobalResources.<lang code>.resx, where <lang code> is the code for your language and modify the file. To find out the code for your language, please look at this page and use the code located in the collumn 639-1. If you have created a new language, consider sharing it with me so i can add it as a download.

Downloads and resources

Update 2015-10-08: Added 3 items on the overview page: Firstname, Lastname and days until the password expires. (new field in the resx files)
Update 2015-10-21: Implemented bootstrap based layout. Some bugfixes

Update 2017-03-22

I have fixed a bug in the tool. The tool used a method called setpassword instead of changepassword which made it possible for users to use a password which do not comply with the security policy. I have also tested the tool against a 2016 active directory. If the tool doesn’t appear to work, make sure the netlogon service is running on your DC’s.

  • Download the tool
  1. Driver
    Driver10-01-2015

    Thank you for this! Can you add the information when the password will expire and first/last username on the Overview page?
    Maybe it is the good idea to check if the account is active, expired or don’t exist without typing the password. What do you think?

    • Luke
      Luke10-08-2015

      Thanks for your feedback! I have uploaded a modified version which displays the Firstname, Lastname and how many days till password expiration. I don’t think its a good idea to check the account without typing the password. This page can be made accessible to the public and robot’s can try to brute force the page that way (find out username’s and then brute force the password).

      You can update you version by overwriting the files (except web.config and maybe any custom css).

  2. Driver
    Driver10-09-2015

    There is a problem with log in by the user. When I type intentionally wrong password there is an immediately reply with a wrong password /InvalidPassword field/. When I type correct password (Windows Event Viewer shows the user is successfully authenticated) page is loading about 15 sec. with a message wrong password /InvalidPassword field/ – message from GlobalResources.resx line 244. I don’t know how to debug this?

    Additionally is it possible to add SMTP password for sending mail?

    I asked about checking the account without typing the password because sometimes there is a situation that somebody can’t log in, don’t remember the password or just want to check the account status. I don’t think the robots can brute force the password knowing the user login because all passwords have a default lockout threshold of 5 invalid logon attempts. Moreover it is always possible to add the captcha mechanizm on the login page. 🙂

  3. gio
    gio10-20-2015

    Hi Luke,

    I’m trying to use your script for our small (lab) AD but when I try to login in to the website i get Always the same error no matter what user I use:

    2015-10-20 11:19:48,174 [11] ERROR PasswordHelper [(null)] – On ValidateLogin for user mar_apa@dev.local – System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests.
    at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
    at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind()
    at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions)
    at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)
    at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)
    at PasswordChanger.PasswordHelper.ValidateLogin(String CurrentPassword)

    I followed all the steps you outline but with no luck.

    Do you happen to have an idea on what the problem could be?

    thanks!

    • Luke
      Luke10-20-2015

      Can you change the applicationpool identity from LocalMachine(or System) to NetworkService?

  4. gio
    gio10-20-2015

    Hi Luke,

    Thanks for your answer, I can login now that I changed to Network Service but when I try to change the pwd I get some sort of exception related to permssions

    2015-10-20 14:24:56,566 [15] INFO PasswordHelper [(null)] – Updating user: S-1-5-21-2781054729-538393738-368619762-1257, Old principalname fca_nafta@tmsdev.local – New principalname mar_apac@dev.local
    2015-10-20 14:25:19,707 [10] INFO PasswordHelper [(null)] – Updating user: S-1-5-21-2781054729-538393738-368619762-1257 Old principal name fca_nafta@tmsdev.local – New principal name fca_nafta@tmsdev.local, Old e-mail:fca_nafta@tmsdev.local – New e-mail mar_apac@dev.local
    2015-10-20 14:25:19,770 [10] ERROR PasswordHelper [(null)] – On ChangePassword for user fca_mar_apac@dev.local – System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
    — End of inner exception stack trace —
    at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args)
    at System.DirectoryServices.AccountManagement.SDSUtils.SetPassword(DirectoryEntry de, String newPassword)
    at System.DirectoryServices.AccountManagement.ADStoreCtx.SetPassword(AuthenticablePrincipal p, String newPassword)
    at PasswordChanger.PasswordHelper.ChangePassword(String NewPassword)

    I tried to add passwordchanger to the admin Group but I actually believe that it’s something related to IIS and the possibility to perform admin operation while using Network Service.

    Do you have any ideas?

    Tnx again,

    Gio

  5. gio
    gio10-20-2015

    Hi Luke!

    it works now, I just gave same rights that password changer has to Network Service accounts.

    One last thing, I realized that the app doesn’t take into account that if the password must be changed at next logon. It returns the following exception:

    Runtime Error

    Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.

    Details: To enable the details of this specific error message to be viewable on remote machines, please create a tag within a “web.config” configuration file located in the root directory of the current web application. This tag should then have its “mode” attribute set to “Off”.

    Should your app cover this case of is normal that it doesn’t work?

    Kind Regards,

    Giovanni

    • Luke
      Luke10-21-2015

      Hi gio,

      I have done some testing to find out the instructions where not 100% accurate. The following settings worked for me (on 2012 R2):
      – Identity of the application pool should be the built in account: ApplicationPoolIdentity
      – The Active Directory account needs one more security setting: Write lockoutTime
      I have updated the page. For your information, i have the following setup:
      – 1 2012 R2 webserver (non domain joined)
      – 1 2012 R2 Active Directory server

      Kind Regards,
      Luke

  6. Driver
    Driver10-22-2015

    I have updated to the latest version but still receiving the error message when the user supplied the wrong password. I tried for many accounts and always the same message. I have 1 2008 R2 Active Directory and webserver, Microsoft SQL Server 2014. Don’t have any messages in the log.txt file. Don’t know what to do..

    • Luke
      Luke10-22-2015

      Few questions:
      – Have you uncommented/configured the log4net section as described?
      – If you delete log.txt, is it recreated? (in addition to the above question)
      – Are you a 100% sure your Search String is correct and the user exists in the OU?
      – Did you try different users?

      I am planning to add much more debug logging so i can fix issue’s faster. i hope to finish this soon.

  7. Driver
    Driver10-23-2015

    Luke,
    I had a wrong reference to the database, but now I can successfully log in. Thanks for your tips! 🙂
    Only one thing is not working – the most important – changing the password:

    ERROR PasswordHelper On ChangePassword for user test@contoso.com System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
    — End of inner exception stack trace —
    at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args)
    at System.DirectoryServices.AccountManagement.SDSUtils.SetPassword(DirectoryEntry de, String newPassword)
    at System.DirectoryServices.AccountManagement.ADStoreCtx.SetPassword(AuthenticablePrincipal p, String newPassword)
    at PasswordChanger.PasswordHelper.ChangePassword(String NewPassword)

    Trying to fix this I gave all grant permissions for the PasswordChanger user in AD. <- won't help
    My application Identity is ApplicationPoolIdentity. In the Event Viewer I don't see any permission denied warnings related to these accounts.

    My other suggestions:
    – please add the username in the overview page (change 'Overview' to 'Username: xxx')
    – in the AD there is a mail attribute where we can store email, why sql database is needed for this?
    – could you change 'Password expires in days' to 'Expiration date'?
    – when the account is disabled,expired in AD, then instead of this information we can see the password is wrong message
    – it will be also a nice feature to add ability to display custom AD attribute on an overview page

  8. gio
    gio10-26-2015

    Hi Luke,

    I installed the new version of the site and it look much better!

    I wanted to ask you how does the expiration day for the password works because you ask to set this in the setup.exe but I suppose it should read this directly from the AD don’t you think?

    Kind Regards,

    Giovanni

    • Luke
      Luke11-04-2015

      I think i did this because it is impossible or at least difficult to read account policy information from the group policy.

  9. gio
    gio11-04-2015

    Hi Luke,

    Can you please tell me how can I remove the line “Password expires in days” from the overview.aspx?

    I tried to remove de div that contains it but I got an error.

    I don’t want to allow my userd to see this.

    Let me know please

    Thanks a lot!

    Gio

    • Luke
      Luke11-04-2015

      Hi Gio,

      Add the following to the div: style=”display: none;”
      This will hide the div

  10. gio
    gio11-04-2015

    Hi Luke,

    Sorry but I could’t make it work, I tried all div’s inclueded in that part of the code:

    <asp:Label ID="lblDaysBeforeExpire" runat="server" CssClass="col-sm-4" Text="” />

    Would you please let me know exactly where to put it?

    Thanks a lot and sorry 🙁

    Gio

  11. Driver
    Driver11-05-2015

    Hi Luke,
    And what about my problem?
    Big thanks!
    Driver

    • Luke
      Luke11-11-2015

      Hi Driver,

      I haven’t had much time to look into your problems, Gio’s problem was simple ;). So you still receive the error when changing the password when you give the PasswordChanger user in AD maximum permissions? (like domain admins). Maybe the password is set to user cannot change password on the test user?

      In response to your suggestions:
      – Good one, will build this
      – I am not sure if i can read and set the e-mail attribute via code. The database still exists for storing session and reset tokens. But maybe i will develop a version without the need for a SQL database.
      – You can change this yourself by modifying the resx file. You can use this http://sourceforge.net/projects/resx/ for example
      – I don’t understand
      – This is indeed nice to have, will look into it (same story as e-mail attribute)

      Thanks for you feedback so far

  12. KSYap
    KSYap01-21-2016

    Hi Luke,
    I have problem saving settings on the setup page. once clicking Save, it did not prompt for error, but when i re-opened the setup page, the default settings are still there.

  13. Gio
    Gio02-29-2016

    Hi Luke,

    Hope you are doing fine!

    Would it be possible for you to share the source code of the application? That way we can share and improve the tool together?

    If not, that is not a problem,

    Kind Regardsm

    Gio

  14. Tam
    Tam06-29-2016

    Hi Luke,

    I finish setup but when I login, it appear error “Connection to Active Directory failed!”. Can you help me fix it?

    Thanks,
    Tam

    • Brian Rarzum
      Brian Rarzum09-12-2016

      Tam,
      I’m having the same issue.

      • Luke
        Luke09-13-2016

        Have you enabled log4net so you can send me the log? If not, can you enable it?

  15. Keith
    Keith09-21-2016

    I tried installing this on Windows 2008 R2 / IIS 7.5, following the instructions exactly, but whenever I try to sign in, I get the error “Exception occured, please contact the site admin.”. Turned on log4net and got nothing in the log :-(. Any way to turn on debug to see what’s going on during the process so I can try to ascertain where it’s failing?

  16. Gerrit
    Gerrit11-24-2016

    Hi Luke,

    Is it correct your application does not look at history of passwords?
    My AD GPO says it should remember the last 24 passwords, so they cannot use the same password again.
    But a user can simply set the same password as his previous password.

    Is there a way to force a user to not use one of his last passwords?

    ps: great interface you build 🙂

  17. Arjan
    Arjan01-18-2017

    Hi luke,

    I am runing into a database connection problem which i can’t figure out…

    Server 2012R2
    SQL2014 Standard configured is SQL and Windows authentication.
    Datapase and SQL user created with your script.
    web.config file created via setup web page.
    Webserver and database both on the same server.

    pwcUsername = ‘pwc’
    pwcPassword = ‘pwc’
    pwcDatabaseName = ‘PasswordChanger’

    When i login with an incorrect password i get an reply right away “Gebruikersnaam of wachtwoord fout!”
    When i login with the correct password the page wait’s for about 15 seconds and then also gives the error “Gebruikersnaam of wachtwoord fout!”
    But the logging say’s it cant connect to the database.
    Do you have any ideas of what might cause this?

    • Arjan
      Arjan01-18-2017

      Web.config file (left out the log4net part):

      ?xml version=”1.0″ encoding=”utf-8″?>

      • Arjan
        Arjan01-18-2017

        Errorlog:

        2017-01-18 11:55:50,309 [10] WARN PasswordHelper [(null)] – On SetKey (Session) for SID S-1-5-21-728633124-991371654-946914093-1750 – System.Data.Entity.Core.EntityException: The underlying provider failed on Open. —> System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 – Could not open a connection to SQL Server) —> System.ComponentModel.Win32Exception: The system cannot find the file specified
        — End of inner exception stack trace —
        at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling)
        at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
        at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
        at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
        at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
        at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
        at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
        at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
        at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
        at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
        at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
        at System.Data.SqlClient.SqlConnection.Open()
        at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
        at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.Open(DbConnection connection, DbInterceptionContext interceptionContext)
        at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.c__DisplayClass1.b__0()
        at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
        at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
        — End of inner exception stack trace —
        at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
        at System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions)
        at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
        at System.Data.Entity.Core.Objects.ObjectQuery`1.c__DisplayClass3.b__1()
        at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
        at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
        at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable.GetEnumerator>b__0()
        at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
        at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
        at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
        at PasswordChanger.PWCUser.GetSingle(Func`2 where)
        at PasswordChanger.PasswordHelper.SetKey(UserPrincipal ADUser, KeyType type)

        • Arjan
          Arjan01-20-2017

          Found the solution!
          In the field “Database server” on the setup page you should not only fill in the servernam,e of the SQL server but Servername\Instancename.
          After that it worked.

      • Arjan
        Arjan01-18-2017
        • Arjan
          Arjan01-18-2017

          doesnt want to post the config file??

  18. Jeroen
    Jeroen03-31-2017

    Hi Luke

    I’ve downloaded the latest version (v31) but it looks like the db.sql file is empty size says 0kb and if I open it in ssms 2016 I can’t see and find the variables

    • Luke
      Luke03-31-2017

      Hi, i have uploaded a new version with the correct db.sql. Thanks for letting me know

  19. Jeroen
    Jeroen04-25-2017

    Hi Luke,

    I have a question about the e-mail address which you can put in. If you change it I think it will only be changed in the database, but is there also a way it will be changed in the AD. I have another program which uses the E-mail address field under General in the AD. If your program is able to change this field I also can use it to change the email address of a user.

    Thanks in advance
    Jeroen

  20. Thorsten
    Thorsten09-13-2017

    Hi,

    great Tool! We have it running for months in our invironment.

    In another implemenation I have a Problem. I can open the Login Site but when I fill in my credentials I receive an error: “Wrong Username or Password!”. The credentials are correct. I tried it with many AD-Users and I get every time the same error.
    Another Thing is, that I have to set my IIS ApplicationPool Identity from ApplicationPoolIdentiy to LocalSystem or the same Active Directoy Account I have created for PasswordChanger.
    Here are the results from the log.txt file:

    2017-09-13 18:53:24,676 [7] WARN PasswordHelper [(null)] – On SetKey (Session) for SID S-1-5-21-1259274664-1037449705-3059413000-1473 – System.Data.Entity.Core.EntityException: The underlying provider failed on Open. —> System.Data.SqlClient.SqlException: Login failed for user ‘pwc’.
    at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling)
    at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
    at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
    at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
    at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
    at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
    at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
    at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
    at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
    at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
    at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
    at System.Data.SqlClient.SqlConnection.Open()
    at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
    at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.Open(DbConnection connection, DbInterceptionContext interceptionContext)
    at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.c__DisplayClass1.b__0()
    at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
    at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
    — End of inner exception stack trace —
    at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
    at System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions)
    at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.c__DisplayClass3.b__1()
    at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable.GetEnumerator>b__0()
    at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
    at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at PasswordChanger.PWCUser.GetSingle(Func`2 where)
    at PasswordChanger.PasswordHelper.SetKey(UserPrincipal ADUser, KeyType type)

  21. Thorsten
    Thorsten09-14-2017

    Found the solution:
    I had to add the following into the connectionString in the web.config file: ;Integrated Security=true;
    After that Change it is working fine. I can log in and Change the Password successfully.

    The only Problem I have now is that the Password Change over the email link is not working. The Link is working and the Website appears. When I now click on “Change” after I set the Password an error occured :

    Server Error in Application.

    Value cannot be null.
    Parameter name: s
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.ArgumentNullException: Value cannot be null.
    Parameter name: s

    • Luke
      Luke09-14-2017

      Hi Thorsten, This seems to be a bug. I could reproduce this in my test envoirment. I have fixed the bug and uploaded a new version. You only have to replace the dll’s in the bin directory.

      • Thorsten
        Thorsten09-14-2017

        Hi Luke,
        that´s great. Thanks for your work and the fast fixing. It is working fine now!

  22. Chris H
    Chris H11-29-2017

    Hi Luke, I am receiving the following error when I try to login, “Exception occured, please contact the site admin.”, Although I know I am using the correct user and password the log from the SQL server shows the following. I have tried with my personal account and receive the same. Any assistance is appreciated.

    2017-11-29 09:59:11.533 37 ERROR PasswordHelper On Load(Username) constructor. Username: domainname\passwordtester System.Security.Authentication.AuthenticationException: The user name or password is incorrect.
    —> System.DirectoryServices.DirectoryServicesCOMException: The user name or password is incorrect.

    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, String identityValue)
    at System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, String identityValue)
    at PasswordChanger.PasswordHelper.Load(String UserName)

    • Chris H
      Chris H11-29-2017

      Got it corrected. A simple typo on my part screwed the whole thing up.

  23. Chris
    Chris12-01-2017

    Hi, I am having issues getting the app to email users the Password Reset. We use an external SMTP Relay server and it Requires TLS. The Setup does not have an option for TLS, is this something that can be added or is there a change that can be mad in a config file to enable TLS. Additionally I am not seeing any error in the log.

Leave a Reply