You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a third OpenIDM repository backend — a new bundle openidm-repo-ldap — that persists OpenIDM objects in an LDAPv3 directory, alongside the existing embedded OrientDB (openidm-repo-orientdb) and relational JDBC (openidm-repo-jdbc) backends.
Many deployments already run an LDAPv3 directory (OpenDJ) as the system of record for identities. Letting OpenIDM store its identity objects natively in that directory — as real inetOrgPerson/groupOfNames entries rather than as opaque blobs — makes the data usable by other LDAP clients, indexable, and searchable with native directory tooling, while reusing the same repository SPI OpenIDM already exposes.
Current backends (context)
OpenIDM selects a repository purely by the presence of a conf/repo.<type>.json config file; whichever bundle registers a RepoBootService first wins (no central switch). Any backend implements one service class exposing three interfaces: CREST RequestHandler (7 handleXxx methods), RepositoryService and RepoBootService (CRUD + query, with mandatory query-all-ids). MVCC is enforced via _rev (create returns a _rev; update/delete require the caller's revision, mismatch → PreconditionFailedException).
Proposed design
Storage model — explicit mapping. Each resource type maps to real LDAP objectClasses/attributes (e.g. managed/user → inetOrgPerson); every JSON field maps to a dedicated LDAP attribute. This mirrors the JDBC explicitMapping/MappedTableHandler model (its objectToColumn becomes objectToAttribute). Deeply nested/opaque sub-structures are JSON-encoded into a dedicated attribute per mapping (per-field escape hatch, not a whole-object blob).
LDAP SDK — OpenDJ opendj-core + opendj-grizzly 5.1.1 (Open Identity Platform fork, already reachable via the openicf BOM → opendj-parent:5.1.1). Its async, Promise-based Connection/LDAPConnectionFactory API maps cleanly onto CREST promises.
MVCC via an auxiliary objectClass fr-idm-metadata carrying an fr-idm-rev attribute, with compare-and-set enforced by the LDAP Assertion Control (RFC 4528): assert (fr-idm-rev=<expected>) on modify/delete; assertionFailed → PreconditionFailedException.
Query translation._queryFilter → RFC 4515 LDAP filter via a new QueryFilterVisitor<Filter, …, JsonPointer> (present → (a=*), startsWith → (a=v*), contains → (a=*v*), eq/ge/le/…). _queryId → a preconfigured search spec (base/scope/filter template) with token substitution reusing OpenIDM's TokenHandler. _queryExpression → raw LDAP filter. Paging via Simple Paged Results Control (RFC 2696), sorting via Server-Side Sort Control (RFC 2891).
Deployment — both modes. External LDAP by default (repo.ldap.json → host/port/bindDN/baseDN); optional embedded OpenDJ (embeddedServer.enabled=true, via opendj-embedded) so it works out of the box for dev/tests, like embedded OrientDB. OrientDB stays the default; LDAP is opt-in by swapping the repo config (same staging approach as JDBC's db/<type>/conf/).
New module layout (openidm-repo-ldap/)
LDAPRepoService — main service (the three interfaces + CRUD + getRepoBootService).
A pure explicit mapping needs an entry per resource type OpenIDM persists — not only identity types (users/roles/groups, which fit inetOrgPerson/groupOfNames natively) but also internal ones (config, link, relationship, cluster, scheduler, locks, audit, …), some of which carry arbitrary nested JSON. The MVP would cover identity types natively plus the internal types required for OpenIDM to boot (config/link/relationship/cluster/scheduler), using a dedicated JSON-encoded attribute for uncovered/nested properties, and document that full backend parity needs the complete mapping set.
Scope
In (MVP): full openidm-repo-ldap bundle — CRUD, MVCC (RFC 4528), query-all-ids + _queryFilter→RFC 4515 + _queryId/_queryExpression, connection pool, external + embedded modes, distribution wiring, embedded-OpenDJ tests, docs.
Out: generic (JSON-blob) storage model; explicit mappings for every internal type (audit, locks, …); making LDAP the default repository (stays opt-in).
Open questions for the community
Preferred _id → RDN strategy: a dedicated stable id attribute (fr-idm-id=<uuid>) vs a real field (uid) when guaranteed stable/unique?
_rev carrier: custom fr-idm-rev aux objectClass vs OpenDJ's etag operational attribute for MVCC?
Which internal resource types must ship with mappings in the first release to be genuinely usable?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
Add a third OpenIDM repository backend — a new bundle
openidm-repo-ldap— that persists OpenIDM objects in an LDAPv3 directory, alongside the existing embedded OrientDB (openidm-repo-orientdb) and relational JDBC (openidm-repo-jdbc) backends.Vote to raise the priority 🖐️
Motivation
Many deployments already run an LDAPv3 directory (OpenDJ) as the system of record for identities. Letting OpenIDM store its identity objects natively in that directory — as real
inetOrgPerson/groupOfNamesentries rather than as opaque blobs — makes the data usable by other LDAP clients, indexable, and searchable with native directory tooling, while reusing the same repository SPI OpenIDM already exposes.Current backends (context)
OpenIDM selects a repository purely by the presence of a
conf/repo.<type>.jsonconfig file; whichever bundle registers aRepoBootServicefirst wins (no central switch). Any backend implements one service class exposing three interfaces: CRESTRequestHandler(7handleXxxmethods),RepositoryServiceandRepoBootService(CRUD +query, with mandatoryquery-all-ids). MVCC is enforced via_rev(create returns a_rev; update/delete require the caller's revision, mismatch →PreconditionFailedException).Proposed design
managed/user→inetOrgPerson); every JSON field maps to a dedicated LDAP attribute. This mirrors the JDBCexplicitMapping/MappedTableHandlermodel (itsobjectToColumnbecomesobjectToAttribute). Deeply nested/opaque sub-structures are JSON-encoded into a dedicated attribute per mapping (per-field escape hatch, not a whole-object blob).opendj-core+opendj-grizzly5.1.1 (Open Identity Platform fork, already reachable via theopenicfBOM →opendj-parent:5.1.1). Its async,Promise-basedConnection/LDAPConnectionFactoryAPI maps cleanly onto CREST promises.fr-idm-metadatacarrying anfr-idm-revattribute, with compare-and-set enforced by the LDAP Assertion Control (RFC 4528): assert(fr-idm-rev=<expected>)on modify/delete;assertionFailed→PreconditionFailedException._queryFilter→ RFC 4515 LDAP filter via a newQueryFilterVisitor<Filter, …, JsonPointer>(present →(a=*), startsWith →(a=v*), contains →(a=*v*), eq/ge/le/…)._queryId→ a preconfigured search spec (base/scope/filter template) with token substitution reusing OpenIDM'sTokenHandler._queryExpression→ raw LDAP filter. Paging via Simple Paged Results Control (RFC 2696), sorting via Server-Side Sort Control (RFC 2891).repo.ldap.json→ host/port/bindDN/baseDN); optional embedded OpenDJ (embeddedServer.enabled=true, viaopendj-embedded) so it works out of the box for dev/tests, like embedded OrientDB. OrientDB stays the default; LDAP is opt-in by swapping the repo config (same staging approach as JDBC'sdb/<type>/conf/).New module layout (
openidm-repo-ldap/)LDAPRepoService— main service (the three interfaces + CRUD +getRepoBootService).Activator— bootstrapRepoBootServiceregistration (bootrepo.ldap).LDAPClient— connection factory/pool, SSL/StartTLS.mapping/—ResourceMapping,MappingConfig,EntryMapper(JSON ↔Entry, DN computation, id/rev metadata).query/—Queries,LdapQueryFilterVisitor(+ paging/sort controls).EmbeddedOpenDJService— optional embedded server.LdapErrorMapper— LDAPResultCode→ CRESTResourceException.schema/fr-idm-metadata.ldif— custom schema for the metadata aux objectClass.query-all-ids,_queryFilter, MVCC conflict, paging.Wiring changes
pom.xml; add it as aruntimedependency ofopenidm-zip(auto-included into/openidm/bundle).repo.ldap.json(+ schema LDIF) underopenidm-zip/.../db/ldap/conf/as staging (not the active default).HealthServicerequired-services/bundles regexes(orientdb|jdbc)→(orientdb|jdbc|ldap)so startup with the LDAP repo reports READY.Example
repo.ldap.json{ "embeddedServer": { "enabled": false, "port": 1389, "baseDN": "dc=openidm" }, "connection": { "host": "&{openidm.repo.host}", "port": "&{openidm.repo.port}", "bindDN": "cn=Directory Manager", "bindPassword": { "$crypto": { } }, "useSSL": false, "useStartTLS": false, "poolMinSize": 5, "poolMaxSize": 20 }, "baseDN": "dc=openidm", "resourceMapping": { "explicitMapping": { "managed/user": { "baseDN": "ou=user,ou=managed", "objectClasses": ["top","person","organizationalPerson","inetOrgPerson","fr-idm-metadata"], "rdnAttribute": "fr-idm-id", "objectToAttribute": { "_id":"fr-idm-id","_rev":"fr-idm-rev", "userName":"uid","givenName":"givenName","sn":"sn","mail":"mail" } } } }, "queries": { "query-all-ids": { "base":"${_resource}", "scope":"sub", "filter":"(objectClass=*)" } } }Known constraint
A pure explicit mapping needs an entry per resource type OpenIDM persists — not only identity types (users/roles/groups, which fit
inetOrgPerson/groupOfNamesnatively) but also internal ones (config,link,relationship,cluster,scheduler,locks,audit, …), some of which carry arbitrary nested JSON. The MVP would cover identity types natively plus the internal types required for OpenIDM to boot (config/link/relationship/cluster/scheduler), using a dedicated JSON-encoded attribute for uncovered/nested properties, and document that full backend parity needs the complete mapping set.Scope
openidm-repo-ldapbundle — CRUD, MVCC (RFC 4528),query-all-ids+_queryFilter→RFC 4515 +_queryId/_queryExpression, connection pool, external + embedded modes, distribution wiring, embedded-OpenDJ tests, docs.Open questions for the community
_id→ RDN strategy: a dedicated stable id attribute (fr-idm-id=<uuid>) vs a real field (uid) when guaranteed stable/unique?_revcarrier: customfr-idm-revaux objectClass vs OpenDJ'setagoperational attribute for MVCC?Beta Was this translation helpful? Give feedback.
All reactions