mirror of
https://github.com/Kozea/Radicale.git
synced 2025-09-15 20:36:55 +00:00
Merge pull request #1861 from marschap/ldap-group-search
LDAP auth: group memberships based on separate search
This commit is contained in:
commit
126b1a13d2
4 changed files with 296 additions and 118 deletions
143
DOCUMENTATION.md
143
DOCUMENTATION.md
|
@ -987,7 +987,8 @@ Default: `Radicale - Password Required`
|
|||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
The URI to the ldap server
|
||||
URI to the LDAP server.
|
||||
Mandatory for auth type `ldap`.
|
||||
|
||||
Default: `ldap://localhost`
|
||||
|
||||
|
@ -995,39 +996,44 @@ Default: `ldap://localhost`
|
|||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
LDAP base DN of the ldap server. This parameter must be provided if auth type is ldap.
|
||||
Base DN of the LDAP server.
|
||||
Mandatory for auth type `ldap`.
|
||||
|
||||
Default:
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_reader_dn
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
The DN of a ldap user with read access to get the user accounts. This parameter must be provided if auth type is ldap.
|
||||
DN of a LDAP user with read access users and - if defined - groups.
|
||||
Mandatory for auth type `ldap`.
|
||||
|
||||
Default:
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_secret
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
The password of the ldap_reader_dn. Either this parameter or `ldap_secret_file` must be provided if auth type is ldap.
|
||||
Password of `ldap_reader_dn`.
|
||||
Mandatory for auth type `ldap` unless `ldap_secret_file` is given.
|
||||
|
||||
Default:
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_secret_file
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
Path of the file containing the password of the ldap_reader_dn. Either this parameter or `ldap_secret` must be provided if auth type is ldap.
|
||||
Path to the file containing the password of `ldap_reader_dn`.
|
||||
Mandatory for auth type `ldap` unless `ldap_secret` is given.
|
||||
|
||||
Default:
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_filter
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
The search filter to find the user DN to authenticate by the username. User '{0}' as placeholder for the user name.
|
||||
Filter to search for the LDAP entry of the user to authenticate.
|
||||
It must contain '{0}' as placeholder for the login name.
|
||||
|
||||
Default: `(cn={0})`
|
||||
|
||||
|
@ -1035,66 +1041,117 @@ Default: `(cn={0})`
|
|||
|
||||
_(>= 3.4.0)_
|
||||
|
||||
The LDAP attribute whose value shall be used as the user name after successful authentication
|
||||
LDAP attribute whose value shall be used as the username after successful authentication.
|
||||
|
||||
Default: not set, i.e. the login name given is used directly.
|
||||
If set, you can use flexible logins in `ldap_filter` and still have consolidated usernames,
|
||||
e.g. to allow login in using mail addresses as an alternative to cn, simply set
|
||||
```
|
||||
ldap_filter = (&(objectclass=inetOrgPerson)(|(cn={0})(mail={0})))
|
||||
ldap_user_attribute = cn
|
||||
```
|
||||
Even for simple filter setups, it is recommended to set it in order to get usernames exactly
|
||||
as they are stored in LDAP and to avoid inconsistencies in the upper-/lower-case spelling of the
|
||||
login names.
|
||||
|
||||
##### ldap_groups_attribute
|
||||
|
||||
_(>= 3.4.0)_
|
||||
|
||||
The LDAP attribute to read the group memberships from in the authenticated user's LDAP entry.
|
||||
|
||||
If set, load the LDAP group memberships from the attribute given
|
||||
These memberships can be used later on to define rights.
|
||||
This also gives you access to the group calendars, if they exist.
|
||||
* The group calendar will be placed under collection_root_folder/GROUPS
|
||||
* The name of the calendar directory is the base64 encoded group name.
|
||||
* The group calendar folders will not be created automatically. This must be done manually. In the [LDAP-authentication section of Radicale's wiki](https://github.com/Kozea/Radicale/wiki/LDAP-authentication) you can find a script to create a group calendar.
|
||||
|
||||
Use 'memberOf' if you want to load groups on Active Directory and alikes, 'groupMembership' on Novell eDirectory, ...
|
||||
|
||||
Default: (unset)
|
||||
Default: (unset, in which case the login name is directly used as the username)
|
||||
|
||||
##### ldap_use_ssl
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
Use ssl on the ldap connection (soon to be deprecated, use ldap_security instead)
|
||||
Use ssl on the LDAP connection. **Deprecated**, use `ldap_security` instead**!**
|
||||
|
||||
##### ldap_security
|
||||
|
||||
_(>= 3.5.2)_
|
||||
|
||||
Use encryption on the ldap connection. none, tls, starttls
|
||||
Use encryption on the LDAP connection. One of `none`, `tls`, `starttls`.
|
||||
|
||||
Default: none
|
||||
Default: `none`
|
||||
|
||||
##### ldap_ssl_verify_mode
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
The certificate verification mode. Works for tls and starttls. NONE, OPTIONAL or REQUIRED
|
||||
Certificate verification mode for tls and starttls. One of `NONE`, `OPTIONAL`, `REQUIRED`.
|
||||
|
||||
Default: REQUIRED
|
||||
Default: `REQUIRED`
|
||||
|
||||
##### ldap_ssl_ca_file
|
||||
|
||||
_(>= 3.3.0)_
|
||||
|
||||
The path to the CA file in pem format which is used to certificate the server certificate
|
||||
Path to the CA file in PEM format which is used to certify the server certificate
|
||||
|
||||
Default:
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_groups_attribute
|
||||
|
||||
_(>= 3.4.0)_
|
||||
|
||||
LDAP attribute in the authenticated user's LDAP entry to read the group memberships from.
|
||||
|
||||
E.g. `memberOf` to get groups on Active Directory and alikes, `groupMembership` on Novell eDirectory, ...
|
||||
|
||||
If set, get the user's LDAP groups from the attribute given.
|
||||
|
||||
For DN-valued attributes, the value of the RDN is used to determine the group names.
|
||||
The implementation also supports non-DN-valued attributes: their values are taken directly.
|
||||
|
||||
The user's group names can be used later on to define rights.
|
||||
They also give you access to the group calendars, if those exist.
|
||||
* Group calendars are placed directly under *collection_root_folder*`/GROUPS/`
|
||||
with the base64-encoded group name as the calendar folder name.
|
||||
* Group calendar folders are not created automatically.
|
||||
This must be done manually. In the [LDAP-authentication section of Radicale's wiki](https://github.com/Kozea/Radicale/wiki/LDAP-authentication) you can find a script to create a group calendar.
|
||||
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_group_members_attribute
|
||||
|
||||
_(>= 3.5.6)_
|
||||
|
||||
Attribute in the group entries to read the group's members from.
|
||||
|
||||
E.g. `member` for groups with objectclass `groupOfNames`.
|
||||
|
||||
Using `ldap_group_members_attribute`, `ldap_group_base` and `ldap_group_filter` is an alternative
|
||||
approach to getting the user's groups. Instead of reading them from `ldap_groups_attribute`
|
||||
in the user's entry, an additional query is performed to seach for those groups beneath `ldap_group_base`,
|
||||
that have the user's DN in their `ldap_group_members_attribute` and additionally fulfil `ldap_group_filter`.
|
||||
|
||||
As with DN-valued `ldap_groups_attribute`, the value of the RDN is used to determine the group names.
|
||||
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_group_base
|
||||
|
||||
_(>= 3.5.6)_
|
||||
|
||||
Base DN to search for groups.
|
||||
Only necessary if `ldap_group_members_attribute` is set, and if the base DN for groups differs from `ldap_base`.
|
||||
|
||||
Default: (unset, in which case `ldap_base` is used as fallback)
|
||||
|
||||
##### ldap_group_filter
|
||||
|
||||
_(>= 3.5.6)_
|
||||
|
||||
Search filter to search for groups having the user DN found as member.
|
||||
Only necessary `ldap_group_members_attribute` is set, and you want the groups returned to be restricted
|
||||
instead of all groups the user's DN is in.
|
||||
|
||||
Default: (unset)
|
||||
|
||||
##### ldap_ignore_attribute_create_modify_timestamp
|
||||
|
||||
_(>= 3.5.1)_
|
||||
|
||||
Add modifyTimestamp and createTimestamp to the exclusion list of internal ldap3 client
|
||||
so that these schema attributes are not checked. This is needed at least for Authentik
|
||||
LDAP server as not providing these both attributes.
|
||||
Quirks for Authentik LDAP server, which violates the LDAP RFCs:
|
||||
add modifyTimestamp and createTimestamp to the exclusion list of internal ldap3 client
|
||||
so that these schema attributes are not checked.
|
||||
|
||||
Default: false
|
||||
Default: `false`
|
||||
|
||||
##### dovecot_connection_type = AF_UNIX
|
||||
|
||||
|
@ -1177,7 +1234,9 @@ providers like ldap, kerberos
|
|||
|
||||
Default: `False`
|
||||
|
||||
Note: cannot be enabled together with `uc_username`
|
||||
Notes:
|
||||
* `lc_username` and `uc_username` are mutually exclusive
|
||||
* for auth type `ldap` the use of `ldap_user_attribute` is preferred
|
||||
|
||||
##### uc_username
|
||||
|
||||
|
@ -1188,7 +1247,9 @@ providers like ldap, kerberos
|
|||
|
||||
Default: `False`
|
||||
|
||||
Note: cannot be enabled together with `lc_username`
|
||||
Notes:
|
||||
* `uc_username` and `lc_username` are mutually exclusive
|
||||
* for auth type `ldap` the use of `ldap_user_attribute` is preferred
|
||||
|
||||
##### strip_domain
|
||||
|
||||
|
|
42
config
42
config
|
@ -75,46 +75,54 @@
|
|||
## Expiration time of caching failed logins in seconds
|
||||
#cache_failed_logins_expiry = 90
|
||||
|
||||
# Ignore modifyTimestamp and createTimestamp attributes. Required e.g. for Authentik LDAP server
|
||||
#ldap_ignore_attribute_create_modify_timestamp = false
|
||||
|
||||
# URI to the LDAP server
|
||||
#ldap_uri = ldap://localhost
|
||||
|
||||
# The base DN where the user accounts have to be searched
|
||||
# Base DN of the LDAP server to search for user accounts
|
||||
#ldap_base = ##BASE_DN##
|
||||
|
||||
# The reader DN of the LDAP server
|
||||
# Reader DN of the LDAP server; (needs read access to users and - if defined - groups)
|
||||
#ldap_reader_dn = CN=ldapreader,CN=Users,##BASE_DN##
|
||||
|
||||
# Password of the reader DN
|
||||
# Password of the reader DN (better: use 'ldap_secret_file'!)
|
||||
#ldap_secret = ldapreader-secret
|
||||
|
||||
# Path of the file containing password of the reader DN
|
||||
# Path to the file containing the password of the reader DN
|
||||
#ldap_secret_file = /run/secrets/ldap_password
|
||||
|
||||
# the attribute to read the group memberships from in the user's LDAP entry (default: not set)
|
||||
#ldap_groups_attribute = memberOf
|
||||
|
||||
# The filter to find the DN of the user. This filter must contain a python-style placeholder for the login
|
||||
# Filter to search for the LDAP entry of the user to authenticate. It must contain '{0}' as placeholder for the login name.
|
||||
#ldap_filter = (&(objectClass=person)(uid={0}))
|
||||
|
||||
# the attribute holding the value to be used as username after authentication
|
||||
# Attribute holding the value to be used as username after authentication
|
||||
#ldap_user_attribute = cn
|
||||
|
||||
# Use ssl on the ldap connection
|
||||
# Soon to be deprecated, use ldap_security instead
|
||||
# Use ssl on the LDAP connection (DEPRECATED - use 'ldap_security'!)
|
||||
#ldap_use_ssl = False
|
||||
|
||||
# the encryption mode to be used: tls, starttls, default is none
|
||||
# Encryption mode to be used. Default: none; one of: none, tls, starttls
|
||||
#ldap_security = none
|
||||
|
||||
# The certificate verification mode. Works for ssl and starttls. NONE, OPTIONAL, default is REQUIRED
|
||||
# Certificate verification mode for tls & starttls. Default: REQUIRED; one of NONE, OPTIONAL, REQUIRED
|
||||
#ldap_ssl_verify_mode = REQUIRED
|
||||
|
||||
# The path to the CA file in pem format which is used to certificate the server certificate
|
||||
# Path to the CA file in PEM format to certify the server certificate
|
||||
#ldap_ssl_ca_file =
|
||||
|
||||
# Attribute in the user's LDAP entry to read the group memberships from; default: not set
|
||||
#ldap_groups_attribute = memberOf
|
||||
|
||||
# Attribute in the group entries to read the group's members from, e.g. member; default: not set
|
||||
#ldap_group_members_attribute = member
|
||||
|
||||
# Base DN to search for groups; only if it differs from 'ldap_base' and if 'ldap_group_members_attribute' is set
|
||||
#ldap_group_base = ##GROUP_BASE_DN##
|
||||
|
||||
# Search filter to search for groups having the user DN found as member; only if 'ldap_group_members_attribute' is set
|
||||
#ldap_group_filter = (objectclass=groupOfNames)
|
||||
|
||||
# Quirks for Authentik LDAP server: ignore modifyTimestamp and createTimestamp attributes
|
||||
#ldap_ignore_attribute_create_modify_timestamp = false
|
||||
|
||||
# Connection type for dovecot authentication (AF_UNIX|AF_INET|AF_INET6)
|
||||
# Note: credentials are transmitted in cleartext
|
||||
#dovecot_connection_type = AF_UNIX
|
||||
|
|
|
@ -16,20 +16,36 @@
|
|||
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
Authentication backend that checks credentials with a LDAP server.
|
||||
Following parameters are needed in the configuration:
|
||||
ldap_uri The LDAP URL to the server like ldap://localhost
|
||||
ldap_base The baseDN of the LDAP server
|
||||
ldap_reader_dn The DN of a LDAP user with read access to get the user accounts
|
||||
ldap_secret The password of the ldap_reader_dn
|
||||
ldap_secret_file The path of the file containing the password of the ldap_reader_dn
|
||||
ldap_filter The search filter to find the user to authenticate by the username
|
||||
ldap_user_attribute The attribute to be used as username after authentication
|
||||
ldap_groups_attribute The attribute containing group memberships in the LDAP user entry
|
||||
Following parameters controls SSL connections:
|
||||
ldap_use_ssl If ssl encryption should be used (to be deprecated)
|
||||
ldap_security The encryption mode to be used: *none*|tls|starttls
|
||||
ldap_ssl_verify_mode The certificate verification mode. Works for tls and starttls. NONE, OPTIONAL, default is REQUIRED
|
||||
ldap_ssl_ca_file
|
||||
The following parameters are needed in the configuration:
|
||||
ldap_uri URI to the LDAP server
|
||||
ldap_base Base DN of the LDAP server
|
||||
ldap_reader_dn DN of an LDAP user with read access to get the user accounts
|
||||
ldap_secret Password of the 'ldap_reader_dn'
|
||||
Better: use 'ldap_secret_file'!
|
||||
ldap_secret_file Path of the file containing the password of the 'ldap_reader_dn'
|
||||
ldap_filter Search filter to find the user DN to authenticate
|
||||
The following parameters control TLS connections:
|
||||
ldap_use_ssl Use ssl on the ldap connection.
|
||||
Deprecated, use 'ldap_security' instead!
|
||||
ldap_security Encryption mode to be used,
|
||||
one of: *none* | tls | starttls
|
||||
ldap_ssl_verify_mode Certificate verification mode for tls and starttls;
|
||||
one of: *REQUIRED* | OPTIONAL | NONE
|
||||
ldap_ssl_ca_file Path to the CA file in PEM format to certify the server certificate
|
||||
The following parameters are optional:
|
||||
ldap_user_attribute Attribute to be used as username after authentication, e.g. cn;
|
||||
if not given, the name used to logon is used.
|
||||
ldap_groups_attribute Attribute in the user entry to read the user's group memberships from,
|
||||
e.g. memberof, groupMememberShip. This may even be a non-DN attribute!
|
||||
ldap_group_base Base DN to search for groups;
|
||||
only if it differs from 'ldap_base' and if 'ldap_group_members_attribute' is set
|
||||
ldap_group_filter Search filter to search for groups having the user DN found as member;
|
||||
only if 'ldap_group_members_attribute' is set
|
||||
ldap_group_members_attribute Attribute in the group entries to read the group's members from,
|
||||
e.g. member.
|
||||
The following parameters are for LDAP servers with oddities
|
||||
ldap_ignore_attribute_create_modify_timestamp
|
||||
Ignore modifyTimestamp and createTimestamp attributes. Needed for Authentik LDAP server
|
||||
|
||||
"""
|
||||
import ssl
|
||||
|
@ -47,7 +63,11 @@ class Auth(auth.BaseAuth):
|
|||
_ldap_attributes: list[str] = []
|
||||
_ldap_user_attr: str
|
||||
_ldap_groups_attr: str
|
||||
_ldap_group_base: str
|
||||
_ldap_group_filter: str
|
||||
_ldap_group_members_attr: str
|
||||
_ldap_module_version: int = 3
|
||||
_use_encryption: bool = False
|
||||
_ldap_use_ssl: bool = False
|
||||
_ldap_security: str = "none"
|
||||
_ldap_ssl_verify_mode: int = ssl.CERT_REQUIRED
|
||||
|
@ -61,6 +81,7 @@ class Auth(auth.BaseAuth):
|
|||
except ImportError:
|
||||
try:
|
||||
import ldap
|
||||
import ldap.filter
|
||||
self._ldap_module_version = 2
|
||||
self.ldap = ldap
|
||||
except ImportError as e:
|
||||
|
@ -78,6 +99,9 @@ class Auth(auth.BaseAuth):
|
|||
self._ldap_filter = configuration.get("auth", "ldap_filter")
|
||||
self._ldap_user_attr = configuration.get("auth", "ldap_user_attribute")
|
||||
self._ldap_groups_attr = configuration.get("auth", "ldap_groups_attribute")
|
||||
self._ldap_group_base = configuration.get("auth", "ldap_group_base")
|
||||
self._ldap_group_filter = configuration.get("auth", "ldap_group_filter")
|
||||
self._ldap_group_members_attr = configuration.get("auth", "ldap_group_members_attribute")
|
||||
ldap_secret_file_path = configuration.get("auth", "ldap_secret_file")
|
||||
if ldap_secret_file_path:
|
||||
with open(ldap_secret_file_path, 'r') as file:
|
||||
|
@ -110,6 +134,19 @@ class Auth(auth.BaseAuth):
|
|||
logger.info("auth.ldap_groups_attribute: %r" % self._ldap_groups_attr)
|
||||
else:
|
||||
logger.info("auth.ldap_groups_attribute: (not provided)")
|
||||
if self._ldap_group_base:
|
||||
logger.info("auth.ldap_group_base : %r" % self._ldap_group_base)
|
||||
else:
|
||||
logger.info("auth.ldap_group_base : (not provided, using ldap_base)")
|
||||
self._ldap_group_base = self._ldap_base
|
||||
if self._ldap_group_filter:
|
||||
logger.info("auth.ldap_group_filter: %r" % self._ldap_group_filter)
|
||||
else:
|
||||
logger.info("auth.ldap_group_filter: (not provided)")
|
||||
if self._ldap_group_members_attr:
|
||||
logger.info("auth.ldap_group_members_attr: %r" % self._ldap_group_members_attr)
|
||||
else:
|
||||
logger.info("auth.ldap_group_members_attr: (not provided)")
|
||||
if ldap_secret_file_path:
|
||||
logger.info("auth.ldap_secret_file_path: %r" % ldap_secret_file_path)
|
||||
if self._ldap_secret:
|
||||
|
@ -160,6 +197,30 @@ class Auth(auth.BaseAuth):
|
|||
user_entry = res[0]
|
||||
user_dn = user_entry[0]
|
||||
logger.debug(f"_login2 found LDAP user DN {user_dn}")
|
||||
|
||||
"""Let's collect the groups of the user."""
|
||||
groupDNs = []
|
||||
if self._ldap_groups_attr:
|
||||
groupDNs = user_entry[1][self._ldap_groups_attr]
|
||||
|
||||
"""Search for all groups having the user_dn found as member."""
|
||||
if self._ldap_group_members_attr:
|
||||
groupDNs = []
|
||||
res = conn.search_s(
|
||||
self._ldap_group_base,
|
||||
self.ldap.SCOPE_SUBTREE,
|
||||
filterstr="(&{0}({1}={2}))".format(
|
||||
self._ldap_group_filter,
|
||||
self._ldap_group_members_attr,
|
||||
self.ldap.filter.escape_filter_chars(user_dn)),
|
||||
attrlist=['1.1']
|
||||
)
|
||||
"""Fill groupDNs with DNs of groups found"""
|
||||
if len(res) > 0:
|
||||
groupDNs = []
|
||||
for dn, entry in res:
|
||||
groupDNs.append(dn)
|
||||
|
||||
"""Close LDAP connection"""
|
||||
conn.unbind()
|
||||
except Exception as e:
|
||||
|
@ -171,23 +232,26 @@ class Auth(auth.BaseAuth):
|
|||
conn.protocol_version = 3
|
||||
conn.set_option(self.ldap.OPT_REFERRALS, 0)
|
||||
conn.simple_bind_s(user_dn, password)
|
||||
tmp: list[str] = []
|
||||
if self._ldap_groups_attr:
|
||||
tmp = []
|
||||
for g in user_entry[1][self._ldap_groups_attr]:
|
||||
"""Get group g's RDN's attribute value"""
|
||||
try:
|
||||
rdns = self.ldap.dn.explode_dn(g, notypes=True)
|
||||
tmp.append(rdns[0])
|
||||
except Exception:
|
||||
tmp.append(g.decode('utf8'))
|
||||
self._ldap_groups = set(tmp)
|
||||
logger.debug("_login2 LDAP groups of user: %s", ",".join(self._ldap_groups))
|
||||
if self._ldap_user_attr:
|
||||
if user_entry[1][self._ldap_user_attr]:
|
||||
tmplogin = user_entry[1][self._ldap_user_attr][0]
|
||||
login = tmplogin.decode('utf-8')
|
||||
login = user_entry[1][self._ldap_user_attr][0]
|
||||
if isinstance(login, bytes):
|
||||
login = login.decode('utf-8')
|
||||
logger.debug(f"_login2 user set to: '{login}'")
|
||||
|
||||
"""Get RDNs of groups' DNs"""
|
||||
tmp = []
|
||||
for g in groupDNs:
|
||||
try:
|
||||
rdns = self.ldap.dn.explode_dn(g, notypes=True)
|
||||
tmp.append(rdns[0])
|
||||
except Exception:
|
||||
if isinstance(g, bytes):
|
||||
g = g.decode('utf-8')
|
||||
tmp.append(g)
|
||||
self._ldap_groups = set(tmp)
|
||||
logger.debug("_login2 LDAP groups of user: %s", ",".join(self._ldap_groups))
|
||||
|
||||
conn.unbind()
|
||||
logger.debug(f"_login2 {login} successfully authenticated")
|
||||
return login
|
||||
|
@ -249,9 +313,42 @@ class Auth(auth.BaseAuth):
|
|||
return ""
|
||||
|
||||
user_entry = conn.response[0]
|
||||
conn.unbind()
|
||||
user_dn = user_entry['dn']
|
||||
logger.debug(f"_login3 found LDAP user DN {user_dn}")
|
||||
|
||||
"""Let's collect the groups of the user."""
|
||||
groupDNs = []
|
||||
if self._ldap_groups_attr:
|
||||
if user_entry['attributes'][self._ldap_groups_attr]:
|
||||
if isinstance(user_entry['attributes'][self._ldap_groups_attr], list):
|
||||
groupDNs = user_entry['attributes'][self._ldap_groups_attr]
|
||||
else:
|
||||
groupDNs.append(user_entry['attributes'][self._ldap_groups_attr])
|
||||
|
||||
"""Search for all groups having the user_dn found as member."""
|
||||
if self._ldap_group_members_attr:
|
||||
try:
|
||||
conn.search(
|
||||
search_base=self._ldap_group_base,
|
||||
search_filter="(&{0}({1}={2}))".format(
|
||||
self._ldap_group_filter,
|
||||
self._ldap_group_members_attr,
|
||||
self.ldap3.utils.conv.escape_filter_chars(user_dn)),
|
||||
search_scope=self.ldap3.SUBTREE,
|
||||
attributes=['1.1']
|
||||
)
|
||||
except Exception as e:
|
||||
"""LDAP search failed: consider it as non-fatal - only groups missing"""
|
||||
logger.debug(f"_ldap3: LDAP group search failed: {e}")
|
||||
else:
|
||||
"""Fill groupDNs with DNs of groups found"""
|
||||
groupDNs = []
|
||||
for group in conn.response:
|
||||
groupDNs.append(group['dn'])
|
||||
|
||||
"""Close LDAP connection"""
|
||||
conn.unbind()
|
||||
|
||||
try:
|
||||
"""Try to bind as the user itself"""
|
||||
try:
|
||||
|
@ -264,18 +361,18 @@ class Auth(auth.BaseAuth):
|
|||
if not conn.bind(read_server_info=False):
|
||||
logger.debug(f"_login3 user '{login}' cannot be found")
|
||||
return ""
|
||||
tmp: list[str] = []
|
||||
if self._ldap_groups_attr:
|
||||
tmp = []
|
||||
for g in user_entry['attributes'][self._ldap_groups_attr]:
|
||||
"""Get group g's RDN's attribute value"""
|
||||
try:
|
||||
rdns = self.ldap3.utils.dn.parse_dn(g)
|
||||
tmp.append(rdns[0][1])
|
||||
except Exception:
|
||||
tmp.append(g)
|
||||
self._ldap_groups = set(tmp)
|
||||
logger.debug("_login3 LDAP groups of user: %s", ",".join(self._ldap_groups))
|
||||
|
||||
"""Get RDNs of groups' DNs"""
|
||||
tmp = []
|
||||
for g in groupDNs:
|
||||
try:
|
||||
rdns = self.ldap3.utils.dn.parse_dn(g)
|
||||
tmp.append(rdns[0][1])
|
||||
except Exception:
|
||||
tmp.append(g)
|
||||
self._ldap_groups = set(tmp)
|
||||
logger.debug("_login3 LDAP groups of user: %s", ",".join(self._ldap_groups))
|
||||
|
||||
if self._ldap_user_attr:
|
||||
if user_entry['attributes'][self._ldap_user_attr]:
|
||||
if isinstance(user_entry['attributes'][self._ldap_user_attr], list):
|
||||
|
|
|
@ -261,58 +261,70 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([
|
|||
"value": "1",
|
||||
"help": "incorrect authentication delay",
|
||||
"type": positive_float}),
|
||||
("ldap_ignore_attribute_create_modify_timestamp", {
|
||||
"value": "false",
|
||||
"help": "Ignore modifyTimestamp and createTimestamp attributes. Need if Authentik LDAP server is used.",
|
||||
"type": bool}),
|
||||
("ldap_uri", {
|
||||
"value": "ldap://localhost",
|
||||
"help": "URI to the ldap server",
|
||||
"help": "URI to the LDAP server",
|
||||
"type": str}),
|
||||
("ldap_base", {
|
||||
"value": "",
|
||||
"help": "LDAP base DN of the ldap server",
|
||||
"help": "Base DN of the LDAP server",
|
||||
"type": str}),
|
||||
("ldap_reader_dn", {
|
||||
"value": "",
|
||||
"help": "the DN of a ldap user with read access to get the user accounts",
|
||||
"help": "DN of an LDAP user with read access to users anmd - if defined - groups",
|
||||
"type": str}),
|
||||
("ldap_secret", {
|
||||
"value": "",
|
||||
"help": "the password of the ldap_reader_dn",
|
||||
"help": "Password of ldap_reader_dn (better: use ldap_secret_file)",
|
||||
"type": str}),
|
||||
("ldap_secret_file", {
|
||||
"value": "",
|
||||
"help": "path of the file containing the password of the ldap_reader_dn",
|
||||
"help": "Path to the file containing the password of ldap_reader_dn",
|
||||
"type": str}),
|
||||
("ldap_filter", {
|
||||
"value": "(cn={0})",
|
||||
"help": "the search filter to find the user DN to authenticate by the username",
|
||||
"help": "Filter to search for the LDAP entry of the user to authenticate",
|
||||
"type": str}),
|
||||
("ldap_user_attribute", {
|
||||
"value": "",
|
||||
"help": "the attribute to be used as username after authentication",
|
||||
"type": str}),
|
||||
("ldap_groups_attribute", {
|
||||
"value": "",
|
||||
"help": "attribute to read the group memberships from",
|
||||
"help": "Attribute to be used as username after authentication",
|
||||
"type": str}),
|
||||
("ldap_use_ssl", {
|
||||
"value": "False",
|
||||
"help": "Use ssl on the ldap connection. Soon to be deprecated, use ldap_security instead",
|
||||
"help": "Use ssl on the LDAP connection. Deprecated, use ldap_security instead!",
|
||||
"type": bool}),
|
||||
("ldap_security", {
|
||||
"value": "none",
|
||||
"help": "the encryption mode to be used: *none*|tls|starttls",
|
||||
"help": "Encryption mode to be used: *none*|tls|starttls",
|
||||
"type": str}),
|
||||
("ldap_ssl_verify_mode", {
|
||||
"value": "REQUIRED",
|
||||
"help": "The certificate verification mode. Works for tls and starttls. NONE, OPTIONAL, default is REQUIRED",
|
||||
"help": "Certificate verification mode for tls and starttls. NONE, OPTIONAL, default is REQUIRED",
|
||||
"type": str}),
|
||||
("ldap_ssl_ca_file", {
|
||||
"value": "",
|
||||
"help": "The path to the CA file in pem format which is used to certificate the server certificate",
|
||||
"help": "Path to the CA file in PEM format which is used to certify the server certificate",
|
||||
"type": str}),
|
||||
("ldap_groups_attribute", {
|
||||
"value": "",
|
||||
"help": "Attribute in the user's LDAP entry to read the group memberships from",
|
||||
"type": str}),
|
||||
("ldap_group_members_attribute", {
|
||||
"value": "",
|
||||
"help": "Attribute in the group entries to read the group's members from",
|
||||
"type": str}),
|
||||
("ldap_group_base", {
|
||||
"value": "",
|
||||
"help": "Base DN to search for groups. Only if it differs from ldap_base and if ldap_group_members_attribute is set",
|
||||
"type": str}),
|
||||
("ldap_group_filter", {
|
||||
"value": "",
|
||||
"help": "Search filter to search for groups having the user as member. Only if ldap_group_members_attribute is set",
|
||||
"type": str}),
|
||||
("ldap_ignore_attribute_create_modify_timestamp", {
|
||||
"value": "false",
|
||||
"help": "Quirk for Authentik LDAP server: ignore modifyTimestamp and createTimestamp attributes.",
|
||||
"type": bool}),
|
||||
("imap_host", {
|
||||
"value": "localhost",
|
||||
"help": "IMAP server hostname: address|address:port|[address]:port|*localhost*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue