Here is the code I wrote that only enforced 2fa for users outside our local networks.
There is some commented out code there that additionally allowed me to specify users in a group so only that group was force to 2fa
def _two_factor_required(auth_user):
"""
check whether we need to enforce MFA on this login
We enforce MFA only on logins external to our network.
Returns
-------
bool - enforce MFA
- True means this login requires MFA
- False means we will not enforce MFA for this login
"""
import ipaddress
return False # temp use to disable mfa
if len(request.args) > 0 and request.args[0] == "login":
if auth_user.mfa_override and datetime.datetime.now() <= auth_user.mfa_override:
# no mfa required if the user override is set - we added a field in auth_user to allow us to override if a user was having trouble or lost their phone or something
return False
qlf_networks = [
"
9.9.9.9/22",
"
9.9.9.0/24",
"
9.9.9.101/24",
]
ip_list = []
for range in qlf_networks:
ip_list.extend(ipaddress.IPv4Network(unicode(range)))
if ipaddress.IPv4Address(unicode(request.client)) in ip_list:
# if the client address is in the local address list, then do NOT require MFA so set to False
return_value = False
# build the MFA Required group members
# if return_value:
# print(datetime.datetime.now())
# ag = db(db.auth_group.role == "MFA Required (web2py)").select().first()
# if not ag:
# ag = db.auth_group.insert("MFA Required (web2py)")
# for ou in db(
# (db.auth_user.active == True)
# | (
# (db.auth_user.mfa_override == None)
# & (db.auth_user.mfa_override <= datetime.datetime.now())
# )
# ).select():
# db.auth_membership.update_or_insert(user_id=
ou.id, group_id=ag)
#
# # clear out any members that are currently exempt from MFA
# if ag:
# for exempt_user in db(
# (db.auth_user.mfa_override >= datetime.datetime.now())
# & (db.auth_user.active == True)
# ).select():
# db(
# (db.auth_membership.group_id ==
ag.id)
# & (db.auth_membership.user_id ==
exempt_user.id)
# ).delete()
# db.commit()
#
# print(datetime.datetime.now())
#
# # set to False to force web2py to check the two_factor_authentication group
# return_value = False
Then....
I wrote this code, but then we ended up not implementing. The web2py code is going away for us. All the same concepts work in py4web (nudge wink wink)