Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Allow users to reset their own passwords with First Use Authenticator #2
FirstUseAuthenticator is a JupyterHub authenticator where the first password a user uses is considered their password of record. This works great for simple use cases, but is problematic when users need to reset their own password.
For this task, make a GitHub Pull Request to the FirstUseAuthenticator github repo with a feature that lets users change their own passwords:
Comment on this issue, or ping us on Gitter for help!
Hi guys! I started the implementation:
I'm having some doubts about:
Thank you for your help!
That sounds like great progress!
You are right that modifying jupyterhub/jupyterhub probably isn't the right approach, but the principles ought to be the same, it's just a bit of a question about where the code lands. In this case, it should all live in
I would put it in
Jinja has the ability to load templates from multiple sources. One way to do that is to register your path with the jinja environment. We can then add this by creating a ChoiceLoader, which takes one or more Loaders and iterates through them until it finds a match:
import os from jinja2 import ChoiceLoader, FileSystemLoader # a 'templates' directory next to the current file TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates") class ResetPasswordHandler(BaseHandler): """Render the reset password page.""" # flag to indicate whether the template path has been loaded _loaded = False def _register_template_path(self): if ResetPasswordHandler._loaded: # already loaded, do nothing return # create a FileSystemLoader that will find our template self.log.debug("Adding %s to template path", TEMPLATE_DIR) my_loader = FileSystemLoader([TEMPLATE_DIR]) # register our loader with the jinja environment # *in addition to* the existing loaders env = self.settings['jinja2_env'] previous_loader = env.loader env.loader = ChoiceLoader([previous_loader, my_loader]) # signal that this modification should only occur once ResetPasswordHandler._loaded = True @web.authenticated async def get(self): # make sure our template is registered self._register_template_path() ...
This would generally be in the form of a POST request coming from a
In practice, it usually doesn't matter too much, but as a general guideline in JupyterHub and web applications in general, I like to get as much logic implemented in portable classes (Authenticator, Spawner, etc.) so that they can be used and tested without a web application. Then the only job of the Handler is to expose the APIs on those objects via the web.
@minrk thank you for your comments. They were extremely helpful!
I created a Pull Request but @yuvipanda comments puts a link for testing the Authenticator. Since no tests were available, I created a PR without it and came here to ask for help on this subject. Should this be done with tests? Should I created tests for everything?
Again, thank you both for your help :)
@leportella If you'd like to take a stab at adding tests, that would be awesome, but since we haven't set up the initial testing on that repo, I don't think we can reasonably ask you to do that right now. I've started the basics in jupyterhub/firstuseauthenticator#9, which should make it doable to add a test for the