forked from Github-Mirrors/canaille
ACL filters are no more LDAP filters but user attribute mappings.
This commit is contained in:
parent
3884a1d37c
commit
edb64cbfe1
7 changed files with 84 additions and 31 deletions
|
@ -13,6 +13,7 @@ Changed
|
||||||
- Moved OIDC related configuration entries in ``OIDC``
|
- Moved OIDC related configuration entries in ``OIDC``
|
||||||
- Moved ``LDAP`` configuration entry to ``BACKENDS.LDAP``
|
- Moved ``LDAP`` configuration entry to ``BACKENDS.LDAP``
|
||||||
- Bumped to htmx 1.9.0 :pr:`124`
|
- Bumped to htmx 1.9.0 :pr:`124`
|
||||||
|
- ACL filters are no more LDAP filters but user attribute mappings. :pr:`125`
|
||||||
|
|
||||||
Fixed
|
Fixed
|
||||||
*****
|
*****
|
||||||
|
|
|
@ -91,18 +91,25 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
||||||
# A 'user' variable is available.
|
# A 'user' variable is available.
|
||||||
# GROUP_USER_FILTER = "member={user.dn}"
|
# GROUP_USER_FILTER = "member={user.dn}"
|
||||||
|
|
||||||
|
[ACL]
|
||||||
# You can define access controls that define what users can do on canaille
|
# You can define access controls that define what users can do on canaille
|
||||||
# An access control consists in a FILTER to match users, a list of PERMISSIONS
|
# An access control consists in a FILTER to match users, a list of PERMISSIONS
|
||||||
# matched users will be able to perform, and fields users will be able
|
# matched users will be able to perform, and fields users will be able
|
||||||
# to READ and WRITE. Users matching several filters will cumulate permissions.
|
# to READ and WRITE. Users matching several filters will cumulate permissions.
|
||||||
#
|
#
|
||||||
# A 'FILTER' parameter that is a LDAP filter used to determine if a user
|
# 'FILTER' parameter can be:
|
||||||
# belongs to an access control. If absent, all the users will match this
|
# - absent, in which case all the users will match this access control
|
||||||
# access control. If your LDAP server has the 'memberof' overlay, you can
|
# - a mapping where keys are user attributes name and the values those user
|
||||||
# filter against group membership.
|
# attribute values. All the values must be matched for the user to be part
|
||||||
|
# of the access control.
|
||||||
|
# - a list of those mappings. If a user values match at least one mapping,
|
||||||
|
# then the user will be part of the access control
|
||||||
|
#
|
||||||
# Here are some examples
|
# Here are some examples
|
||||||
# FILTER = 'uid=admin'
|
# FILTER = {'user_name': 'admin'}
|
||||||
# FILTER = 'memberof=cn=admins,ou=groups,dc=mydomain,dc=tld'
|
# FILTER =
|
||||||
|
# - {'groups': 'admin'}
|
||||||
|
# - {'groups': 'moderators'}
|
||||||
#
|
#
|
||||||
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
||||||
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
||||||
|
@ -142,7 +149,7 @@ WRITE = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[ACL.ADMIN]
|
[ACL.ADMIN]
|
||||||
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"
|
FILTER = {"groups": "admins"}
|
||||||
PERMISSIONS = [
|
PERMISSIONS = [
|
||||||
"manage_users",
|
"manage_users",
|
||||||
"manage_groups",
|
"manage_groups",
|
||||||
|
|
|
@ -63,6 +63,27 @@ class User(LDAPObject):
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def acl_filter_to_ldap_filter(cls, filter_):
|
||||||
|
if isinstance(filter_, dict):
|
||||||
|
return (
|
||||||
|
"(&"
|
||||||
|
+ "".join(
|
||||||
|
f"({cls.attribute_table.get(key, key)}={value})"
|
||||||
|
for key, value in filter_.items()
|
||||||
|
)
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(filter_, list):
|
||||||
|
return (
|
||||||
|
"(|"
|
||||||
|
+ "".join(cls.acl_filter_to_ldap_filter(mapping) for mapping in filter_)
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
|
return filter_
|
||||||
|
|
||||||
def load_groups(self):
|
def load_groups(self):
|
||||||
group_filter = (
|
group_filter = (
|
||||||
current_app.config["BACKENDS"]["LDAP"]
|
current_app.config["BACKENDS"]["LDAP"]
|
||||||
|
@ -159,9 +180,9 @@ class User(LDAPObject):
|
||||||
conn = self.ldap_connection()
|
conn = self.ldap_connection()
|
||||||
|
|
||||||
for access_group_name, details in current_app.config["ACL"].items():
|
for access_group_name, details in current_app.config["ACL"].items():
|
||||||
if not details.get("FILTER") or (
|
filter_ = self.acl_filter_to_ldap_filter(details.get("FILTER"))
|
||||||
self.id
|
if not filter_ or (
|
||||||
and conn.search_s(self.id, ldap.SCOPE_SUBTREE, details["FILTER"])
|
self.id and conn.search_s(self.id, ldap.SCOPE_SUBTREE, filter_)
|
||||||
):
|
):
|
||||||
self.permissions |= set(details.get("PERMISSIONS", []))
|
self.permissions |= set(details.get("PERMISSIONS", []))
|
||||||
self.read |= set(details.get("READ", []))
|
self.read |= set(details.get("READ", []))
|
||||||
|
|
|
@ -92,18 +92,25 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
||||||
# A 'user' variable is available.
|
# A 'user' variable is available.
|
||||||
# GROUP_USER_FILTER = "member={user.dn}"
|
# GROUP_USER_FILTER = "member={user.dn}"
|
||||||
|
|
||||||
|
[ACL]
|
||||||
# You can define access controls that define what users can do on canaille
|
# You can define access controls that define what users can do on canaille
|
||||||
# An access control consists in a FILTER to match users, a list of PERMISSIONS
|
# An access control consists in a FILTER to match users, a list of PERMISSIONS
|
||||||
# matched users will be able to perform, and fields users will be able
|
# matched users will be able to perform, and fields users will be able
|
||||||
# to READ and WRITE. Users matching several filters will cumulate permissions.
|
# to READ and WRITE. Users matching several filters will cumulate permissions.
|
||||||
#
|
#
|
||||||
# A 'FILTER' parameter that is a LDAP filter used to determine if a user
|
# 'FILTER' parameter can be:
|
||||||
# belongs to an access control. If absent, all the users will match this
|
# - absent, in which case all the users will match this access control
|
||||||
# access control. If your LDAP server has the 'memberof' overlay, you can
|
# - a mapping where keys are user attributes name and the values those user
|
||||||
# filter against group membership.
|
# attribute values. All the values must be matched for the user to be part
|
||||||
|
# of the access control.
|
||||||
|
# - a list of those mappings. If a user values match at least one mapping,
|
||||||
|
# then the user will be part of the access control
|
||||||
|
#
|
||||||
# Here are some examples
|
# Here are some examples
|
||||||
# FILTER = 'uid=admin'
|
# FILTER = {'user_name': 'admin'}
|
||||||
# FILTER = 'memberof=cn=admins,ou=groups,dc=mydomain,dc=tld'
|
# FILTER =
|
||||||
|
# - {'groups': 'admin'}
|
||||||
|
# - {'groups': 'moderators'}
|
||||||
#
|
#
|
||||||
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
||||||
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
||||||
|
@ -143,7 +150,7 @@ WRITE = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[ACL.ADMIN]
|
[ACL.ADMIN]
|
||||||
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"
|
FILTER = {"groups": "admins"}
|
||||||
PERMISSIONS = [
|
PERMISSIONS = [
|
||||||
"manage_users",
|
"manage_users",
|
||||||
"manage_groups",
|
"manage_groups",
|
||||||
|
@ -154,7 +161,7 @@ PERMISSIONS = [
|
||||||
WRITE = ["groups"]
|
WRITE = ["groups"]
|
||||||
|
|
||||||
[ACL.HALF_ADMIN]
|
[ACL.HALF_ADMIN]
|
||||||
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"
|
FILTER = {"groups": "moderators"}
|
||||||
PERMISSIONS = ["manage_users", "manage_groups", "delete_account"]
|
PERMISSIONS = ["manage_users", "manage_groups", "delete_account"]
|
||||||
WRITE = ["groups"]
|
WRITE = ["groups"]
|
||||||
|
|
||||||
|
|
|
@ -92,18 +92,25 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
||||||
# A 'user' variable is available.
|
# A 'user' variable is available.
|
||||||
# GROUP_USER_FILTER = "member={user.dn}"
|
# GROUP_USER_FILTER = "member={user.dn}"
|
||||||
|
|
||||||
|
[ACL]
|
||||||
# You can define access controls that define what users can do on canaille
|
# You can define access controls that define what users can do on canaille
|
||||||
# An access control consists in a FILTER to match users, a list of PERMISSIONS
|
# An access control consists in a FILTER to match users, a list of PERMISSIONS
|
||||||
# matched users will be able to perform, and fields users will be able
|
# matched users will be able to perform, and fields users will be able
|
||||||
# to READ and WRITE. Users matching several filters will cumulate permissions.
|
# to READ and WRITE. Users matching several filters will cumulate permissions.
|
||||||
#
|
#
|
||||||
# A 'FILTER' parameter that is a LDAP filter used to determine if a user
|
# 'FILTER' parameter can be:
|
||||||
# belongs to an access control. If absent, all the users will match this
|
# - absent, in which case all the users will match this access control
|
||||||
# access control. If your LDAP server has the 'memberof' overlay, you can
|
# - a mapping where keys are user attributes name and the values those user
|
||||||
# filter against group membership.
|
# attribute values. All the values must be matched for the user to be part
|
||||||
|
# of the access control.
|
||||||
|
# - a list of those mappings. If a user values match at least one mapping,
|
||||||
|
# then the user will be part of the access control
|
||||||
|
#
|
||||||
# Here are some examples
|
# Here are some examples
|
||||||
# FILTER = 'uid=admin'
|
# FILTER = {'user_name': 'admin'}
|
||||||
# FILTER = 'memberof=cn=admins,ou=groups,dc=mydomain,dc=tld'
|
# FILTER =
|
||||||
|
# - {'groups': 'admin'}
|
||||||
|
# - {'groups': 'moderators'}
|
||||||
#
|
#
|
||||||
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
||||||
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
||||||
|
@ -143,7 +150,7 @@ WRITE = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[ACL.ADMIN]
|
[ACL.ADMIN]
|
||||||
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"
|
FILTER = {"groups": "admins"}
|
||||||
PERMISSIONS = [
|
PERMISSIONS = [
|
||||||
"manage_users",
|
"manage_users",
|
||||||
"manage_groups",
|
"manage_groups",
|
||||||
|
@ -154,7 +161,7 @@ PERMISSIONS = [
|
||||||
WRITE = ["groups"]
|
WRITE = ["groups"]
|
||||||
|
|
||||||
[ACL.HALF_ADMIN]
|
[ACL.HALF_ADMIN]
|
||||||
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"
|
FILTER = {"groups": "moderators"}
|
||||||
PERMISSIONS = ["manage_users", "manage_groups", "delete_account"]
|
PERMISSIONS = ["manage_users", "manage_groups", "delete_account"]
|
||||||
WRITE = ["groups"]
|
WRITE = ["groups"]
|
||||||
|
|
||||||
|
|
|
@ -132,9 +132,19 @@ The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
|
||||||
object that users will be able to read and/or write.
|
object that users will be able to read and/or write.
|
||||||
|
|
||||||
:FILTER:
|
:FILTER:
|
||||||
*Optional.* A filter to test on the users to test if they belong to this ACL.
|
*Optional.* It can be:
|
||||||
If absent, all the users will have the permissions in this ACL.
|
|
||||||
e.g. ``uid=admin`` or ``memberof=cn=admin,ou=groups,dc=mydomain,dc=tld``
|
- absent, in which case all the users will have the permissions in this ACL.
|
||||||
|
- a mapping where keys are user attributes name and the values those user
|
||||||
|
attribute values. All the values must be matched for the user to be part
|
||||||
|
of the access control.
|
||||||
|
- a list of those mappings. If a user values match at least one mapping,
|
||||||
|
then the user will be part of the access control
|
||||||
|
|
||||||
|
Here are some examples:
|
||||||
|
|
||||||
|
- ``FILTER = {'user_name': 'admin'}``
|
||||||
|
- ``FILTER = [{'groups': 'admin'}, {'groups': 'moderators'}]``
|
||||||
|
|
||||||
:PERMISSIONS:
|
:PERMISSIONS:
|
||||||
*Optional.* A list of items the users in the access control will be able to manage. Values can be:
|
*Optional.* A list of items the users in the access control will be able to manage. Values can be:
|
||||||
|
|
|
@ -115,7 +115,7 @@ def configuration(slapd_server, smtpd):
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"ADMIN": {
|
"ADMIN": {
|
||||||
"FILTER": "(|(uid=admin)(sn=admin))",
|
"FILTER": [{"user_name": "admin"}, {"family_name": "admin"}],
|
||||||
"PERMISSIONS": [
|
"PERMISSIONS": [
|
||||||
"manage_users",
|
"manage_users",
|
||||||
"manage_oidc",
|
"manage_oidc",
|
||||||
|
@ -128,7 +128,7 @@ def configuration(slapd_server, smtpd):
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"MODERATOR": {
|
"MODERATOR": {
|
||||||
"FILTER": "(|(uid=moderator)(sn=moderator))",
|
"FILTER": [{"user_name": "moderator"}, {"family_name": "moderator"}],
|
||||||
"PERMISSIONS": ["manage_users", "manage_groups", "delete_account"],
|
"PERMISSIONS": ["manage_users", "manage_groups", "delete_account"],
|
||||||
"WRITE": [
|
"WRITE": [
|
||||||
"groups",
|
"groups",
|
||||||
|
|
Loading…
Reference in a new issue