f45349e0cd
Reported: creating any user via the API failed with
{"name":"InvalidSyntaxError","message":"gidNumber: value #0 invalid per syntax Code: 0x15"}
Root cause: addPosixGroup() computes the next gidNumber as
`Math.max(...groups.map(i => i.gidNumber)) + 1`. theta-env's
bootstrap.js creates the first admin via raw ldapadd with a hardcoded
uidNumber/gidNumber (10000) directly on the user entry, but never
creates a matching posixGroup entry -- so on a theta-env-bootstrapped
directory there are zero posixGroup entries, `Math.max()` on an empty
array is `-Infinity` in JS (not 0), and `-Infinity + 1` stringifies to
"-Infinity" -- an invalid LDAP integer, rejected by the directory. This
broke every single user creation, not just this one.
Separately: the reporter's intended scheme is for organically-created
users to start at uidNumber/gidNumber 1500, distinct from the
bootstrap admin's reserved 10000. Fixing the crash with a bare "floor
of 1500" alone wouldn't achieve that, since addPosixAccount's own
Math.max() would still find the admin's posixAccount entry (uidNumber
10000, found via a different, correctly-indexed search) and allocate
10001 for the next user.
Added a shared nextPosixId(entries, key) helper: takes the highest
existing value strictly below conf.ldap.uidGidReservedFloor (default
9000) plus one, or conf.ldap.uidGidMin (default 1500) if there are no
such entries. Ids at/above the reserved floor -- like the bootstrap
admin's 10000 -- are ignored entirely when computing the next
available number, so real users always start at 1500 and grow upward
regardless of the admin's reserved id.
Verified against a real theta-env deployment end to end:
- Reproduced the exact reported crash on a fresh bootstrap
- After the fix: first real user gets uidNumber/gidNumber "1500",
second gets "1501" -- admin's 10000 never enters the calculation
- New unit tests (nodejs/tests/posix_id.test.js, no LDAP required):
6/6 pass, covering the empty-array case, the reserved-floor
exclusion, and the NaN-from-missing-value case
- npm test: 18/18 passing tests still pass (unchanged); the other 155
failures are pre-existing/environmental (no LDAP server in this
sandbox) -- confirmed via git stash before starting this fix
55 lines
1.9 KiB
JavaScript
55 lines
1.9 KiB
JavaScript
'use strict';
|
|
|
|
// Base configuration — generic defaults usable by anyone.
|
|
//
|
|
// These are NON-secret defaults. Per-deployment values (LDAP bind DN, user/group
|
|
// bases, SMTP host/user, OAuth issuer, sender address) should be overridden via
|
|
// conf/secrets.js or `app_*` environment variables (see @simpleworkjs/conf).
|
|
// Secret values (passwords, JWT secret, API keys) MUST come from secrets.js or
|
|
// `app_*` env vars — never commit them here.
|
|
module.exports = {
|
|
name: "SSO Manager", // displayed in the UI and outbound email
|
|
userModel: 'ldap', // pam, redis, ldap
|
|
redis: {
|
|
prefix: 'sso_manager_'
|
|
},
|
|
ldap: {
|
|
url: 'ldap://localhost',
|
|
bindDN: 'cn=admin,dc=example,dc=com',
|
|
bindPassword: '__in secrets file__',
|
|
userBase: 'ou=people,dc=example,dc=com',
|
|
groupBase: 'ou=groups,dc=example,dc=com',
|
|
userFilter: '(objectClass=posixAccount)',
|
|
userNameAttribute: 'uid',
|
|
// New users/personal groups (see addPosixAccount/addPosixGroup in
|
|
// models/user_ldap.js) get the next uid/gidNumber >= uidGidMin.
|
|
// Existing entries >= uidGidReservedFloor are ignored when computing
|
|
// that "next available" number, so a deliberately high, easily
|
|
// recognizable id (e.g. the bootstrap admin at 10000 — see
|
|
// theta-env's bootstrap.js) doesn't drag every real user's id up
|
|
// into that same range.
|
|
uidGidMin: 1500,
|
|
uidGidReservedFloor: 9000,
|
|
},
|
|
oauth: {
|
|
issuer: '', // falls back to the request host at runtime (routes/index.js)
|
|
jwtSecret: '__in secrets file__',
|
|
token_lifetime: {
|
|
access_token: 3600, // 1 hour (seconds)
|
|
refresh_token: 2592000 // 30 days (seconds)
|
|
}
|
|
},
|
|
voipms: {
|
|
username: '__in secrets file__',
|
|
password: '__in secrets file__',
|
|
did: '__in secrets file__',
|
|
},
|
|
smtp: {
|
|
host: 'localhost',
|
|
port: 587,
|
|
secure: false,
|
|
user: 'noreply@example.com',
|
|
pass: '__in secrets file__',
|
|
from: 'SSO Manager <noreply@example.com>',
|
|
},
|
|
}; |