mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
Merge pull request #395 from GeorgianaElena/admin_pass_on_setup
Set admin password during install
This commit is contained in:
@@ -72,6 +72,12 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
.circleci/integration-test.py run-test basic-tests test_hub.py test_install.py test_extensions.py
|
.circleci/integration-test.py run-test basic-tests test_hub.py test_install.py test_extensions.py
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Run admin tests
|
||||||
|
command: |
|
||||||
|
.circleci/integration-test.py run-test --installer-args "--admin admin:admin" basic-tests test_admin_installer.py
|
||||||
|
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
name: Run plugin tests
|
name: Run plugin tests
|
||||||
command: |
|
command: |
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ The easiest & safest way to develop & test TLJH is with `Docker <https://www.doc
|
|||||||
|
|
||||||
python3 /srv/src/bootstrap/bootstrap.py --admin admin
|
python3 /srv/src/bootstrap/bootstrap.py --admin admin
|
||||||
|
|
||||||
|
Or, if you would like to setup the admin's password during install,
|
||||||
|
you can use this command (replace "admin" with the desired admin username
|
||||||
|
and "password" with the desired admin password):
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
python3 /srv/src/bootstrap/bootstrap.py --admin admin:password
|
||||||
|
|
||||||
The primary hub environment will also be in your PATH already for convenience.
|
The primary hub environment will also be in your PATH already for convenience.
|
||||||
|
|
||||||
#. You should be able to access the JupyterHub from your browser now at
|
#. You should be able to access the JupyterHub from your browser now at
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ so attackers can not easily gain control of the system.
|
|||||||
.. important::
|
.. important::
|
||||||
|
|
||||||
You should make sure an admin user is present when you **install** TLJH
|
You should make sure an admin user is present when you **install** TLJH
|
||||||
the very first time. The ``:ref:`--admin <topic/customizing-installer/admin>```
|
the very first time. It is recommended that you also set a password
|
||||||
|
for the admin at this step. The :ref:`--admin <topic/customizing-installer/admin>`
|
||||||
flag passed to the installer does this. If you had forgotten to do so, the
|
flag passed to the installer does this. If you had forgotten to do so, the
|
||||||
easiest way to fix this is to run the installer again.
|
easiest way to fix this is to run the installer again.
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,24 @@ This page documents the various options you can pass as commandline parameters t
|
|||||||
Adding admin users
|
Adding admin users
|
||||||
===================
|
===================
|
||||||
|
|
||||||
``--admin <username>`` adds user ``<username>`` to JupyterHub as an admin user.
|
``--admin <username>:<password>`` adds user ``<username>`` to JupyterHub as an admin user
|
||||||
This can be repeated multiple times.
|
and sets its password to be ``<password>``.
|
||||||
|
Although it is not recommended, it is possible to only set the admin username at this point
|
||||||
|
and set the admin password after the installation.
|
||||||
|
|
||||||
For example, to add ``admin-user1`` and ``admin-user2`` as admins when installing, you
|
Also, the ``--admin`` flag can be repeated multiple times. For example, to add ``admin-user1``
|
||||||
would do:
|
and ``admin-user2`` as admins when installing, depending if you would like to set their passwords
|
||||||
|
during install you would:
|
||||||
|
|
||||||
|
* set ``admin-user1`` with password ``password-user1`` and ``admin-user2`` with ``password-user2`` using:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
curl https://raw.githubusercontent.com/jupyterhub/the-littlest-jupyterhub/master/bootstrap/bootstrap.py \
|
||||||
|
| sudo python3 - \
|
||||||
|
--admin admin-user1:password-user1 --admin admin-user2:password-user2
|
||||||
|
|
||||||
|
* set ``admin-user1`` and ``admin-user2`` to be admins, without any passwords at this stage, using:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@@ -32,6 +45,14 @@ would do:
|
|||||||
| sudo python3 - \
|
| sudo python3 - \
|
||||||
--admin admin-user1 --admin admin-user2
|
--admin admin-user1 --admin admin-user2
|
||||||
|
|
||||||
|
* set ``admin-user1`` with password ``password-user1`` and ``admin-user2`` with no password at this stage using:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
curl https://raw.githubusercontent.com/jupyterhub/the-littlest-jupyterhub/master/bootstrap/bootstrap.py \
|
||||||
|
| sudo python3 - \
|
||||||
|
--admin admin-user1:password-user1 --admin admin-user2
|
||||||
|
|
||||||
Installing python packages in the user environment
|
Installing python packages in the user environment
|
||||||
==================================================
|
==================================================
|
||||||
|
|
||||||
|
|||||||
45
integration-tests/test_admin_installer.py
Normal file
45
integration-tests/test_admin_installer.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from hubtraf.user import User
|
||||||
|
from hubtraf.auth.dummy import login_dummy
|
||||||
|
import pytest
|
||||||
|
from functools import partial
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_admin_login():
|
||||||
|
"""
|
||||||
|
Test if the admin that was added during install can login with
|
||||||
|
the password provided.
|
||||||
|
"""
|
||||||
|
hub_url = 'http://localhost'
|
||||||
|
username = "admin"
|
||||||
|
password = "admin"
|
||||||
|
|
||||||
|
async with User(username, hub_url, partial(login_dummy, password=password)) as u:
|
||||||
|
await u.login()
|
||||||
|
await u.ensure_server()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"username, password",
|
||||||
|
[
|
||||||
|
("admin", ""),
|
||||||
|
("admin", "wrong_passw"),
|
||||||
|
("user", "password"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_unsuccessful_login(username, password):
|
||||||
|
"""
|
||||||
|
Ensure nobody but the admin that was added during install can login
|
||||||
|
"""
|
||||||
|
hub_url = 'http://localhost'
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with User(username, hub_url, partial(login_dummy, password="")) as u:
|
||||||
|
await u.login()
|
||||||
|
except Exception:
|
||||||
|
# This is what we except to happen
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise
|
||||||
1
setup.py
1
setup.py
@@ -17,6 +17,7 @@ setup(
|
|||||||
'passlib',
|
'passlib',
|
||||||
'backoff',
|
'backoff',
|
||||||
'requests',
|
'requests',
|
||||||
|
'bcrypt',
|
||||||
'jupyterhub-traefik-proxy==0.1.*'
|
'jupyterhub-traefik-proxy==0.1.*'
|
||||||
],
|
],
|
||||||
entry_points={
|
entry_points={
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Unit test functions in installer.py
|
Unit test functions in installer.py
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import pytest
|
||||||
|
|
||||||
from tljh import installer
|
from tljh import installer
|
||||||
from tljh.yaml import yaml
|
from tljh.yaml import yaml
|
||||||
@@ -21,10 +22,17 @@ def test_ensure_config_yaml(tljh_dir):
|
|||||||
# verify that old config doesn't exist
|
# verify that old config doesn't exist
|
||||||
assert not os.path.exists(os.path.join(tljh_dir, 'config.yaml'))
|
assert not os.path.exists(os.path.join(tljh_dir, 'config.yaml'))
|
||||||
|
|
||||||
def test_ensure_admins(tljh_dir):
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"admins, expected_config",
|
||||||
|
[
|
||||||
|
([['a1'], ['a2'], ['a3']], ['a1', 'a2', 'a3']),
|
||||||
|
([['a1:p1'], ['a2']], ['a1', 'a2']),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_ensure_admins(tljh_dir, admins, expected_config):
|
||||||
# --admin option called multiple times on the installer
|
# --admin option called multiple times on the installer
|
||||||
# creates a list of argument lists.
|
# creates a list of argument lists.
|
||||||
admins = [['a1'], ['a2'], ['a3']]
|
|
||||||
installer.ensure_admins(admins)
|
installer.ensure_admins(admins)
|
||||||
|
|
||||||
config_path = installer.CONFIG_FILE
|
config_path = installer.CONFIG_FILE
|
||||||
@@ -32,4 +40,4 @@ def test_ensure_admins(tljh_dir):
|
|||||||
config = yaml.load(f)
|
config = yaml.load(f)
|
||||||
|
|
||||||
# verify the list was flattened
|
# verify the list was flattened
|
||||||
assert config['users']['admin'] == ['a1', 'a2', 'a3']
|
assert config['users']['admin'] == expected_config
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Installation logic for TLJH"""
|
"""Installation logic for TLJH"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import dbm
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -10,9 +11,11 @@ import sys
|
|||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
import bcrypt
|
||||||
import pluggy
|
import pluggy
|
||||||
import requests
|
import requests
|
||||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||||
|
from getpass import getpass
|
||||||
|
|
||||||
from tljh import (
|
from tljh import (
|
||||||
apt,
|
apt,
|
||||||
@@ -126,8 +129,6 @@ def ensure_jupyterhub_service(prefix):
|
|||||||
Ensure JupyterHub Services are set up properly
|
Ensure JupyterHub Services are set up properly
|
||||||
"""
|
"""
|
||||||
|
|
||||||
os.makedirs(STATE_DIR, mode=0o700, exist_ok=True)
|
|
||||||
|
|
||||||
remove_chp()
|
remove_chp()
|
||||||
systemd.reload_daemon()
|
systemd.reload_daemon()
|
||||||
|
|
||||||
@@ -271,11 +272,13 @@ def ensure_user_environment(user_requirements_txt_file):
|
|||||||
conda.ensure_pip_requirements(USER_ENV_PREFIX, user_requirements_txt_file)
|
conda.ensure_pip_requirements(USER_ENV_PREFIX, user_requirements_txt_file)
|
||||||
|
|
||||||
|
|
||||||
def ensure_admins(admins):
|
def ensure_admins(admin_password_list):
|
||||||
"""
|
"""
|
||||||
Setup given list of users as admins.
|
Setup given list of users as admins.
|
||||||
"""
|
"""
|
||||||
if not admins:
|
os.makedirs(STATE_DIR, mode=0o700, exist_ok=True)
|
||||||
|
|
||||||
|
if not admin_password_list:
|
||||||
return
|
return
|
||||||
logger.info("Setting up admin users")
|
logger.info("Setting up admin users")
|
||||||
config_path = CONFIG_FILE
|
config_path = CONFIG_FILE
|
||||||
@@ -286,9 +289,22 @@ def ensure_admins(admins):
|
|||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
config['users'] = config.get('users', {})
|
config['users'] = config.get('users', {})
|
||||||
# Flatten admin lists
|
|
||||||
config['users']['admin'] = [admin for admin_sublist in admins
|
db_passw = os.path.join(STATE_DIR, 'passwords.dbm')
|
||||||
for admin in admin_sublist]
|
|
||||||
|
admins = []
|
||||||
|
for admin_password_entry in admin_password_list:
|
||||||
|
for admin_password_pair in admin_password_entry:
|
||||||
|
if ":" in admin_password_pair:
|
||||||
|
admin, password = admin_password_pair.split(':')
|
||||||
|
admins.append(admin)
|
||||||
|
# Add admin:password to the db
|
||||||
|
password = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
|
||||||
|
with dbm.open(db_passw, 'c', 0o600) as db:
|
||||||
|
db[admin] = password
|
||||||
|
else:
|
||||||
|
admins.append(admin_password_pair)
|
||||||
|
config['users']['admin'] = admins
|
||||||
|
|
||||||
with open(config_path, 'w+') as f:
|
with open(config_path, 'w+') as f:
|
||||||
yaml.dump(config, f)
|
yaml.dump(config, f)
|
||||||
|
|||||||
Reference in New Issue
Block a user