charmlibs-interfaces-ldap 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- charmlibs_interfaces_ldap-1.0.0/.gitignore +187 -0
- charmlibs_interfaces_ldap-1.0.0/CHANGELOG.md +5 -0
- charmlibs_interfaces_ldap-1.0.0/PKG-INFO +30 -0
- charmlibs_interfaces_ldap-1.0.0/README.md +11 -0
- charmlibs_interfaces_ldap-1.0.0/interface/v0/README.md +93 -0
- charmlibs_interfaces_ldap-1.0.0/interface/v0/interface.yaml +19 -0
- charmlibs_interfaces_ldap-1.0.0/interface/v0/schema.py +72 -0
- charmlibs_interfaces_ldap-1.0.0/pyproject.toml +100 -0
- charmlibs_interfaces_ldap-1.0.0/src/charmlibs/interfaces/ldap/__init__.py +158 -0
- charmlibs_interfaces_ldap-1.0.0/src/charmlibs/interfaces/ldap/_ldap.py +411 -0
- charmlibs_interfaces_ldap-1.0.0/src/charmlibs/interfaces/ldap/_version.py +15 -0
- charmlibs_interfaces_ldap-1.0.0/src/charmlibs/interfaces/ldap/py.typed +0 -0
- charmlibs_interfaces_ldap-1.0.0/tests/unit/conftest.py +97 -0
- charmlibs_interfaces_ldap-1.0.0/tests/unit/test_ldap_requirer.py +114 -0
- charmlibs_interfaces_ldap-1.0.0/uv.lock +326 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
cos-tool*
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.coverage-*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
.report/
|
|
55
|
+
|
|
56
|
+
# Translations
|
|
57
|
+
*.mo
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
# Django stuff:
|
|
61
|
+
*.log
|
|
62
|
+
local_settings.py
|
|
63
|
+
db.sqlite3
|
|
64
|
+
db.sqlite3-journal
|
|
65
|
+
|
|
66
|
+
# Flask stuff:
|
|
67
|
+
instance/
|
|
68
|
+
.webassets-cache
|
|
69
|
+
|
|
70
|
+
# Scrapy stuff:
|
|
71
|
+
.scrapy
|
|
72
|
+
|
|
73
|
+
# Sphinx documentation
|
|
74
|
+
docs/_build/
|
|
75
|
+
|
|
76
|
+
# PyBuilder
|
|
77
|
+
.pybuilder/
|
|
78
|
+
target/
|
|
79
|
+
|
|
80
|
+
# Jupyter Notebook
|
|
81
|
+
.ipynb_checkpoints
|
|
82
|
+
|
|
83
|
+
# IPython
|
|
84
|
+
profile_default/
|
|
85
|
+
ipython_config.py
|
|
86
|
+
|
|
87
|
+
# pyenv
|
|
88
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
89
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
90
|
+
# .python-version
|
|
91
|
+
|
|
92
|
+
# pipenv
|
|
93
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
94
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
95
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
96
|
+
# install all needed dependencies.
|
|
97
|
+
#Pipfile.lock
|
|
98
|
+
|
|
99
|
+
# UV
|
|
100
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
101
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
102
|
+
# commonly ignored for libraries.
|
|
103
|
+
#uv.lock
|
|
104
|
+
|
|
105
|
+
# poetry
|
|
106
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
107
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
108
|
+
# commonly ignored for libraries.
|
|
109
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
110
|
+
#poetry.lock
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
#pdm.lock
|
|
115
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
116
|
+
# in version control.
|
|
117
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
118
|
+
.pdm.toml
|
|
119
|
+
.pdm-python
|
|
120
|
+
.pdm-build/
|
|
121
|
+
|
|
122
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
123
|
+
__pypackages__/
|
|
124
|
+
|
|
125
|
+
# Celery stuff
|
|
126
|
+
celerybeat-schedule
|
|
127
|
+
celerybeat.pid
|
|
128
|
+
|
|
129
|
+
# SageMath parsed files
|
|
130
|
+
*.sage.py
|
|
131
|
+
|
|
132
|
+
# Environments
|
|
133
|
+
.env
|
|
134
|
+
.venv
|
|
135
|
+
env/
|
|
136
|
+
venv/
|
|
137
|
+
ENV/
|
|
138
|
+
env.bak/
|
|
139
|
+
venv.bak/
|
|
140
|
+
|
|
141
|
+
# Spyder project settings
|
|
142
|
+
.spyderproject
|
|
143
|
+
.spyproject
|
|
144
|
+
|
|
145
|
+
# Rope project settings
|
|
146
|
+
.ropeproject
|
|
147
|
+
|
|
148
|
+
# mkdocs documentation
|
|
149
|
+
/site
|
|
150
|
+
|
|
151
|
+
# mypy
|
|
152
|
+
.mypy_cache/
|
|
153
|
+
.dmypy.json
|
|
154
|
+
dmypy.json
|
|
155
|
+
|
|
156
|
+
# Pyre type checker
|
|
157
|
+
.pyre/
|
|
158
|
+
|
|
159
|
+
# pytype static type analyzer
|
|
160
|
+
.pytype/
|
|
161
|
+
|
|
162
|
+
# Cython debug symbols
|
|
163
|
+
cython_debug/
|
|
164
|
+
|
|
165
|
+
# PyCharm
|
|
166
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
167
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
168
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
169
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
170
|
+
.idea/
|
|
171
|
+
|
|
172
|
+
# PyPI configuration file
|
|
173
|
+
.pypirc
|
|
174
|
+
|
|
175
|
+
# packed charms
|
|
176
|
+
.packed
|
|
177
|
+
|
|
178
|
+
# temporary directory for packing charms
|
|
179
|
+
.tmp
|
|
180
|
+
|
|
181
|
+
# uv.lock from example libraries as we don't commit these
|
|
182
|
+
.example/**/uv.lock
|
|
183
|
+
.tutorial/**/uv.lock
|
|
184
|
+
interfaces/.example/**/uv.lock
|
|
185
|
+
|
|
186
|
+
# Workshop lock file (machine-local state)
|
|
187
|
+
.workshop.lock
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: charmlibs-interfaces-ldap
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The charmlibs.interfaces.ldap package.
|
|
5
|
+
Project-URL: Documentation, https://canonical.com/juju/docs/charmlibs/reference/charmlibs/interfaces/ldap
|
|
6
|
+
Project-URL: Repository, https://github.com/canonical/charmlibs/tree/main/interfaces/ldap
|
|
7
|
+
Project-URL: Issues, https://github.com/canonical/charmlibs/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/canonical/charmlibs/blob/main/interfaces/ldap/CHANGELOG.md
|
|
9
|
+
Author: Identity Team at Canonical
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: ops<4,>=2.23.1
|
|
17
|
+
Requires-Dist: pydantic>=2.13.4
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# charmlibs.interfaces.ldap
|
|
21
|
+
|
|
22
|
+
The `ldap` interface library.
|
|
23
|
+
|
|
24
|
+
To install, add `charmlibs-interfaces-ldap` to your Python dependencies. Then in your Python code, import as:
|
|
25
|
+
|
|
26
|
+
```py
|
|
27
|
+
from charmlibs.interfaces import ldap
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
See the [reference documentation](https://canonical.com/juju/docs/charmlibs/reference/charmlibs/interfaces/ldap) for more.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# charmlibs.interfaces.ldap
|
|
2
|
+
|
|
3
|
+
The `ldap` interface library.
|
|
4
|
+
|
|
5
|
+
To install, add `charmlibs-interfaces-ldap` to your Python dependencies. Then in your Python code, import as:
|
|
6
|
+
|
|
7
|
+
```py
|
|
8
|
+
from charmlibs.interfaces import ldap
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
See the [reference documentation](https://canonical.com/juju/docs/charmlibs/reference/charmlibs/interfaces/ldap) for more.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# `ldap/v0`
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
|
|
5
|
+
This relation interface describes the expected behavior of any charm claiming to
|
|
6
|
+
be able to provide or consume the LDAP authentication configuration data.
|
|
7
|
+
|
|
8
|
+
## Glossary of LDAP Terms
|
|
9
|
+
|
|
10
|
+
| Abbreviation | Term |
|
|
11
|
+
|:------------:|:--------------------------:|
|
|
12
|
+
| DN | Distinguished Name |
|
|
13
|
+
| DIT | Directory Information Tree |
|
|
14
|
+
|
|
15
|
+
## Direction
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart TD
|
|
19
|
+
Requirer -- user, \ngroup --> Provider
|
|
20
|
+
Provider -- urls, \nbase_dn, \nbind_dn, \nbind_password_secret, \nauth_method, \nstarttls --> Requirer
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Behavior
|
|
24
|
+
|
|
25
|
+
Both the `provider` and the `requirer` need to adhere to a certain set of
|
|
26
|
+
criteria to be considered compatible with the `ldap` interface.
|
|
27
|
+
|
|
28
|
+
Sensitive information is transmitted through Juju Secrets rather than directly
|
|
29
|
+
through the relation databag(s).
|
|
30
|
+
|
|
31
|
+
### Provider
|
|
32
|
+
|
|
33
|
+
- Is expected to use `user` and `group` provided by the `requirer` to create a
|
|
34
|
+
bind DN in the DIT for the `requirer` to use for the `bind` operation. If
|
|
35
|
+
the `requirer` does not provide `user` and `group`, the `provider`
|
|
36
|
+
leverages `requirer`'s Juju application name and model name.
|
|
37
|
+
- Is expected to provide the `requirer` with necessary configuration for
|
|
38
|
+
performing LDAP authentications and operations.
|
|
39
|
+
- Is expected to update the application databag if any field's data is changed
|
|
40
|
+
in the `provider` charmed application.
|
|
41
|
+
|
|
42
|
+
### Requirer
|
|
43
|
+
|
|
44
|
+
- Is expected to optionally provide `user` and `group` for the `provider` to
|
|
45
|
+
generate the bind DN.
|
|
46
|
+
- Is expected to consume the LDAP configuration data provided by the `provider`
|
|
47
|
+
to configure the `requirer`'s charmed application.
|
|
48
|
+
|
|
49
|
+
> #### ⚠️ Use of special characters
|
|
50
|
+
> Try to avoid the special characters
|
|
51
|
+
> listed [here](https://datatracker.ietf.org/doc/html/rfc2253#section-2.4)
|
|
52
|
+
> for the `user` and `group` in the `requirer`'s databag.
|
|
53
|
+
|
|
54
|
+
## Relation Data
|
|
55
|
+
|
|
56
|
+
[\[Pydantic Schema\]](./schema.py)
|
|
57
|
+
|
|
58
|
+
### Provider
|
|
59
|
+
|
|
60
|
+
The `provider` provides LDAP URL, base DN, and bind DN, and LDAP
|
|
61
|
+
authentication method for the `requirer` to connect and perform LDAP operations.
|
|
62
|
+
It should be placed in the **application** databag.
|
|
63
|
+
|
|
64
|
+
#### Example
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
relation-info:
|
|
68
|
+
- endpoint: ldap
|
|
69
|
+
related-endpoint: ldap
|
|
70
|
+
application-data:
|
|
71
|
+
urls: [ldap://ldap.canonical.com:3893, ldap://ldap.ubuntu.com:3893]
|
|
72
|
+
base_dn: dc=canonical,dc=com
|
|
73
|
+
bind_dn: cn=app,ou=model,dc=canonical,dc=com
|
|
74
|
+
bind_password_secret: secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub6vubg2s77p3nio0
|
|
75
|
+
auth_method: simple
|
|
76
|
+
starttls: true
|
|
77
|
+
``````
|
|
78
|
+
|
|
79
|
+
### Requirer
|
|
80
|
+
|
|
81
|
+
The `requirer` provides LDAP client information. It should be placed in the
|
|
82
|
+
**application** databag.
|
|
83
|
+
|
|
84
|
+
#### Example
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
relation-info:
|
|
88
|
+
- endpoint: ldap
|
|
89
|
+
related-endpoint: ldap
|
|
90
|
+
application-data:
|
|
91
|
+
user: sssd
|
|
92
|
+
group: machine-localhost
|
|
93
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: ldap
|
|
2
|
+
version: 0
|
|
3
|
+
status: draft
|
|
4
|
+
lib: charmlibs.interfaces.ldap
|
|
5
|
+
summary: Configure and connect to a Lightweight Directory Access Protocol (LDAP) server.
|
|
6
|
+
description: |
|
|
7
|
+
The `ldap` interface supports sharing configuration and connection information for a Lightweight Directory Access Protocol (LDAP) server.
|
|
8
|
+
The provider is responsible for sharing the LDAP URL and other information needed for the requirer to connect and perform LDAP operations.
|
|
9
|
+
|
|
10
|
+
providers:
|
|
11
|
+
- name: glauth-k8s
|
|
12
|
+
url: https://github.com/canonical/glauth-k8s-operator
|
|
13
|
+
- name: authentik-ldap-outpost
|
|
14
|
+
url: https://github.com/canonical/authentik-ldap-outpost-operator
|
|
15
|
+
requirers:
|
|
16
|
+
- name: sssd
|
|
17
|
+
url: https://github.com/canonical/sssd-operator
|
|
18
|
+
|
|
19
|
+
maintainer: identity
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Copyright 2026 Canonical Ltd.
|
|
2
|
+
# See LICENSE file for licensing details.
|
|
3
|
+
|
|
4
|
+
"""LDAP relation schema definitions.
|
|
5
|
+
|
|
6
|
+
This file defines the schemas for the provider and requirer sides of this
|
|
7
|
+
relation interface.
|
|
8
|
+
|
|
9
|
+
It must expose two interfaces.schema_base.DataBagSchema subclasses called:
|
|
10
|
+
- ProviderSchema
|
|
11
|
+
- RequirerSchema
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from interface_tester.schema_base import DataBagSchema
|
|
15
|
+
from pydantic import AnyUrl, BaseModel, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LdapProviderData(BaseModel):
|
|
19
|
+
"""LDAP provider relation data schema."""
|
|
20
|
+
|
|
21
|
+
urls: list[AnyUrl] = Field(
|
|
22
|
+
description='List of LDAP URLs',
|
|
23
|
+
title='LDAP URLs',
|
|
24
|
+
example=['ldap://ldap.canonical.com:3893', 'ldap://ldap.ubuntu.com:3893'],
|
|
25
|
+
)
|
|
26
|
+
base_dn: str = Field(
|
|
27
|
+
description='The base entry as the starting point for LDAP search operation',
|
|
28
|
+
title='Base DN',
|
|
29
|
+
example='dc=canonical,dc=com',
|
|
30
|
+
)
|
|
31
|
+
bind_dn: str = Field(
|
|
32
|
+
description='The distinguished name (DN) of the bind account',
|
|
33
|
+
title='Bind DN',
|
|
34
|
+
example='cn=admin,ou=engineering,dc=canonical,dc=com',
|
|
35
|
+
)
|
|
36
|
+
bind_password_secret: str = Field(
|
|
37
|
+
description="The juju secret ID of the bind account's password",
|
|
38
|
+
example='secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub6vubg2s77p3nio0',
|
|
39
|
+
)
|
|
40
|
+
auth_method: str = Field(
|
|
41
|
+
description='The LDAP authentication method',
|
|
42
|
+
title='Authentication Method',
|
|
43
|
+
example='simple',
|
|
44
|
+
)
|
|
45
|
+
starttls: bool = Field(
|
|
46
|
+
description='The indicator of StartTLS operation enabled or not',
|
|
47
|
+
title='StartTLS',
|
|
48
|
+
example=True,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class LdapRequirerData(BaseModel):
|
|
53
|
+
"""LDAP requirer relation data schema."""
|
|
54
|
+
|
|
55
|
+
user: str | None = Field(
|
|
56
|
+
description='The user name provided by the requirer charmed operator',
|
|
57
|
+
)
|
|
58
|
+
group: str | None = Field(
|
|
59
|
+
description='The group name provided by the requirer charmed operator',
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ProviderSchema(DataBagSchema):
|
|
64
|
+
"""The schema for the provider side of the ldap interface."""
|
|
65
|
+
|
|
66
|
+
app: LdapProviderData
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class RequirerSchema(DataBagSchema):
|
|
70
|
+
"""The schema for the requirer side of the ldap interface."""
|
|
71
|
+
|
|
72
|
+
app: LdapRequirerData
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "charmlibs-interfaces-ldap"
|
|
3
|
+
description = "The charmlibs.interfaces.ldap package."
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
authors = [
|
|
7
|
+
{name="Identity Team at Canonical"},
|
|
8
|
+
]
|
|
9
|
+
license = "Apache-2.0"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Operating System :: POSIX :: Linux",
|
|
14
|
+
"Development Status :: 5 - Production/Stable",
|
|
15
|
+
]
|
|
16
|
+
dynamic = ["version"]
|
|
17
|
+
dependencies = [
|
|
18
|
+
# Libraries should use clear but wide dependency bounds to avoid overly constraining charms.
|
|
19
|
+
# Ops 3 is backwards compatible with Ops 2, but drops Python 3.8 support.
|
|
20
|
+
# Ops 3 has new features not present in Ops 2.23 (the last Ops 2 feature release).
|
|
21
|
+
# See the Ops 2.23 maintenance branch changelog and the Ops 3 changelog for current information:
|
|
22
|
+
# - https://github.com/canonical/operator/blob/2.23-maintenance/CHANGES.md
|
|
23
|
+
# - https://github.com/canonical/operator/blob/main/CHANGES.md
|
|
24
|
+
# Set the dependency bounds according to the features and fixes your library needs.
|
|
25
|
+
"ops>=2.23.1,<4",
|
|
26
|
+
"pydantic>=2.13.4",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
lint = [ # installed for `just lint interfaces/ldap` (unit, functional, and integration are also installed)
|
|
31
|
+
# "typing_extensions",
|
|
32
|
+
]
|
|
33
|
+
unit = [ # installed for `just unit interfaces/ldap`
|
|
34
|
+
"ops[testing]",
|
|
35
|
+
"charmlibs-interfaces-ldap",
|
|
36
|
+
]
|
|
37
|
+
functional = [ # installed for `just functional interfaces/ldap`
|
|
38
|
+
]
|
|
39
|
+
integration = [ # installed for `just integration interfaces/ldap`
|
|
40
|
+
"jubilant",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
"Documentation" = "https://canonical.com/juju/docs/charmlibs/reference/charmlibs/interfaces/ldap"
|
|
45
|
+
"Repository" = "https://github.com/canonical/charmlibs/tree/main/interfaces/ldap"
|
|
46
|
+
"Issues" = "https://github.com/canonical/charmlibs/issues"
|
|
47
|
+
"Changelog" = "https://github.com/canonical/charmlibs/blob/main/interfaces/ldap/CHANGELOG.md"
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["hatchling"]
|
|
51
|
+
build-backend = "hatchling.build"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.targets.wheel]
|
|
54
|
+
packages = ["src/charmlibs"]
|
|
55
|
+
|
|
56
|
+
[tool.hatch.version]
|
|
57
|
+
path = "src/charmlibs/interfaces/ldap/_version.py"
|
|
58
|
+
|
|
59
|
+
[tool.uv.sources]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
extend = "../../pyproject.toml"
|
|
64
|
+
src = ["src", "tests/unit", "tests/functional", "tests/integration"] # correctly sort local imports in tests
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint.extend-per-file-ignores]
|
|
67
|
+
# add additional per-file-ignores here to avoid overriding repo-level config
|
|
68
|
+
"tests/**/*" = [
|
|
69
|
+
# "E501", # line too long
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[tool.pyright]
|
|
73
|
+
extends = "../../pyproject.toml"
|
|
74
|
+
include = ["src", "tests"]
|
|
75
|
+
pythonVersion = "3.10" # check no python > 3.10 features are used
|
|
76
|
+
reportUntypedFunctionDecorator = false
|
|
77
|
+
reportCallIssue = false
|
|
78
|
+
reportUnknownVariableType = false
|
|
79
|
+
reportIncompatibleMethodOverride = false
|
|
80
|
+
reportAssignmentType = false
|
|
81
|
+
reportUnknownMemberType = false
|
|
82
|
+
reportUnknownArgumentType = false
|
|
83
|
+
reportUnknownParameterType = false
|
|
84
|
+
reportMissingTypeArgument = false
|
|
85
|
+
reportDeprecated = false
|
|
86
|
+
reportUnnecessaryTypeIgnoreComment = false
|
|
87
|
+
reportUnnecessaryComparison = false
|
|
88
|
+
reportArgumentType = false
|
|
89
|
+
reportReturnType = false
|
|
90
|
+
reportGeneralTypeIssues = false
|
|
91
|
+
|
|
92
|
+
[tool.charmlibs.functional]
|
|
93
|
+
ubuntu = [] # ubuntu versions to run functional tests with, e.g. "24.04" (defaults to just "latest")
|
|
94
|
+
pebble = [] # pebble versions to run functional tests with, e.g. "v1.0.0", "master" (defaults to no pebble versions)
|
|
95
|
+
sudo = false # whether to run functional tests with sudo (defaults to false)
|
|
96
|
+
|
|
97
|
+
[tool.charmlibs.integration]
|
|
98
|
+
# tags to run integration tests with (defaults to running once with no tag, i.e. tags = [''])
|
|
99
|
+
# Available in CI in tests/integration/pack.sh and integration tests as CHARMLIBS_TAG
|
|
100
|
+
tags = [] # Not used by the pack.sh and integration tests generated by the template
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Copyright 2026 Canonical Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""The charmlibs.interfaces.ldap package.
|
|
16
|
+
|
|
17
|
+
Juju Charm Library for the `ldap` Juju Interface
|
|
18
|
+
================================================
|
|
19
|
+
|
|
20
|
+
This Juju charm library contains the Provider and Requirer classes for handling
|
|
21
|
+
the ``ldap`` interface.
|
|
22
|
+
|
|
23
|
+
Requirer Charm
|
|
24
|
+
--------------
|
|
25
|
+
|
|
26
|
+
The requirer charm is expected to:
|
|
27
|
+
|
|
28
|
+
- Provide information for the provider charm to deliver LDAP related
|
|
29
|
+
information in the juju integration, in order to communicate with the LDAP
|
|
30
|
+
server and authenticate LDAP operations
|
|
31
|
+
- Listen to the custom juju event ``LdapReadyEvent`` to obtain the LDAP
|
|
32
|
+
related information from the integration
|
|
33
|
+
- Listen to the custom juju event ``LdapUnavailableEvent`` to handle the
|
|
34
|
+
situation when the LDAP integration is broken
|
|
35
|
+
|
|
36
|
+
.. code-block:: python
|
|
37
|
+
|
|
38
|
+
from charmlibs.interfaces.ldap import (
|
|
39
|
+
LdapRequirer,
|
|
40
|
+
LdapReadyEvent,
|
|
41
|
+
LdapUnavailableEvent,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
class RequirerCharm(CharmBase):
|
|
45
|
+
# LDAP requirer charm that integrates with an LDAP provider charm.
|
|
46
|
+
|
|
47
|
+
def __init__(self, *args):
|
|
48
|
+
super().__init__(*args)
|
|
49
|
+
|
|
50
|
+
self.ldap_requirer = LdapRequirer(self)
|
|
51
|
+
self.framework.observe(
|
|
52
|
+
self.ldap_requirer.on.ldap_ready,
|
|
53
|
+
self._on_ldap_ready,
|
|
54
|
+
)
|
|
55
|
+
self.framework.observe(
|
|
56
|
+
self.ldap_requirer.on.ldap_unavailable,
|
|
57
|
+
self._on_ldap_unavailable,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def _on_ldap_ready(self, event: LdapReadyEvent) -> None:
|
|
61
|
+
# Consume the LDAP related information
|
|
62
|
+
ldap_data = self.ldap_requirer.consume_ldap_relation_data(
|
|
63
|
+
relation=event.relation,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Configure the LDAP requirer charm
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
def _on_ldap_unavailable(self, event: LdapUnavailableEvent) -> None:
|
|
70
|
+
# Handle the situation where the LDAP integration is broken
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
As shown above, the library offers custom juju events to handle specific
|
|
74
|
+
situations, which are listed below:
|
|
75
|
+
|
|
76
|
+
- ``ldap_ready``: event emitted when the LDAP related information is ready for
|
|
77
|
+
requirer charm to use.
|
|
78
|
+
- ``ldap_unavailable``: event emitted when the LDAP integration is broken.
|
|
79
|
+
|
|
80
|
+
Additionally, the requirer charmed operator needs to declare the ``ldap``
|
|
81
|
+
interface in the ``metadata.yaml``:
|
|
82
|
+
|
|
83
|
+
.. code-block:: yaml
|
|
84
|
+
|
|
85
|
+
requires:
|
|
86
|
+
ldap:
|
|
87
|
+
interface: ldap
|
|
88
|
+
|
|
89
|
+
Provider Charm
|
|
90
|
+
--------------
|
|
91
|
+
|
|
92
|
+
The provider charm is expected to:
|
|
93
|
+
|
|
94
|
+
- Use the information provided by the requirer charm to provide LDAP related
|
|
95
|
+
information for the requirer charm to connect and authenticate to the LDAP
|
|
96
|
+
server
|
|
97
|
+
- Listen to the custom juju event ``LdapRequestedEvent`` to offer LDAP related
|
|
98
|
+
information in the integration
|
|
99
|
+
|
|
100
|
+
.. code-block:: python
|
|
101
|
+
|
|
102
|
+
from charmlibs.interfaces.ldap import (
|
|
103
|
+
LdapProvider,
|
|
104
|
+
LdapRequestedEvent,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
class ProviderCharm(CharmBase):
|
|
108
|
+
# LDAP provider charm.
|
|
109
|
+
|
|
110
|
+
def __init__(self, *args):
|
|
111
|
+
super().__init__(*args)
|
|
112
|
+
|
|
113
|
+
self.ldap_provider = LdapProvider(self)
|
|
114
|
+
self.framework.observe(
|
|
115
|
+
self.ldap_provider.on.ldap_requested,
|
|
116
|
+
self._on_ldap_requested,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def _on_ldap_requested(self, event: LdapRequestedEvent) -> None:
|
|
120
|
+
# Consume the information provided by the requirer charm
|
|
121
|
+
requirer_data = event.data
|
|
122
|
+
|
|
123
|
+
# Prepare the LDAP related information using the requirer's data
|
|
124
|
+
ldap_data = ...
|
|
125
|
+
|
|
126
|
+
# Update the integration data
|
|
127
|
+
self.ldap_provider.update_relations_app_data(
|
|
128
|
+
relation.id,
|
|
129
|
+
ldap_data,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
As shown above, the library offers custom juju events to handle specific
|
|
133
|
+
situations, which are listed below:
|
|
134
|
+
|
|
135
|
+
- ``ldap_requested``: event emitted when the requirer charm is requesting the
|
|
136
|
+
LDAP related information in order to connect and authenticate to the LDAP server.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
from ._ldap import (
|
|
140
|
+
LdapProvider,
|
|
141
|
+
LdapProviderData,
|
|
142
|
+
LdapReadyEvent,
|
|
143
|
+
LdapRequestedEvent,
|
|
144
|
+
LdapRequirer,
|
|
145
|
+
LdapRequirerData,
|
|
146
|
+
LdapUnavailableEvent,
|
|
147
|
+
)
|
|
148
|
+
from ._version import __version__ as __version__
|
|
149
|
+
|
|
150
|
+
__all__ = [
|
|
151
|
+
'LdapProvider',
|
|
152
|
+
'LdapProviderData',
|
|
153
|
+
'LdapReadyEvent',
|
|
154
|
+
'LdapRequestedEvent',
|
|
155
|
+
'LdapRequirer',
|
|
156
|
+
'LdapRequirerData',
|
|
157
|
+
'LdapUnavailableEvent',
|
|
158
|
+
]
|