I had a chance to discuss this with Burke and this is what we agreed on, it is not very different from what has been suggested on this thread.
What needs to be done now in the reference application?
In the admin UI module when creating a new user, the admin sets a password for the user which is technically temporary because a user account can’t be created in the API without a password, when the form is submitted and the user had been saved, the code would also set the user property for force password change to true, this is already an existing a standard user property defined in core and probably in the future we need to add it as a column in the user table. Upon a user’s first successful login attempt, the login controller in the reference application module should check the user property, if it is set to true, it redirects the user to the change my password form. When the user submits the change password form and the operation is successful, the controller should set the user property back to false if the authenticated user is actually that user and we are done.
Now what do we want to do in the long run?
We want to move this behavior to the API with the option of the admin to set a global property to opt out of it for flexibility in case of what i call ‘clueless and controlling’ admins who want to create passwords for all their users who forget the user can actually change it later to something else anyways OR in Burke’s case of automated systems communicating with OpenMRS i.e where there is nothing like a user interface to send a user to change their password, this global property can be used to by pass the force password change, though i still think this is easy to get around because the admin can edit the associated user account and unset the user property.
The way we would implement it in the API is such that, when you save a user account, it should set the user property to true for a new user account if the admin hasn’t opted out. And whenever Context.authenticate is called, upon successful login it throws an exception say a new one PasswordChangeException if force password change is set to true for that user. Then we tweak the changePassword logic in core to unset the user property upon a successful password change if the authenticated user is actually that user.
Then we get rid of the logic that sets the user property from the admin UI module and update the login controller in the reference application to redirect the user to the change password form whenever this exception type is thrown. Same thing in REST, the AuthorizationFilter filter should always catch this exception type and send back the appropriate http code and message to inform the client about what went wrong.
I can create the platform tickets if you agree, what do you think?