Skip to content

Commit f194b64

Browse files
committed
Add signup_prefilter similar to peers_prefilter to ease filtering of unwanted
account requests like e.g. internal users signing up as external users. Eliminated the old obsolete `forced_org_email_match` checks, which can now be implemented better with a `signup_prefilter` on email and optionally organization. Minor polish and sync of reqcert and reqoid for consistency.
1 parent ba904c2 commit f194b64

File tree

9 files changed

+73
-85
lines changed

9 files changed

+73
-85
lines changed

mig/install/MiGserver-template.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,12 @@ password_policy = __PASSWORD_POLICY__
757757
password_legacy_policy = __PASSWORD_LEGACY_POLICY__
758758
# Optional additional guard against simple passwords with the cracklib library
759759
password_cracklib = __ENABLE_CRACKLIB__
760+
# Optional prefilter on users who may sign up as site users with sign up forms.
761+
# Used as a coarse filter to reject invalid user requests early by only
762+
# filtering on form values (organization, email). E.g. to avoid internal users
763+
# signing up as externals. Space separated list of user field and regexp-filter
764+
# pattern pairs separated by colons.
765+
signup_prefilter = __SIGNUP_PREFILTER__
760766
# Optional prefilter on users who may potenially invite peers as site users.
761767
# Used as a coarse filter to reject clearly invalid user requests early by only
762768
# filtering on form values (peers_full_name and peers_email). Space separated

mig/shared/accountreq.py

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,51 +1182,6 @@ def prefilter_potential_peers(peers_list, configuration):
11821182
return potential_peers
11831183

11841184

1185-
def forced_org_email_match(org, email, configuration):
1186-
"""Check that email and organization follow the required policy"""
1187-
1188-
logger = configuration.logger
1189-
# Policy regexps: prioritized order with most general last
1190-
force_org_email = [('DIKU', ['^[a-zA-Z0-9_.+-]+@diku.dk$',
1191-
'^[a-zA-Z0-9_.+-]+@di.ku.dk$']),
1192-
('NBI', ['^[a-zA-Z0-9_.+-]+@nbi.ku.dk$',
1193-
'^[a-zA-Z0-9_.+-]+@nbi.dk$',
1194-
'^[a-zA-Z0-9_.+-]+@fys.ku.dk$']),
1195-
('IMF', ['^[a-zA-Z0-9_.+-]+@math.ku.dk$']),
1196-
# Keep this KU catch-all last and do not generalize it!
1197-
('KU', ['^[a-zA-Z0-9_.+-]+@(alumni.|)ku.dk$']),
1198-
]
1199-
force_org_email_dict = dict(force_org_email)
1200-
is_forced_email = False
1201-
is_forced_org = False
1202-
if org.upper() in force_org_email_dict:
1203-
is_forced_org = True
1204-
# Consistent casing
1205-
org = org.upper()
1206-
email_hit = '__BOGUS__'
1207-
for (forced_org, forced_email_list) in force_org_email:
1208-
for forced_email in forced_email_list:
1209-
# Consistent casing
1210-
if re.match(forced_email, email.lower()):
1211-
is_forced_email = True
1212-
email_hit = forced_email
1213-
logger.debug('email match on %s vs %s' % (email, forced_email))
1214-
break
1215-
1216-
# Use first hit to avoid catch-all overriding specific hits
1217-
if is_forced_email or is_forced_org and org == forced_org:
1218-
break
1219-
if is_forced_org != is_forced_email or \
1220-
not email_hit in force_org_email_dict.get(org, ['__BOGUS__']):
1221-
logger.error('Illegal email and organization combination: %s' %
1222-
([email, org, is_forced_org, is_forced_email,
1223-
email_hit, force_org_email_dict.get(org,
1224-
['__BOGUS__'])]))
1225-
return False
1226-
else:
1227-
return True
1228-
1229-
12301185
def save_account_request(configuration, req_dict):
12311186
"""Save req_dict account request as pickle in configured user_pending
12321187
location.
@@ -1331,6 +1286,17 @@ def auto_add_user_allowed_with_peer(configuration, user_dict):
13311286
return __auto_add_user_allowed(configuration, user_dict,
13321287
configuration.auto_add_user_with_peer)
13331288

1289+
1290+
def signup_prefilter_allowed(configuration, user_dict):
1291+
"""Check if user with user_dict is potentially allowed to sign up in forms
1292+
soleley based on optional configuration prefilter.
1293+
"""
1294+
for (key, val) in configuration.site_signup_prefilter:
1295+
if not re.match(val, user_dict.get(key, 'NO SUCH FIELD')):
1296+
return False
1297+
return True
1298+
1299+
13341300
def peers_prefilter_allowed(configuration, user_dict):
13351301
"""Check if user with user_dict is potentially allowed to manage peers
13361302
soleley based on optional configuration prefilter.

mig/shared/configuration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ def get(self, *args, **kwargs):
526526
'site_signup_methods': ['extcert'],
527527
'site_login_methods': ['extcert'],
528528
'site_signup_hint': "",
529+
'site_signup_prefilter': [('email', '.*')],
529530
'site_peers_prefilter': [('peers_email', '.*')],
530531
'site_peers_permit': [('distinguished_name', '.*')],
531532
'site_peers_notice': "",
@@ -2131,6 +2132,9 @@ def reload_config(self, verbose, skip_log=False, disable_auth_log=False,
21312132
self.site_login_methods = self.site_signup_methods
21322133
if config.has_option('SITE', 'signup_hint'):
21332134
self.site_signup_hint = config.get('SITE', 'signup_hint').strip()
2135+
if config.has_option('SITE', 'signup_prefilter'):
2136+
req = config.get('SITE', 'signup_prefilter').split()
2137+
self.site_signup_prefilter = [i.split(':', 2) for i in req]
21342138
if config.has_option('SITE', 'peers_prefilter'):
21352139
req = config.get('SITE', 'peers_prefilter').split()
21362140
self.site_peers_prefilter = [i.split(':', 2) for i in req]

mig/shared/functionality/reqcertaction.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,16 @@
2929

3030
from __future__ import absolute_import
3131

32-
# TODO: this backend is horribly KU/UCPH-specific, should move that to conf
32+
# TODO: this backend is somewhat KU/UCPH-specific, should move that to conf
3333

3434
import os
3535
import time
3636
import tempfile
3737

3838
from mig.shared import returnvalues
39-
from mig.shared.accountreq import existing_country_code, forced_org_email_match, \
40-
prefilter_potential_peers, user_manage_commands, save_account_request
39+
from mig.shared.accountreq import existing_country_code, \
40+
prefilter_potential_peers, save_account_request, signup_prefilter_allowed, \
41+
user_manage_commands
4142
from mig.shared.accountstate import default_account_expire
4243
from mig.shared.base import client_id_dir, canonical_user, mask_creds, \
4344
generate_https_urls, fill_distinguished_name
@@ -111,6 +112,7 @@ def main(client_id, user_arguments_dict):
111112
country = accepted['country'][-1].strip()
112113
state = accepted['state'][-1].strip()
113114
org = accepted['org'][-1].strip()
115+
# NOTE: safeinput thoroughly checks that emails are on valid form
114116
email = accepted['email'][-1].strip()
115117
password = accepted['password'][-1]
116118
verifypassword = accepted['verifypassword'][-1]
@@ -206,23 +208,6 @@ def main(client_id, user_arguments_dict):
206208
'class': 'genericbutton', 'text': "Try again"})
207209
return (output_objects, returnvalues.CLIENT_ERROR)
208210

209-
# TODO: move this check to conf?
210-
211-
if not forced_org_email_match(org, email, configuration):
212-
output_objects.append({'object_type': 'error_text', 'text':
213-
'''Illegal email and organization combination:
214-
Please read and follow the instructions in red on the request page!
215-
If you are a student with only a @*.ku.dk address please just use KU as
216-
organization. As long as you state that you want the account for course
217-
purposes in the comment field, you will be given access to the necessary
218-
resources anyway.
219-
'''})
220-
output_objects.append(
221-
{'object_type': 'link',
222-
'destination': 'javascript:history.back();',
223-
'class': 'genericbutton', 'text': "Try again"})
224-
return (output_objects, returnvalues.CLIENT_ERROR)
225-
226211
raw_user = {
227212
'full_name': cert_name,
228213
'organization': org,
@@ -246,6 +231,19 @@ def main(client_id, user_arguments_dict):
246231
# Title name, lowercase email, uppercase country and state, etc.
247232
user_dict = canonical_user(configuration, raw_user, raw_user.keys())
248233
fill_distinguished_name(user_dict)
234+
235+
if not signup_prefilter_allowed(configuration, raw_user):
236+
output_objects.append({'object_type': 'error_text', 'text':
237+
'''Invalid sign up request:
238+
Please read and follow the sign up help and instructions on the request page!
239+
Namely, make sure to use the correct sign up based on your organizational
240+
affiliation. You may also read more about sign up in the site documentation.
241+
'''})
242+
output_objects.append(
243+
{'object_type': 'link', 'destination': 'javascript:history.back();',
244+
'class': 'genericbutton', 'text': "Try again"})
245+
return (output_objects, returnvalues.CLIENT_ERROR)
246+
249247
user_id = user_dict['distinguished_name']
250248
user_dict['authorized'] = (user_id == client_id)
251249
if configuration.user_openid_providers and configuration.user_openid_alias:
@@ -285,7 +283,7 @@ def main(client_id, user_arguments_dict):
285283
helper_commands = user_manage_commands(configuration, mig_user, req_path,
286284
user_id, user_dict, 'cert')
287285
user_dict.update(helper_commands)
288-
user_dict['site'] = configuration.short_title
286+
user_dict['site'] = short_title
289287
user_dict['vgrid_label'] = configuration.site_vgrid_label
290288
user_dict['vgridman_links'] = generate_https_urls(
291289
configuration, '%(auto_base)s/%(auto_bin)s/vgridman.py', {})

mig/shared/functionality/reqoidaction.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,16 @@
2929

3030
from __future__ import absolute_import
3131

32-
# TODO: this backend is horribly KU/UCPH-specific, should move that to conf
32+
# TODO: this backend is somewhat KU/UCPH-specific, should move that to conf
3333

3434
import os
3535
import time
3636
import tempfile
3737

3838
from mig.shared import returnvalues
39-
from mig.shared.accountreq import existing_country_code, forced_org_email_match, \
40-
prefilter_potential_peers, user_manage_commands, save_account_request
39+
from mig.shared.accountreq import existing_country_code, \
40+
prefilter_potential_peers, save_account_request, signup_prefilter_allowed, \
41+
user_manage_commands
4142
from mig.shared.accountstate import default_account_expire
4243
from mig.shared.base import client_id_dir, canonical_user, mask_creds, \
4344
force_utf8, force_unicode, force_native_str, force_native_str_rec, \
@@ -208,22 +209,6 @@ def main(client_id, user_arguments_dict):
208209
'''Invalid peers specification:
209210
Please read and follow the sign up help and instructions on the request page!
210211
You may also read more about the Peers system in the site documentation.
211-
'''})
212-
output_objects.append(
213-
{'object_type': 'link', 'destination': 'javascript:history.back();',
214-
'class': 'genericbutton', 'text': "Try again"})
215-
return (output_objects, returnvalues.CLIENT_ERROR)
216-
217-
# TODO: move this check to conf?
218-
219-
if not forced_org_email_match(org, email, configuration):
220-
output_objects.append({'object_type': 'error_text', 'text':
221-
'''Illegal email and organization combination:
222-
Please read and follow the instructions in red on the request page!
223-
If you are a student with only a @*.ku.dk address please just use KU as
224-
organization. As long as you state that you want the account for course
225-
purposes in the comment field, you will be given access to the necessary
226-
resources anyway.
227212
'''})
228213
output_objects.append(
229214
{'object_type': 'link', 'destination': 'javascript:history.back();',
@@ -261,6 +246,19 @@ def main(client_id, user_arguments_dict):
261246
# Title name, lowercase email, uppercase country and state, etc.
262247
user_dict = canonical_user(configuration, raw_user, raw_user.keys())
263248
fill_distinguished_name(user_dict)
249+
250+
if not signup_prefilter_allowed(configuration, raw_user):
251+
output_objects.append({'object_type': 'error_text', 'text':
252+
'''Invalid sign up request:
253+
Please read and follow the sign up help and instructions on the request page!
254+
Namely, make sure to use the correct sign up based on your organizational
255+
affiliation. You may also read more about sign up in the site documentation.
256+
'''})
257+
output_objects.append(
258+
{'object_type': 'link', 'destination': 'javascript:history.back();',
259+
'class': 'genericbutton', 'text': "Try again"})
260+
return (output_objects, returnvalues.CLIENT_ERROR)
261+
264262
user_id = user_dict['distinguished_name']
265263
user_dict['authorized'] = (user_id == client_id)
266264
if configuration.user_openid_providers and configuration.user_openid_alias:

mig/shared/install.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ def generate_confs(
447447
daemon_pubkey_from_dns=False,
448448
daemon_show_address='',
449449
alias_field='',
450+
signup_prefilter='email:.*',
450451
peers_prefilter='peers_email:.*',
451452
peers_permit='distinguished_name:.*',
452453
vgrid_creators='distinguished_name:.*',
@@ -771,6 +772,7 @@ def _generate_confs_prepare(
771772
daemon_pubkey_from_dns,
772773
daemon_show_address,
773774
alias_field,
775+
signup_prefilter,
774776
peers_prefilter,
775777
peers_permit,
776778
vgrid_creators,
@@ -1056,6 +1058,7 @@ def _generate_confs_prepare(
10561058
user_dict['__SEAFILE_RO_ACCESS__'] = "%s" % seafile_ro_access
10571059
user_dict['__PUBLIC_USE_HTTPS__'] = "%s" % public_use_https
10581060
user_dict['__ALIAS_FIELD__'] = alias_field
1061+
user_dict['__SIGNUP_PREFILTER__'] = signup_prefilter
10591062
user_dict['__PEERS_PREFILTER__'] = peers_prefilter
10601063
user_dict['__PEERS_PERMIT__'] = peers_permit
10611064
user_dict['__VGRID_CREATORS__'] = vgrid_creators

tests/fixture/confs-stdlocal/MiGserver.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,12 @@ password_policy = MEDIUM
757757
password_legacy_policy =
758758
# Optional additional guard against simple passwords with the cracklib library
759759
password_cracklib = False
760+
# Optional prefilter on users who may sign up as site users with sign up forms.
761+
# Used as a coarse filter to reject invalid user requests early by only
762+
# filtering on form values (organization, email). E.g. to avoid internal users
763+
# signing up as externals. Space separated list of user field and regexp-filter
764+
# pattern pairs separated by colons.
765+
signup_prefilter = email:.*
760766
# Optional prefilter on users who may potenially invite peers as site users.
761767
# Used as a coarse filter to reject clearly invalid user requests early by only
762768
# filtering on form values (peers_full_name and peers_email). Space separated

tests/fixture/mig_shared_configuration--new.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@
191191
"site_signup_methods": [
192192
"extcert"
193193
],
194+
"site_signup_prefilter": [
195+
[
196+
"email",
197+
".*"
198+
]
199+
],
194200
"site_skin": "",
195201
"site_vgrid_creators": [
196202
[

tests/fixture/mig_shared_configuration--new.json.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
auto_add_user_permit = array_of_tuples
33
auto_add_user_with_peer = array_of_tuples
44
site_cloud_access = array_of_tuples
5+
site_signup_prefilter = array_of_tuples
56
site_peers_prefilter = array_of_tuples
67
site_peers_permit = array_of_tuples
78
site_vgrid_creators = array_of_tuples

0 commit comments

Comments
 (0)