Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ef04c4c
implementation of Default User Role scenario.
sauzher Feb 17, 2021
4ec27ea
Merge branch 'master' of github.com:sauzher/pas.plugins.ldap into def…
sauzher Nov 16, 2021
0a33b1e
update changelog
sauzher Nov 16, 2021
2b5ece9
better changelog
sauzher Nov 16, 2021
41116be
add uninstall profile
valipod Jul 31, 2023
3a43a4f
remove registry keys and controlpanel when uninstalling
valipod Aug 2, 2023
bb5597a
Merge pull request #1 from eea/develop
valipod Aug 3, 2023
a0e6e7c
update yafowil.plone version to match the custom eea one
valipod Aug 3, 2023
10155cd
Merge pull request #2 from eea/develop
valipod Aug 3, 2023
44ee73d
chore: use dev0 version
valentinab25 Aug 11, 2023
2259d74
chore: use dev0 version
Aug 11, 2023
d22f039
Merge pull request #3 from eea/develop
valentinab25 Aug 11, 2023
f7138dc
update version to 1.8.3.dev1 for wheel compliance
valipod Aug 25, 2023
157ec4e
update dependency to yafowil.plone
valipod Aug 25, 2023
3d73e36
use exact_match for searchUsers/searchGroups in getRolesForPrincipal/…
mamico Oct 17, 2023
565f96a
fix: Dependency yafowil.plone>=5.0.0a1 and yafowil.bootstrap>=2.0.0a1
avoinea Oct 18, 2023
7521524
Merge pull request #118 from collective/exact_match
jensens Nov 8, 2023
608f7cc
just as eee did in pull request 119 - but without changing CHANGES.rs…
Dec 7, 2023
06bd7fb
Merge pull request #120 from greskwerk/main
jensens Dec 9, 2023
415383c
Merge branch 'main' into master
avoinea Feb 15, 2024
bc67f91
Merge pull request #119 from eea/master
jensens Feb 15, 2024
5bddad9
fix: avoid credential logging in debug mode
mamoep Sep 16, 2024
40d1fef
Merge pull request #126 from mamoep/credential-logging-fix
rnixx Sep 16, 2024
fcf997e
Add tls_cacertfile, tls_cacertdir, tls_clcertfile and tls_clkeyfile o…
metbosch Oct 8, 2024
84fb64c
Add start_tls option
metbosch Oct 8, 2024
32d634a
Fix LDAP option value
metbosch Oct 8, 2024
e453496
Merge pull request #128 from metbosch/main
rnixx Oct 9, 2024
90a0d3a
Preparing release 1.8.3
avoinea Nov 13, 2024
a3d135b
Back to development: 1.8.4
avoinea Nov 13, 2024
bc532ee
Merge branch 'main' into default-user-roles
mamico Jan 29, 2025
d1ba512
default value
mamico Jan 30, 2025
a0d336c
black
mamico Jan 30, 2025
0c82588
bump version on feature level (semver, minor)
jensens Feb 3, 2025
7f844d9
Merge pull request #112 from sauzher/default-user-roles
jensens Feb 3, 2025
29d4c6e
Remove five.globalrequest
cillianderoiste Jun 23, 2025
d18aece
Merge pull request #134 from collective/remove-five-globalrequest
jensens Jun 23, 2025
9480b2e
Merge remote-tracking branch 'origin/main' into ale/p6
ale-rt Jun 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ History
- Remove five.globalrequest dependency.
[cillianderoiste]


1.9.0 (unreleased)
------------------

- Added Spanish translation #132
[macagua]

Expand All @@ -38,6 +34,19 @@ History
- Drop support for Plone 5/ Python < 3.9
[jensens]

- Default user roles configuration implementation.
[sauzher]


1.8.3 (2024-11-13)
------------------

- Add uninstall profile
[dumitval]
- Fix: use exact_match for searchUsers/searchGroups in getRolesForPrincipal/getPropertiesForUser
to avoid unexpected results
[mamico]


1.8.2 (2022-10-31)
------------------
Expand Down
7 changes: 1 addition & 6 deletions src/pas/plugins/ldap/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
i18n_domain="pas.plugins.ldap"
>

<include package="five.globalrequest" />

<five:registerPackage
package="."
initialize=".initialize"
/>
<five:registerPackage package="." initialize=".initialize" />

<i18n:registerTranslations directory="locales" />

Expand Down
5 changes: 5 additions & 0 deletions src/pas/plugins/ldap/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"server.password": "secret",
"server.ignore_cert": False,
"server.start_tls": False,
"server.tls_cacertfile": None,
"server.tls_cacertdir": None,
"server.tls_clcertfile": None,
"server.tls_clkeyfile": None,
"server.page_size": 1000,
"server.roles": ["Member"],
"server.conn_timeout": 5,
"server.op_timeout": 600,
"cache.cache": False,
Expand Down
8 changes: 8 additions & 0 deletions src/pas/plugins/ldap/plonecontrolpanel/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
directory="profiles/default"
/>

<genericsetup:registerProfile
name="uninstall"
title="Uninstall LDAP Plugin for PAS"
directory="profiles/uninstall"
description="Uninstalls the pas.plugins.ldap add-on."
provides="Products.GenericSetup.interfaces.EXTENSION"
post_handler=".setuphandlers.uninstall" />

<genericsetup:upgradeStep
title="Unregister broken old persistent import step"
profile="pas.plugins.ldap.plonecontrolpanel:default"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<object name="portal_controlpanel">
<configlet action_id="LDAP_Configuration"
remove="True">
</configlet>
</object>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<registry>

<!-- yafowil.widget.array -->
<record name="yafowil.widget.array.common" remove="True" />

<!-- yafowil.widget.dict -->
<record name="yafowil.widget.dict.common" remove="True" />

</registry>
39 changes: 39 additions & 0 deletions src/pas/plugins/ldap/plonecontrolpanel/setuphandlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from zope.component.hooks import getSite
from pas.plugins.ldap.plugin import LDAPPlugin
import logging


logger = logging.getLogger(__name__)


TITLE = "LDAP plugin (pas.plugins.ldap)"


def _removePlugin(pas, PLUGIN_ID="pasldap"):
installed = pas.objectIds()
if PLUGIN_ID not in installed:
return TITLE + " already uninstalled."
plugin = getattr(pas, PLUGIN_ID)
if not isinstance(plugin, LDAPPlugin):
logger.warning(
"Uninstall aborted. PAS plugin %s is not an LDAPPlugin.",
PLUGIN_ID)
for info in pas.plugins.listPluginTypeInfo():
interface = info["interface"]
if not interface.providedBy(plugin):
continue
try:
pas.plugins.deactivatePlugin(interface, plugin.getId())
except KeyError:
# the plugin was not active
pass
pas._delObject(PLUGIN_ID)
logger.info("Removed LDAPPlugin %s from acl_users.", PLUGIN_ID)


def uninstall(context):
site = getSite()
pas = site.acl_users
_removePlugin(pas)

12 changes: 6 additions & 6 deletions src/pas/plugins/ldap/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def authenticateCredentials(self, credentials):
pw = credentials.get("password")
if not (login and pw):
return default
logger.debug("credentials: %s" % credentials)
logger.debug("login: %s" % login)
users = self.users
if not users:
return default
Expand Down Expand Up @@ -442,8 +442,8 @@ def getRolesForPrincipal(self, principal, request=None):
users = self.users
if not users:
return default
if self.enumerateUsers(id=principal.getId()):
return ("Member",)
if self.enumerateUsers(id=principal.getId(), exact_match=True):
return tuple(set(self._ldap_props.roles))
return default

@security.private
Expand Down Expand Up @@ -564,7 +564,9 @@ def getPropertiesForUser(self, user_or_group, request=None):
if not isinstance(ugid, str):
ugid = ugid.decode("utf-8")
try:
if self.enumerateUsers(id=ugid) or self.enumerateGroups(id=ugid):
if self.enumerateUsers(id=ugid, exact_match=True) or self.enumerateGroups(
id=ugid, exact_match=True
):
return LDAPUserPropertySheet(user_or_group, self)
except KeyError:
pass
Expand Down Expand Up @@ -690,7 +692,6 @@ def getGroupById(self, group_id):
for propfinder_id, propfinder in plugins.listPlugins(
pas_interfaces.IPropertiesPlugin
):

data = propfinder.getPropertiesForUser(group, None)
if not data:
continue
Expand All @@ -699,7 +700,6 @@ def getGroupById(self, group_id):
group._addGroups(pas._getGroupsForPrincipal(group, None, plugins=plugins))
# add roles
for rolemaker_id, rolemaker in plugins.listPlugins(pas_interfaces.IRolesPlugin):

roles = rolemaker.getRolesForPrincipal(group, None)
if not roles:
continue
Expand Down
27 changes: 17 additions & 10 deletions src/pas/plugins/ldap/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def fetch(name, default=UNSET):
return val

props.uri = fetch("server.uri")

if not fetch("server.anonymous"):
props.user = fetch("server.user")
password = fetch("server.password")
Expand All @@ -111,12 +112,12 @@ def fetch(name, default=UNSET):
props.user = ""
props.password = ""
props.ignore_cert = fetch("server.ignore_cert")
props.start_tls = fetch('server.start_tls')
props.tls_cacertfile = fetch('server.tls_cacertfile')
props.tls_cacertdir = fetch('server.tls_cacertdir')
props.tls_clcertfile = fetch('server.tls_clcertfile')
props.tls_clkeyfile = fetch('server.tls_clkeyfile')
# TODO: later
# props.start_tls = fetch('server.start_tls')
# props.tls_cacertfile = fetch('server.tls_cacertfile')
# props.tls_cacertdir = fetch('server.tls_cacertdir')
# props.tls_clcertfile = fetch('server.tls_clcertfile')
# props.tls_clkeyfile = fetch('server.tls_clkeyfile')
# props.retry_max = fetch(at('server.retry_max')
# props.retry_delay = fetch('server.retry_delay')
props.page_size = fetch("server.page_size")
Expand All @@ -125,8 +126,11 @@ def fetch(name, default=UNSET):
props.cache = fetch("cache.cache")
props.memcached = fetch("cache.memcached")
props.timeout = fetch("cache.timeout")

props.roles = fetch("users.roles") # a server wide variable, but related to user

users.baseDN = fetch("users.dn")
# build attrmap from static keys and dynamic keys inputs
# build attrmap from static keys and dynamic keys inputs
users.attrmap = odict()
users.attrmap.update(fetch("users.aliases_attrmap"))
users_propsheet_attrmap = fetch("users.propsheet_attrmap")
Expand Down Expand Up @@ -242,18 +246,21 @@ def __init__(self, plugin):
self.plugin = plugin

# XXX: Later
tls_cacertfile = ""
tls_cacertdir = ""
tls_clcertfile = ""
tls_clkeyfile = ""
retry_max = 3
retry_delay = 5

uri = propproxy("server.uri")
user = propproxy("server.user")
roles = propproxy("server.roles")
password = propproxy("server.password")
start_tls = propproxy("server.start_tls")
ignore_cert = propproxy("server.ignore_cert")
start_tls = propproxy("server.start_tls")
tls_cacertfile = propproxy("server.tls_cacertfile")
tls_cacertdir = propproxy("server.tls_cacertdir")
tls_clcertfile = propproxy("server.tls_clcertfile")
tls_clkeyfile = propproxy("server.tls_clkeyfile")

page_size = propproxy("server.page_size")
conn_timeout = propproxy("server.conn_timeout")
op_timeout = propproxy("server.op_timeout")
Expand Down
39 changes: 39 additions & 0 deletions src/pas/plugins/ldap/properties.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,36 @@ widgets:
props:
label: i18n:lbl_ignore_certificate_check:Ignore certificate check?
help: i18n:help_ignore_certificate_check:If set on authenticate a failing certificate chain check including CA is ignored.
- start_tls:
factory: '#field:checkbox'
value: expr:context.props.start_tls
props:
label: Use TLS connection
help: If set, the connection is upgraded to TLS.
- tls_cacertfile:
factory: '#field:text'
value: expr:context.props.tls_cacertfile
props:
label: Path to CA certificate file for TLS communication (OPT_X_TLS_CACERTFILE)
help: If set, the LDAP server certificate is checked against the CA certificate file.
- tls_cacertdir:
factory: '#field:text'
value: expr:context.props.tls_cacertdir
props:
label: Path to folder with CA certificate files for TLS communication (OPT_X_TLS_CACERTDIR)
help: If set, the LDAP server certificate is checked against the CA certificates in folder.
- tls_clcertfile:
factory: '#field:text'
value: expr:context.props.tls_clcertfile
props:
label: Path to client certificate file for TLS communication (OPT_X_TLS_CERTFILE). Requires tls_clkeyfile
help: If set, the client certificate is sent to the server.
- tls_clkeyfile:
factory: '#field:text'
value: expr:context.props.tls_clkeyfile
props:
label: Path to client certificate key for TLS communication (OPT_X_TLS_KEYFILE). Requires tls_clcertfile
help: If set, the client certificate is sent to the server.
- page_size:
factory: '#field:number'
value: expr:context.props.page_size
Expand Down Expand Up @@ -100,6 +130,15 @@ widgets:
value: expr:context.users.memberOfSupport
props:
label: i18n:lbl_memberOf_attribute_supported:memberOf attribute supported?
- roles:
factory: '#array'
value: expr:context.props.roles
props:
label: Roles aquired
array.label: Roles acquired
widgets:
- roles:
factory: field:text
- recursiveGroups:
factory: '#field:checkbox'
value: expr:context.users.recursiveGroups
Expand Down
1 change: 1 addition & 0 deletions tests/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def ldapprops(context):

props.uri = ldaptesting.props.uri
props.user = ldaptesting.props.user
props.roles = ldaptesting.props.roles
props.password = ldaptesting.props.password
props.cache = ldaptesting.props.cache
props.page_size = ldaptesting.props.page_size
Expand Down
Loading