Skip to content

Commit 3717717

Browse files
committed
Merge remote-tracking branch 'origin/master' into edge
2 parents 066ad85 + a093e66 commit 3717717

File tree

9 files changed

+240
-68
lines changed

9 files changed

+240
-68
lines changed

mig/install/generateconfs.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
# NOTE: moved mig imports into try/except to avoid autopep8 moving to top!
4848
try:
49+
from mig.shared.defaults import MIG_BASE, MIG_ENV
4950
from mig.shared.install import generate_confs
5051
except ImportError:
5152
print("ERROR: the migrid modules must be in PYTHONPATH")
@@ -351,14 +352,25 @@ def usage(options):
351352
if settings['destination_suffix'] == 'DEFAULT':
352353
suffix = "-%s" % datetime.datetime.now().isoformat()
353354
settings['destination_suffix'] = suffix
355+
if os.getenv('MIG_ENV', 'default') == 'local':
356+
output_path = os.path.join(MIG_BASE, 'envhelp/output')
357+
elif settings['destination'] == 'DEFAULT' or \
358+
not os.path.isabs(settings['destination']):
359+
# Default to generate in subdir of CWD ...
360+
output_path = os.getcwd()
361+
else:
362+
# ... but use verbatim passthrough for absolute destination
363+
output_path = settings['destination']
354364
print('# Creating confs with:')
355365
# NOTE: force list to avoid problems with in-line edits
356366
for (key, val) in list(settings.items()):
357367
print('%s: %s' % (key, val))
358368
# Remove default values to use generate_confs default values
359369
if val == 'DEFAULT':
360370
del settings[key]
361-
options = generate_confs(**settings)
371+
372+
options = generate_confs(output_path, **settings)
373+
362374
# TODO: avoid reconstructing this path (also done inside generate_confs)
363375
instructions_path = os.path.join(options['destination_dir'],
364376
'instructions.txt')

mig/shared/configuration.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2486,11 +2486,17 @@ def reload_config(self, verbose, skip_log=False):
24862486

24872487
# Init auth logger
24882488

2489+
auth_logger_logfile = None
2490+
if skip_log:
2491+
auth_logger_logfile = None
2492+
else:
2493+
auth_logger_logfile = self.user_auth_log
2494+
24892495
if self.auth_logger_obj:
24902496
self.auth_logger_obj.reopen()
24912497
else:
24922498
self.auth_logger_obj = Logger(
2493-
self.loglevel, logfile=self.user_auth_log, app='main-auth')
2499+
self.loglevel, logfile=auth_logger_logfile, app='main-auth')
24942500
self.auth_logger = self.auth_logger_obj.logger
24952501

24962502
# cert and key for generating a default proxy for nordugrid/ARC

mig/shared/defaults.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,6 @@
7777
any_protocol = keyword_any
7878
any_state = keyword_any
7979

80-
mig_user = {
81-
'default': 'mig',
82-
'local': keyword_auto,
83-
}[MIG_ENV]
84-
85-
mig_group = {
86-
'default': 'mig',
87-
'local': keyword_auto,
88-
}[MIG_ENV]
89-
90-
default_source = {
91-
'default': keyword_auto,
92-
'local': os.path.join(MIG_BASE, "mig/install"),
93-
}[MIG_ENV]
94-
95-
default_destination = {
96-
'default': keyword_auto,
97-
'local': os.path.join(MIG_BASE, "envhelp/output/confs"),
98-
}[MIG_ENV]
99-
100-
default_enable_events = {
101-
'default': True,
102-
'local': False
103-
}[MIG_ENV]
104-
10580
AUTH_NONE, AUTH_GENERIC, AUTH_CERTIFICATE = "None", "Generic", "X.509 Certificate"
10681
AUTH_OPENID_CONNECT, AUTH_OPENID_V2 = "OpenID Connect", "OpenID 2.0"
10782

mig/shared/install.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@
5050
import sys
5151

5252
from mig.shared.defaults import default_http_port, default_https_port, \
53-
MIG_BASE, mig_user, mig_group, default_source, default_destination, \
54-
auth_openid_mig_db, auth_openid_ext_db, STRONG_TLS_CIPHERS, \
53+
auth_openid_mig_db, auth_openid_ext_db, MIG_BASE, STRONG_TLS_CIPHERS, \
5554
STRONG_TLS_CURVES, STRONG_SSH_KEXALGOS, STRONG_SSH_LEGACY_KEXALGOS, \
5655
STRONG_SSH_CIPHERS, STRONG_SSH_LEGACY_CIPHERS, STRONG_SSH_MACS, \
5756
STRONG_SSH_LEGACY_MACS, CRACK_USERNAME_REGEX, CRACK_WEB_REGEX, \
@@ -257,14 +256,14 @@ def template_remove(template_file, remove_pattern):
257256

258257

259258
_GENERATE_CONFS_NOFORWARD_KEYS = [
259+
'generateconfs_output_path',
260260
'generateconfs_command',
261261
'source',
262262
'destination',
263263
'destination_suffix',
264264
'group',
265265
'user',
266266
'timezone',
267-
'_getcwd',
268267
'_getpwnam',
269268
'_prepare',
270269
'_writefiles',
@@ -273,12 +272,13 @@ def template_remove(template_file, remove_pattern):
273272

274273

275274
def generate_confs(
275+
generateconfs_output_path,
276276
# NOTE: make sure command line args with white-space are properly wrapped
277277
generateconfs_command=subprocess.list2cmdline(sys.argv),
278-
source=default_source,
279-
destination=default_destination,
280-
user=mig_user,
281-
group=mig_group,
278+
source=keyword_auto,
279+
destination=keyword_auto,
280+
user=keyword_auto,
281+
group=keyword_auto,
282282
timezone=keyword_auto,
283283
destination_suffix="",
284284
base_fqdn='',
@@ -315,9 +315,9 @@ def generate_confs(
315315
apache_log='/var/log/apache2',
316316
apache_worker_procs=256,
317317
openssh_version='7.4',
318-
mig_code='/home/mig/mig',
319-
mig_state='/home/mig/state',
320-
mig_certs='/home/mig/certs',
318+
mig_code=keyword_auto,
319+
mig_state=keyword_auto,
320+
mig_certs=keyword_auto,
321321
auto_add_cert_user=False,
322322
auto_add_oid_user=False,
323323
auto_add_oidc_user=False,
@@ -498,14 +498,16 @@ def generate_confs(
498498
ca_fqdn='',
499499
ca_user='mig-ca',
500500
ca_smtp='localhost',
501-
_getcwd=os.getcwd,
502501
_getpwnam=pwd.getpwnam,
503502
_prepare=None,
504503
_writefiles=None,
505504
_instructions=None,
506505
):
507506
"""Generate Apache and MiG server confs with specified variables"""
508507

508+
assert os.path.isabs(
509+
generateconfs_output_path), "output directory must be an absolute path"
510+
509511
# TODO: override in signature as a non-functional follow-up change
510512
if _prepare is None:
511513
_prepare = _generate_confs_prepare
@@ -521,29 +523,44 @@ def generate_confs(
521523
_GENERATE_CONFS_NOFORWARD_KEYS}
522524

523525
# expand any directory path specific as "auto" relative to CWD
524-
thecwd = _getcwd()
525526

526527
if source == keyword_auto:
527528
# use the templates from this copy of the code tree
528529
template_dir = os.path.join(MIG_BASE, "mig/install")
529530
else:
530531
# construct a path using the supplied value made absolute
531-
template_dir = abspath(source, start=thecwd)
532+
template_dir = abspath(source, start=generateconfs_output_path)
532533

533534
if destination == keyword_auto:
534535
# write output into a confs folder within the CWD
535-
destination = os.path.join(thecwd, 'confs')
536+
destination = os.path.join(generateconfs_output_path, 'confs')
537+
elif os.path.isabs(destination):
538+
# take the caller at face-value and do not change the path
539+
pass
536540
else:
537541
# construct a path from the supplied value made absolute
538-
destination = abspath(destination, start=thecwd)
542+
destination = abspath(destination, start=generateconfs_output_path)
539543

540544
# finalize destination paths up-front
541545
destination_link = destination
542546
destination_dir = "%s%s" % (destination, destination_suffix)
543547

548+
# expand mig, certs and state paths relative to base if left to "AUTO"
549+
550+
if mig_code == keyword_auto:
551+
mig_code = expanded['mig_code'] = os.path.join(MIG_BASE, 'mig')
552+
553+
if mig_certs == keyword_auto:
554+
mig_certs = expanded['mig_certs'] = os.path.join(MIG_BASE, 'certs')
555+
556+
if mig_state == keyword_auto:
557+
mig_state = expanded['mig_state'] = os.path.join(MIG_BASE, 'state')
558+
544559
# expand any user information marked as "auto" based on the environment
560+
545561
if user == keyword_auto:
546562
user = pwd.getpwuid(os.getuid())[0]
563+
547564
if group == keyword_auto:
548565
group = grp.getgrgid(os.getgid())[0]
549566

mig/unittest/__init__.py

Whitespace-only changes.

mig/unittest/testcore.py

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,57 @@
2828
"""Unit tests for core helper functions"""
2929
from __future__ import print_function
3030

31+
from configparser import ConfigParser
32+
import os
33+
import stat
3134
import sys
3235
import time
3336
import logging
3437

38+
sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), "../..")))
39+
from tests.support import MIG_BASE, PY2, is_path_within
40+
3541
from mig.shared.base import client_id_dir, client_dir_id, get_short_id, \
3642
invisible_path, allow_script, brief_list
3743

3844

39-
if __name__ == "__main__":
45+
_LOCAL_MIG_BASE = '/usr/src/app' if PY2 else MIG_BASE # account for execution in container
46+
_PYTHON_MAJOR = '2' if PY2 else '3'
47+
_TEST_CONF_DIR = os.path.join(MIG_BASE, "envhelp/output/testconfs-py%s" % (_PYTHON_MAJOR,))
48+
_TEST_CONF_FILE = os.path.join(_TEST_CONF_DIR, "MiGserver.conf")
49+
_TEST_CONF_SYMLINK = os.path.join(MIG_BASE, "envhelp/output/testconfs")
50+
51+
52+
def _assert_local_config():
53+
try:
54+
link_stat = os.lstat(_TEST_CONF_SYMLINK)
55+
assert stat.S_ISLNK(link_stat.st_mode)
56+
configdir_stat = os.stat(_TEST_CONF_DIR)
57+
assert stat.S_ISDIR(configdir_stat.st_mode)
58+
config = ConfigParser()
59+
config.read([_TEST_CONF_FILE])
60+
return config
61+
except Exception as exc:
62+
raise AssertionError('local configuration invalid or missing: %s' % (str(exc),))
63+
64+
65+
def _assert_local_config_global_values(config):
66+
config_global_values = dict(config.items('GLOBAL'))
67+
68+
for path in ('mig_path', 'certs_path', 'state_path'):
69+
path_value = config_global_values.get(path)
70+
if not is_path_within(path_value, start=_LOCAL_MIG_BASE):
71+
raise AssertionError('local config contains bad path: %s=%s' % (path, path_value))
72+
73+
return config_global_values
74+
75+
76+
def main(_exit=sys.exit):
77+
config = _assert_local_config()
78+
config_global_values = _assert_local_config_global_values(config)
79+
4080
from mig.shared.conf import get_configuration_object
41-
configuration = get_configuration_object()
81+
configuration = get_configuration_object(_TEST_CONF_FILE, skip_log=True)
4282
logging.basicConfig(filename=None, level=logging.INFO,
4383
format="%(asctime)s %(levelname)s %(message)s")
4484
configuration.logger = logging
@@ -66,15 +106,16 @@
66106
if client_id != test_id:
67107
print("ERROR: Expected match on IDs but found: %s vs %s" %
68108
(client_id, test_id))
69-
sys.exit(1)
109+
_exit(1)
70110
if client_dir != test_dir:
71111
print("ERROR: Expected match on dirs but found: %s vs %s" %
72112
(client_dir, test_dir))
73-
sys.exit(1)
113+
_exit(1)
74114
if client_short != test_short:
75115
print("ERROR: Expected match on %s but found: %s vs %s" %
76116
(short_alias, client_short, test_short))
77-
sys.exit(1)
117+
_exit(1)
118+
78119

79120
orig_id = '/X=ab/Y=cdef ghi/Z=klmn'
80121
client_dir = client_id_dir(orig_id)
@@ -106,12 +147,12 @@
106147
for path in legal:
107148
if invisible_path(path):
108149
print("ERROR: Expected visible on %s but not the case" % path)
109-
sys.exit(1)
150+
_exit(1)
110151
# print("check that these are invisible:")
111152
for path in illegal:
112153
if not invisible_path(path):
113154
print("ERROR: Expected invisible on %s but not the case" % path)
114-
sys.exit(1)
155+
_exit(1)
115156

116157
print("Check script restrictions:")
117158
access_any = ['reqoid.py', 'docs.py', 'ls.py']
@@ -121,33 +162,36 @@
121162
if not allow:
122163
print("ERROR: Expected anon access to %s but not the case" %
123164
script_name)
124-
sys.exit(1)
165+
_exit(1)
125166
(allow, msg) = allow_script(configuration, script_name, client_id)
126167
if not allow:
127168
print("ERROR: Expected auth access to %s but not the case" %
128169
script_name)
129-
sys.exit(1)
170+
_exit(1)
130171
for script_name in access_auth:
131172
(allow, msg) = allow_script(configuration, script_name, '')
132173
if configuration.site_enable_gdp and allow:
133174
print("ERROR: Expected anon restrict to %s but not the case" %
134175
script_name)
135-
sys.exit(1)
176+
_exit(1)
136177
(allow, msg) = allow_script(configuration, script_name, client_id)
137178
if not allow:
138179
print("ERROR: Expected auth access to %s but not the case" %
139180
script_name)
140-
sys.exit(1)
181+
_exit(1)
141182

142183
print("Check brief format list limit")
143184
for (size, outlen) in [(5, 15), (30, 58), (200, 63)]:
144-
shortened = "%s" % brief_list(range(size))
185+
shortened = "%s" % brief_list(list(range(size)))
145186
if len(shortened) != outlen:
146187
print("ERROR: Expected brief range %d list of length %d but not the case: %s" %
147188
(size, outlen, len(shortened)))
148-
sys.exit(1)
189+
_exit(1)
149190

150191
print("Completed shared base functions tests")
151192

152193
print("Done running unit test on shared core functions")
153-
sys.exit(0)
194+
_exit(0)
195+
196+
if __name__ == "__main__":
197+
main()

tests/support.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ def __init__(self, *args):
174174
def setUp(self):
175175
if not self._skip_logging:
176176
self._reset_logging(stream=self.logger)
177+
self.before_each()
177178

178179
def tearDown(self):
179180
if not self._skip_logging:
@@ -191,6 +192,10 @@ def tearDown(self):
191192
else:
192193
continue
193194

195+
# hooks
196+
def before_each(self):
197+
pass
198+
194199
def _reset_logging(self, stream):
195200
root_logger = logging.getLogger()
196201
root_handler = root_logger.handlers[0]
@@ -234,6 +239,11 @@ def assertPathExists(self, relative_path):
234239
else:
235240
return "file"
236241

242+
def assertPathWithin(self, path, start=None):
243+
if not is_path_within(path, start=start):
244+
raise AssertionError(
245+
"path %s is not within directory %s" % (path, start))
246+
237247
@staticmethod
238248
def pretty_display_path(absolute_path):
239249
assert os.path.isabs(absolute_path)
@@ -242,6 +252,15 @@ def pretty_display_path(absolute_path):
242252
return relative_path
243253

244254

255+
def is_path_within(path, start=None, _msg=None):
256+
try:
257+
assert os.path.isabs(path), _msg
258+
relative = os.path.relpath(path, start=start)
259+
except:
260+
return False
261+
return not relative.startswith('..')
262+
263+
245264
def cleanpath(relative_path, test_case):
246265
assert isinstance(test_case, MigTestCase)
247266
tmp_path = os.path.join(TEST_OUTPUT_DIR, relative_path)

0 commit comments

Comments
 (0)