Tiered LDAP groups
This commit is contained in:
@@ -42,6 +42,78 @@ Stripe outages do not extend locally recorded paid expiry. Already-issued Dex
|
||||
tokens and downstream sessions do not instantly lose their cached claims; set
|
||||
short token lifetimes and enforce reauthorization in each relying application.
|
||||
|
||||
## Service access by membership level
|
||||
|
||||
Additional LDAP service benefits are configured separately from Stripe prices in
|
||||
[membership/service-groups.eom.json](membership/service-groups.eom.json). Set
|
||||
`MEMBERSHIP_SERVICE_GROUPS_FILE` to that file, or supply an equivalent object in
|
||||
`MEMBERSHIP_SERVICE_GROUPS_JSON` (which takes precedence). The default is empty;
|
||||
the shipped file contains empty lists for levels 0–5, granting nothing until
|
||||
you supply real, reviewed group DNs. Existing paid tiers and their `group_dn`
|
||||
continue working unchanged.
|
||||
|
||||
The shape is a level-to-list mapping, for example:
|
||||
|
||||
```json
|
||||
{
|
||||
"0": ["cn=community-chat,ou=membership-services,dc=example,dc=org"],
|
||||
"1": ["cn=community-chat,ou=membership-services,dc=example,dc=org"],
|
||||
"2": [
|
||||
"cn=community-chat,ou=membership-services,dc=example,dc=org",
|
||||
"cn=game-servers,ou=membership-services,dc=example,dc=org"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Keys are canonical level strings: `"0"` or an existing paid tier's positive
|
||||
level. Values are lists of full LDAP group DNs. Omitted levels/empty lists grant
|
||||
no additional service access. **The highest currently paid level selects exactly
|
||||
one list**. There is no implicit inheritance: in this example level 2 gets chat
|
||||
and games, while levels 3–5 get neither unless explicitly listed. Level 0 means
|
||||
free accounts only, not a baseline automatically inherited by paid accounts.
|
||||
To offer a service to everyone, repeat its DN under every configured level.
|
||||
An active Stripe and SHKeeper combination still selects the highest paid level;
|
||||
it does not combine lower service lists. Normal per-tier group grants remain
|
||||
additive for each valid paid entitlement, as before.
|
||||
|
||||
The worker computes the level from paid subscription/invoice expiry on **every
|
||||
pass**, never from cached Dex groups or the account's stored level. Expiry falls
|
||||
back to level 0 and revokes paid-only service access without contacting payment
|
||||
providers. Editing/removing a DN, removing a tier or changing levels reconciles
|
||||
on the next sweep. Historical `ManagedGroup` records are retained so old grants
|
||||
are revoked even after configuration removal; management intent commits before
|
||||
LDAP changes so failed writes can be retried safely. Login/registration records
|
||||
intent but does not grant groups directly. Level 0 grants cover local membership
|
||||
accounts (including first-time Dex sign-ins), not every LDAP account that has
|
||||
never used this application.
|
||||
|
||||
**Provision and secure the groups before enabling a mapping:**
|
||||
|
||||
- Targets must already be `groupOfUniqueNames` groups with the configured
|
||||
sentinel entry. Allow the worker narrowly scoped read/write of `uniqueMember`
|
||||
on these groups only. No LDAP schema, group or ACL is created automatically.
|
||||
- Mapping a DN hands this application control of that group's membership for
|
||||
**every local member**, including revocations of manual grants to noneligible
|
||||
members. Use dedicated groups for membership-controlled service access. Do not
|
||||
map administrator, staff, existing independently managed entitlement groups,
|
||||
the sentinel DN or groups where such removals would be unsafe. Configure
|
||||
services/Dex to authorize these dedicated groups and review any service-specific
|
||||
user provisioning requirements separately. Only administrators edit mappings;
|
||||
browser forms and Dex claims cannot choose entitlement groups.
|
||||
- Keep removed groups and ACL access available until the worker has successfully
|
||||
removed old grants. Missing groups/LDAP outages fail synchronization and delay
|
||||
grants/revocations; they must not be hidden by deleting historical tracking.
|
||||
- Group names/tokens already cached by Dex and relying services must refresh.
|
||||
Revocation is not an instantaneous logout across services.
|
||||
|
||||
For Kubernetes, use the role's `www_membership_service_groups` variable, not an
|
||||
image-baked file: the role mounts its own mapping next to its tiers configuration.
|
||||
Change the variable and rerun the role; its revision includes this mapping and
|
||||
rolls web/worker so they reload it. Directly changing a ConfigMap does not reload
|
||||
Django settings. Build/deploy the updated image and role once before using the
|
||||
new setting. No database migration is needed for service mappings. Changes to
|
||||
the benefit display text remain separate from actual authorization rules.
|
||||
|
||||
## Existing Stripe product
|
||||
|
||||
The live Stripe dashboard was inspected on 2026-10-23. This integration reuses
|
||||
|
||||
Reference in New Issue
Block a user