Source: projects/identity-management/ldap-shop-seeding/README.md
> Source: projects/identity-management/ldap-shop-seeding/README.md
LDAP Shop Seeding - Plan v0.1
Goal
Create a small fictional LDAP entitlement catalog in the sandbox OpenDJ directory so One Identity Manager can be used to test:
- LDAP group synchronization into
LDAPGroup - LDAP account-to-group assignments through
LDAPAccountInLDAPGroup - requestable LDAP group products in the IT Shop
- product-node generation through
BaseTreeHasLDAPGroup/ITShopOrgHasLDAPGroup - behavior differences between direct LDAP assignment and IT Shop-originated assignment
No LDAP or OneIM mutation is part of this plan. Implementation should be a separate, locked sandbox change.
Current Sandbox Evidence
Live OneIM v10 DB checks on 2026-04-27 confirm these LDAP tables exist:
| Area | Tables / views |
|---|---|
| LDAP objects | LDAPAccount, LDAPGroup, LDAPContainer |
| LDAP memberships | LDAPAccountInLDAPGroup, LDAPGroupInLDAPGroup, LDAPGroupCollection, LDAPGroupExclusion |
| IT Shop publication | BaseTreeHasLDAPGroup, ITShopOrgHasLDAPGroup |
LDAPGroup has the IT Shop publication columns needed for the same basic pattern used for AD groups:
UID_AccProductIsForITShopIsITShopOnly
Current OpenDJ/OIM inventory, checked read-only on 2026-04-27:
| Object type | Current state | Conflict result |
|---|---|---|
| Containers | dc=ldap,dc=com, ou=People, ou=Groups | ou=oim-managed,dc=ldap,dc=com does not exist yet |
| Accounts | 14 inetOrgPerson entries under ou=People; user IDs like ANDREASN, BERITA, SER_OIM | planned ldap.* user IDs do not collide |
| Groups | 4 groupOfNames entries under ou=Groups: Linux Admins, Oracle DBA, Team Development Sweden, Team IT Sweden | planned ldap_* group CNs do not collide |
| OIM memberships | LDAPAccountInLDAPGroup = 0, LDAPGroupInLDAPGroup = 0 | membership import still needs a focused proof test |
Design decision from this inventory: keep the seed in a new ou=oim-managed,dc=ldap,dc=com subtree instead of adding to the existing ou=People / ou=Groups containers. This avoids collisions and makes cleanup/reset unambiguous.
No LDAP-specific PWODecisionMethod was found by name. For v1, prefer a generic approval policy over reusing an AD-named policy.
Recommended v1 approval policy:
| UID | Ident |
|---|---|
QER-D00B0CE0F1DA984A83D4E565D2880067 | Recipient's manager and product owner (with peer group analysis) |
No LDAP-specific policy was found by name. Avoid reusing the AD-named policy for LDAP products.
If sandbox manager/product-owner routing is incomplete, use a simpler temporary test policy only for cart-flow validation.
LDAP DIT Structure
Discovery result from 2026-04-27:
dn:
namingContexts: dc=ldap,dc=com
vendorName: Open Identity Platform Community
vendorVersion: OpenDJ Server 5.1.0
Use dc=ldap,dc=com below for the discovered writable suffix.
Proposed project-owned subtree:
ou=oim-managed,dc=ldap,dc=com
ou=people
ou=employees
ou=service-accounts
ou=anchors
ou=groups
ou=applications
ou=docsuite
ou=codeforge
ou=packagehub
ou=observatory
ou=learnlab
ou=platform
ou=business-roles
ou=access-bundles
ou=distribution
Design choices:
- Keep LDAP separate from the existing AD
OU=OIM-Managedtree so connector behavior is easy to compare. - Use a flat group CN naming scheme inside typed containers; do not encode every app as a deep tree unless the LDAP sync mapping benefits from it.
- Add a stable marker to
description:[OIM-SANDBOX-SEED:ldap-shop-seeding:v1]. - Prefer static groups in v1. Do not create a separate edge-case OU in v1; it adds structure without helping the first membership and IT Shop tests.
- Access OpenDJ locally on the VM through
localhost:1389. From the workstation,im.sandbox.local:389/636is Active Directory, whileim.sandbox.local:1389timed out during research.
LDAP Entry Model
Recommended group object class for v1:
objectClass: top
objectClass: groupOfNames
cn: ldap_app_docsuite_reader
description: [OIM-SANDBOX-SEED:ldap-shop-seeding:v1] ...
Why groupOfNames:
- Existing sandbox OpenDJ groups already use
groupOfNamesunderou=Groups,dc=ldap,dc=com. - Common LDAP group pattern.
- Membership is DN-based through
member, but v1 does not seed members because LDAP accounts are provisioned by OneIM account definitions. - The current OneIM synchronization maps
groupOfNames.memberto the LDAP-group virtual membership property. - OpenDJ schema in this sandbox has
memberasMAY, notMUST; emptygroupOfNamesentries are valid.
LDAP account model:
LDAP accounts are not created by this seed. They should be provisioned from OneIM by assigning or ordering the related LDAP account definition. The ou=people subtree remains as a target area for account-definition provisioning tests.
LDAP Account Provisioning
Do not seed LDAP accounts directly in OpenDJ for this project. Use OneIM account definitions so later sync evidence distinguishes:
- LDAP entitlements seeded externally in OpenDJ.
- LDAP accounts provisioned by OneIM.
- Group assignments added by assignment/order workflows instead of unmanaged seed data.
Fictional LDAP Entitlement Catalog
Total v1 groups: 41.
Application Groups - 20
Five fictional LDAP-backed applications with four tiers each:
| App | Code | Groups |
|---|---|---|
| DocSuite Wiki | docsuite | ldap_app_docsuite_reader, ldap_app_docsuite_contributor, ldap_app_docsuite_publisher, ldap_app_docsuite_admin |
| CodeForge Repos | codeforge | ldap_app_codeforge_reader, ldap_app_codeforge_developer, ldap_app_codeforge_maintainer, ldap_app_codeforge_admin |
| PackageHub Registry | packagehub | ldap_app_packagehub_reader, ldap_app_packagehub_publisher, ldap_app_packagehub_curator, ldap_app_packagehub_admin |
| Observatory Metrics | observatory | ldap_app_observatory_viewer, ldap_app_observatory_operator, ldap_app_observatory_editor, ldap_app_observatory_admin |
| LearnLab LMS | learnlab | ldap_app_learnlab_learner, ldap_app_learnlab_author, ldap_app_learnlab_instructor, ldap_app_learnlab_admin |
Platform Groups - 6
| Group | Purpose |
|---|---|
ldap_platform_linux_ssh_users | Linux SSH access simulation |
ldap_platform_linux_sudo_readonly | low-risk privileged command simulation |
ldap_platform_linux_sudo_operator | higher-risk privileged command simulation |
ldap_platform_file_projects_rw | project share read/write simulation |
ldap_platform_secrets_readers | secrets read access simulation |
ldap_platform_service_accounts | technical account grouping |
Business-Role Marker Groups - 6
These are LDAP marker groups, not native OneIM business roles:
| Group | Purpose |
|---|---|
ldap_br_engineering | engineering population marker |
ldap_br_operations | operations population marker |
ldap_br_finance | finance population marker |
ldap_br_hr | HR population marker |
ldap_br_sales | sales population marker |
ldap_br_support | support population marker |
Access Bundle Groups - 5
These can later become native ESet system roles, but v1 keeps them as LDAP groups for connector testing:
| Group | Intended included groups |
|---|---|
ldap_bundle_workforce_base | docsuite reader, learnlab learner |
ldap_bundle_engineering_core | codeforge developer, packagehub reader, observatory viewer |
ldap_bundle_ops_oncall | observatory operator, linux ssh users, file projects rw |
ldap_bundle_analytics_user | observatory viewer, docsuite reader |
ldap_bundle_privileged_support | linux sudo operator, secrets readers |
Distribution-List-Shaped Groups - 4
These are LDAP static groups only, not mail-enabled distribution lists:
| Group | Purpose |
|---|---|
ldap_dl_allstaff | all-staff style test group |
ldap_dl_engineering | engineering communication group |
ldap_dl_operations | operations communication group |
ldap_dl_release_announce | release announcement group |
Initial Memberships
Do not seed initial memberships in v1. Keep all 41 LDAP groups empty until OneIM has synced them and account-definition provisioning is in place.
Expected tests:
- Provision an LDAP account from OneIM by account definition.
- Request a published LDAP group in IT Shop and verify the assignment path.
- If direct LDAP membership import still needs proof, add and remove a temporary membership only after a OneIM-provisioned account exists.
- Test nested group sync only after direct static memberships are understood.
IT Shop Structure
Create these service categories in AccProductGroup:
| Category | Purpose |
|---|---|
| Sandbox LDAP Applications | Application groups |
| Sandbox LDAP Platform Access | platform groups |
| Sandbox LDAP Business Roles | business-role marker groups |
| Sandbox LDAP Access Bundles | bundle/placeholder groups |
| Sandbox LDAP Distribution Lists | distribution-list-shaped groups |
Create matching BO shelves directly below Identity & Access Lifecycle:
Identity & Access Lifecycle
Sandbox LDAP Applications (BO)
Sandbox LDAP Platform Access (BO)
Sandbox LDAP Business Roles (BO)
Sandbox LDAP Access Bundles (BO)
Sandbox LDAP Distribution Lists (BO)
Do not create nested BO shelves. The existing IT Shop learning showed BO below BO is rejected by trigger logic.
IT Shop Publication Mapping
After LDAP sync creates LDAPGroup rows:
1. Create one AccProduct per publishable LDAPGroup.
2. Set AccProduct.UID_AccProductGroup to the matching sandbox LDAP service category.
3. Set AccProduct.UID_PWODecisionMethod to the selected generic approval policy.
4. Update LDAPGroup.UID_AccProduct.
5. Set LDAPGroup.IsForITShop = 1.
6. Keep LDAPGroup.IsITShopOnly = 0 in v1, so direct LDAP assignment testing remains possible.
7. Insert the shelf relation through BaseTreeHasLDAPGroup.
8. Let product-node processing create ITShopOrg PR nodes.
Expected assignment table:
| LDAP group category | OIM shelf | Relation table/view |
|---|---|---|
| Application groups | Sandbox LDAP Applications | BaseTreeHasLDAPGroup / ITShopOrgHasLDAPGroup |
| Platform groups | Sandbox LDAP Platform Access | BaseTreeHasLDAPGroup / ITShopOrgHasLDAPGroup |
| Business-role markers | Sandbox LDAP Business Roles | BaseTreeHasLDAPGroup / ITShopOrgHasLDAPGroup |
| Bundles | Sandbox LDAP Access Bundles | BaseTreeHasLDAPGroup / ITShopOrgHasLDAPGroup |
| Distribution-list-shaped groups | Sandbox LDAP Distribution Lists | BaseTreeHasLDAPGroup / ITShopOrgHasLDAPGroup |
Implementation Phases
Phase 0 - Discovery
- Confirm OpenDJ local access path and credentials before mutation.
- OpenDJ suffix is
dc=ldap,dc=com; targetou=oim-managed,dc=ldap,dc=com. - Current OIM sync metadata indicates whole-suffix synchronization: system connection
im.sandbox.local:1389, initial start infoSynchronize dc=ldap,dc=com, and noDPRSystemScopeFilterrows found. - Capture live counts for
LDAPContainer,LDAPGroup,LDAPAccount,LDAPAccountInLDAPGroup. - Confirm object-key format for
ITShopOrgHasLDAPGroupby inspecting view metadata and any existing rows. - Before membership tests, provision at least one LDAP account through OneIM account definitions. Do not seed test accounts directly in OpenDJ.
Phase 1 - LDAP Seed
- Add a JSON catalog under
projects/identity-management/ldap-shop-seeding/data/ldap-shop-catalog.json. - Add an idempotent PowerShell seeder under
scripts/sandbox/seed/Invoke-LdapShopSeed.ps1. - Seeder should support
-WhatIfand-Json. - Seeder should never delete; only create missing entries and converge agent-owned attributes.
- Mutations must use
Invoke-WithSandboxLock.
Status 2026-04-27:
- Completed on OpenDJ via
scripts/sandbox/seed/Invoke-LdapShopSeed.ps1. - Created
ou=oim-managed,dc=ldap,dc=complus the planned project-owned subtree. - Created 41 empty
groupOfNamesentitlement groups. - Removed the earlier six project-created
inetOrgPersontest accounts and removed all seeded groupmembervalues. - Verification below
ou=oim-managed,dc=ldap,dc=com: 57 total entries, 16 containers, 0 project-created accounts, 41 groups, 0membervalues. - Next handoff: run OneIM LDAP sync for
dc=ldap,dc=com, then publish the syncedLDAPGrouprows into IT Shop.
Phase 2 - OIM Sync Verification
- Run or trigger the LDAP synchronization project.
- Verify expected entries in:
LDAPContainerLDAPAccountLDAPGroupLDAPAccountInLDAPGroup- Record before/after snapshots under
projects/identity-management/oim-kb-update/sandbox-db/.
Phase 3 - IT Shop Publication
- Create service categories and BO shelves.
- Publish the 41 planned LDAP groups as IT Shop products after sync verification.
- Use a generated SQL script only after schema validation, following the same safety model used for the AD publication.
- Verify:
LDAPGroup.IsForITShop = 1LDAPGroup.IsITShopOnly = 0LDAPGroup.UID_AccProductpopulatedBaseTreeHasLDAPGroupshelf assignments present- generated
ITShopOrgPRnodes exist
Status 2026-04-27:
- Completed after Viktor confirmed LDAP sync.
- Sync verification before publication: 16 project
LDAPContainerrows, 41 projectLDAPGrouprows, 0 projectLDAPAccountrows, 0 LDAP membership rows. - Created 5 project-owned LDAP service categories in
AccProductGroup. - Created 5 project-owned LDAP BO shelves under
Identity & Access Lifecycle: Sandbox LDAP Applications- 20 groupsSandbox LDAP Platform Access- 6 groupsSandbox LDAP Business Roles- 6 groupsSandbox LDAP Access Bundles- 5 groupsSandbox LDAP Distribution Lists- 4 groups- Published all 41 synced
LDAPGrouprows with: IsForITShop = 1IsITShopOnly = 0- linked
UID_AccProduct - approval policy
Recipient's manager and product owner (with peer group analysis) BaseTreeHasLDAPGroupBO shelf placement- DB-side downstream result: 41
AccProductrows, 41 generatedITShopOrgPRproduct nodes, 41 BO placement links, and 41 PR placement links.
Phase 4 - Assignment Tests
- Direct LDAP membership add/remove test.
- IT Shop cart/order test for one low-risk LDAP application group.
- Compare assignment origins and DBQueue/job behavior.
- Test nested/dynamic/long-description edge behavior later as a separate lab, not in the v1 entitlement seed.
Researched Open Questions
Evidence note: projects/identity-management/oim-kb-update/sandbox-host/2026-04-27-opendj-ldap-shop-open-questions.md
| Question | Answer |
|---|---|
| Writable OpenDJ suffix | dc=ldap,dc=com |
| Proposed subtree in sync scope? | Likely yes. Current sync start info is Synchronize dc=ldap,dc=com; no scope/filter rows were found. |
LDAP classes mapped to LDAPGroup | groupOfNames, groupOfUniqueNames, groupOfEntries, groupOfURLs |
Non-empty uniqueMember required? | No. In this OpenDJ schema, groupOfUniqueNames has MUST cn and MAY uniqueMember. Existing groupOfNames also permits empty groups. |
| Best v1 approval policy | Recipient's manager and product owner (with peer group analysis); avoid custom LDAP-specific policy until baseline behavior is proven. |
| Bundle modeling | Keep ldap_bundle_* as direct LDAP groups in v1; model native ESet system roles in phase 2. |
Remaining risk:
- Membership import should be proven only after OneIM has provisioned at least one LDAP account by account definition.