<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Jupyter Blog - Leticia Portella</title><link href="https://jasongrout.github.io/medium-archive/pelican/" rel="alternate"/><link href="https://jasongrout.github.io/medium-archive/pelican/feeds/author-leticia-portella.atom.xml" rel="self"/><id>https://jasongrout.github.io/medium-archive/pelican/</id><updated>2019-03-04T14:41:00+00:00</updated><subtitle>The Project Jupyter blog: news, releases, and community stories, archived from blog.jupyter.org.</subtitle><entry><title>Simpler authentication for small scale JupyterHubs with NativeAuthenticator</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/" rel="alternate"/><published>2019-02-26T16:31:00+00:00</published><updated>2019-03-04T14:41:00+00:00</updated><author><name>Leticia Portella</name></author><id>tag:jasongrout.github.io,2019-02-26:/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/</id><summary type="html">&lt;p&gt;NativeAuthenticator adds traditional username / password based sign up, login, &amp;amp; user management features to JupyterHub&lt;/p&gt;
</summary><content type="html">&lt;p&gt;In this post I’ll tell you about the new &lt;a href="https://jupyterhub.readthedocs.io/en/stable/"&gt;JupyterHub&lt;/a&gt; authenticator I implemented in the last couple of months, not only technically but also the context in which it was built. If you have no idea what JupyterHub is and how it works, I recommend &lt;a href="https://www.youtube.com/watch?v=4GJFNQBB26s&amp;amp;t=973s"&gt;this short talk&lt;/a&gt; by the awesome &lt;a href="https://twitter.com/WillingCarol"&gt;Carol Willing&lt;/a&gt; 🙃.&lt;/p&gt;
&lt;p&gt;But first things first, let me introduce myself! My name is &lt;a href="https://leportella.com/"&gt;Leticia&lt;/a&gt; and I’m Brazilian 🇧🇷. Last year (2018) I saw an opening for an internship program called &lt;a href="https://www.outreachy.org/"&gt;Outreachy&lt;/a&gt;. I am a woman, a self-taught programmer with a non traditional background (&lt;a href="https://leportella.com/english/2016/03/16/from-oceanographer-to-programmer.html"&gt;I’m an oceanographer&lt;/a&gt;) and I had no job at this time. The program would fit me perfectly. Lucky me, Jupyter was one of the projects available! Thus, everything you’ll see here is the result (so far) of everything I’ve been doing with the internship and the help of my mentors.&lt;/p&gt;
&lt;p&gt;Before going any further I would also like to thank the &lt;a href="https://bids.berkeley.edu/"&gt;Berkeley Institute for Data Science&lt;/a&gt; and &lt;a href="https://numfocus.org/"&gt;NumFocus&lt;/a&gt; for jointly sponsoring my Outreachy internship. This was a huge opportunity for me ❤️&lt;/p&gt;
&lt;h2 id="why-do-we-need-another-authenticator"&gt;Why do we need another authenticator?&lt;/h2&gt;
&lt;p&gt;JupyterHub authenticators determine how users on a particular installation of JupyterHub can log in. For example, here are a few common authenticators already available to JupyterHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jupyterhub.readthedocs.io/en/stable/getting-started/authenticators-users-basics.html"&gt;&lt;strong&gt;PAM Authenticator&lt;/strong&gt;&lt;/a&gt;: Any whitelisted user with an account and password on the system will be allowed to login;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jupyterhub/oauthenticator"&gt;&lt;strong&gt;OAuthenticator&lt;/strong&gt;&lt;/a&gt;: An authenticator that uses the login of other services (OAuth) to authenticate on the Jupyterhub (such as Azure, Github or Moodle);&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jupyterhub/firstuseauthenticator"&gt;&lt;strong&gt;First Use Authenticator&lt;/strong&gt;&lt;/a&gt;: A new user is created when the user logs in for the first time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Large installations usually rely on a third party service (using OAuthenticator), while smaller ones maintain user accounts by hand (PAM Authenticator). However, maintining user lists by hand can be a lot of effort, especially as the number of users grows. &lt;strong&gt;Native Authenticator&lt;/strong&gt; was created to supply smaller JupyterHub installations with a more convenient authentication system instead of maintaining user accounts by hand, without the overhead of needing an external third party service.&lt;/p&gt;
&lt;h2 id="native-authenticator-features"&gt;Native Authenticator features&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://native-authenticator.readthedocs.io/en/latest/"&gt;&lt;strong&gt;Native Authenticator&lt;/strong&gt;&lt;/a&gt; was added to &lt;a href="https://pypi.org/"&gt;PyPI&lt;/a&gt; this week and we are super excited about this! The default features available on the authenticator are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://native-authenticator.readthedocs.io/en/latest/quickstart.html#adding-new-users"&gt;&lt;strong&gt;A signup page&lt;/strong&gt; that creates new users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Username sanitation&lt;/strong&gt; (avoiding spaces, commas and backslashes)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“Administrator” privileges&lt;/strong&gt; that can be given to specific users&lt;/li&gt;
&lt;li&gt;The ability for users to &lt;strong&gt;change their passwords&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;A panel for &lt;strong&gt;controlling access to the system&lt;/strong&gt; on a user-by-user basis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some optional features are available and can be activated through &lt;a href="https://jupyterhub.readthedocs.io/en/latest/getting-started/config-basics.html#generate-a-default-config-file"&gt;the configuration file&lt;/a&gt; and will be discussed further on this post 🙃&lt;/p&gt;
&lt;h2 id="installing-and-using-native-authenticator"&gt;Installing and using Native Authenticator&lt;/h2&gt;
&lt;p&gt;To use the authenticator, you can install it through &lt;code&gt;pip&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;jupyterhub-nativeauthenticator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can configure JupyterHub to work with &lt;strong&gt;Native Authenticator&lt;/strong&gt; by adding the following line to the configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.JupyterHub.authenticator_class = &amp;#39;nativeauthenticator.NativeAuthenticator&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and that is it 😉&lt;/p&gt;
&lt;h2 id="default-authenticator-workflow"&gt;Default authenticator workflow&lt;/h2&gt;
&lt;p&gt;Once you’ve configured your JupyterHub installation to work with &lt;strong&gt;Native Authenticator&lt;/strong&gt;, no new user can enter the system. To enter the system, a new user must sign up. To do so, the operator of the Hub should point users to&lt;code&gt;/hub/signup&lt;/code&gt; and create a new username and password. After submitting the information, the user receives a message indicating that the information was sent to an admin.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/001-1_j03d42mqjsyDxqn_8ckcpA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;By default, &lt;em&gt;all users that Sign Up are unauthorized and can’t login to the system&lt;/em&gt;. The admin will need to enter the Authorization Area dashboard at &lt;code&gt;/hub/authorize&lt;/code&gt; and authorize the users into the system. The panel looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/002-1_EWg9RdlOG21IcB1ogCcpTg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Authorized users are shown with a green background while unauthorized users have a white background. Each has a button to change the authorization status. Once a user is authorized, it will be able to go to the &lt;code&gt;/&lt;/code&gt; endpoint and login.&lt;/p&gt;
&lt;p&gt;The default workflow of the Native Authenticator is like this:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Default workflow of Native Authenticator" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/003-1_PiSAI-wFEma2dUz_MgQ7nw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Default workflow of Native Authenticator&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A quick remark on this workflow: this only works for users that are &lt;strong&gt;not&lt;/strong&gt; listed as admins. Any username that is listed as an admin in the JupyterHub configuration file will automatically have authorization to login when they sign up. You can add admins by adding this line to the configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.Authenticator.admin_users = { &amp;#39;johnsnow&amp;#39; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Admins still need to sign up in order to define a password, but they already have authorization to login.&lt;/p&gt;
&lt;h2 id="open-signup"&gt;&lt;strong&gt;Open SignUp&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Although the default workflow can be useful for avoiding unwanted people to enter the system, it can lead to a bottleneck if you have a lot of users that need to quickly enter the system. So, one option is to allow everyone in, and later block any users you don’t want to access your system.&lt;/p&gt;
&lt;p&gt;To do this, you need to activate the Open SignUp feature on &lt;strong&gt;Native Authenticator&lt;/strong&gt;, which is done by adding the following line to the JupyterHub configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.NativeAuthenticator.open_signup = True
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the workflow is much simpler:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Workflow of Native Authenticator when you configured an Open Signup" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/004-1_6CFAojIq8vUuGUdWtRLOMg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Workflow of Native Authenticator when you configured an Open Signup&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="increasing-password-security"&gt;&lt;strong&gt;Increasing password security&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;We wanted to give an option to increase security, if needed. So, with Native Authenticator you can add verification of strong passwords. But, what is indeed a “&lt;em&gt;strong password&lt;/em&gt;”? We followed &lt;a href="https://auth0.com/blog/dont-pass-on-the-new-nist-password-guidelines/"&gt;the NSIT guidelines described beautifully on this post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first thing is that we added an option to see the password while typing. As said on the post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Typos are common when entering passwords, and when characters turn into dots as soon as they’re typed, it’s difficult to tell where you went wrong. This motivates users to pick shorter passwords that they’re less likely to mess up&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, we added this on &lt;em&gt;SignUp&lt;/em&gt; and &lt;em&gt;Change Password&lt;/em&gt; (and soon to the login as well 🙃).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/005-1_kNVLn4UYGS58YAEGmsYLOA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Example of input box for passwords with hidden password (left) and open text password (right)" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/006-1_aSz7IYH4Ox-T4BUO53mx7Q.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Example of input box for passwords with hidden password (left) and open text password (right)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Also, you can add a verification for a minimum number of characters in a password by adding the value in the configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.NativeAuthenticator.minimum_password_length = 10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will prevent users to signup if the password is less then 10 characters. An error message appears in case the password is not good enough:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Error indicating the password is not long enough" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/007-1_lD3D5a2W8GHc3g-J6A-hDQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Error indicating the password is not long enough&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Additionally, you can add a verification to avoid common passwords. Instead of asking for users to add special characters or upper case letters, the guide suggests to check for common passwords instead. Passwords such as &lt;code&gt;123456&lt;/code&gt; or &lt;code&gt;qwerty&lt;/code&gt; are common and not nearly secure enough. We used &lt;a href="https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10-million-password-list-top-10000.txt"&gt;a list of 10 thousand common passwords&lt;/a&gt; that will be checked when this option is activated. To activate this verification add to the configuration file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.NativeAuthenticator.check_common_password = True
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="avoid-throttling-of-failed-login"&gt;Avoid throttling of failed login&lt;/h2&gt;
&lt;p&gt;Another thing that increases security is to block users when they’ve had a number of failed logins. &lt;a href="https://native-authenticator.readthedocs.io/en/latest/options.html#block-users-after-failed-logins"&gt;In &lt;strong&gt;Native Authenticator&lt;/strong&gt; you can activate this behavior.&lt;/a&gt; The system will add a count for every consecutive failed login attempt. If the user exceeds the number of attempts that is permitted, it will check if some time has passed since the last attempt. If not enough time has passed, the system will keep them blocked until they wait a while longer before attempting to sign-in again.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/008-1_BUap43L0AqEpdc_4YVA9xg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;As you can imagine, both the number of attempts permitted and the wait time are configurable.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.NativeAuthenticator.allowed_failed_logins = 3
c.NativeAuthenticator.seconds_before_next_try = 1200
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="how-we-accomplished-this"&gt;How we accomplished this&lt;/h2&gt;
&lt;p&gt;To construct this new Authenticator, Project Jupyter decided to get an intern (me!) through the &lt;a href="https://www.outreachy.org/"&gt;Outreachy&lt;/a&gt; Program. &lt;a href="https://github.com/jupyterhub/outreachy/blob/master/ideas/native-jupyterhub-user-management.rst"&gt;The description of the project&lt;/a&gt; was made in advance and potential interns applied by resolving a &lt;a href="https://github.com/jupyterhub/outreachy/issues?q=is%3Aopen+is%3Aissue+label%3Amicrotask"&gt;micro-task&lt;/a&gt; defined in a specific repository. The main workflow was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a profile on the Outreachy website;&lt;/li&gt;
&lt;li&gt;Submit a pull request for a micro-task of the project you want to participate;&lt;/li&gt;
&lt;li&gt;Fill a more complete profile about yourself;&lt;/li&gt;
&lt;li&gt;Wait for the selection 🤓&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The full presentation of the Project Jupyter participation, a list of mentors, and more details can be seen on &lt;a href="/posts/2018/outreachy-jupyter-supporting-diversity-in-open/"&gt;this post&lt;/a&gt;, and more technical details on the micro-task I submitted can be seen &lt;a href="https://leportella.com/english/2018/12/12/outreachy-I.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="technical-details-and-day-to-day-development"&gt;Technical details and day-to-day development&lt;/h2&gt;
&lt;p&gt;There were a lot of struggles to get things going. As part of the Outreachy program, I had to write about the tasks and struggles I had in posts &lt;a href="https://leportella.com/"&gt;on my personal blog&lt;/a&gt;. If you would like to check the details for how the process went at each you can checkout each of the available posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leportella.com/english/2018/12/12/outreachy-I.html"&gt;Outreachy Report I&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leportella.com/english/2019/01/11/outreachy-II.html"&gt;Outreachy Report II&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leportella.com/english/2019/01/23/outreachy-III.html"&gt;Outreachy Report III&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leportella.com/english/2019/02/05/outreachy-IV.html"&gt;Outreachy Report IV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leportella.com/english/2019/02/21/outreachy-V.html"&gt;Outreachy Report V&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See ya :)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/simpler-authentication-for-small-scale-jupyterhubs-with/images/009-fWgAW7WZtPMBjmpa3V-giphy.mp4" alt="See Ya Kiss GIF by CBC" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="JupyterHub"/><category term="Outreachy"/></entry></feed>