Skip to content

Commit 9e70982

Browse files
authored
Use f-string on _scaffold and ldap_plugin (#985)
1 parent c5e3a24 commit 9e70982

3 files changed

Lines changed: 64 additions & 58 deletions

File tree

apps/_scaffold/common.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
"""
2-
This file defines cache, session, and translator T object for the app
3-
These are fixtures that every app needs so probably you will not be editing this file
2+
This module sets up core fixtures and utilities for a py4web application, including:
3+
4+
- Logging: Configures a custom logger using application settings.
5+
- Database: Connects to the database using settings from the configuration.
6+
- Caching: Instantiates a cache object for use throughout the app.
7+
- Translation: Sets up the translation object for internationalization.
8+
- Session Management: Selects and configures the session backend (cookies, Redis, Memcache, or database) based on settings.
9+
- Authentication: Initializes the Auth object, configures its parameters, and defines authentication tables and actions.
10+
- Email: Configures the email sender for authentication-related emails if SMTP settings are provided.
11+
- User Groups: Sets up tagging for user groups if the authentication database is available.
12+
- Auth Plugins: Optionally registers authentication plugins (PAM, LDAP, OAuth2 for Google, GitHub, Facebook, Okta) based on settings.
13+
- File Download: Defines an action for downloading uploaded files if an upload folder is specified.
14+
- Scheduler: Optionally starts a background scheduler for running tasks if enabled in settings.
15+
- Decorators: Provides convenience action factories for authenticated and unauthenticated routes.
16+
17+
This file is intended to be a foundational part of the application and typically does not require modification.
418
"""
519

620
import os
@@ -47,7 +61,7 @@
4761
session = Session(secret=settings.SESSION_SECRET_KEY)
4862

4963
elif settings.SESSION_TYPE == "redis":
50-
import redis
64+
import redis # type: ignore[reportMissingImports]
5165

5266
host, port = settings.REDIS_SERVER.split(":")
5367
# for more options: https://github.com/andymccurdy/redis-py/blob/master/redis/client.py
@@ -62,7 +76,7 @@
6276
elif settings.SESSION_TYPE == "memcache":
6377
import time
6478

65-
import memcache
79+
import memcache # type: ignore[reportMissingImports]
6680

6781
conn = memcache.Client(settings.MEMCACHE_CLIENTS, debug=0)
6882
session = Session(secret=settings.SESSION_SECRET_KEY, storage=conn)

apps/_scaffold/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,6 @@
119119

120120
# try import private settings
121121
try:
122-
from .settings_private import *
122+
from .settings_private import * # type: ignore[reportMissingImports]
123123
except (ImportError, ModuleNotFoundError):
124124
pass

py4web/utils/auth_plugins/ldap_plugin.py

Lines changed: 45 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,10 @@ class LDAPPlugin(UsernamePassword):
6969
base_dn='ou=Users,dc=domain,dc=com',
7070
tls=True))
7171
72-
If you need to bind to the directory with an admin account in order to
73-
search it then specify bind_dn & bind_pw to use for this.
74-
- currently only implemented for Active Directory
72+
If you need to bind to the directory with a bind account in order to
73+
search it, then specify bind_dn & bind_pw to use for this.
74+
- currently only implemented for Active Directory where anonymous bind
75+
is normally not allowed.
7576
7677
If you need to restrict the set of allowed users (e.g. to members of a
7778
department) then specify an rfc4515 search filter string.
@@ -88,7 +89,12 @@ class LDAPPlugin(UsernamePassword):
8889
))
8990
9091
Where:
91-
manage_user - let web2py handle user data from ldap
92+
manage_user: bool
93+
If True py4web will fetch and update user profile
94+
fields (first name, last name, email) from LDAP/AD on each login and
95+
keep them in sync with its db.
96+
If False, only authentication is performed and user profile fields
97+
are taken only from py4web db.
9298
user_firstname_attrib - the attribute containing the user's first name
9399
optionally you can specify parts.
94100
Example: cn: "John Smith" - 'cn:1'='John'
@@ -112,7 +118,7 @@ class LDAPPlugin(UsernamePassword):
112118
))
113119
114120
Where:
115-
manage_groups - let web2py handle the groups from ldap
121+
manage_groups - let py4web handle the groups from ldap
116122
db - is the database object (need to have auth_user, auth_group,
117123
auth_membership)
118124
group_dn - the ldap branch of the groups
@@ -140,10 +146,8 @@ class LDAPPlugin(UsernamePassword):
140146
group_filterstr - as the filterstr but for group select
141147
142148
If using Active Directory you must specify bind_dn and bind_pw for
143-
allowed_groups unless anonymous bind works.
149+
allowed_groups because anonymous bind is not normally allowed.
144150
145-
You can set the logging level with the "logging_level" parameter, default
146-
is "error" and can be set to error, warning, info, debug.
147151
"""
148152

149153
def __init__(
@@ -237,8 +241,8 @@ def check_credentials(self, username, password):
237241
logger.warning("blank password not allowed")
238242
return False
239243
logger.debug(
240-
"mode: [%s] manage_user: [%s] custom_scope: [%s] manage_groups: [%s]"
241-
% (str(mode), str(manage_user), str(custom_scope), str(manage_groups))
244+
f"mode: {str(mode)}, manage_user: {str(manage_user)}, \
245+
custom_scope: {str(custom_scope)}, manage_groups: {str(manage_groups)}" \
242246
)
243247
if manage_user:
244248
if user_firstname_attrib.count(":") > 0:
@@ -275,7 +279,7 @@ def check_credentials(self, username, password):
275279
for x in base_dn.split(","):
276280
if "DC=" in x.upper():
277281
domain.append(x.split("=")[-1])
278-
username = "%s@%s" % (username, ".".join(domain))
282+
username = f"{username}@{".".join(domain)}"
279283
username_bare = username.split("@")[0]
280284
con.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
281285
# In cases where ForestDnsZones and DomainDnsZones are found,
@@ -299,14 +303,14 @@ def check_credentials(self, username, password):
299303
result = con.search_ext_s(
300304
base_dn,
301305
ldap.SCOPE_SUBTREE,
302-
"(&(sAMAccountName=%s)(%s))"
303-
% (ldap.filter.escape_filter_chars(username_bare), filterstr),
306+
f"(&(sAMAccountName={ldap.filter.escape_filter_chars(username_bare)})({filterstr}))",
304307
requested_attrs,
305308
)[0][1]
309+
logger.info(f"Login result: {result}")
306310
if not isinstance(result, dict):
307311
# result should be a dict in the form
308312
# {'sAMAccountName': [username_bare]}
309-
logger.warning("User [%s] not found!" % username)
313+
logger.warning(f"User {username} not found!")
310314
return False
311315
if bind_dn:
312316
# We know the user exists & is in the correct OU
@@ -347,7 +351,7 @@ def check_credentials(self, username, password):
347351
con.simple_bind_s(bind_dn, bind_pw)
348352
dn = "uid=" + username + "," + base_dn
349353
dn = con.search_s(
350-
base_dn, ldap.SCOPE_SUBTREE, "(uid=%s)" % username, [""]
354+
base_dn, ldap.SCOPE_SUBTREE, f"(uid={username, [""]})"
351355
)[0][0]
352356
else:
353357
dn = "uid=" + username + "," + base_dn
@@ -367,10 +371,7 @@ def check_credentials(self, username, password):
367371
# bind anonymously
368372
con.simple_bind_s(dn, pw)
369373
# search by e-mail address
370-
filter = "(&(mail=%s)(%s))" % (
371-
ldap.filter.escape_filter_chars(username),
372-
filterstr,
373-
)
374+
filter = f"(&(mail={ldap.filter.escape_filter_chars(username)})({filterstr}))"
374375
# find the uid
375376
attrs = ["uid"]
376377
if manage_user:
@@ -392,10 +393,7 @@ def check_credentials(self, username, password):
392393
basedns = base_dn
393394
else:
394395
basedns = [base_dn]
395-
filter = "(&(uid=%s)(%s))" % (
396-
ldap.filter.escape_filter_chars(username),
397-
filterstr,
398-
)
396+
filter = f"(&(uid={ldap.filter.escape_filter_chars(username)})({filterstr}))"
399397
found = False
400398
for basedn in basedns:
401399
try:
@@ -409,11 +407,10 @@ def check_credentials(self, username, password):
409407
except ldap.LDAPError:
410408
(exc_type, exc_value) = sys.exc_info()[:2]
411409
logger.warning(
412-
"ldap_auth: searching %s for %s resulted in %s: %s\n"
413-
% (basedn, filter, exc_type, exc_value)
410+
f"ldap_auth: searching {basedn} for {filter} resulted in {exc_type}: {exc_value}\n"
414411
)
415412
if not found:
416-
logger.warning("User [%s] not found!" % username)
413+
logger.warning(f"User [{username}] not found!")
417414
return False
418415
result = result[0][1]
419416
if mode == "custom":
@@ -423,11 +420,7 @@ def check_credentials(self, username, password):
423420
basedns = base_dn
424421
else:
425422
basedns = [base_dn]
426-
filter = "(&(%s=%s)(%s))" % (
427-
username_attrib,
428-
ldap.filter.escape_filter_chars(username),
429-
filterstr,
430-
)
423+
filter = f"(&({username_attrib}={ldap.filter.escape_filter_chars(username)})({filterstr}))"
431424
if custom_scope == "subtree":
432425
scope = ldap.SCOPE_SUBTREE
433426
elif custom_scope == "base":
@@ -447,15 +440,14 @@ def check_credentials(self, username, password):
447440
except ldap.LDAPError:
448441
(exc_type, exc_value) = sys.exc_info()[:2]
449442
logger.warning(
450-
"ldap_auth: searching %s for %s resulted in %s: %s\n"
451-
% (basedn, filter, exc_type, exc_value)
443+
f"ldap_auth: searching {basedn} for {filter} resulted in {exc_type}: {exc_value}\n"
452444
)
453445
if not found:
454-
logger.warning("User [%s] not found!" % username)
446+
logger.warning(f"User {username} not found!")
455447
return False
456448
result = result[0][1]
457449
if manage_user:
458-
logger.info("[%s] Manage user data" % str(username))
450+
logger.info(f"[{str(username)}] Manage user data")
459451
try:
460452
store_sso_id = "ldap:" + username
461453
user_firstname = result[user_firstname_attrib][0]
@@ -526,14 +518,14 @@ def check_credentials(self, username, password):
526518
except ldap.LDAPError:
527519
import traceback
528520

529-
logger.warning("[%s] Error in ldap processing" % str(username))
521+
logger.warning(f"[{str(username)}] Error in Ldap processing")
530522
logger.debug(traceback.format_exc())
531523
print(traceback.format_exc())
532524
return False
533525
except IndexError: # for AD membership test
534526
import traceback
535527

536-
logger.warning("[%s] Ldap result indexing error" % str(username))
528+
logger.warning(f"[{str(username)}] Ldap result indexing error")
537529
logger.debug(traceback.format_exc())
538530
return False
539531

@@ -573,7 +565,7 @@ def do_manage_groups(self, con, username, group_mapping={}):
573565
logger = self.logger
574566
groups = self.groups
575567

576-
logger.info("[%s] Manage user groups" % str(username))
568+
logger.info(f"[{str(username)}] Manage user groups")
577569
try:
578570
#
579571
# Get all group name where the user is in actually in ldap
@@ -586,7 +578,7 @@ def do_manage_groups(self, con, username, group_mapping={}):
586578
if group in group_mapping:
587579
l.append(group_mapping[group])
588580
ldap_groups_of_the_user = l
589-
logger.info("User groups after remapping: %s" % str(l))
581+
logger.info(f"User groups after remapping: {str(l)}")
590582

591583
#
592584
# Get all group name where the user is in actually in local db
@@ -620,7 +612,7 @@ def do_manage_groups(self, con, username, group_mapping={}):
620612
email=username, first_name=username
621613
)
622614
if not db_user_id:
623-
logger.error("There is no username or email for %s!" % username)
615+
logger.error(f"There is no username or email for {username}!")
624616
raise
625617
db_groups_of_the_user = groups.get(db_user_id)
626618

@@ -645,7 +637,7 @@ def do_manage_groups(self, con, username, group_mapping={}):
645637
for callback in manage_groups_callback:
646638
callback()
647639
except:
648-
logger.warning("[%s] Groups are not managed successfully!" % str(username))
640+
logger.warning(f"[{str(username)}] Groups are not managed successfully!")
649641
import traceback
650642

651643
logger.debug(traceback.format_exc())
@@ -654,7 +646,7 @@ def do_manage_groups(self, con, username, group_mapping={}):
654646

655647
def _init_ldap(self):
656648
"""
657-
Inicialize ldap connection
649+
Inizialize ldap connection
658650
"""
659651

660652
server = self.server
@@ -668,11 +660,12 @@ def _init_ldap(self):
668660
tls = self.tls
669661
logger = self.logger
670662

671-
logger.info("[%s] Initialize ldap connection" % str(server))
663+
logger.debug(f"[{str(server)}] Initialize ldap connection")
672664
if secure:
673665
if not port:
674666
port = 636
675667

668+
logger.debug(f"Using Secure LDAP connection to {server}:{port}")
676669
if self_signed_certificate:
677670
# NOTE : If you have a self-signed SSL Certificate pointing over "port=686" and "secure=True" alone
678671
# will not work, you need also to set "self_signed_certificate=True".
@@ -695,7 +688,8 @@ def _init_ldap(self):
695688
else:
696689
if not port:
697690
port = 389
698-
con = ldap.initialize("ldap://" + server + ":" + str(port))
691+
logger.debug(f"Initializing LDAP connection to ldap://{server}:{str(port)}")
692+
con = ldap.initialize(f"ldap://{server}:{str(port)}")
699693
if tls:
700694
con.start_tls_s()
701695
return con
@@ -719,7 +713,7 @@ def get_user_groups_from_ldap(self, username=None, password=None):
719713
if username is None:
720714
return []
721715

722-
logger.info("[%s] Get user groups from ldap" % str(username))
716+
logger.info(f"[{str(username)}] Get user groups from ldap")
723717
#
724718
# Get all group name where the user is in actually in ldap
725719
# #########################################################
@@ -732,7 +726,7 @@ def get_user_groups_from_ldap(self, username=None, password=None):
732726
for x in base_dn.split(","):
733727
if "DC=" in x.upper():
734728
domain.append(x.split("=")[-1])
735-
username = "%s@%s" % (username, ".".join(domain))
729+
username = f"{username}@{".".join(domain)}"
736730
username_bare = username.split("@")[0]
737731
con = self._init_ldap()
738732
con.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
@@ -754,19 +748,17 @@ def get_user_groups_from_ldap(self, username=None, password=None):
754748
username = con.search_ext_s(
755749
base_dn,
756750
ldap.SCOPE_SUBTREE,
757-
"(&(sAMAccountName=%s)(%s))" % (bare, filterstr),
751+
f"(&(sAMAccountName={bare})({filterstr}))",
758752
["cn"],
759753
)[0][0]
760754

761755
# if username is None, return empty list
762756
if username is None:
763757
return []
764758
# search for groups where user is in
765-
filter = "(&(%s=%s)(%s))" % (
766-
ldap.filter.escape_filter_chars(group_member_attrib),
767-
ldap.filter.escape_filter_chars(username),
768-
group_filterstr,
769-
)
759+
filter = f"(&({ldap.filter.escape_filter_chars(group_member_attrib)}=\
760+
{ldap.filter.escape_filter_chars(username)})({group_filterstr}))"
761+
770762
group_search_result = con.search_s(
771763
group_dn, ldap.SCOPE_SUBTREE, filter, [group_name_attrib]
772764
)
@@ -778,5 +770,5 @@ def get_user_groups_from_ldap(self, username=None, password=None):
778770
str(group[group_name_attrib][0], encoding="utf-8")
779771
)
780772

781-
logger.debug("User groups: %s" % ldap_groups_of_the_user)
773+
logger.debug(f"User groups for {username}: {ldap_groups_of_the_user}")
782774
return list(ldap_groups_of_the_user)

0 commit comments

Comments
 (0)