From a16cb646069003244811e464340e9df91c4a5723 Mon Sep 17 00:00:00 2001 From: Aitzol Date: Thu, 16 Nov 2023 13:17:59 +0100 Subject: [PATCH] 2fa-0.5 --- _2fa.tpl | 8 +++--- app.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++-- libs/helper.py | 9 ++++++ start.sh | 7 +++++ 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/_2fa.tpl b/_2fa.tpl index e2bd239..050962d 100644 --- a/_2fa.tpl +++ b/_2fa.tpl @@ -17,10 +17,10 @@ % if data['secureAuth'] == True: -
+ - +
@@ -31,10 +31,10 @@ % else: - + - +
diff --git a/app.py b/app.py index 74db904..fb5383e 100644 --- a/app.py +++ b/app.py @@ -269,11 +269,26 @@ def post_edit_email(): try: edit_email(username, old_email, form('email').lower()) except Error as e: - LOG.warning("Unsuccessful attempt to change email addres for %s: %s" % (username, e)) + LOG.warning("Unsuccessful attempt to change email address for %s: %s" % (username, e)) return error(str(e)) return user_tpl(alerts=[('success', i18n.msg[16], 'fadeOut' )], data=newSession().get(), str=i18n.str) +@post('/enable_2fa') +def post_enable_2fa(): + try: + username=newSession().get()['username'] + add_auth_attribute_step1(username, tools.generate_secret()) + ''' + add attribute authCode + set session data + ''' + except Error as e: + LOG.warning("akatsa") + return error(str(e)) + + return _2fa_tpl(data=newSession().get(), str=i18n.str) + @post('/change_pwd') def post_change_pwd(): form = request.forms.getunicode @@ -648,7 +663,6 @@ def new_email_address(conf, *args): LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) raise Error(i18n.msg[23]) - def update_email_address(conf, username, old_email, new_email): if(old_email == new_email): raise Error(i18n.msg[15]) @@ -662,6 +676,59 @@ def update_email_address(conf, username, old_email, new_email): c.modify(user_dn, {'mail': [( MODIFY_REPLACE, new_email_addresses )]}) newSession().set(get_user_data(user_dn, c)) +# ADD SECUREAUTH ATTRIBUTE - 2FA +def add_auth_attribute_step1(username, code): + changed = [] + + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("Adding secureAuth attribute %s to %s" % (key, username)) + try: + add_auth_attribute_step2(CONF[key], username, code) + changed.append(key) + LOG.debug("%s changed email address on %s" % (username, key)) + except Error as e: + for key in reversed(changed): + LOG.info("Reverting email change in %s for %s" % (key, username)) + try: + new_email_address(CONF[key], username, new_email, old_email) + except Error as e2: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e2)) + raise e + +def add_auth_attribute_step2(conf, *args): + try: + add_auth_attribute_step3(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[26]) + + except LDAPConstraintViolationResult as e: + # Extract useful part of the error message (for Samba 4 / AD). + msg = e.message.split('check_password_restrictions: ')[-1].capitalize() + raise Error(msg) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[23]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[23]) + +def add_auth_attribute_step3(conf, username, code): + + #set current LDAP + superUser = SuperUsers(conf) + + with connect_ldap(conf, user=superUser.admin_dn, password=superUser.admin_pwd) as c: + user_dn = find_user_dn(conf, c, username) + '''OBJECT_CLASS = ['top', 'inetOrgPerson', 'posixAccount', 'accountsManagement']''' + OBJECT_CLASS = ['accountsManagement'] + c.add(dn=user_dn,object_class=OBJECT_CLASS, attributes={'authCode': code}) + newSession().set(get_user_data(user_dn, c)) + #CHANGE PASSWORD def change_passwords(username, old_pass, new_pass): changed = [] @@ -825,7 +892,8 @@ def get_user_email_array(user_dn, conn, old_email, new_email): def get_user_data(user_dn, conn): search_filter = '(objectClass=*)' conn.search(user_dn, search_filter, - attributes=['active','fakeCn','givenName','sn','uid','mail','devices','ip','lastLogin','secureAuth']) + attributes=['active','fakeCn','givenName','sn','uid','mail','devices','ip','lastLogin','secureAuth', + 'authCode']) data = [] data.append(conn.entries[0].active.values[0]) data.append(conn.entries[0].fakeCn.values[0]) @@ -840,6 +908,8 @@ def get_user_data(user_dn, conn): #ts = datetime.strftime(t, '%Y-%m-%d %H:%M:%S') data.append(str(conn.entries[0].lastLogin.values[0])[:-6]) data.append(conn.entries[0].secureAuth.values[0]) + if(conn.entries[0].authCode): + data.append(conn.entries[0].authCode.values[0]) return(data) @@ -942,6 +1012,7 @@ def newSession(): self.ip = data[7] self.lastLogin = data[8] self.secureAuth = data[9] + self.authCode = None self.data['active'] = self.active self.data['fakeCn'] = self.fakeCn @@ -953,6 +1024,7 @@ def newSession(): self.data['ip'] = self.ip self.data['lastLogin'] = self.lastLogin self.data['secureAuth'] = self.secureAuth + self.data['authCode'] = self.authCode def close(self): self.data.pop('username') diff --git a/libs/helper.py b/libs/helper.py index c6fc47e..690edf3 100644 --- a/libs/helper.py +++ b/libs/helper.py @@ -2,6 +2,8 @@ import sqlite3 import re +from onetimepass import valid_totp +from secrets import choice class Tools(): @@ -43,4 +45,11 @@ class Tools(): regex = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!#%*?&]{8,18}$' return(bool(re.fullmatch(regex, e))) + def generate_secret(self): # Function to return a random string with length 16. + secret = '' + while len(secret) < 16: + secret += choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') + return secret + + tools = Tools() diff --git a/start.sh b/start.sh index 896f098..8cfc789 100755 --- a/start.sh +++ b/start.sh @@ -1,3 +1,8 @@ +############################## +## Erabilera: ## +## sudo chmod +x start.sh ## +## ./start.sh $UID ## +############################## #!/bin/bash if [ ! -f settings.ini ]; then cp settings.ini.example settings.ini @@ -6,6 +11,8 @@ fi if [[ $# -gt 0 ]]; then UID_=$1 echo $UID_ + export LDAP_ADMIN_PASSWORD=admin + export LDAP_READONLY_PASSWORD=readonly fi uwsgi --http :9090 --enable-threads --uid $UID_ --wsgi-file app.py