Skip to content
Snippets Groups Projects
Commit dcfa019f authored by Julian's avatar Julian
Browse files

Implemented blacklist functionality for login names

parent 8c4980da
No related branches found
No related tags found
No related merge requests found
...@@ -61,6 +61,8 @@ MAIL_FROM_ADDRESS='foo@bar.com' ...@@ -61,6 +61,8 @@ MAIL_FROM_ADDRESS='foo@bar.com'
# Do not enable this on a public service! There is no spam protection implemented at the moment. # Do not enable this on a public service! There is no spam protection implemented at the moment.
SELF_SIGNUP=False SELF_SIGNUP=False
LOGINNAME_BLACKLIST=['^admin$', '^root$']
#MFA_ICON_URL = 'https://example.com/logo.png' #MFA_ICON_URL = 'https://example.com/logo.png'
#MFA_RP_ID = 'example.com' # If unset, hostname from current request is used #MFA_RP_ID = 'example.com' # If unset, hostname from current request is used
MFA_RP_NAME = 'Uffd Test Service' # Service name passed to U2F/FIDO2 authenticators MFA_RP_NAME = 'Uffd Test Service' # Service name passed to U2F/FIDO2 authenticators
......
import secrets import secrets
import string import string
import re
from flask import current_app from flask import current_app
from ldap3.utils.hashed import hashed, HASHED_SALTED_SHA512 from ldap3.utils.hashed import hashed, HASHED_SALTED_SHA512
...@@ -87,12 +88,16 @@ class BaseUser(ldap.Model): ...@@ -87,12 +88,16 @@ class BaseUser(ldap.Model):
return True return True
return False return False
def set_loginname(self, value): def set_loginname(self, value, ignore_blacklist=False):
if len(value) > 32 or len(value) < 1: if len(value) > 32 or len(value) < 1:
return False return False
for char in value: for char in value:
if not char in string.ascii_lowercase + string.digits + '_-': if not char in string.ascii_lowercase + string.digits + '_-':
return False return False
if not ignore_blacklist:
for expr in current_app.config['LOGINNAME_BLACKLIST']:
if re.match(expr, value):
return False
self.loginname = value self.loginname = value
return True return True
......
...@@ -29,28 +29,36 @@ ...@@ -29,28 +29,36 @@
<div class="form-group col"> <div class="form-group col">
<label for="user-uid">uid</label> <label for="user-uid">uid</label>
{% if user.uid %} {% if user.uid %}
<input type="number" class="form-control" id="user-uid" name="uid" value="{{ user.uid }}" readonly> <input type="number" class="form-control" id="user-uid" name="uid" value="{{ user.uid or '' }}" readonly>
{% else %} {% else %}
<input type="text" class="form-control" id="user-uid" name="uid" placeholder="will be choosen" readonly> <input type="text" class="form-control" id="user-uid" name="uid" placeholder="will be choosen" readonly>
{% endif %} {% endif %}
</div> </div>
<div class="form-group col"> <div class="form-group col">
<label for="user-loginname">Login Name</label> <label for="user-loginname">Login Name</label>
<input type="text" class="form-control" id="user-loginname" name="loginname" value="{{ user.loginname }}" {% if user.uid %}readonly{% endif %}> <input type="text" class="form-control" id="user-loginname" name="loginname" value="{{ user.loginname or '' }}" {% if user.uid %}readonly{% endif %}>
<small class="form-text text-muted"> <small class="form-text text-muted">
Only letters, numbers and underscore ("_") are allowed. At most 32, at least 2 characters. There is a word blacklist. Musst be unique. Only letters, numbers and underscore ("_") are allowed. At most 32, at least 2 characters. There is a word blacklist. Musst be unique.
</small> </small>
</div> </div>
{% if not user.uid %}
<div class="form-group col">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="ignore-loginname-blacklist" name="ignore-loginname-blacklist" value="1" aria-label="enabled">
<label class="form-check-label" for="ignore-loginname-blacklist">Ignore login name blacklist</label>
</div>
</div>
{% endif %}
<div class="form-group col"> <div class="form-group col">
<label for="user-loginname">Display Name</label> <label for="user-loginname">Display Name</label>
<input type="text" class="form-control" id="user-displayname" name="displayname" value="{{ user.displayname }}"> <input type="text" class="form-control" id="user-displayname" name="displayname" value="{{ user.displayname or '' }}">
<small class="form-text text-muted"> <small class="form-text text-muted">
If you leave this empty it will be set to the login name. At most 128, at least 2 characters. No character restrictions. If you leave this empty it will be set to the login name. At most 128, at least 2 characters. No character restrictions.
</small> </small>
</div> </div>
<div class="form-group col"> <div class="form-group col">
<label for="user-mail">Mail</label> <label for="user-mail">Mail</label>
<input type="email" class="form-control" id="user-mail" name="mail" value="{{ user.mail }}"> <input type="email" class="form-control" id="user-mail" name="mail" value="{{ user.mail or '' }}">
<small class="form-text text-muted"> <small class="form-text text-muted">
Do a sanity check here. A user can take over another account if both have the same mail address set. Do a sanity check here. A user can take over another account if both have the same mail address set.
</small> </small>
......
...@@ -69,6 +69,10 @@ testuser5,foobadfar@example.com,0;5;2 ...@@ -69,6 +69,10 @@ testuser5,foobadfar@example.com,0;5;2
testuser2,foobaadsfr@example.com,5;2 testuser2,foobaadsfr@example.com,5;2
</pre> </pre>
<textarea rows="10" class="form-control" name="csv"></textarea> <textarea rows="10" class="form-control" name="csv"></textarea>
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" id="ignore-loginname-blacklist" name="ignore-loginname-blacklist" value="1" aria-label="enabled">
<label class="form-check-label" for="ignore-loginname-blacklist">Ignore login name blacklist</label>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
......
...@@ -41,7 +41,8 @@ def show(uid=None): ...@@ -41,7 +41,8 @@ def show(uid=None):
def update(uid=None): def update(uid=None):
if uid is None: if uid is None:
user = User() user = User()
if not user.set_loginname(request.form['loginname']): ignore_blacklist = request.form.get('ignore-loginname-blacklist', False)
if not user.set_loginname(request.form['loginname'], ignore_blacklist=ignore_blacklist):
flash('Login name does not meet requirements') flash('Login name does not meet requirements')
return redirect(url_for('user.show')) return redirect(url_for('user.show'))
else: else:
...@@ -90,6 +91,8 @@ def csvimport(): ...@@ -90,6 +91,8 @@ def csvimport():
flash('No data for csv import!') flash('No data for csv import!')
return redirect(url_for('user.index')) return redirect(url_for('user.index'))
ignore_blacklist = request.values.get('ignore-loginname-blacklist', False)
roles = Role.query.all() roles = Role.query.all()
usersadded = 0 usersadded = 0
with io.StringIO(initial_value=csvdata) as csvfile: with io.StringIO(initial_value=csvdata) as csvfile:
...@@ -99,7 +102,7 @@ def csvimport(): ...@@ -99,7 +102,7 @@ def csvimport():
flash("invalid line, ignored : {}".format(row)) flash("invalid line, ignored : {}".format(row))
continue continue
newuser = User() newuser = User()
if not newuser.set_loginname(row[0]) or not newuser.set_displayname(row[0]): if not newuser.set_loginname(row[0], ignore_blacklist=ignore_blacklist) or not newuser.set_displayname(row[0]):
flash("invalid login name, skipped : {}".format(row)) flash("invalid login name, skipped : {}".format(row))
continue continue
if not newuser.set_mail(row[1]): if not newuser.set_mail(row[1]):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment