Skip to content

Commit f341ce4

Browse files
rashedmytPrabhakar Kumar
authored andcommitted
matlab-proxy processes created by the jupyter-matlab-proxy package use token authentication by default.
fixes #63
1 parent 4db51b9 commit f341ce4

File tree

2 files changed

+139
-11
lines changed

2 files changed

+139
-11
lines changed

src/jupyter_matlab_proxy/__init__.py

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,42 @@
1-
# Copyright 2020-2021 The MathWorks, Inc.
1+
# Copyright 2020-2023 The MathWorks, Inc.
22

3-
import inspect
3+
import os
44
from pathlib import Path
5+
6+
from matlab_proxy.util.mwi import environment_variables as mwi_env
7+
from matlab_proxy.util.mwi import token_auth as mwi_token_auth
8+
59
from jupyter_matlab_proxy.jupyter_config import config
610

711

12+
def _get_auth_token():
13+
"""
14+
Generate auth token and token hash if the matlab-proxy token authentication
15+
is not explicitly disabled
16+
17+
Returns:
18+
None: If token authentication is explicitly disabled
19+
dict: For all other cases, a token and a token_hash is returned as dictionary
20+
"""
21+
mwi_enable_auth_token = os.getenv(mwi_env.get_env_name_enable_mwi_auth_token(), "")
22+
23+
# Return None if token authentication is explicitly disabled
24+
if mwi_enable_auth_token.lower() == "false":
25+
return None
26+
27+
# Enable token authentication by default
28+
original_env = os.environ.copy()
29+
os.environ[mwi_env.get_env_name_enable_mwi_auth_token()] = "True"
30+
auth_token = mwi_token_auth.generate_mwi_auth_token_and_hash()
31+
32+
# Cleanup environment variables
33+
os.environ = original_env
34+
return auth_token
35+
36+
37+
_mwi_auth_token = _get_auth_token()
38+
39+
840
def _get_env(port, base_url):
941
"""Returns a dict containing environment settings to launch the MATLAB Desktop
1042
@@ -16,14 +48,26 @@ def _get_env(port, base_url):
1648
Returns:
1749
[Dict]: Containing environment settings to launch the MATLAB Desktop.
1850
"""
19-
from matlab_proxy.util.mwi import environment_variables as mwi_env
2051

21-
return {
52+
env = {
2253
mwi_env.get_env_name_app_port(): str(port),
2354
mwi_env.get_env_name_base_url(): f"{base_url}matlab",
2455
mwi_env.get_env_name_app_host(): "127.0.0.1",
2556
}
2657

58+
# Add token authentication related information to the environment variables
59+
# dictionary passed to the matlab-proxy process if token authentication is
60+
# not explicitly disabled.
61+
if _mwi_auth_token:
62+
env.update(
63+
{
64+
mwi_env.get_env_name_enable_mwi_auth_token(): "True",
65+
mwi_env.get_env_name_mwi_auth_token(): _mwi_auth_token.get("token"),
66+
}
67+
)
68+
69+
return env
70+
2771

2872
def setup_matlab():
2973
"""This method is run by jupyter-server-proxy package with instruction to launch the MATLAB Desktop
@@ -42,7 +86,8 @@ def setup_matlab():
4286
logger.debug(f"Icon_path: {icon_path}")
4387
logger.debug(f"Launch Command: {matlab_proxy.get_executable_name()}")
4488
logger.debug(f"Extension Name: {config['extension_name']}")
45-
return {
89+
90+
jsp_config = {
4691
"command": [
4792
matlab_proxy.get_executable_name(),
4893
"--config",
@@ -53,3 +98,13 @@ def setup_matlab():
5398
"absolute_url": True,
5499
"launcher_entry": {"title": "Open MATLAB", "icon_path": icon_path},
55100
}
101+
102+
# Add token_hash information to the request_headers_override option to
103+
# ensure requests from jupyter to matlab-proxy are automatically authenticated.
104+
# We are using token_hash instead of raw token for better security.
105+
if _mwi_auth_token:
106+
jsp_config["request_headers_override"] = {
107+
"mwi_auth_token": _mwi_auth_token.get("token_hash")
108+
}
109+
110+
return jsp_config

tests/unit/test_jupyter_server_proxy.py

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,61 @@
1-
# Copyright 2020-2021 The MathWorks, Inc.
1+
# Copyright 2020-2023 The MathWorks, Inc.
22

3-
import os, inspect
4-
import matlab_proxy, jupyter_matlab_proxy
3+
import inspect
4+
import os
55
from pathlib import Path
6+
7+
import matlab_proxy
68
from matlab_proxy.util.mwi import environment_variables as mwi_env
9+
10+
import jupyter_matlab_proxy
711
from jupyter_matlab_proxy.jupyter_config import config
812

913

14+
def test_get_auth_token():
15+
"""Tests if _get_auth_token() function returns a token and token_hash as a dict by default."""
16+
r = jupyter_matlab_proxy._get_auth_token()
17+
assert r != None
18+
assert r.get("token") != None
19+
assert r.get("token_hash") != None
20+
21+
22+
def test_get_auth_token_with_token_auth_disabled(monkeypatch):
23+
"""Tests if _get_auth_token() function returns None if token authentication is explicitly disabled."""
24+
monkeypatch.setenv(mwi_env.get_env_name_enable_mwi_auth_token(), "False")
25+
r = jupyter_matlab_proxy._get_auth_token()
26+
assert r == None
27+
28+
1029
def test_get_env():
1130
"""Tests if _get_env() method returns the expected enviroment settings as a dict."""
1231

1332
port = 10000
1433
base_url = "/foo/"
1534
r = jupyter_matlab_proxy._get_env(port, base_url)
16-
assert r[mwi_env.get_env_name_app_port()] == str(port)
17-
assert r[mwi_env.get_env_name_base_url()] == f"{base_url}matlab"
35+
assert r.get(mwi_env.get_env_name_app_port()) == str(port)
36+
assert r.get(mwi_env.get_env_name_base_url()) == f"{base_url}matlab"
37+
assert r.get(mwi_env.get_env_name_enable_mwi_auth_token()) == "True"
38+
assert r.get(
39+
mwi_env.get_env_name_mwi_auth_token()
40+
) == jupyter_matlab_proxy._mwi_auth_token.get("token")
41+
42+
43+
def test_get_env_with_token_auth_disabled(monkeypatch):
44+
"""Tests if _get_env() method returns the expected enviroment settings as a dict
45+
when token authentication is explicitly disabled.
46+
"""
47+
48+
port = 10000
49+
base_url = "/foo/"
50+
monkeypatch.setattr(jupyter_matlab_proxy, "_mwi_auth_token", None)
51+
r = jupyter_matlab_proxy._get_env(port, base_url)
52+
assert r.get(mwi_env.get_env_name_app_port()) == str(port)
53+
assert r.get(mwi_env.get_env_name_base_url()) == f"{base_url}matlab"
54+
assert r.get(mwi_env.get_env_name_enable_mwi_auth_token()) == None
55+
assert r.get(mwi_env.get_env_name_mwi_auth_token()) == None
1856

1957

20-
def test_setup_matlab():
58+
def test_setup_matlab(monkeypatch):
2159
"""Tests for a valid Server Process Configuration Dictionary
2260
2361
This test checks if the jupyter proxy returns the expected Server Process Configuration
@@ -27,6 +65,41 @@ def test_setup_matlab():
2765
package_path = Path(inspect.getfile(jupyter_matlab_proxy)).parent
2866
icon_path = package_path / "icon_open_matlab.svg"
2967

68+
expected_matlab_setup = {
69+
"command": [
70+
matlab_proxy.get_executable_name(),
71+
"--config",
72+
config["extension_name"],
73+
],
74+
"timeout": 100,
75+
"environment": jupyter_matlab_proxy._get_env,
76+
"absolute_url": True,
77+
"launcher_entry": {
78+
"title": "Open MATLAB",
79+
"icon_path": icon_path,
80+
},
81+
"request_headers_override": {
82+
"mwi_auth_token": jupyter_matlab_proxy._mwi_auth_token.get("token_hash"),
83+
},
84+
}
85+
86+
actual_matlab_setup = jupyter_matlab_proxy.setup_matlab()
87+
88+
assert expected_matlab_setup == actual_matlab_setup
89+
assert os.path.isfile(actual_matlab_setup["launcher_entry"]["icon_path"])
90+
91+
92+
def test_setup_matlab_with_token_auth_disabled(monkeypatch):
93+
"""Tests for a valid Server Process Configuration Dictionary
94+
95+
This test checks if the jupyter proxy returns the expected Server Process Configuration
96+
Dictionary for the Matlab process when token authentication is explicitly disabled.
97+
"""
98+
# Setup
99+
package_path = Path(inspect.getfile(jupyter_matlab_proxy)).parent
100+
icon_path = package_path / "icon_open_matlab.svg"
101+
monkeypatch.setattr(jupyter_matlab_proxy, "_mwi_auth_token", None)
102+
30103
expected_matlab_setup = {
31104
"command": [
32105
matlab_proxy.get_executable_name(),

0 commit comments

Comments
 (0)