Skip to content

Commit f31b5a8

Browse files
committed
Manually merge PR113 to adjust apache conf to handle Jupyter access restrictions in the way that fits the active authenticed login sessions. Namely, require a valid OpenID Connect user when already authenticated with that method and only require a valid OpenID 2.0 user when authenticated with that method. Includes unit tests of related functions.
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6129 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent 260d13f commit f31b5a8

File tree

7 files changed

+156
-20
lines changed

7 files changed

+156
-20
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__JUPYTER_OIDCS__

mig/install/apache-MiG-template.conf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,7 +1854,7 @@ __IS_VERIFYCERTS_COMMENTED__ <VirtualHost *:${PUBLIC_HTTP_PORT}>
18541854
SSLOptions +StdEnvVars
18551855
</Directory>
18561856

1857-
# Jupyter OpenID auth
1857+
# Jupyter OpenID 2.0 auth
18581858
__JUPYTER_COMMENTED__ Include __APACHE_ETC__/conf.extras.d/MiG-jupyter-openid.conf
18591859

18601860
### The rest are sub-dirs that inherit the general conf above and
@@ -2456,7 +2456,7 @@ __IS_VERIFYCERTS_COMMENTED__ <VirtualHost *:${PUBLIC_HTTP_PORT}>
24562456
SSLOptions +StdEnvVars
24572457
</Directory>
24582458

2459-
# Jupyter OpenID auth
2459+
# Jupyter OpenID 2.0 auth
24602460
__JUPYTER_COMMENTED__ Include __APACHE_ETC__/conf.extras.d/MiG-jupyter-openid.conf
24612461

24622462
### The rest are sub-dirs that inherit the general conf above and
@@ -3368,8 +3368,8 @@ __IS_VERIFYCERTS_COMMENTED__ <VirtualHost *:${PUBLIC_HTTP_PORT}>
33683368
SSLOptions +StdEnvVars
33693369
</Directory>
33703370

3371-
# Jupyter OpenID auth
3372-
__JUPYTER_COMMENTED__ Include __APACHE_ETC__/conf.extras.d/MiG-jupyter-openid.conf
3371+
# Jupyter OpenID Connect auth
3372+
__JUPYTER_COMMENTED__ Include __APACHE_ETC__/conf.extras.d/MiG-jupyter-oidc.conf
33733373

33743374
### The rest are sub-dirs that inherit the general conf above and
33753375
### they can override any settings explicitly

mig/shared/install.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ def _generate_confs_prepare(
851851
user_dict['__JUPYTER_SERVICES__'] = jupyter_services
852852
user_dict['__JUPYTER_DEFS__'] = ''
853853
user_dict['__JUPYTER_OPENIDS__'] = ''
854+
user_dict['__JUPYTER_OIDCS__'] = ''
854855
user_dict['__JUPYTER_REWRITES__'] = ''
855856
user_dict['__JUPYTER_PROXIES__'] = ''
856857
user_dict['__JUPYTER_SECTIONS__'] = ''
@@ -1462,8 +1463,8 @@ def _generate_confs_prepare(
14621463
user_dict['__WEBSOCKETS_COMMENTED__'] = ''
14631464

14641465
# Dynamic apache configuration replacement lists
1465-
jupyter_sections, jupyter_proxies, jupyter_defs, \
1466-
jupyter_openids, jupyter_rewrites = [], [], [], [], []
1466+
jupyter_sections, jupyter_proxies, jupyter_defs = [], [], []
1467+
jupyter_openids, jupyter_oidcs, jupyter_rewrites = [], [], []
14671468
services = user_dict['__JUPYTER_SERVICES__'].split()
14681469

14691470
try:
@@ -1542,9 +1543,13 @@ def _generate_confs_prepare(
15421543
if u_k not in user_dict:
15431544
user_dict[u_k] = u_v
15441545

1545-
# Setup apache openid template
1546-
openid_template = gen_openid_template(url, def_name)
1546+
# Setup apache openid 2.0 and openid connect template
1547+
openid_template = gen_openid_template(url, def_name,
1548+
auth_type="OpenID")
15471549
jupyter_openids.append(openid_template)
1550+
oidc_template = gen_openid_template(url, def_name,
1551+
auth_type="openid-connect")
1552+
jupyter_oidcs.append(oidc_template)
15481553

15491554
# Setup apache rewrite template
15501555
rewrite_template = gen_rewrite_template(url, def_name, name)
@@ -1590,6 +1595,7 @@ def _generate_confs_prepare(
15901595

15911596
user_dict['__JUPYTER_DEFS__'] = '\n'.join(jupyter_defs)
15921597
user_dict['__JUPYTER_OPENIDS__'] = '\n'.join(jupyter_openids)
1598+
user_dict['__JUPYTER_OIDCS__'] = '\n'.join(jupyter_oidcs)
15931599
user_dict['__JUPYTER_REWRITES__'] = '\n'.join(jupyter_rewrites)
15941600
user_dict['__JUPYTER_PROXIES__'] = '\n'.join(jupyter_proxies)
15951601
user_dict['__JUPYTER_SECTIONS__'] = ''.join(jupyter_sections)
@@ -2214,6 +2220,7 @@ def _generate_confs_writefiles(options, user_dict, insert_list=[], cleanup_list=
22142220
("apache-service-template.conf", "apache2.service"),
22152221
("apache-MiG-jupyter-def-template.conf", "MiG-jupyter-def.conf"),
22162222
("apache-MiG-jupyter-openid-template.conf", "MiG-jupyter-openid.conf"),
2223+
("apache-MiG-jupyter-oidc-template.conf", "MiG-jupyter-oidc.conf"),
22172224
("apache-MiG-jupyter-proxy-template.conf", "MiG-jupyter-proxy.conf"),
22182225
("apache-MiG-jupyter-rewrite-template.conf",
22192226
"MiG-jupyter-rewrite.conf"),
@@ -2337,6 +2344,7 @@ def _generate_confs_instructions(options, user_dict):
23372344
sudo mkdir -p %(apache_etc)s/conf.extras.d
23382345
sudo cp %(destination)s/MiG-jupyter-def.conf %(apache_etc)s/conf.extras.d
23392346
sudo cp %(destination)s/MiG-jupyter-openid.conf %(apache_etc)s/conf.extras.d
2347+
sudo cp %(destination)s/MiG-jupyter-oidc.conf %(apache_etc)s/conf.extras.d
23402348
sudo cp %(destination)s/MiG-jupyter-proxy.conf %(apache_etc)s/conf.extras.d
23412349
sudo cp %(destination)s/MiG-jupyter-rewrite.conf %(apache_etc)s/conf.extras.d
23422350
@@ -2808,6 +2816,7 @@ def create_user(
28082816
apache_mig_conf = os.path.join(dst, 'MiG.conf')
28092817
apache_jupyter_def = os.path.join(dst, 'MiG-jupyter-def.conf')
28102818
apache_jupyter_openid = os.path.join(dst, 'MiG-jupyter-openid.conf')
2819+
apache_jupyter_oidc = os.path.join(dst, 'MiG-jupyter-oidc.conf')
28112820
apache_jupyter_proxy = os.path.join(dst, 'MiG-jupyter-proxy.conf')
28122821
apache_jupyter_rewrite = os.path.join(dst, 'MiG-jupyter-rewrite.conf')
28132822
server_conf = os.path.join(dst, 'MiGserver.conf')
@@ -2838,6 +2847,8 @@ def create_user(
28382847
apache_jupyter_def, apache_dir))
28392848
print('sudo cp -f -d %s %s/conf.extras.d/' % (apache_jupyter_openid,
28402849
apache_dir))
2850+
print('sudo cp -f -d %s %s/conf.extras.d/' % (apache_jupyter_oidc,
2851+
apache_dir))
28412852
print('sudo cp -f -d %s %s/conf.extras.d/' % (apache_jupyter_proxy,
28422853
apache_dir))
28432854
print('sudo cp -f -d %s %s/conf.extras.d/' % (apache_jupyter_rewrite,

mig/shared/jupyter.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
21
#!/usr/bin/python
32
# -*- coding: utf-8 -*-
43
#
54
# --- BEGIN_HEADER ---
65
#
76
# jupyter - Helper functions for the jupyter service
8-
# Copyright (C) 2003-2019 The MiG Project lead by Brian Vinter
7+
# Copyright (C) 2003-2024 The MiG Project lead by Brian Vinter
98
#
109
# This file is part of MiG.
1110
#
@@ -28,6 +27,10 @@
2827

2928
""" Jupyter service helper functions """
3029

30+
from __future__ import print_function
31+
from __future__ import absolute_import
32+
from past.builtins import basestring
33+
3134

3235
def gen_balancer_proxy_template(url, define, name, member_hosts,
3336
ws_member_hosts, timeout=600):
@@ -70,7 +73,8 @@ def gen_balancer_proxy_template(url, define, name, member_hosts,
7073

7174
for ws_host in ws_member_hosts:
7275
fill_helpers['ws_hosts'] += ''.join([' ', ws_host])
73-
print("filling in jupyter gen_balancer_proxy_template with helper: (%s)" % fill_helpers)
76+
print("filling in jupyter gen_balancer_proxy_template with helper: (%s)" %
77+
fill_helpers)
7478

7579
template = """
7680
<IfDefine %(define)s>
@@ -101,19 +105,24 @@ def gen_balancer_proxy_template(url, define, name, member_hosts,
101105
</IfDefine>""" % fill_helpers
102106
return template
103107

104-
def gen_openid_template(url, define):
105-
""" Generates an openid apache configuration section template
106-
for a particular jupyter service.
108+
109+
def gen_openid_template(url, define, auth_type):
110+
"""Generates an openid 2.0 or connect apache configuration section template
111+
for a particular jupyter service.
107112
url: Setting the url_path to where the jupyter service is to be located.
108113
define: The name of the apache variable containing the 'url' value.
114+
auth_type: the apache AuthType for this section (OpenID or openid-connect).
109115
"""
110116

111117
assert isinstance(url, basestring)
112118
assert isinstance(define, basestring)
119+
assert isinstance(auth_type, basestring)
120+
assert auth_type in ("OpenID", "openid-connect")
113121

114122
fill_helpers = {
115123
'url': url,
116-
'define': define
124+
'define': define,
125+
'auth_type': auth_type
117126
}
118127
print("filling in jupyter gen_openid_template with helper: (%s)" % fill_helpers)
119128

@@ -122,7 +131,7 @@ def gen_openid_template(url, define):
122131
<Location %(url)s>
123132
# Pass SSL variables on
124133
SSLOptions +StdEnvVars
125-
AuthType OpenID
134+
AuthType %(auth_type)s
126135
require valid-user
127136
</Location>
128137
</IfDefine>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

tests/fixture/confs-stdlocal/MiG.conf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,7 +1854,7 @@ Alias /.well-known/security.txt "/home/mig/state/wwwpublic/.well-known/security.
18541854
SSLOptions +StdEnvVars
18551855
</Directory>
18561856

1857-
# Jupyter OpenID auth
1857+
# Jupyter OpenID 2.0 auth
18581858
#Include /etc/apache2/conf.extras.d/MiG-jupyter-openid.conf
18591859

18601860
### The rest are sub-dirs that inherit the general conf above and
@@ -2456,7 +2456,7 @@ Alias /.well-known/security.txt "/home/mig/state/wwwpublic/.well-known/security.
24562456
SSLOptions +StdEnvVars
24572457
</Directory>
24582458

2459-
# Jupyter OpenID auth
2459+
# Jupyter OpenID 2.0 auth
24602460
#Include /etc/apache2/conf.extras.d/MiG-jupyter-openid.conf
24612461

24622462
### The rest are sub-dirs that inherit the general conf above and
@@ -3368,8 +3368,8 @@ Alias /.well-known/security.txt "/home/mig/state/wwwpublic/.well-known/security.
33683368
SSLOptions +StdEnvVars
33693369
</Directory>
33703370

3371-
# Jupyter OpenID auth
3372-
#Include /etc/apache2/conf.extras.d/MiG-jupyter-openid.conf
3371+
# Jupyter OpenID Connect auth
3372+
#Include /etc/apache2/conf.extras.d/MiG-jupyter-oidc.conf
33733373

33743374
### The rest are sub-dirs that inherit the general conf above and
33753375
### they can override any settings explicitly

tests/test_mig_shared_jupyter.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# --- BEGIN_HEADER ---
4+
#
5+
# test_mig_shared_jupyter - unit test of the corresponding mig shared module
6+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
7+
#
8+
# This file is part of MiG.
9+
#
10+
# MiG is free software: you can redistribute it and/or modify
11+
# it under the terms of the GNU General Public License as published by
12+
# the Free Software Foundation; either version 2 of the License, or
13+
# (at your option) any later version.
14+
#
15+
# MiG is distributed in the hope that it will be useful,
16+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
# GNU General Public License for more details.
19+
#
20+
# You should have received a copy of the GNU General Public License
21+
# along with this program; if not, write to the Free Software
22+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23+
# USA.
24+
#
25+
# --- END_HEADER ---
26+
#
27+
28+
"""Unit tests for the migrid module pointed to in the filename"""
29+
30+
import os
31+
import sys
32+
import time
33+
import unittest
34+
35+
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__))))
36+
37+
from tests.support import TEST_OUTPUT_DIR, MigTestCase, FakeConfiguration, \
38+
cleanpath, testmain
39+
from mig.shared.jupyter import gen_openid_template
40+
41+
42+
class MigSharedJupyter(MigTestCase):
43+
"""Wrap unit tests for the corresponding module"""
44+
45+
def test_jupyter_gen_openid_template_openid_auth(self):
46+
filled = gen_openid_template("/some-jupyter-url", "MyDefine", "OpenID")
47+
expected = """
48+
<IfDefine MyDefine>
49+
<Location /some-jupyter-url>
50+
# Pass SSL variables on
51+
SSLOptions +StdEnvVars
52+
AuthType OpenID
53+
require valid-user
54+
</Location>
55+
</IfDefine>
56+
"""
57+
self.assertEqual(filled, expected)
58+
59+
def test_jupyter_gen_openid_template_oidc_auth(self):
60+
filled = gen_openid_template("/some-jupyter-url", "MyDefine",
61+
"openid-connect")
62+
expected = """
63+
<IfDefine MyDefine>
64+
<Location /some-jupyter-url>
65+
# Pass SSL variables on
66+
SSLOptions +StdEnvVars
67+
AuthType openid-connect
68+
require valid-user
69+
</Location>
70+
</IfDefine>
71+
"""
72+
self.assertEqual(filled, expected)
73+
74+
def test_jupyter_gen_openid_template_invalid_url_type(self):
75+
rejected = False
76+
try:
77+
filled = gen_openid_template(None, "MyDefine",
78+
"no-such-auth-type")
79+
except AssertionError as err:
80+
rejected = True
81+
self.assertTrue(rejected)
82+
83+
def test_jupyter_gen_openid_template_invalid_define_type(self):
84+
rejected = False
85+
try:
86+
filled = gen_openid_template("/some-jupyter-url", None,
87+
"no-such-auth-type")
88+
except AssertionError as err:
89+
rejected = True
90+
self.assertTrue(rejected)
91+
92+
def test_jupyter_gen_openid_template_invalid_auth_type(self):
93+
rejected = False
94+
try:
95+
filled = gen_openid_template("/some-jupyter-url", "MyDefine",
96+
None)
97+
except AssertionError as err:
98+
rejected = True
99+
self.assertTrue(rejected)
100+
101+
def test_jupyter_gen_openid_template_invalid_auth_val(self):
102+
rejected = False
103+
try:
104+
filled = gen_openid_template("/some-jupyter-url", "MyDefine",
105+
"no-such-auth-type")
106+
except AssertionError as err:
107+
rejected = True
108+
self.assertTrue(rejected)
109+
110+
# TODO: add more coverage of module
111+
112+
113+
if __name__ == '__main__':
114+
testmain()

0 commit comments

Comments
 (0)