Skip to content

Commit dc476e6

Browse files
committed
Merge remote-tracking branch 'origin/master' into edge
2 parents 96f3627 + 10ac50f commit dc476e6

File tree

5 files changed

+498
-12
lines changed

5 files changed

+498
-12
lines changed

mig/cgi-bin/accountaction.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# --- BEGIN_HEADER ---
5+
#
6+
# accountaction - account action page front end
7+
# Copyright (C) 2003-2025 The MiG Project by the Science HPC Center at UCPH
8+
#
9+
# This file is part of MiG.
10+
#
11+
# MiG is free software: you can redistribute it and/or modify
12+
# it under the terms of the GNU General Public License as published by
13+
# the Free Software Foundation; either version 2 of the License, or
14+
# (at your option) any later version.
15+
#
16+
# MiG is distributed in the hope that it will be useful,
17+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
# GNU General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; if not, write to the Free Software
23+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24+
#
25+
# -- END_HEADER ---
26+
#
27+
28+
from __future__ import absolute_import
29+
import cgi
30+
31+
from mig.shared.functionality.accountaction import main
32+
from mig.shared.cgiscriptstub import run_cgi_script_possibly_with_cert
33+
34+
run_cgi_script_possibly_with_cert(main)

mig/shared/accountreq.py

+49-5
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@
2626
#
2727

2828
"""This module contains various helper contents for the certificate and OpenID
29-
account request handlers"""
29+
account request handlers.
30+
"""
3031

3132
from __future__ import absolute_import
3233

33-
import re
3434
import os
35+
import re
3536
import time
3637

3738
# NOTE: the external iso3166 module is optional and only used if available
@@ -657,6 +658,48 @@ def account_pw_reset_template(configuration, default_values={}):
657658
return html
658659

659660

661+
def renew_account_access_template(configuration, default_values={}):
662+
"""A general form template used for renewing account access."""
663+
664+
html = """
665+
<div id='account-renew-access-grid' class='form_container'>
666+
"""
667+
668+
_logger = configuration.logger
669+
auth_map = auth_type_description(configuration)
670+
show_auth_types = [(key, auth_map[key]) for key in
671+
default_values.get('show', auth_map.keys())]
672+
filtered_auth_types = [i for i in show_auth_types if i[0] in
673+
configuration.site_signup_methods]
674+
_logger.debug("show_auth_types %s filtered_auth_types %s" %
675+
(show_auth_types, filtered_auth_types))
676+
if not filtered_auth_types:
677+
html += """<p class='warningtext'>
678+
No matching local authentication methods enabled on this site, so no account
679+
access to renew here.
680+
</p>
681+
"""
682+
else:
683+
html += """
684+
<p>
685+
Account access automatically expires after a while and needs to be actively
686+
renewed.
687+
%(peer_acceptance_notice)s
688+
</p>
689+
<!-- use post here to avoid field contents in URL -->
690+
<form method='%(form_method)s' action='%(target_op)s.py'>
691+
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
692+
<input type='hidden' name='action' value='%(account_action)s'/>
693+
<input id='submit_button' type=submit value='Renew %(auth_label)s Account Access'/>
694+
</form>
695+
"""
696+
697+
html += """
698+
</div>
699+
"""
700+
return html
701+
702+
660703
def build_accountreqitem_object(configuration, accountreq_dict):
661704
"""Build a accountreq object based on input accountreq_dict"""
662705

@@ -1250,12 +1293,13 @@ def __auto_add_user_allowed(configuration, user_dict, permit_list):
12501293
is empty.
12511294
"""
12521295

1253-
if not permit_list:
1254-
return False
1296+
match = False
1297+
if permit_list:
1298+
match = True
12551299
for (key, val) in permit_list:
12561300
if not re.match(val, user_dict.get(key, 'NO SUCH FIELD')):
12571301
return False
1258-
return True
1302+
return match
12591303

12601304

12611305
def auto_add_user_allowed_direct(configuration, user_dict):

mig/shared/functionality/account.py

+72-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# --- BEGIN_HEADER ---
55
#
66
# account - account page with info and account management options
7-
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
7+
# Copyright (C) 2003-2025 The MiG Project by the Science HPC Center at UCPH
88
#
99
# This file is part of MiG.
1010
#
@@ -34,9 +34,13 @@
3434
import os
3535

3636
from mig.shared import returnvalues
37+
from mig.shared.accountreq import renew_account_access_template
38+
from mig.shared.defaults import csrf_field, user_home_label
3739
from mig.shared.functional import validate_input_and_cert
38-
from mig.shared.init import initialize_main_variables, find_entry
39-
from mig.shared.htmlgen import html_user_messages, man_base_html, man_base_js
40+
from mig.shared.handlers import get_csrf_limit, make_csrf_token
41+
from mig.shared.htmlgen import html_user_messages, man_base_js
42+
from mig.shared.httpsclient import detect_client_auth, find_auth_type_and_label
43+
from mig.shared.init import find_entry, initialize_main_variables
4044
from mig.shared.useradm import get_full_user_map
4145

4246
_account_field_order = [('full_name', 'Full Name'),
@@ -93,7 +97,7 @@ def html_tmpl(configuration, client_id, environ, title_entry):
9397
user_token += claim_dump
9498
fill_helpers = {'short_title': configuration.short_title,
9599
'user_msg': user_msg, 'show_user_msg': show_user_msg,
96-
'user_account': user_account,
100+
'home_label': user_home_label, 'user_account': user_account,
97101
'user_token': user_token}
98102

99103
html = '''
@@ -129,7 +133,70 @@ def html_tmpl(configuration, client_id, environ, title_entry):
129133
</div>
130134
'''
131135

132-
# TODO: add account management actions
136+
# Account management like renew account access for local users
137+
# TODO: add change password and delete account support for all accounts?
138+
(auth_type_name, auth_flavor) = detect_client_auth(configuration, environ)
139+
(auth_type, auth_label) = find_auth_type_and_label(configuration,
140+
auth_type_name,
141+
auth_flavor)
142+
show_local = [i for i in configuration.site_login_methods
143+
if i.startswith('mig')]
144+
fill_helpers.update({'auth_type': auth_type,
145+
'auth_type_name': auth_type_name,
146+
'auth_flavor': auth_flavor,
147+
'auth_label': auth_label})
148+
html += '''
149+
<div id="manage-container" class="row">
150+
<div class="manage-page__header col-12">
151+
<h2>Manage Account</h2>
152+
<p class="sub-title">Depending on your %(short_title)s account
153+
type you have access to one or more account management actions
154+
below.
155+
</p>
156+
</div>
157+
''' % fill_helpers
158+
form_method = 'post'
159+
csrf_limit = get_csrf_limit(configuration)
160+
target_op = 'accountaction'
161+
csrf_token = make_csrf_token(configuration, form_method, target_op,
162+
client_id, csrf_limit)
163+
fill_helpers.update({'target_op': target_op, 'form_method':
164+
form_method, 'csrf_field': csrf_field,
165+
'csrf_token': csrf_token})
166+
# TODO: extend renew to active ext accounts?
167+
if auth_type in show_local and user_dict.get('status', 'active') == 'temporal':
168+
fill_helpers['account_action'] = "RENEW_ACCESS"
169+
fill_helpers['peer_acceptance_notice'] = ""
170+
if configuration.site_peers_mandatory:
171+
peers_full_name = user_dict.get("peers_full_name", "")
172+
peers_email = user_dict.get("peers_email", "")
173+
peers_list = user_dict.get("peers", [])
174+
if peers_list or (peers_full_name and peers_email):
175+
fill_helpers['peer_acceptance_notice'] = """
176+
Apparently %(peers_full_name)s &lt;%(peers_email)s&gt; accepted you as a peer
177+
and if that peer appointment has not yet ended you can renew your access here
178+
without further operator or peer contact involvement. Otherwise you may need to
179+
obtain or await explicit extension or peer assignment from someone else before
180+
your access renewal can proceed.
181+
""" % user_dict
182+
else:
183+
fill_helpers['peer_acceptance_notice'] = """
184+
It looks like you may need someone with authority to appoint you as their peer
185+
before your access renewal can be accepted.
186+
"""
187+
fill_helpers['renew_helper'] = renew_account_access_template(
188+
configuration, default_values=fill_helpers) % fill_helpers
189+
html += '''
190+
<div class="renew-account-access__header col-12">
191+
<h3>Renew Account Access</h3>
192+
%(renew_helper)s
193+
</div>
194+
''' % fill_helpers
195+
196+
html += '''
197+
<div class="col-lg-12 vertical-spacer"></div>
198+
</div>
199+
'''
133200

134201
return html
135202

0 commit comments

Comments
 (0)