2018-08-28 12:09:05 +02:00
|
|
|
"""tests for the proxy"""
|
|
|
|
|
import os
|
|
|
|
|
import shutil
|
|
|
|
|
import ssl
|
|
|
|
|
import time
|
2023-05-15 08:51:35 +00:00
|
|
|
from subprocess import check_call
|
2018-08-28 12:09:05 +02:00
|
|
|
|
2020-06-08 11:42:10 +03:00
|
|
|
import pytest
|
2023-05-15 08:51:35 +00:00
|
|
|
import toml
|
|
|
|
|
from tornado.httpclient import HTTPClient, HTTPClientError, HTTPRequest
|
2018-08-28 12:09:05 +02:00
|
|
|
|
2020-06-18 17:29:50 +03:00
|
|
|
from tljh.config import (
|
|
|
|
|
CONFIG_DIR,
|
2023-05-15 08:51:35 +00:00
|
|
|
CONFIG_FILE,
|
2020-06-18 17:29:50 +03:00
|
|
|
STATE_DIR,
|
2023-05-15 08:51:35 +00:00
|
|
|
reload_component,
|
|
|
|
|
set_config_value,
|
2020-06-18 17:29:50 +03:00
|
|
|
)
|
2018-08-28 12:09:05 +02:00
|
|
|
|
|
|
|
|
|
2020-06-20 02:05:53 +03:00
|
|
|
def send_request(url, max_sleep, validate_cert=True, username=None, password=None):
|
|
|
|
|
for i in range(max_sleep):
|
|
|
|
|
try:
|
|
|
|
|
req = HTTPRequest(
|
|
|
|
|
url,
|
|
|
|
|
method="GET",
|
|
|
|
|
auth_username=username,
|
|
|
|
|
auth_password=password,
|
|
|
|
|
validate_cert=validate_cert,
|
|
|
|
|
follow_redirects=True,
|
|
|
|
|
max_redirects=15,
|
|
|
|
|
)
|
2023-05-15 10:53:53 +02:00
|
|
|
return HTTPClient().fetch(req)
|
2020-06-20 02:05:53 +03:00
|
|
|
except Exception as e:
|
2023-05-15 10:53:53 +02:00
|
|
|
if i + 1 == max_sleep:
|
|
|
|
|
raise
|
2020-06-20 02:05:53 +03:00
|
|
|
print(e)
|
2023-05-15 10:53:53 +02:00
|
|
|
time.sleep(i)
|
2020-06-20 02:05:53 +03:00
|
|
|
|
|
|
|
|
|
2018-08-28 12:09:05 +02:00
|
|
|
def test_manual_https(preserve_config):
|
|
|
|
|
ssl_dir = "/etc/tljh-ssl-test"
|
|
|
|
|
key = ssl_dir + "/ssl.key"
|
|
|
|
|
cert = ssl_dir + "/ssl.cert"
|
|
|
|
|
os.makedirs(ssl_dir, exist_ok=True)
|
|
|
|
|
os.chmod(ssl_dir, 0o600)
|
|
|
|
|
# generate key and cert
|
|
|
|
|
check_call(
|
|
|
|
|
[
|
|
|
|
|
"openssl",
|
|
|
|
|
"req",
|
|
|
|
|
"-nodes",
|
|
|
|
|
"-newkey",
|
|
|
|
|
"rsa:2048",
|
|
|
|
|
"-keyout",
|
|
|
|
|
key,
|
|
|
|
|
"-x509",
|
|
|
|
|
"-days",
|
|
|
|
|
"1",
|
|
|
|
|
"-out",
|
|
|
|
|
cert,
|
|
|
|
|
"-subj",
|
|
|
|
|
"/CN=tljh.jupyer.org",
|
|
|
|
|
]
|
|
|
|
|
)
|
2024-03-20 15:08:21 -04:00
|
|
|
set_config_value(CONFIG_FILE, "https.enabled", True, True)
|
|
|
|
|
set_config_value(CONFIG_FILE, "https.tls.key", key, True)
|
|
|
|
|
set_config_value(CONFIG_FILE, "https.tls.cert", cert, True)
|
2018-08-28 12:09:05 +02:00
|
|
|
reload_component("proxy")
|
|
|
|
|
for i in range(10):
|
|
|
|
|
time.sleep(i)
|
|
|
|
|
try:
|
|
|
|
|
server_cert = ssl.get_server_certificate(("127.0.0.1", 443))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
else:
|
|
|
|
|
break
|
|
|
|
|
with open(cert) as f:
|
|
|
|
|
file_cert = f.read()
|
|
|
|
|
|
|
|
|
|
# verify that our certificate was loaded by traefik
|
|
|
|
|
assert server_cert == file_cert
|
|
|
|
|
|
2020-06-20 02:05:53 +03:00
|
|
|
# verify that we can still connect to the hub
|
|
|
|
|
resp = send_request(
|
|
|
|
|
url="https://127.0.0.1/hub/api", max_sleep=10, validate_cert=False
|
|
|
|
|
)
|
2020-06-08 11:42:10 +03:00
|
|
|
assert resp.code == 200
|
2018-08-28 12:09:05 +02:00
|
|
|
|
|
|
|
|
# cleanup
|
|
|
|
|
shutil.rmtree(ssl_dir)
|
2024-03-20 15:08:21 -04:00
|
|
|
set_config_value(CONFIG_FILE, "https.enabled", False, True)
|
2020-06-20 02:05:53 +03:00
|
|
|
|
|
|
|
|
reload_component("proxy")
|
2020-06-08 11:42:10 +03:00
|
|
|
|
|
|
|
|
|
2020-06-21 13:55:52 +03:00
|
|
|
def test_extra_traefik_config():
|
2020-06-20 02:05:53 +03:00
|
|
|
extra_static_config_dir = os.path.join(CONFIG_DIR, "traefik_config.d")
|
|
|
|
|
os.makedirs(extra_static_config_dir, exist_ok=True)
|
2020-06-08 11:42:10 +03:00
|
|
|
|
2020-06-21 13:55:52 +03:00
|
|
|
dynamic_config_dir = os.path.join(STATE_DIR, "rules")
|
|
|
|
|
os.makedirs(dynamic_config_dir, exist_ok=True)
|
|
|
|
|
|
2020-06-20 02:05:53 +03:00
|
|
|
extra_static_config = {
|
2023-05-15 10:53:53 +02:00
|
|
|
"entryPoints": {"alsoHub": {"address": "127.0.0.1:9999"}},
|
2020-06-08 11:42:10 +03:00
|
|
|
}
|
|
|
|
|
|
2020-06-21 13:55:52 +03:00
|
|
|
extra_dynamic_config = {
|
2023-05-15 10:53:53 +02:00
|
|
|
"http": {
|
|
|
|
|
"middlewares": {
|
|
|
|
|
"testHubStripPrefix": {
|
|
|
|
|
"stripPrefix": {"prefixes": ["/the/hub/runs/here/too"]}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"routers": {
|
|
|
|
|
"test1": {
|
|
|
|
|
"rule": "PathPrefix(`/hub`)",
|
|
|
|
|
"entryPoints": ["alsoHub"],
|
|
|
|
|
"service": "test",
|
2020-06-21 13:55:52 +03:00
|
|
|
},
|
2023-05-15 10:53:53 +02:00
|
|
|
"test2": {
|
|
|
|
|
"rule": "PathPrefix(`/the/hub/runs/here/too`)",
|
|
|
|
|
"middlewares": ["testHubStripPrefix"],
|
|
|
|
|
"entryPoints": ["http"],
|
|
|
|
|
"service": "test",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"services": {
|
|
|
|
|
"test": {
|
|
|
|
|
"loadBalancer": {
|
|
|
|
|
# forward requests to the hub
|
|
|
|
|
"servers": [{"url": "http://127.0.0.1:15001"}]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
2020-06-21 13:55:52 +03:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-08 11:42:10 +03:00
|
|
|
success = False
|
|
|
|
|
for i in range(5):
|
|
|
|
|
try:
|
|
|
|
|
with pytest.raises(HTTPClientError, match="HTTP 401: Unauthorized"):
|
2023-05-15 10:53:53 +02:00
|
|
|
# The default api entrypoint requires authentication, so it should fail
|
|
|
|
|
HTTPClient().fetch("http://localhost:8099/api")
|
2020-06-08 11:42:10 +03:00
|
|
|
success = True
|
|
|
|
|
break
|
2023-05-15 10:53:53 +02:00
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
time.sleep(i)
|
2020-06-08 11:42:10 +03:00
|
|
|
|
|
|
|
|
assert success == True
|
|
|
|
|
|
2020-06-20 02:05:53 +03:00
|
|
|
# write the extra static config
|
|
|
|
|
with open(
|
|
|
|
|
os.path.join(extra_static_config_dir, "extra.toml"), "w+"
|
|
|
|
|
) as extra_config_file:
|
|
|
|
|
toml.dump(extra_static_config, extra_config_file)
|
|
|
|
|
|
|
|
|
|
# write the extra dynamic config
|
2020-06-18 17:29:50 +03:00
|
|
|
with open(
|
|
|
|
|
os.path.join(dynamic_config_dir, "extra_rules.toml"), "w+"
|
|
|
|
|
) as extra_config_file:
|
2020-06-20 02:05:53 +03:00
|
|
|
toml.dump(extra_dynamic_config, extra_config_file)
|
|
|
|
|
|
|
|
|
|
# load the extra config
|
2020-06-18 17:29:50 +03:00
|
|
|
reload_component("proxy")
|
|
|
|
|
|
2023-05-15 10:53:53 +02:00
|
|
|
# check hub page
|
2020-06-21 13:55:52 +03:00
|
|
|
# the new dashboard entrypoint shouldn't require authentication anymore
|
2023-05-15 10:53:53 +02:00
|
|
|
resp = send_request(url="http://127.0.0.1:9999/hub/login", max_sleep=5)
|
2020-06-21 13:55:52 +03:00
|
|
|
assert resp.code == 200
|
|
|
|
|
|
2020-06-20 02:05:53 +03:00
|
|
|
# test extra dynamic config
|
|
|
|
|
resp = send_request(url="http://127.0.0.1/the/hub/runs/here/too", max_sleep=5)
|
2020-06-18 17:29:50 +03:00
|
|
|
assert resp.code == 200
|
2020-12-23 18:02:45 +02:00
|
|
|
assert "http://127.0.0.1/hub/login" in resp.effective_url
|
2020-06-18 17:29:50 +03:00
|
|
|
|
|
|
|
|
# cleanup
|
2020-06-21 13:55:52 +03:00
|
|
|
os.remove(os.path.join(extra_static_config_dir, "extra.toml"))
|
2020-06-20 02:05:53 +03:00
|
|
|
os.remove(os.path.join(dynamic_config_dir, "extra_rules.toml"))
|
2020-06-21 13:55:52 +03:00
|
|
|
open(os.path.join(STATE_DIR, "traefik.toml"), "w").close()
|