Metadata-Version: 2.4
Name: pas.plugins.ldap
Version: 2.0.0rc1
Summary: LDAP/AD Plugin for Plone/Zope PluggableAuthService (users+groups)
Project-URL: ChangeLog, https://github.com/collective/pas.plugins.ldap/blob/main/CHANGES.md
Project-URL: Homepage, https://github.com/collective/pas.plugins.ldap/
Project-URL: Issue Tracker, https://github.com/collective/pas.plugins.ldap/issues
Project-URL: Source Code, https://github.com/collective/pas.plugins.ldap
Author-email: BlueDynamics Alliance <dev@bluedynamics.com>
License: GPL 2.0
License-File: LICENSE.GPL
License-File: LICENSE.md
Keywords: authentication,groups,ldap,pas,plone,plugin,users,zope
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Plone
Classifier: Framework :: Plone :: 6.0
Classifier: Framework :: Plone :: 6.1
Classifier: Framework :: Plone :: 6.2
Classifier: Framework :: Plone :: Addon
Classifier: Framework :: Zope
Classifier: Framework :: Zope :: 5
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
Requires-Dist: bda-cache
Requires-Dist: node-ext-ldap>=2.0.0
Requires-Dist: odict
Requires-Dist: plone-api
Requires-Dist: plone-registry
Requires-Dist: products-cmfcore
Requires-Dist: products-genericsetup
Requires-Dist: products-plonepas
Requires-Dist: products-pluggableauthservice
Requires-Dist: products-statusmessages
Requires-Dist: python-ldap>=3.4.0
Requires-Dist: yafowil-plone>=6.0.0
Requires-Dist: yafowil-widget-array>=2.0.0
Requires-Dist: yafowil-widget-dict>=2.0.0
Requires-Dist: yafowil-yaml
Requires-Dist: zope-globalrequest
Requires-Dist: zope>=5
Provides-Extra: plone
Requires-Dist: products-cmfplone; extra == 'plone'
Provides-Extra: test
Requires-Dist: plone-testing; extra == 'test'
Requires-Dist: pytest-plone; extra == 'test'
Description-Content-Type: text/markdown

[![Latest PyPI version](https://img.shields.io/pypi/v/pas.plugins.ldap.svg)](https://pypi.python.org/pypi/pas.plugins.ldap)

[![Number of PyPI downloads](https://img.shields.io/pypi/dm/pas.plugins.ldap.svg)](https://pypi.python.org/pypi/pas.plugins.ldap)

[![CI](https://github.com/collective/pas.plugins.ldap/actions/workflows/ci.yaml/badge.svg)](https://github.com/collective/pas.plugins.ldap/actions/workflows/ci.yaml)

This is a [LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) Plugin for the [Zope](https://www.zope.dev/) [Pluggable Authentication Service (PAS)](https://pypi.org/project/Products.PluggableAuthService/).

`pas.plugins.ldap` is **not** releated to the old [LDAPUserFolder](https://pypi.org/project/Products.LDAPUserFolder/) / [LDAPMultiPlugins](https://pypi.org/project/Products.LDAPMultiPlugins/) and the packages (i.e. [PloneLDAP](https://pypi.org/project/Products.PloneLDAP/)) stacked on top of it in any way.

It is based on [node.ext.ldap](https://pypi.org/project/node.ext.ldap/), an almost framework independent LDAP stack.

# Features

- If [Plone](https://plone.org) is installed an integration layer with a `setup profile` and a `Plone Controlpanel` page is available.
- It works in a plain Zope even if it depends on [PlonePAS](https://pypi.org/project/Products.PlonePAS).
- LDAP authentication and authorization for users and groups.
- It provides users and/or groups from an LDAP directory.
- LDAP properties for users and groups, which can be used in the rest of the system as well.
- For now users and groups can't be added or deleted. Properties on both are read/write.

## TODO

For a detailed list of TODO tasks to this project, please checkout the [TODO file](https://github.com/collective/pas.plugins.ldap/blob/main/TODO.md).

# Screenshots

After installation, you will find a new behavior available, go to `Site Setup` > `Users` > `LDAP / AD Support` as the following screenshot:

[![pas.plugins.ldap Plone control panel](https://raw.githubusercontent.com/collective/pas.plugins.ldap/refs/heads/main/docs/images/ldap-settings.png)](https://github.com/collective/pas.plugins.ldap/)

# Translations

This product has been translated into

- English
- Spanish

# Installation

This package supports Zope applications and Plone sites using Volto and Classic UI.

## Dependencies

This package depends on [python-ldap](https://pypi.org/project/python-ldap/) package.

To build it correctly you need to have some development libraries included in your system.

On a Debian-based installation use:

```console
sudo apt install python-dev libldap2-dev libsasl2-dev libssl-dev
```

---

## Zope

Install `pas.plugins.ldap` by adding it to the `instance` section of your `buildout`:

```ini
eggs =
    ...
    pas.plugins.ldap

zcml =
    ...
    pas.plugins.ldap
```

Run `buildout` and then restart the `Zope` instance.

Then browse to your `acl_users` folder and add an `LDAP Plugin` object.

Configure it using the `LDAP Settings` form and choose the functionality this
`LDAP Plugin` will perform with the `Activate` tab.

- `Authentication` (`authenticateCredentials`)
- `Group_Enumeration` (`enumerateGroups`)
- `Group_Introspection` (`getGroupById`)
- `Group_Management` (`addGroup`)
- `Groups` (`getGroupsForPrincipal`)
- `Properties` (`getPropertiesForUser`)
- `Roles` (`getRolesForPrincipal`)
- `User_Adder` (`doAddUser`)
- `User_Enumeration` (`enumerateUsers`)
- `User_Management` (`doChangeUser`)

---

## Plone

To install `pas.plugins.ldap` in a Plone site, you need by adding it to the
`instance` section of your `buildout`:

```ini
eggs =
    ...
    pas.plugins.ldap
```

Run `buildout` and then restart the `Plone` instance.

Then go to the Plone control-panel, select `Addons` and install the `LDAP / Active Directory Support`.

So, you can navigate to `Site Setup` > `Users` > `LDAP / AD Support` and click it and configure the plugin there.

To use an own integration-profile, add to the profiles `metadata.xml` file:

```xml
...
<dependencies>
    ...
    <dependency>profile-pas.plugins.ldap.plonecontrolpanel:default</dependency>
</dependencies>
...
```

Additionally the `LDAP Settings` can be exported and imported with `portal_setup` tool.
You can place the exported `ldapsettings.xml` file in your integration profile, so it will be imported with your next install again.

**Warning:**

**The LDAP-password is stored in there in plain text!**

But anonymous bindings are possible.

---

## Logging

To get detailed output of all LDAP-operations and much more set the logging level to debug.
Attention, this is lots of output.

LDAP as an external service might be down, non-responsive or slow.
This package logs such events to raise awareness.
There are two environment variables to control the logging of LDAP-errors:

`PAS_PLUGINS_LDAP_ERROR_LOG_TIMEOUT`
: First LDAP-error is logged, further errors ignored until the given number of seconds have passed.
  This supresses flooding logs if LDAP is down.
  Default: 300.0 (time in seconds, float).

`PAS_PLUGINS_LDAP_LONG_RUNNING_LOG_THRESHOLD`
: Log long running LDAP/PAS operations.
  If a PAS operation takes longer than he given number of seconds, log it as error.
  Default: 5 (time in seconds, float).

---

## Timeouts

Global LDAP timeouts are set and controlled by two environment variables:

`PAS_PLUGINS_LDAP_OPT_NETWORK_TIMEOUT`
: Connection timeout.
  Default: 1.0s

`PAS_PLUGINS_LDAP_OPT_TIMEOUT`
: Overall timeout.
  Default: 30.0s

See details in [python-ldap](https://pypi.org/project/python-ldap/) documentation: OPT_NETWORK_TIMEOUT and OPT_TIMEOUT.

---

## Caching

**Without caching this module is slow** (as any other module talking to LDAP will be).

By **default** the LDAP-queries are **not cached**.

A **must have** for a production environment is having [memcached](https://memcached.org/) server configured as LDAP query cache.

Cache at least for ~6 seconds, so a page load with all its resources is covered also in worst case.

The UGM tree is cached by default on the request, that means its built up every request from (cached) ldap queries.

There is an alternative adapter available which will cache the ugm tree as volatile attribute (`_v_...`) on the persistent plugin.

Volatile attributes are not persisted in the ZODB.

If the plugin object vanishes from ZODB cache the atrribute is gone.

The volatile plugin cache can be activated by loading its zcml with `<include package="pas.plugins.ldap" file="cache_volatile.zcml"`.

The caching time can be influenced by overriding the value in `pas.plugins.ldap.cache.VOLATILE_CACHE_MAXAGE`.

It defaults to 10 and its unit is seconds.

**Note:**

**Caching the UGM tree longer than one request means it could contain outdated data.**

If you plan a different implementation of UGM tree caching,provide your own adapter implementing `pas.plugins.ldap.interfaces.IPluginCacheHandler`.

# Limitations and Future Optimizations

This package was not tested/developed with Windows.
It may work under Windows if [python-ldap](https://pypi.org/project/python-ldap/) is installed properly and recognized by buildout.

This package works fine for several 10000 users or groups, **unless you list users**.

This is not that much a problem for small amount of users.
There is room for future optimization in the underlying [node.ext.ldap](https://pypi.org/project/node.ext.ldap/).

---

# Development Workflow

1. Install requirements:

```shell
make install
```

2. Start Zope instance:

```shell
make zope-start
```

3. Zpretty format and lint XML/ZCML:

```shell
make zpretty-check && make zpretty-format && make zpretty-check
```

4. Lint and format Python code with [ruff](https://docs.astral.sh/ruff/)
   (this is what CI enforces):

```shell
uvx ruff check . && uvx ruff format .
```

5. Extract i18n messages:

```shell
make gettext-create && make gettext-update && make gettext-compile
```

   The compiled `.mo` catalogs are also generated automatically when the
   package is built (sdist/wheel), so they always ship in a release.

6. Run unit tests:

```shell
make test
```

7. Run coverage unit tests:

```shell
make coverage
```

---

# Source Code

If you want to help with the development (improvement, update, bug-fixing, ...) of `pas.plugins.ldap` this is a great idea!

- The code is located in the [GitHub Collective](https://github.com/collective/pas.plugins.ldap).

- You can clone it or [get access to the GitHub Collective](https://collective.github.io/) and work directly on the project.

## Authors

This product was developed by [BlueDynamics Alliance](https://bluedynamics.com/) team.

[![BlueDynamics Alliance](https://bluedynamics.com/++theme++bda.theme/static/bda-media/bda-logo.svg)](https://bluedynamics.com/)

Maintainers are Robert Niederreiter, Jens Klein and the [BlueDynamics Alliance](https://bluedynamics.com/) developer team.

# Support

We appreciate any contribution. Releases to PyPI are automated via tagging and
Trusted Publishing; see [RELEASE.md](https://github.com/collective/pas.plugins.ldap/blob/main/RELEASE.md)
for the process. If you need a release done, please contact one of us:
[dev@bluedynamics dot com](mailto:dev@bluedynamics.com).

- If you are having issues, please let us know at our [issue tracker](https://github.com/collective/pas.plugins.ldap/issues).

# Contributors

For a list of all contributors to this project, please checkout the following resources:

- The [CONTRIBUTORS file](https://github.com/collective/pas.plugins.ldap/blob/main/CONTRIBUTORS.md).

- The [Contributors page on GitHub](https://github.com/collective/pas.plugins.ldap/graphs/contributors).

# License

The project is licensed under the GPLv2.
