ldap-rest 2.0.3 → 2.0.4
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.
- package/dist/lib/entitySchema/validator.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/plugins/auth/authzDynamic.js +1 -1
- package/dist/plugins/auth/trustedProxy.js +1 -1
- package/dist/plugins/ldap/departmentSync.js +1 -1
- package/dist/plugins/scim/baseResolver.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +6 -6
- package/dist/src/abstract/plugin.d.ts +11 -11
- package/dist/src/abstract/twakePlugin.d.ts +4 -4
- package/dist/src/bin/index.d.ts +10 -10
- package/dist/src/browser/ldap-browser/LdapBrowser.d.ts +1 -1
- package/dist/src/browser/ldap-browser/api/RawApiClient.d.ts +1 -1
- package/dist/src/browser/ldap-browser/components/EntryTree.d.ts +2 -2
- package/dist/src/browser/ldap-browser/components/EntryView.d.ts +2 -2
- package/dist/src/browser/ldap-browser/index.d.ts +4 -5
- package/dist/src/browser/ldap-browser/schema.d.ts +1 -1
- package/dist/src/browser/ldap-group-editor/LdapGroupEditor.d.ts +2 -2
- package/dist/src/browser/ldap-group-editor/api/GroupApiClient.d.ts +1 -1
- package/dist/src/browser/ldap-group-editor/components/CreateGroupModal.d.ts +2 -2
- package/dist/src/browser/ldap-group-editor/components/GroupPropertyEditor.d.ts +1 -1
- package/dist/src/browser/ldap-group-editor/components/MoveGroupModal.d.ts +1 -1
- package/dist/src/browser/ldap-group-editor/types.d.ts +1 -1
- package/dist/src/browser/ldap-resource-editor/api/ResourceApiClient.d.ts +2 -2
- package/dist/src/browser/ldap-resource-editor/index.d.ts +2 -2
- package/dist/src/browser/ldap-resource-editor/types.d.ts +1 -1
- package/dist/src/browser/ldap-tree-viewer/LdapTreeViewer.d.ts +1 -1
- package/dist/src/browser/ldap-tree-viewer/components/TreeNode.d.ts +2 -2
- package/dist/src/browser/ldap-tree-viewer/components/TreeRoot.d.ts +2 -2
- package/dist/src/browser/ldap-tree-viewer/index.d.ts +2 -3
- package/dist/src/browser/ldap-tree-viewer/store/actions.d.ts +2 -2
- package/dist/src/browser/ldap-tree-viewer/store/reducers.d.ts +2 -2
- package/dist/src/browser/ldap-unit-editor/LdapUnitEditor.d.ts +1 -1
- package/dist/src/browser/ldap-unit-editor/api/UnitApiClient.d.ts +1 -1
- package/dist/src/browser/ldap-unit-editor/components/MoveUnitModal.d.ts +1 -1
- package/dist/src/browser/ldap-unit-editor/components/UnitPropertyEditor.d.ts +1 -1
- package/dist/src/browser/ldap-unit-editor/types.d.ts +1 -1
- package/dist/src/browser/ldap-user-editor/LdapUserEditor.d.ts +2 -2
- package/dist/src/browser/ldap-user-editor/api/UserApiClient.d.ts +2 -2
- package/dist/src/browser/ldap-user-editor/components/MoveUserModal.d.ts +1 -1
- package/dist/src/browser/ldap-user-editor/components/PointerField.d.ts +2 -2
- package/dist/src/browser/ldap-user-editor/components/UserEditor.d.ts +1 -1
- package/dist/src/browser/ldap-user-editor/components/UserList.d.ts +1 -1
- package/dist/src/browser/ldap-user-editor/components/UserTree.d.ts +1 -1
- package/dist/src/browser/ldap-user-editor/index.d.ts +2 -3
- package/dist/src/browser/ldap-user-editor/types.d.ts +1 -1
- package/dist/src/browser/shared/components/Modal.d.ts +1 -1
- package/dist/src/browser/shared/index.d.ts +7 -7
- package/dist/src/browser/shared/utils/form.d.ts +1 -1
- package/dist/src/browser/shared/utils/schema.d.ts +1 -1
- package/dist/src/config/args.d.ts +3 -3
- package/dist/src/config/options.d.ts +2 -2
- package/dist/src/config/schema.d.ts +1 -1
- package/dist/src/hooks.d.ts +5 -5
- package/dist/src/lib/auth/base.d.ts +2 -2
- package/dist/src/lib/authz/base.d.ts +6 -6
- package/dist/src/lib/authz/composition.d.ts +4 -4
- package/dist/src/lib/entitySchema/validator.d.ts +23 -2
- package/dist/src/lib/expressFormatedResponses.d.ts +1 -1
- package/dist/src/lib/health.d.ts +1 -1
- package/dist/src/lib/hookBus.d.ts +1 -1
- package/dist/src/lib/ldap/schema.d.ts +2 -2
- package/dist/src/lib/ldapActions.d.ts +5 -5
- package/dist/src/lib/mailDomains.d.ts +1 -1
- package/dist/src/lib/parseConfig.d.ts +1 -1
- package/dist/src/lib/schemaFile.d.ts +1 -1
- package/dist/src/lib/staticFiles.d.ts +1 -1
- package/dist/src/lib/storage/store.d.ts +1 -1
- package/dist/src/lib/utils.d.ts +3 -3
- package/dist/src/logger/winston.d.ts +1 -1
- package/dist/src/plugins/auth/auth.options.d.ts +39 -39
- package/dist/src/plugins/auth/authzDynamic.d.ts +24 -11
- package/dist/src/plugins/auth/authzLinid1.d.ts +7 -7
- package/dist/src/plugins/auth/authzPerBranch.d.ts +8 -8
- package/dist/src/plugins/auth/authzPerRoute.d.ts +2 -2
- package/dist/src/plugins/auth/authzScope.d.ts +1 -1
- package/dist/src/plugins/auth/crowdsec.d.ts +4 -4
- package/dist/src/plugins/auth/fake.d.ts +3 -3
- package/dist/src/plugins/auth/hmac.d.ts +4 -4
- package/dist/src/plugins/auth/llng.d.ts +20 -5
- package/dist/src/plugins/auth/openidconnect.d.ts +9 -9
- package/dist/src/plugins/auth/rateLimit.d.ts +3 -3
- package/dist/src/plugins/auth/token.d.ts +3 -3
- package/dist/src/plugins/auth/totp.d.ts +5 -5
- package/dist/src/plugins/auth/trustedProxy.d.ts +16 -32
- package/dist/src/plugins/bcl.d.ts +4 -4
- package/dist/src/plugins/bcl.options.d.ts +3 -3
- package/dist/src/plugins/configApi.d.ts +1 -1
- package/dist/src/plugins/demo/helloworld.d.ts +1 -1
- package/dist/src/plugins/ldap/accountLifecycle.d.ts +1 -1
- package/dist/src/plugins/ldap/bulkImport.d.ts +5 -5
- package/dist/src/plugins/ldap/departmentSync.d.ts +14 -3
- package/dist/src/plugins/ldap/enterpriseRules.d.ts +7 -7
- package/dist/src/plugins/ldap/externalUsersInGroups.d.ts +6 -6
- package/dist/src/plugins/ldap/flatGeneric.d.ts +6 -6
- package/dist/src/plugins/ldap/groups.d.ts +8 -8
- package/dist/src/plugins/ldap/ldap.options.d.ts +45 -45
- package/dist/src/plugins/ldap/onChange.d.ts +4 -4
- package/dist/src/plugins/ldap/organization.d.ts +1 -1
- package/dist/src/plugins/ldap/organizations.d.ts +12 -12
- package/dist/src/plugins/ldap/passwordPolicy.d.ts +11 -11
- package/dist/src/plugins/ldap/raw.d.ts +8 -8
- package/dist/src/plugins/ldap/trash.d.ts +6 -6
- package/dist/src/plugins/metrics.d.ts +3 -3
- package/dist/src/plugins/metrics.options.d.ts +3 -3
- package/dist/src/plugins/rabbitmq.d.ts +4 -4
- package/dist/src/plugins/rabbitmq.options.d.ts +3 -3
- package/dist/src/plugins/scim/baseResolver.d.ts +3 -3
- package/dist/src/plugins/scim/bulk.d.ts +7 -7
- package/dist/src/plugins/scim/discovery.d.ts +4 -4
- package/dist/src/plugins/scim/errors.d.ts +3 -3
- package/dist/src/plugins/scim/filter.d.ts +1 -1
- package/dist/src/plugins/scim/groups.d.ts +8 -8
- package/dist/src/plugins/scim/list.d.ts +1 -1
- package/dist/src/plugins/scim/mapping.d.ts +2 -2
- package/dist/src/plugins/scim/patch.d.ts +2 -2
- package/dist/src/plugins/scim/scim.d.ts +30 -30
- package/dist/src/plugins/scim/scim.options.d.ts +27 -27
- package/dist/src/plugins/scim/users.d.ts +6 -6
- package/dist/src/plugins/static.d.ts +6 -6
- package/dist/src/plugins/static.options.d.ts +6 -6
- package/dist/src/plugins/storage/file.d.ts +2 -2
- package/dist/src/plugins/storage/ldap.d.ts +2 -2
- package/dist/src/plugins/storage/postgres.d.ts +2 -2
- package/dist/src/plugins/storage/valkey.d.ts +2 -2
- package/dist/src/plugins/storage.d.ts +13 -13
- package/dist/src/plugins/storage.options.d.ts +11 -11
- package/dist/src/plugins/twake/appAccounts.options.d.ts +6 -6
- package/dist/src/plugins/twake/appAccountsApi.d.ts +7 -7
- package/dist/src/plugins/twake/appAccountsConsistency.d.ts +9 -9
- package/dist/src/plugins/twake/calendar.d.ts +14 -14
- package/dist/src/plugins/twake/calendar.options.d.ts +11 -11
- package/dist/src/plugins/twake/calendarResources.d.ts +1 -1
- package/dist/src/plugins/twake/cloudery.options.d.ts +18 -18
- package/dist/src/plugins/twake/clouderyProvision.d.ts +19 -19
- package/dist/src/plugins/twake/cozy.options.d.ts +14 -14
- package/dist/src/plugins/twake/cozyProvision.d.ts +15 -15
- package/dist/src/plugins/twake/drive.d.ts +9 -9
- package/dist/src/plugins/twake/drive.options.d.ts +7 -7
- package/dist/src/plugins/twake/groups.d.ts +16 -16
- package/dist/src/plugins/twake/instances.d.ts +38 -38
- package/dist/src/plugins/twake/james.d.ts +18 -18
- package/dist/src/plugins/twake/james.options.d.ts +13 -13
- package/dist/src/plugins/twake/lifecycleAttributes.d.ts +2 -2
- package/dist/src/plugins/twake/lifecycleEvents.d.ts +13 -13
- package/dist/src/plugins/twake/migrationProxy.d.ts +11 -11
- package/dist/src/plugins/twake/migrationProxy.options.d.ts +8 -8
- package/dist/src/plugins/twake/spaces.d.ts +12 -12
- package/dist/src/plugins/twake/tombstone.d.ts +10 -10
- package/dist/src/plugins/twake/twakeGroups.options.d.ts +12 -12
- package/dist/src/plugins/twake/twakeInstances.options.d.ts +35 -35
- package/dist/src/plugins/twake/twakeLifecycle.options.d.ts +12 -12
- package/dist/src/plugins/twake/twakeSpaces.options.d.ts +11 -11
- package/dist/src/plugins/twake/twakeTombstone.options.d.ts +9 -9
- package/dist/src/plugins/weblogs.d.ts +1 -1
- package/docs/client-development/schemas/README.md +6 -1
- package/docs/development/contracts.md +22 -0
- package/docs/presentations/en.md +1 -1
- package/docs/presentations/fr.md +1 -1
- package/docs/usage/plugins/auth/authz-dynamic.md +3 -1
- package/docs/usage/plugins/auth/trusted-proxy.md +11 -1
- package/docs/usage/upgrading.md +27 -0
- package/package.json +4 -3
- package/static/browser/ldap-user-editor.esm.js.map +1 -1
- package/static/browser/ldap-user-editor.js.map +1 -1
- package/static/browser/ldap-user-editor.min.js.map +1 -1
- package/static/browser/shared/utils/schema.js.map +1 -1
- package/static/browser/shared.esm.js.map +1 -1
- package/static/browser/shared.js.map +1 -1
- package/static/browser/shared.min.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BadRequestError as e}from"../errors.js";import{knownAttributeName as t}from"../utils.js";import{toDirectoryEntry as r,missingRequiredAttribute as i,toDirectoryChanges as s,schemaAttribute as a,tooLongValue as n,tooLongMessage as o,maxLengthOf as d,checkDnValues as c,matchesPattern as u,invalidValueMessage as
|
|
1
|
+
import{BadRequestError as e}from"../errors.js";import{knownAttributeName as t}from"../utils.js";import{toDirectoryEntry as r,missingRequiredAttribute as i,toDirectoryChanges as s,schemaAttribute as a,tooLongValue as n,tooLongMessage as o,maxLengthOf as d,checkDnValues as c,matchesPattern as u,invalidValueMessage as f}from"../../config/schema.js";class EntityValidator{schema;deps;constructor(e,t){this.schema=e,this.deps=t}async validateNew(t){const s=this.renameDeclared(t);if(this.dropUndeclaredEmpty(s),!this.schema)return r(void 0,s),s;this.refuseFixedOptions(s),applyFixedDefaults(this.schema,s),await this.checkValues(s);const a=i(this.schema,s,this.deps.loadedPlugins);if(a)throw new e(`Attribute "${a}" is required`);return r(this.schema,s),s}async validateChanges(t){t.add&&(t.add=this.renameDeclared(t.add)),t.replace&&(t.replace=this.renameDeclared(t.replace)),t.delete&&(t.delete=Array.isArray(t.delete)?this.renameDeclaredNames(t.delete):this.renameDeclared(t.delete));for(const e of["add","replace"]){const r=t[e];r&&("add"===e&&this.dropUndeclaredEmpty(r),await this.checkValues(r,e))}if(!this.schema)return s(void 0,t),t;if(t.delete){const whole=e=>{if(Array.isArray(t.delete))return!0;const r=t.delete[e];return!r||isNoValue(r)},r=Array.isArray(t.delete)?t.delete:Object.keys(t.delete);for(const t of r){const r=this.attribute(t);if(r?.fixed)throw new e(`Attribute "${t}" is fixed and cannot be deleted`);if(r?.required&&whole(t))throw new e(`Attribute "${t}" is required`)}}return s(this.schema,t),t}renameDeclared(e){const t=Object.keys(e),r=this.renameDeclaredNames(t);if(t.every((e,t)=>e===r[t]))return e;const i=Object.create(null);for(const[s,a]of r.entries())i[a]=e[t[s]];return i}renameDeclaredNames(t){const r=new Map;return t.map(t=>{const i=this.attributeIdentity(t),s=r.get(i);if(void 0!==s&&s!==t)throw new e(`"${s}" and "${t}" name the same attribute`);return r.set(i,t),this.schemaSpelling(t)})}attributeIdentity(e){const r=split(e)[0];return(a(this.schema,r)?.[0]??t(r)??r).toLowerCase()}schemaSpelling(e){const[t,r]=split(e),i=a(this.schema,t)?.[0];return void 0===i?e:r?`${i};${r}`:i}refuseFixedOptions(t){for(const r of Object.keys(t)){const[,t]=split(r),i=t?this.declaredAttribute(r):void 0;if(i?.fixed&&void 0!==i.default)throw new e(`Attribute "${r}" is fixed and cannot be modified`)}}declaredAttribute(e){const r=this.attributeIdentity(e);for(const[e,i]of Object.entries(this.schema?.attributes??{}))if((t(e)??e).toLowerCase()===r)return i}dropUndeclaredEmpty(e){for(const[t,r]of Object.entries(e))null!=r||this.attribute(t)||delete e[t]}async checkValues(t,r){for(const[i,s]of Object.entries(t)){const a=this.attribute(i);if(a?.fixed&&r)throw new e(`Attribute "${i}" is fixed and cannot be modified`);if(a?.required&&!r&&isMissing(s)&&!a.generated)throw new e(`Attribute "${i}" is required`);(a||r)&&(t[i]=asStored(await this.validateValue(i,s)))}}async validateValue(t,r){if(!this.schema)return r;const i=this.attribute(t);if(!i)return r;if(isNoValue(r)){if(i.required)throw new e(`Attribute "${t}" is required`);return r}let s=r;if("array"===i.type){Array.isArray(r)||(s=[r]);for(const e of s)assertScalar(t,e,i.items?.type)}else{if(Array.isArray(r)){if(r.length>1)throw new e(`Attribute "${t}" must be a single value`);s=r[0]}i.normalize&&"string"==typeof s||assertScalar(t,s,i.type)}if(void 0!==n(i,s))throw new e(o(t,d(i)));if(await c(t,i,s,this.deps.entryExists),!u(i,s))throw new e(f(t,i));return s}attribute(t){const r=a(this.schema,t)?.[1];if(!r&&this.schema?.strict)throw new e(`Unknown attribute "${t}" for ${this.deps.singularName}`);return r}}function applyFixedDefaults(e,t){if(e)for(const[r,i]of Object.entries(e.attributes))i.fixed&&void 0!==i.default&&"objectclass"!==r.toLowerCase()&&(t[r]=i.default)}const split=e=>{const[t,...r]=e.split(";");return[t,r.find(Boolean)?.toLowerCase()]},isNoValue=e=>null==e||Array.isArray(e)&&0===e.length,isMissing=e=>isNoValue(e)||""===e,asStored=e=>isNoValue(e)?[]:e,l=/^-?\d+(\.\d+)?$/,h=/^-?\d+$/;function assertScalar(t,r,i){const s="number"==typeof r&&Number.isFinite(r)?String(r):void 0,reads=e=>void 0!==s?e.test(s):"string"==typeof r&&e.test(r);if(!(()=>{switch(i){case"number":return reads(l)&&("number"!=typeof r||!Number.isInteger(r)||Number.isSafeInteger(r));case"integer":return reads(h)&&("number"!=typeof r||Number.isSafeInteger(r));case"boolean":return"boolean"==typeof r||"string"==typeof r&&("TRUE"===r||"FALSE"===r);default:return"string"==typeof r||Buffer.isBuffer(r)}})()){throw new e(`Attribute "${t}" must be ${"number"===i||"integer"===i||"boolean"===i?`a${"integer"===i?"n":""} ${i}`:"a string"}`)}}export{EntityValidator,applyFixedDefaults};
|
package/dist/lib/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BadRequestError as e}from"./errors.js";import"./expressFormatedResponses.js";import"./metrics.js";import"./requestContext.js";const n=new Map;function getCompiledRegex(e,t){const r=t?`${e}:${t}`:e;let i=n.get(r);return i||(i=new RegExp(e,t),n.set(r,i)),i}function escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}const transformSchemas=(e,n)=>e.toString().replace(/__(\S+)__/g,(e,t)=>{if(!t||"string"!=typeof t)return e;const r=t.trim().toLowerCase(),i=n;return i[r]?"object"!=typeof i[r]?i[r]:JSON.stringify(i[r]):e});function escapeLdapFilter(e){return e.replace(/\\/g,"\\5c").replace(/\*/g,"\\2a").replace(/\(/g,"\\28").replace(/\)/g,"\\29").replace(/\0/g,"\\00")}function substringSearchFilter(n,t){const r=/^[a-zA-Z][a-zA-Z0-9-]*$/,i=t.split(",").map(e=>e.trim()).filter(Boolean);if(0===i.length||!i.every(e=>r.test(e)))throw new e("Invalid LDAP attribute name");const o=escapeLdapFilter(n),s=i.map(e=>`(${e}=*${o}*)`);return 1===s.length?s[0]:`(|${s.join("")})`}function fillPattern(e,n,t){return e.split(n).join(t)}function escapeDnValue(e){let n=e.replace(/[\\,+"<>;=]/g,e=>`\\${e}`).replace(/[\0-\x1f\x7f]/g,e=>`\\${hexByte(e.charCodeAt(0))}`);return e.startsWith(" ")&&(n=`\\${n}`),e.length>1&&e.endsWith(" ")&&(n=`${n.slice(0,-1)}\\ `),e.startsWith("#")&&(n=`\\${n}`),n}const t=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0});function unescapeDnValue(n){if("string"!=typeof n)throw new e("DN value must be a string");let t="",r=0,i=[];const flushBytes=()=>{if(i.length){for(const e of utf8Chars(i))t+="number"==typeof e?String.fromCharCode(e):e;i=[]}};for(;r<n.length;)if("\\"===n[r]&&r+1<n.length){const e=n[r+1];if(/[0-9a-fA-F]/.test(e)&&r+2<n.length){const e=n.substring(r+1,r+3);if(/^[0-9a-fA-F]{2}$/.test(e)){i.push(parseInt(e,16)),r+=3;continue}}flushBytes(),t+=e,r+=2}else flushBytes(),t+=n[r],r++;return flushBytes(),t}function validateDnValue(e,n){if(null==e||"string"!=typeof e)throw new Error(`${n} must be a string`);if(0===e.trim().length)throw new Error(`${n} must be a non-empty string`);if(/[\x00-\x1F\x7F]/.test(e))throw new Error(`${n} contains invalid control characters`);if(/[\u200B-\u200F\uFEFF]/.test(e))throw new Error(`${n} contains invalid invisible characters`)}function asciiSpace(e){return" "===e||e>="\t"&&e<="\r"}function trimUnescaped(e){let n=0,t=e.length;for(;n<t&&asciiSpace(e[n]);)n++;for(;t>n&&asciiSpace(e[t-1]);)t--;if(t<e.length){let r=0;for(let i=t-1;i>=n&&"\\"===e[i];i--)r++;r%2==1&&t++}return e.slice(n,t)}function parseDn(n){if("string"!=typeof n)throw new e("DN must be a string");const t=[];let r="",i=!1,o=!1;for(let e=0;e<n.length;e++){const s=n[e];i?(r+=s,i=!1):"\\"===s?(r+=s,i=!0):'"'===s&&(o||opensValue(r))?(r+=s,o=!o):o||","!==s&&";"!==s?r+=s:(t.push(trimUnescaped(r)),r="")}if(o)throw new e("DN has an unbalanced quote");return r&&t.push(trimUnescaped(r)),t}function opensValue(e){const n=e.trimEnd();if(!n.endsWith("="))return!1;let t=0;for(let e=n.length-2;e>=0&&"\\"===n[e];e--)t++;return t%2==0}function isDnSyntax(e){let n;try{n=parseDn(e)}catch{return!1}if(0===n.length)return!1;const t=/^\s*(?:[A-Za-z][A-Za-z0-9-]*|(?:OID\.)?\d+(?:\.\d+)+)\s*=/i;return n.every(e=>{if(!e)return!1;const n=[];let r="",i=!1;for(const t of e){if(i)i=!1;else if("\\"===t)i=!0;else if("+"===t){n.push(r),r="";continue}r+=t}return n.push(r),n.every(e=>t.test(e))})}const r=new Set(['"',"+",",",";","<",">","\\","#","="," "]);function hasOnlyRfc4514Escapes(e){for(let n=0;n<e.length;n++){if("\\"!==e[n])continue;const t=e[n+1];if(void 0===t)return!1;if(r.has(t))n++;else{if(!/^[0-9a-fA-F]{2}$/.test(e.slice(n+1,n+3)))return!1;n+=2}}return!0}function assertRfc4514Escapes(n,t){if(!hasOnlyRfc4514Escapes(n))throw new e(`${t} uses an escape RFC 4514 does not define`)}function getParentDn(e){const n=parseDn(e);return n.length<=1?e:n.slice(1).join(",")}function getRdn(e){return parseDn(e)[0]||""}function rdnValue(e){const[n]=parseDn(e);return rdnValueOf(n)}function unquotedValue(e){let n=0;for(let t=e.length-2;t>0&&"\\"===e[t];t--)n++;return e.length>=2&&e.startsWith('"')&&e.endsWith('"')&&n%2==0?e.slice(1,-1):e}function rdnValueOf(e){if(!e)return"";const n=e.indexOf("=");if(n<=0)return"";let t=n+1;for(;t<e.length&&asciiSpace(e[t]);)t++;return unescapeDnValue(unquotedValue(e.slice(t)))}function dropSpaces(e){const n=e.filter((n,t)=>" "!==n||" "!==e[t-1]);let t=0,r=n.length;for(;t<r&&" "===n[t];)t++;for(;r>t&&" "===n[r-1];)r--;return n.slice(t,r)}function assertedRdnValue(e,n,t){const[r]=parseDn(e),i=r?r.indexOf("="):-1;return i<=0||r.slice(0,i).trim().toLowerCase()!==n.toLowerCase()||splitRdn(r).length>1?null:void 0===t||isDirectChildOf(e,t)?dropSpaces([...rdnValueOf(r).normalize("NFKC")]).join(""):null}function namesByDn(e,n){try{const[t]=parseDn(e),r=t?t.indexOf("="):-1;return r>0&&t.slice(0,r).trim().toLowerCase()===n.toLowerCase()}catch{return!1}}function isChildOf(e,n){try{return isDnInBranch(e,n)&&!isDnInBranch(n,e)}catch{return!1}}function isDirectChildOf(e,n){try{const[,...t]=parseDn(e);return t.length>0&&normalizeDn(t.join(","))===normalizeDn(n)}catch{return!1}}const i=/((?:\\[0-9a-fA-F]{2})+)|\\([^])/g;function hexByte(e){return e.toString(16).padStart(2,"0")}function utf8Chars(e){const n=[],r=Uint8Array.from(e);for(let i=0;i<e.length;){const o=utf8Length(e[i]);let s;if(o&&i+o<=e.length)try{s=t.decode(r.subarray(i,i+o))}catch{}void 0===s?n.push(e[i++]):(n.push(...s),i+=o)}return n}function utf8Length(e){return e<128?1:e>>5==6?2:e>>4==14?3:e>>3==30?4:0}const o=new Map,s=new Map;function registerAttributeTypes(e){for(const{oid:n,names:t}of e){const e=(t[0]??n).toLowerCase();for(const r of[n,...t])o.set(r.toLowerCase(),e),s.set(r.toLowerCase(),t[0]??n)}}function knownAttributeName(e){return s.get(e.toLowerCase().replace(/^oid\./,""))}function rdnTypes(e){return splitRdn(parseDn(e)[0]??"").map(e=>{const n=e.indexOf("=");return-1===n?"":canonicalType(e.slice(0,n).trim())})}function canonicalType(e){const n=e.toLowerCase().replace(/^oid\./,"");return o.get(n)??n}function splitRdn(e){const n=[];let t="",r=!1,i=!1;for(const o of e){if(r)r=!1;else if("\\"===o)r=!0;else if('"'===o&&(i||opensValue(t)))i=!i;else if("+"===o&&!i){n.push(t),t="";continue}t+=o}return n.push(t),n}function normalizeDn(e){return normalizedRdns(e).join(",")}function canonicalDn(e){return normalizedRdns(e,!1).join(",")}function normalizedRdns(e,n=!0){return parseDn(e).map(e=>splitRdn(e).map(e=>{const t=e.indexOf("=");if(-1===t)return e.trim().toLowerCase();const r=function(e,n=!0){const t=trimUnescaped(e);if(/^#(?:[0-9a-fA-F]{2})+$/.test(t))return t;e=unquotedValue(t);const r=[];let o=0;const plain=e=>{for(const n of e)r.push(n)};for(const n of e.matchAll(i)){plain(e.slice(o,n.index)),o=n.index+n[0].length;const[,t,i]=n;if(void 0!==i){r.push(i);continue}const s=t.split("\\").filter(Boolean).map(e=>parseInt(e,16));for(const e of utf8Chars(s))"number"==typeof e?r.push(`\\${hexByte(e)}`):plain(e)}o<e.length&&plain(e.slice(o));const kept=e=>3===e.length&&"\\"===e[0],fold=e=>(n?e.toLowerCase():e).normalize("NFKC"),s=[];let a="";for(const e of r)kept(e)?(s.push(...fold(a),e),a=""):a+=e;s.push(...fold(a));const c=dropSpaces(s);let u="";for(const[e,n]of c.entries())kept(n)?u+=n:n.charCodeAt(0)<32||127===n.charCodeAt(0)?u+=`\\${hexByte(n.charCodeAt(0))}`:',+"\\<>;='.includes(n)||0===e&&"#"===n?u+=`\\${n}`:u+=n;return u}(e.slice(t+1),n);return`${canonicalType(e.slice(0,t).trim())}=${n?r.toLowerCase():r}`}).sort().join("+")).filter(e=>e.length>0)}function isDummyMemberDn(e,n){if(!n||"string"!=typeof e)return!1;if(e===n)return!0;try{return normalizeDn(e)===normalizeDn(n)}catch{return!1}}function organizationLink(e){for(const n of Array.isArray(e)?e:[e]){if(null==n)continue;const e=String(n).trim();if(e.length>0)return e}}function isDnInBranch(e,n){const t=normalizedRdns(n);if(0===t.length)return!1;const r=normalizedRdns(e);if(r.length<t.length)return!1;return r.slice(r.length-t.length).every((e,n)=>e===t[n])}function movedToTrash(e,n,t){return!!e&&isDnInBranch(t,e)&&!isDnInBranch(n,e)}function parseDirectoryDate(e){const n=String(e).trim(),t=/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})?(\d{2})?(?:[.,](\d+))?(Z|[+-]\d{2}(?::?\d{2})?)?$/.exec(n);if(!t){const e=new Date(n);return isNaN(e.getTime())?null:e}const[,r,i,o,s,a,c,u,l]=t,[f,d,p,m,h,g]=[r,i,o,s,a,c].map(e=>void 0===e?0:Number(e));if(d<1||d>12||m>23||h>59||g>60)return null;const D=new Date(0);if(D.setUTCFullYear(f,d-1,p),D.getUTCMonth()!==d-1||D.getUTCDate()!==p)return null;D.setUTCHours(m,h,g);let y=D.getTime();if(void 0!==u){const e=void 0!==c?1e3:void 0!==a?6e4:36e5;y+=Math.round(Number(`0.${u}`)*e)}if(l&&"Z"!==l){const e=l.slice(1).replace(":",""),n=Number(e.slice(0,2)),t=e.length>2?Number(e.slice(2,4)):0;if(n>23||t>59)return null;y-=("-"===l[0]?-1:1)*(60*n+t)*6e4}return new Date(y)}registerAttributeTypes([{oid:"2.5.4.0",names:["objectClass"]},{oid:"2.5.4.3",names:["cn","commonName"]},{oid:"2.5.4.4",names:["sn","surname"]},{oid:"2.5.4.5",names:["serialNumber"]},{oid:"2.5.4.6",names:["c","countryName"]},{oid:"2.5.4.7",names:["l","localityName"]},{oid:"2.5.4.8",names:["st","stateOrProvinceName"]},{oid:"2.5.4.9",names:["street","streetAddress"]},{oid:"2.5.4.10",names:["o","organizationName"]},{oid:"2.5.4.11",names:["ou","organizationalUnitName"]},{oid:"2.5.4.12",names:["title"]},{oid:"2.5.4.42",names:["givenName","gn"]},{oid:"2.5.4.43",names:["initials"]},{oid:"2.5.4.46",names:["dnQualifier"]},{oid:"2.5.4.65",names:["pseudonym"]},{oid:"0.9.2342.19200300.100.1.1",names:["uid","userid"]},{oid:"0.9.2342.19200300.100.1.3",names:["mail","rfc822Mailbox"]},{oid:"0.9.2342.19200300.100.1.25",names:["dc","domainComponent"]},{oid:"2.16.840.1.113730.3.1.241",names:["displayName"]},{oid:"2.16.840.1.113730.3.1.3",names:["employeeNumber"]},{oid:"1.3.6.1.1.1.1.0",names:["uidNumber"]},{oid:"1.3.6.1.1.1.1.1",names:["gidNumber"]}]);const asyncHandler=e=>(n,t,r)=>{Promise.resolve(e(n,t,r)).catch(r)};export{assertRfc4514Escapes,assertedRdnValue,asyncHandler,canonicalDn,escapeDnValue,escapeLdapFilter,escapeRegex,fillPattern,getCompiledRegex,getParentDn,getRdn,hasOnlyRfc4514Escapes,isChildOf,isDirectChildOf,isDnInBranch,isDnSyntax,isDummyMemberDn,knownAttributeName,movedToTrash,namesByDn,normalizeDn,organizationLink,parseDirectoryDate,parseDn,rdnTypes,rdnValue,registerAttributeTypes,substringSearchFilter,transformSchemas,unescapeDnValue,validateDnValue};
|
|
1
|
+
import{BadRequestError as e}from"./errors.js";import"./expressFormatedResponses.js";import"./metrics.js";import"./requestContext.js";const n=new Map;function getCompiledRegex(e,t){const r=t?`${e}:${t}`:e;let i=n.get(r);return i||(i=new RegExp(e,t),n.set(r,i)),i}function escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}const transformSchemas=(e,n)=>e.toString().replace(/__(\S+)__/g,(e,t)=>{if(!t||"string"!=typeof t)return e;const r=t.trim().toLowerCase(),i=n;return i[r]?"object"!=typeof i[r]?i[r]:JSON.stringify(i[r]):e});function escapeLdapFilter(e){return e.replace(/\\/g,"\\5c").replace(/\*/g,"\\2a").replace(/\(/g,"\\28").replace(/\)/g,"\\29").replace(/\0/g,"\\00")}function substringSearchFilter(n,t){const r=/^[a-zA-Z][a-zA-Z0-9-]*$/,i=t.split(",").map(e=>e.trim()).filter(Boolean);if(0===i.length||!i.every(e=>r.test(e)))throw new e("Invalid LDAP attribute name");const s=escapeLdapFilter(n),o=i.map(e=>`(${e}=*${s}*)`);return 1===o.length?o[0]:`(|${o.join("")})`}function fillPattern(e,n,t){return e.split(n).join(t)}function escapeDnValue(e){let n=e.replace(/[\\,+"<>;=]/g,e=>`\\${e}`).replace(/[\0-\x1f\x7f]/g,e=>`\\${hexByte(e.charCodeAt(0))}`);return e.startsWith(" ")&&(n=`\\${n}`),e.length>1&&e.endsWith(" ")&&(n=`${n.slice(0,-1)}\\ `),e.startsWith("#")&&(n=`\\${n}`),n}const t=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0});function unescapeDnValue(n){if("string"!=typeof n)throw new e("DN value must be a string");let t="",r=0,i=[];const flushBytes=()=>{if(i.length){for(const e of utf8Chars(i))t+="number"==typeof e?String.fromCharCode(e):e;i=[]}};for(;r<n.length;)if("\\"===n[r]&&r+1<n.length){const e=n[r+1];if(/[0-9a-fA-F]/.test(e)&&r+2<n.length){const e=n.substring(r+1,r+3);if(/^[0-9a-fA-F]{2}$/.test(e)){i.push(parseInt(e,16)),r+=3;continue}}flushBytes(),t+=e,r+=2}else flushBytes(),t+=n[r],r++;return flushBytes(),t}function validateDnValue(e,n){if(null==e||"string"!=typeof e)throw new Error(`${n} must be a string`);if(0===e.trim().length)throw new Error(`${n} must be a non-empty string`);if(/[\x00-\x1F\x7F]/.test(e))throw new Error(`${n} contains invalid control characters`);if(/[\u200B-\u200F\uFEFF]/.test(e))throw new Error(`${n} contains invalid invisible characters`)}function asciiSpace(e){return" "===e||e>="\t"&&e<="\r"}function trimUnescaped(e){let n=0,t=e.length;for(;n<t&&asciiSpace(e[n]);)n++;for(;t>n&&asciiSpace(e[t-1]);)t--;if(t<e.length){let r=0;for(let i=t-1;i>=n&&"\\"===e[i];i--)r++;r%2==1&&t++}return e.slice(n,t)}function parseDn(n){if("string"!=typeof n)throw new e("DN must be a string");const t=[];let r="",i=!1,s=!1;for(let e=0;e<n.length;e++){const o=n[e];i?(r+=o,i=!1):"\\"===o?(r+=o,i=!0):'"'===o&&(s||opensValue(r))?(r+=o,s=!s):s||","!==o&&";"!==o?r+=o:(t.push(trimUnescaped(r)),r="")}if(s)throw new e("DN has an unbalanced quote");return r&&t.push(trimUnescaped(r)),t}function opensValue(e){const n=e.trimEnd();if(!n.endsWith("="))return!1;let t=0;for(let e=n.length-2;e>=0&&"\\"===n[e];e--)t++;return t%2==0}function isDnSyntax(e){let n;try{n=parseDn(e)}catch{return!1}if(0===n.length)return!1;const t=/^\s*(?:[A-Za-z][A-Za-z0-9-]*|(?:OID\.)?\d+(?:\.\d+)+)\s*=/i;return n.every(e=>{if(!e)return!1;const n=[];let r="",i=!1;for(const t of e){if(i)i=!1;else if("\\"===t)i=!0;else if("+"===t){n.push(r),r="";continue}r+=t}return n.push(r),n.every(e=>{if(!t.test(e))return!1;return!trimUnescaped(e.slice(e.indexOf("=")+1)).startsWith("#")})})}const r=new Set(['"',"+",",",";","<",">","\\","#","="," "]);function hasOnlyRfc4514Escapes(e){for(let n=0;n<e.length;n++){if("\\"!==e[n])continue;const t=e[n+1];if(void 0===t)return!1;if(r.has(t))n++;else{if(!/^[0-9a-fA-F]{2}$/.test(e.slice(n+1,n+3)))return!1;n+=2}}return!0}function assertRfc4514Escapes(n,t){if(!hasOnlyRfc4514Escapes(n))throw new e(`${t} uses an escape RFC 4514 does not define`)}function getParentDn(e){const n=parseDn(e);return n.length<=1?e:n.slice(1).join(",")}function getRdn(e){return parseDn(e)[0]||""}function rdnValue(e){const[n]=parseDn(e);return rdnValueOf(n)}function unquotedValue(e){let n=0;for(let t=e.length-2;t>0&&"\\"===e[t];t--)n++;return e.length>=2&&e.startsWith('"')&&e.endsWith('"')&&n%2==0?e.slice(1,-1):e}function rdnValueOf(e){if(!e)return"";const n=e.indexOf("=");if(n<=0)return"";let t=n+1;for(;t<e.length&&asciiSpace(e[t]);)t++;return unescapeDnValue(unquotedValue(e.slice(t)))}function dropSpaces(e){const n=e.filter((n,t)=>" "!==n||" "!==e[t-1]);let t=0,r=n.length;for(;t<r&&" "===n[t];)t++;for(;r>t&&" "===n[r-1];)r--;return n.slice(t,r)}function assertedRdnValue(e,n,t){const[r]=parseDn(e),i=r?r.indexOf("="):-1;return i<=0||r.slice(0,i).trim().toLowerCase()!==n.toLowerCase()||splitRdn(r).length>1?null:void 0===t||isDirectChildOf(e,t)?dropSpaces([...rdnValueOf(r).normalize("NFKC")]).join(""):null}function namesByDn(e,n){try{const[t]=parseDn(e),r=t?t.indexOf("="):-1;return r>0&&t.slice(0,r).trim().toLowerCase()===n.toLowerCase()}catch{return!1}}function isChildOf(e,n){try{return isDnInBranch(e,n)&&!isDnInBranch(n,e)}catch{return!1}}function isDirectChildOf(e,n){try{const[,...t]=parseDn(e);return t.length>0&&normalizeDn(t.join(","))===normalizeDn(n)}catch{return!1}}const i=/((?:\\[0-9a-fA-F]{2})+)|\\([^])/g;function hexByte(e){return e.toString(16).padStart(2,"0")}function utf8Chars(e){const n=[],r=Uint8Array.from(e);for(let i=0;i<e.length;){const s=utf8Length(e[i]);let o;if(s&&i+s<=e.length)try{o=t.decode(r.subarray(i,i+s))}catch{}void 0===o?n.push(e[i++]):(n.push(...o),i+=s)}return n}function utf8Length(e){return e<128?1:e>>5==6?2:e>>4==14?3:e>>3==30?4:0}const s=new Map,o=new Map;function registerAttributeTypes(e){for(const{oid:n,names:t}of e){const e=(t[0]??n).toLowerCase();for(const r of[n,...t])s.set(r.toLowerCase(),e),o.set(r.toLowerCase(),t[0]??n)}}function knownAttributeName(e){return o.get(e.toLowerCase().replace(/^oid\./,""))}function rdnTypes(e){return splitRdn(parseDn(e)[0]??"").map(e=>{const n=e.indexOf("=");return-1===n?"":canonicalType(e.slice(0,n).trim())})}function canonicalType(e){const n=e.toLowerCase().replace(/^oid\./,"");return s.get(n)??n}function splitRdn(e){const n=[];let t="",r=!1,i=!1;for(const s of e){if(r)r=!1;else if("\\"===s)r=!0;else if('"'===s&&(i||opensValue(t)))i=!i;else if("+"===s&&!i){n.push(t),t="";continue}t+=s}return n.push(t),n}function normalizeDn(e){return normalizedRdns(e).join(",")}function canonicalDn(e){return normalizedRdns(e,!1).join(",")}function normalizedRdns(e,n=!0){return parseDn(e).map(e=>splitRdn(e).map(e=>{const t=e.indexOf("=");if(-1===t)return e.trim().toLowerCase();const r=function(e,n=!0){const t=trimUnescaped(e);if(/^#(?:[0-9a-fA-F]{2})+$/.test(t))return t;e=unquotedValue(t);const r=[];let s=0;const plain=e=>{for(const n of e)r.push(n)};for(const n of e.matchAll(i)){plain(e.slice(s,n.index)),s=n.index+n[0].length;const[,t,i]=n;if(void 0!==i){r.push(i);continue}const o=t.split("\\").filter(Boolean).map(e=>parseInt(e,16));for(const e of utf8Chars(o))"number"==typeof e?r.push(`\\${hexByte(e)}`):plain(e)}s<e.length&&plain(e.slice(s));const kept=e=>3===e.length&&"\\"===e[0],fold=e=>(n?e.toLowerCase():e).normalize("NFKC"),o=[];let a="";for(const e of r)kept(e)?(o.push(...fold(a),e),a=""):a+=e;o.push(...fold(a));const c=dropSpaces(o);let u="";for(const[e,n]of c.entries())kept(n)?u+=n:n.charCodeAt(0)<32||127===n.charCodeAt(0)?u+=`\\${hexByte(n.charCodeAt(0))}`:',+"\\<>;='.includes(n)||0===e&&"#"===n?u+=`\\${n}`:u+=n;return u}(e.slice(t+1),n);return`${canonicalType(e.slice(0,t).trim())}=${n?r.toLowerCase():r}`}).sort().join("+")).filter(e=>e.length>0)}function isDummyMemberDn(e,n){if(!n||"string"!=typeof e)return!1;if(e===n)return!0;try{return normalizeDn(e)===normalizeDn(n)}catch{return!1}}function organizationLink(e){for(const n of Array.isArray(e)?e:[e]){if(null==n)continue;const e=String(n).trim();if(e.length>0)return e}}function isDnInBranch(e,n){const t=normalizedRdns(n);if(0===t.length)return!1;const r=normalizedRdns(e);if(r.length<t.length)return!1;return r.slice(r.length-t.length).every((e,n)=>e===t[n])}function movedToTrash(e,n,t){return!!e&&isDnInBranch(t,e)&&!isDnInBranch(n,e)}function parseDirectoryDate(e){const n=String(e).trim(),t=/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})?(\d{2})?(?:[.,](\d+))?(Z|[+-]\d{2}(?::?\d{2})?)?$/.exec(n);if(!t){const e=new Date(n);return isNaN(e.getTime())?null:e}const[,r,i,s,o,a,c,u,l]=t,[f,d,p,m,h,g]=[r,i,s,o,a,c].map(e=>void 0===e?0:Number(e));if(d<1||d>12||m>23||h>59||g>60)return null;const D=new Date(0);if(D.setUTCFullYear(f,d-1,p),D.getUTCMonth()!==d-1||D.getUTCDate()!==p)return null;D.setUTCHours(m,h,g);let y=D.getTime();if(void 0!==u){const e=void 0!==c?1e3:void 0!==a?6e4:36e5;y+=Math.round(Number(`0.${u}`)*e)}if(l&&"Z"!==l){const e=l.slice(1).replace(":",""),n=Number(e.slice(0,2)),t=e.length>2?Number(e.slice(2,4)):0;if(n>23||t>59)return null;y-=("-"===l[0]?-1:1)*(60*n+t)*6e4}return new Date(y)}registerAttributeTypes([{oid:"2.5.4.0",names:["objectClass"]},{oid:"2.5.4.3",names:["cn","commonName"]},{oid:"2.5.4.4",names:["sn","surname"]},{oid:"2.5.4.5",names:["serialNumber"]},{oid:"2.5.4.6",names:["c","countryName"]},{oid:"2.5.4.7",names:["l","localityName"]},{oid:"2.5.4.8",names:["st","stateOrProvinceName"]},{oid:"2.5.4.9",names:["street","streetAddress"]},{oid:"2.5.4.10",names:["o","organizationName"]},{oid:"2.5.4.11",names:["ou","organizationalUnitName"]},{oid:"2.5.4.12",names:["title"]},{oid:"2.5.4.42",names:["givenName","gn"]},{oid:"2.5.4.43",names:["initials"]},{oid:"2.5.4.46",names:["dnQualifier"]},{oid:"2.5.4.65",names:["pseudonym"]},{oid:"0.9.2342.19200300.100.1.1",names:["uid","userid"]},{oid:"0.9.2342.19200300.100.1.3",names:["mail","rfc822Mailbox"]},{oid:"0.9.2342.19200300.100.1.25",names:["dc","domainComponent"]},{oid:"2.16.840.1.113730.3.1.241",names:["displayName"]},{oid:"2.16.840.1.113730.3.1.3",names:["employeeNumber"]},{oid:"1.3.6.1.1.1.1.0",names:["uidNumber"]},{oid:"1.3.6.1.1.1.1.1",names:["gidNumber"]}]);const asyncHandler=e=>(n,t,r)=>{Promise.resolve(e(n,t,r)).catch(r)};export{assertRfc4514Escapes,assertedRdnValue,asyncHandler,canonicalDn,escapeDnValue,escapeLdapFilter,escapeRegex,fillPattern,getCompiledRegex,getParentDn,getRdn,hasOnlyRfc4514Escapes,isChildOf,isDirectChildOf,isDnInBranch,isDnSyntax,isDummyMemberDn,knownAttributeName,movedToTrash,namesByDn,normalizeDn,organizationLink,parseDirectoryDate,parseDn,rdnTypes,rdnValue,registerAttributeTypes,substringSearchFilter,transformSchemas,unescapeDnValue,validateDnValue};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"../../abstract/plugin.js";import t from"../../lib/auth/base.js";import{runTogether as e}from"../../lib/authz/composition.js";import{AuthzRefusedError as i}from"../../lib/errors.js";import{unauthorized as n,ok as s}from"../../lib/expressFormatedResponses.js";import{getParentDn as a,isDnInBranch as r}from"../../lib/utils.js";import{dynamicOptions as o}from"./auth.options.js";import{verifyLdapPassword as h}from"./authzDynamicHash.js";import{defineRoute as u}from"../../lib/route.js";function asString(t){if(null!=t){if(Array.isArray(t)){const e=t[0];return null==e?void 0:Buffer.isBuffer(e)?e.toString():String(e)}return Buffer.isBuffer(t)?t.toString():String(t)}}class AuthzDynamic extends t{static optionDefinitions=o;name="authzDynamic";roles=["auth","authz","configurable"];tokens=[];lastLoad=0;lastFailure=0;cacheTtlMs;failureBackoffMs;base;tokenAttr;configAttr;tenantAttr;reloadEndpoint;loading;constructor(t){super(t);const e=this.options(o);if(this.base=e.authz_dynamic_base,this.cacheTtlMs=1e3*e.authz_dynamic_cache_ttl,this.failureBackoffMs=Math.max(Math.floor(this.cacheTtlMs/4),5e3),this.tokenAttr=e.authz_dynamic_token_attribute,this.configAttr=e.authz_dynamic_config_attribute,this.tenantAttr=e.authz_dynamic_tenant_attribute,this.reloadEndpoint=e.authz_dynamic_reload_endpoint,!this.base)throw new Error("authzDynamic requires --authz-dynamic-base (the LDAP branch holding token entries)")}api(t){if(super.api(t),this.reloadEndpoint){const e=this.config.api_prefix||"/api";u(t,{method:"post",path:`${e}/v1/authz-dynamic/reload`,handler:async({req:t,res:e})=>{t.authzToken?(await this.reload(),s(e,{success:!0,tokens:this.tokens.length})):n(e)}}),this.logger.info(`authzDynamic reload endpoint registered at ${e}/v1/authz-dynamic/reload`)}}async reload(){try{const t=Array.from(new Set(["dn","cn",this.tokenAttr,this.configAttr,this.tenantAttr])),e=await this.server.ldap.system.search({filter:"(objectClass=*)",scope:"sub",paged:!1,attributes:t},this.base),i=[];for(const t of e.searchEntries||[]){const e="string"==typeof t.dn?t.dn:String(t.dn),n=asString(t.cn)||"",s=asString(t[this.tokenAttr])||"";if(!s)continue;let a,r=[];const o=asString(t[this.configAttr]);if(o)try{const t=JSON.parse(o);t&&"string"==typeof t.tenant&&t.tenant&&(a=t.tenant),t&&Array.isArray(t.bases)&&(r=t.bases.filter(t=>t&&"string"==typeof t.dn&&t.dn.length>0).map(t=>({dn:t.dn,read:
|
|
1
|
+
import"../../abstract/plugin.js";import t from"../../lib/auth/base.js";import{runTogether as e}from"../../lib/authz/composition.js";import{AuthzRefusedError as i}from"../../lib/errors.js";import{unauthorized as n,ok as s}from"../../lib/expressFormatedResponses.js";import{getParentDn as a,isDnInBranch as r}from"../../lib/utils.js";import{dynamicOptions as o}from"./auth.options.js";import{verifyLdapPassword as h}from"./authzDynamicHash.js";import{defineRoute as u}from"../../lib/route.js";function asString(t){if(null!=t){if(Array.isArray(t)){const e=t[0];return null==e?void 0:Buffer.isBuffer(e)?e.toString():String(e)}return Buffer.isBuffer(t)?t.toString():String(t)}}class AuthzDynamic extends t{static optionDefinitions=o;name="authzDynamic";roles=["auth","authz","configurable"];tokens=[];lastLoad=0;lastFailure=0;cacheTtlMs;failureBackoffMs;base;tokenAttr;configAttr;tenantAttr;reloadEndpoint;loading;constructor(t){super(t);const e=this.options(o);if(this.base=e.authz_dynamic_base,this.cacheTtlMs=1e3*e.authz_dynamic_cache_ttl,this.failureBackoffMs=Math.max(Math.floor(this.cacheTtlMs/4),5e3),this.tokenAttr=e.authz_dynamic_token_attribute,this.configAttr=e.authz_dynamic_config_attribute,this.tenantAttr=e.authz_dynamic_tenant_attribute,this.reloadEndpoint=e.authz_dynamic_reload_endpoint,!this.base)throw new Error("authzDynamic requires --authz-dynamic-base (the LDAP branch holding token entries)")}api(t){if(super.api(t),this.reloadEndpoint){const e=this.config.api_prefix||"/api";u(t,{method:"post",path:`${e}/v1/authz-dynamic/reload`,handler:async({req:t,res:e})=>{t.authzToken?(await this.reload(),s(e,{success:!0,tokens:this.tokens.length})):n(e)}}),this.logger.info(`authzDynamic reload endpoint registered at ${e}/v1/authz-dynamic/reload`)}}async reload(){try{const t=Array.from(new Set(["dn","cn",this.tokenAttr,this.configAttr,this.tenantAttr])),e=await this.server.ldap.system.search({filter:"(objectClass=*)",scope:"sub",paged:!1,attributes:t},this.base),i=[];for(const t of e.searchEntries||[]){const e="string"==typeof t.dn?t.dn:String(t.dn),n=asString(t.cn)||"",s=asString(t[this.tokenAttr])||"";if(!s)continue;let a,r=[];const o=asString(t[this.configAttr]);if(o)try{const t=JSON.parse(o);t&&"string"==typeof t.tenant&&t.tenant&&(a=t.tenant),t&&Array.isArray(t.bases)&&(r=t.bases.filter(t=>t&&"string"==typeof t.dn&&t.dn.length>0).map(t=>({dn:t.dn,read:this.aclFlag(t.read,"read",t.dn,e),write:this.aclFlag(t.write,"write",t.dn,e),delete:this.aclFlag(t.delete,"delete",t.dn,e)})))}catch(t){this.logger.warn(`authzDynamic: invalid JSON in ${this.configAttr} of ${e}: ${String(t)}`)}const h="cn"===this.tenantAttr?n:asString(t[this.tenantAttr])||n,u=a||h;i.push({dn:e,cn:n,tenant:u,hash:s,bases:r})}this.tokens=i,this.lastLoad=Date.now(),this.lastFailure=0,this.logger.info(`authzDynamic: loaded ${i.length} token(s) from ${this.base}`)}catch(t){this.lastFailure=Date.now(),this.logger.error(`authzDynamic: failed to load tokens from ${this.base}: ${String(t)}`)}}aclFlag(t,e,i,n){return"boolean"==typeof t?t:(void 0!==t&&this.logger.warn(`authzDynamic: ${e} flag of ${i} in ${n} is ${String(JSON.stringify(t))}, not a boolean: permission refused`),!1)}async ensureFresh(){const t=Date.now();if(!(this.lastLoad>0&&t-this.lastLoad<this.cacheTtlMs||this.lastFailure>0&&t-this.lastFailure<this.failureBackoffMs))return this.loading||(this.loading=this.reload().finally(()=>{this.loading=void 0})),this.loading}bypassReason(t,e){if(0===e.length)return;const i=t;return e.includes("trusted-proxy")&&!0===i.trustedProxy&&i.proxyAuthUser?`trusted-proxy vouching for ${i.proxyAuthUser}`:t.user?e.includes("any-authenticated")?"any-authenticated":e.includes(t.user)?`identity ${t.user}`:void 0:void 0}identitySource(){return"req.user and req.userName: the token's tenant"}afterLoad(){super.afterLoad();const t=Object.values(this.server.loadedPlugins).filter(t=>t!==this&&t.roles?.includes("auth")&&e(this,{name:t.name,pathPrefixes:t.pathPrefixes||[]})).map(t=>t.name);if(0===t.length)return;const i=this.options(o).authz_dynamic_bypass;this.logger.warn(`authzDynamic: ${t.join(", ")} authenticate the same paths as this plugin, so a request can arrive already identified. It is `+(0===i.length?"checked against the ACLs of the token it carries, and refused without one — set --authz-dynamic-bypass to let an identity through without a token.":`let through without a token when it matches ${i.join(", ")} (--authz-dynamic-bypass), and checked against its token ACLs otherwise.`))}afterChain(t,e,i){const s=t;if(!s.authzDynamicPending)return i();s.authzDynamicPending=!1;const a=s.authzDynamicBypass??this.options(o).authz_dynamic_bypass,r=this.bypassReason(s,a);if(r)return this.logger.info(`authzDynamic: request allowed past the token ACLs (${r})`),i();this.logger.warn(s.authzDynamicPendingReason||"authzDynamic: no token on a request no bypass covers"),n(e)}refuseOrDefer(t,e,i,s,a){const r=this.bypassReason(t,a);if(r)return this.logger.info(`authzDynamic: request allowed past the token ACLs (${r})`),void this.passThrough(t,i);if(!t.user&&a.length>0){const e=t;return e.authzDynamicPending=!0,e.authzDynamicPendingReason=s,e.authzDynamicBypass=a,void this.passThrough(t,i)}this.logger.warn(s),n(e)}authMethod(t,e,i){const s=this.options(o).authz_dynamic_bypass,a=this.bypassReason(t,s);if(a)return this.logger.info(`authzDynamic: request allowed past the token ACLs (${a})`),void this.passThrough(t,i);this.ensureFresh().then(()=>{const n=t.headers.authorization;if(!n||!/^Bearer\s+/.test(n))return void this.refuseOrDefer(t,e,i,"authzDynamic: missing or invalid Authorization header",s);const a=n.slice(n.indexOf(" ")+1).trim();if(!a)return void this.refuseOrDefer(t,e,i,"authzDynamic: empty bearer token",s);let r;for(const t of this.tokens)if(h(a,t.hash)){r=t;break}if(!r){const n=a.length>8?`${a.substring(0,8)}...`:"***";return void this.refuseOrDefer(t,e,i,`authzDynamic: unauthorized token ${n}`,s)}t.user||this.publishIdentity(t,r.tenant),t.authzToken=r,i()}).catch(t=>{this.logger.error(`authzDynamic: authMethod error: ${String(t)}`),n(e)})}hooks={ldapsearchrequest:([t,e,i])=>{const n=this.activeToken(i);return n?(this.requireBranchPermission(n,t,"read"),[t,e,i]):[t,e,i]},ldapaddrequest:([t,e,i])=>{const n=this.activeToken(i);return n?(this.requireBranchPermission(n,a(t),"write"),[t,e,i]):[t,e,i]},ldapmodifyrequest:([t,e,i,n])=>{const s=this.activeToken(n);return s?(this.requireBranchPermission(s,a(t),"write"),[t,e,i,n]):[t,e,i,n]},ldapdeleterequest:([t,e])=>{const i=this.activeToken(e);if(!i)return[t,e];const n=Array.isArray(t)?t:[t];for(const t of n)this.requireBranchPermission(i,a(t),"delete");return[t,e]},ldaprenamerequest:([t,e,i])=>{const n=this.activeToken(i);return n?(this.requireBranchPermission(n,a(t),"read"),this.requireBranchPermission(n,a(e),"write"),[t,e,i]):[t,e,i]}};activeToken(t){return t?.authzToken}requireBranchPermission(t,e,n){for(const i of t.bases){let t;try{t=r(e,i.dn)}catch{continue}if(t&&i[n])return}throw this.logger.debug(`authzDynamic: token "${t.tenant}" denied ${n} on ${e}`),new i(`Token does not have ${n} permission on this branch`)}getConfigApiData(){return{enabled:!0,base:this.base,cacheTtlSeconds:this.cacheTtlMs/1e3,tokenCount:this.tokens.length,reloadEndpoint:this.reloadEndpoint?`${this.config.api_prefix||"/api"}/v1/authz-dynamic/reload`:void 0,tokenAttribute:this.tokenAttr,configAttribute:this.configAttr,tenantAttribute:this.tenantAttr}}_tokens(){return this.tokens}}export{AuthzDynamic as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import r from"../../abstract/plugin.js";import{trustedProxyOptions as
|
|
1
|
+
import{isIP as r}from"node:net";import e from"../../abstract/plugin.js";import{trustedProxyOptions as t}from"./auth.options.js";class TrustedProxy extends e{static optionDefinitions=t;name="trustedProxy";roles=["protect"];trustedNetworks=[];authHeader;constructor(...r){super(...r);const e=this.options(t),s=e.trusted_proxy;if(0===s.length)throw new Error("TrustedProxy plugin requires trusted_proxy configuration (array of IPs or CIDR ranges)");for(const r of s)try{this.trustedNetworks.push(this.parseCIDR(r))}catch(e){throw new Error(`Invalid trusted proxy address "${r}": ${e instanceof Error?e.message:String(e)}`)}this.authHeader=e.trusted_proxy_auth_header.toLowerCase(),this.logger.info(`Trusted proxy validation enabled for ${s.length} address(es): ${s.join(", ")} (auth header: ${this.authHeader})`)}api(r){r.use((r,e,t)=>{const s=r.socket.remoteAddress;if(!s)return this.logger.debug("No remote address, removing X-Forwarded-For header"),delete r.headers["x-forwarded-for"],t();const o=r.headers["x-forwarded-for"];if(this.isTrustedProxy(s)){r.trustedProxy=!0;const e=r.headers[this.authHeader];e?(r.proxyAuthUser=Array.isArray(e)?e[0]:e,this.logger.debug(`Request from trusted proxy ${s}, Auth-User: ${r.proxyAuthUser}, X-Forwarded-For: ${o?String(o):"(none)"}`)):this.logger.debug(`Request from trusted proxy ${s}, X-Forwarded-For: ${o?String(o):"(none)"}`)}else r.trustedProxy=!1,o&&(this.logger.warn(`Removing X-Forwarded-For header from untrusted source ${s} (was: ${String(o)})`),delete r.headers["x-forwarded-for"]);t()})}isTrustedProxy(r){try{const e=this.parseIP(r);for(const r of this.trustedNetworks)if(this.isInNetwork(e,r))return!0;return!1}catch(e){return this.logger.error(`Failed to parse IP address "${r}": ${e instanceof Error?e.message:String(e)}`),!1}}isInNetwork(r,e){const t=[];if(r.isIPv6===e.isIPv6&&t.push(r.ip),r.isIPv6&&!e.isIPv6){const e=this.mappedIPv4(r.ip);void 0!==e&&t.push(e)}return t.some(r=>(r&e.mask)===(e.ip&e.mask))}mappedIPv4(r){return r>>32n==0xffffn?0xffffffffn&r:void 0}parseIP(e){const t=e.indexOf("%"),s=e.includes(":")&&-1!==t?e.slice(0,t):e,o=r(s);if(6===o)return{ip:this.parseIPv6(s),isIPv6:!0};if(4===o)return{ip:this.parseIPv4(s),isIPv6:!1};throw new Error(`Invalid IP address: ${e}`)}parseCIDR(r){const e=r.indexOf("/"),t=-1===e?r:r.slice(0,e),s=-1===e?void 0:r.slice(e+1);if(t.includes("%"))throw new Error(`Invalid network address: ${t}`);const o=this.parseIP(t);let i,{isIPv6:n}=o,{ip:d}=o;if(void 0!==s){if(!/^\d{1,3}$/.test(s))throw new Error(`Invalid prefix length: ${s}`);if(i=Number(s),i>(n?128:32))throw new Error(`Invalid prefix length: ${s}`)}if(n&&(void 0===i||i>=96)){const r=this.mappedIPv4(d);void 0!==r&&(n=!1,d=r,void 0!==i&&(i-=96))}const a=n?128:32;let f;if(void 0===i)f=(1n<<BigInt(a))-1n;else if(0===i)f=0n;else{const r=BigInt(a);f=(1n<<r)-1n^(1n<<r-BigInt(i))-1n}return{ip:d,mask:f,isIPv6:n}}parseIPv4(e){if(4!==r(e))throw new Error(`Invalid IPv4 address: ${e}`);return e.split(".").reduce((r,e)=>r<<8n|BigInt(Number(e)),0n)}parseIPv6(e){if(6!==r(e))throw new Error(`Invalid IPv6 address: ${e}`);const t=/^(.*:)(\d+\.\d+\.\d+\.\d+)$/.exec(e);let s,o=e;if(t){const r=this.parseIPv4(t[2]);o=`${t[1]}${(r>>16n).toString(16)}:${(0xffffn&r).toString(16)}`}const i=o.split("::");if(i.length>2)throw new Error(`Invalid IPv6 address: ${e}`);if(2===i.length){const r=i[0]?i[0].split(":"):[],t=i[1]?i[1].split(":"):[],o=8-r.length-t.length;if(o<0)throw new Error(`Invalid IPv6 address: ${e}`);s=[...r,...Array(o).fill("0"),...t]}else s=o.split(":");if(8!==s.length)throw new Error(`Invalid IPv6 address: ${e}`);let n=0n;for(const r of s){if(!/^[0-9a-fA-F]{1,4}$/.test(r))throw new Error(`Invalid IPv6 address: ${e}`);n=n<<16n|BigInt(parseInt(r,16))}return n}}export{TrustedProxy as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"../../abstract/plugin.js";import{roleAttribute as e}from"../../config/schema.js";import{isDnInBranch as r,
|
|
1
|
+
import t from"../../abstract/plugin.js";import{roleAttribute as e}from"../../config/schema.js";import{isDnInBranch as r,getParentDn as a,parseDn as n,normalizeDn as i,rdnValue as s,escapeLdapFilter as o,rdnTypes as h}from"../../lib/utils.js";import{organizationOptionsOf as c}from"./ldap.options.js";function isOrganizationDn(t){try{return h(t).includes("ou")}catch{return!1}}class LdapDepartmentSync extends t{name="ldapDepartmentSync";roles=["consistency"];settings;linkAttr;pathAttr;constructor(t){super(t),this.settings=c(t.config),this.linkAttr=this.settings.ldap_organization_link_attribute,this.pathAttr=this.settings.ldap_organization_path_attribute}organizationPathAttribute(){const t=this.server.loadedPlugins.ldapOrganizations;return e(t?.schema,"organizationPath")||this.pathAttr}linkedAttributes(){const t=[],r=this.server.loadedPlugins.ldapFlatGeneric;for(const e of r?.instances||[])t.push(e.schema);const a=this.server.loadedPlugins.ldapGroups;t.push(a?.schema);const n=[];for(const r of t){const t=e(r,"organizationLink");t&&n.push({link:t,path:e(r,"organizationPath")||this.pathAttr})}n.push({link:this.linkAttr,path:this.pathAttr});const i=new Set;return n.filter(({link:t,path:e})=>{const r=`${t.toLowerCase()} ${e.toLowerCase()}`;return!i.has(r)&&(i.add(r),!0)})}hooks={ldaprenamedone:async(t,e)=>{const n=this.settings.ldap_top_organization;if(n&&r(t,n)&&isOrganizationDn(t)){this.logger.info(`Organization renamed from ${t} to ${e}, synchronizing linked resources...`);try{const r=a(n);await this.updateOrganizationPaths(e);for(const a of this.linkedAttributes())await this.updateLinkedResources(t,e,r,a),await this.updateDescendantReferences(t,e,r,a)}catch(t){this.logger.error(`Error synchronizing department links after rename: ${t}`)}}}};async updateOrganizationPaths(t){const e=this.organizationPathAttribute(),o=this.settings.ldap_top_organization;if(!o||!r(t,o))return;const h=this.settings.ldap_organization_path_separator,c=await this.server.ldap.system.search({paged:!0,scope:"sub",filter:`(${e}=*)`,attributes:[e]},t),d=[];for await(const t of c)for(const r of t.searchEntries){const t=String(r.dn);if(!isOrganizationDn(t))continue;const a=r[e];d.push({dn:t,path:String(Array.isArray(a)?a[0]:a)})}d.sort((t,e)=>n(t.dn).length-n(e.dn).length);const l=i(o),g=new Map;let p=0;for(const{dn:t,path:r}of d){const n=a(t),o=i(n);let c;if(o!==l&&(c=g.get(o)??await this.readPath(n)??void 0,void 0===c)){this.logger.warn(`Organization ${n} has no ${e}: the path of ${t} is left as it is`);continue}const d=s(t),u=c?`${c}${h}${d}`:d;if(g.set(i(t),u),u!==r)try{await this.server.ldap.system.modify(t,{replace:{[e]:u}}),p++}catch(e){this.logger.error(`Failed to update the path of ${t} after organization rename: ${e}`)}}this.logger.info(`Updated the path of ${p} organizations below ${t}`)}async readPath(t){const e=this.organizationPathAttribute();try{const r=await this.server.ldap.system.search({paged:!1,scope:"base",attributes:[e]},t),a=r.searchEntries[0]?.[e];return void 0===a?null:String(Array.isArray(a)?a[0]:a)}catch{return null}}async updateLinkedResources(t,e,r,a){const n=`(${a.link}=${o(t)})`;this.logger.debug(`Searching for resources directly linked to ${t}: ${n}`);const i=await this.server.ldap.system.search({paged:!0,filter:n,attributes:[a.link,a.path]},r);let s=0;for await(const t of i)for(const r of t.searchEntries){const t=String(r.dn);try{const r=await this.getDepartmentPath(e);await this.server.ldap.system.modify(t,{replace:{[a.link]:e,[a.path]:r}}),s++,this.logger.debug(`Updated ${t}: ${a.link}=${e}, ${a.path}=${r}`)}catch(e){this.logger.error(`Failed to update ${t} after organization rename: ${e}`)}}this.logger.info(`Updated ${s} resources directly linked to the renamed organization`)}async updateDescendantReferences(t,e,a,n){const s=`(${n.link}=*)`;this.logger.debug(`Searching for resources linked to descendants of ${t}: ${s}`);const o=await this.server.ldap.system.search({paged:!0,filter:s,attributes:[n.link,n.path]},a);let h=0;for await(const a of o)for(const s of a.searchEntries){const a=String(s.dn),o=s[n.link],c=Array.isArray(o)?String(o[0]):String(o);if(i(c)!==i(t)&&r(c,t))try{const r=this.replaceDnTail(c,t,e),i=await this.getDepartmentPath(r);await this.server.ldap.system.modify(a,{replace:{[n.link]:r,[n.path]:i}}),h++,this.logger.debug(`Updated descendant link ${a}: ${n.link}=${r}, ${n.path}=${i}`)}catch(t){this.logger.error(`Failed to update descendant reference ${a}: ${t}`)}}this.logger.info(`Updated ${h} resources linked to descendants of the renamed organization`)}replaceDnTail(t,e,r){const a=n(t),i=n(e).length;return[...a.slice(0,a.length-i),r].join(",")}async getDepartmentPath(t){const e=this.organizationPathAttribute();try{const r=await this.server.ldap.system.search({paged:!1,scope:"base",attributes:[e,"ou","o"]},t);if(!r.searchEntries||0===r.searchEntries.length)throw new Error(`Organization ${t} not found`);const a=r.searchEntries[0];if(a[e]){const t=a[e];return Array.isArray(t)?String(t[0]):String(t)}const n=a.ou||a.o;if(n){return`/${Array.isArray(n)?String(n[0]):String(n)}`}return this.logger.warn(`Organization ${t} has no ${e} attribute, using DN`),t}catch(e){throw new Error(`Failed to fetch organization ${t}: ${String(e)}`,{cause:e})}}}export{LdapDepartmentSync as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"fs";import{readOptions as s}from"../../config/options.js";import{assertIdentityMode as r,identityFor as t}from"../../lib/auth/base.js";import{fillPattern as a,escapeDnValue as o,isChildOf as
|
|
1
|
+
import e from"fs";import{readOptions as s}from"../../config/options.js";import{assertIdentityMode as r,identityFor as t}from"../../lib/auth/base.js";import{fillPattern as a,escapeDnValue as o,isDnSyntax as i,isChildOf as u,normalizeDn as p}from"../../lib/utils.js";import{scimOptions as h}from"./scim.options.js";class BaseResolver{defaultUserBase;defaultGroupBase;userTemplate;groupTemplate;map;userBaseHeader;groupBaseHeader;headerRoot;config;constructor(t,a=s(h,t)){r(t,"scim base resolver"),this.config=t;const o=t.ldap_base||"";this.defaultUserBase=a.scim_user_base||o,this.defaultGroupBase=a.scim_group_base||o,this.userTemplate=a.scim_user_base_template,this.groupTemplate=a.scim_group_base_template,this.userBaseHeader=a.scim_user_base_header.toLowerCase(),this.groupBaseHeader=a.scim_group_base_header.toLowerCase(),this.headerRoot=a.scim_base_header_root;const i=a.scim_base_map;if(i)try{const s=e.readFileSync(i,"utf8");this.map=JSON.parse(s)}catch(e){throw new Error(`Failed to load SCIM base map from ${i}: ${e instanceof Error?e.message:String(e)}`)}}applyTemplate(e,s){return a(e,"{user}",s?o(s):"")}readHeader(e,s){if(!e||"object"!=typeof e)return;const r=e;if("function"==typeof r.get){const e=r.get(s);if("string"==typeof e&&e.length>0)return e}const t=r.headers?.[s];return"string"==typeof t&&t.length>0?t:Array.isArray(t)&&"string"==typeof t[0]&&t[0].length>0?t[0]:void 0}resolve(e,s){const r=s&&"object"==typeof s?t(s,this.config).value:void 0;if(this.map&&r&&this.map[r]){const s=this.map[r];if("user"===e&&s.userBase)return s.userBase;if("group"===e&&s.groupBase)return s.groupBase}const a="user"===e?this.userBaseHeader:this.groupBaseHeader;if(a&&this.headerRoot){const e=this.readHeader(s,a)?.trim();if(e&&i(e)&&!/[\u0000-\u001f\u007f]/.test(e)&&(e.toLowerCase()===this.headerRoot.toLowerCase()||u(e,this.headerRoot)))return p(e)}if(this.map&&this.map["*"]){const s=this.map["*"];if("user"===e&&s.userBase)return this.applyTemplate(s.userBase,r);if("group"===e&&s.groupBase)return this.applyTemplate(s.groupBase,r)}const o="user"===e?this.userTemplate:this.groupTemplate;return o?this.applyTemplate(o,r):"user"===e?this.defaultUserBase:this.defaultGroupBase}userBase(e){return this.resolve("user",e)}groupBase(e){return this.resolve("group",e)}}export{BaseResolver};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Express, Request, Response } from 'express';
|
|
2
|
-
import type { DM } from '../bin';
|
|
3
|
-
import type ldapActions from '../lib/ldapActions';
|
|
4
|
-
import type { AttributesList, AttributeValue, LdapList, ModifyRequest } from '../lib/ldapActions';
|
|
5
|
-
import type { Schema } from '../config/schema';
|
|
6
|
-
import { EntityValidator } from '../lib/entitySchema/validator';
|
|
7
|
-
import DmPlugin from './plugin';
|
|
2
|
+
import type { DM } from '../bin/index.js';
|
|
3
|
+
import type ldapActions from '../lib/ldapActions.js';
|
|
4
|
+
import type { AttributesList, AttributeValue, LdapList, ModifyRequest } from '../lib/ldapActions.js';
|
|
5
|
+
import type { Schema } from '../config/schema.js';
|
|
6
|
+
import { EntityValidator } from '../lib/entitySchema/validator.js';
|
|
7
|
+
import DmPlugin from './plugin.js';
|
|
8
8
|
/** What {@link LdapFlat.listEntries} is asked for. */
|
|
9
9
|
export interface ListEntriesOptions {
|
|
10
10
|
/** LDAP filter, every entry of the branch when absent */
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { Express } from 'express';
|
|
6
6
|
import type winston from 'winston';
|
|
7
|
-
import type { Config, DM } from '../bin';
|
|
8
|
-
import type { Hooks, MaybePromise } from '../hooks';
|
|
9
|
-
import type HookBus from '../lib/hookBus';
|
|
10
|
-
import type { HealthStatus } from '../lib/health';
|
|
11
|
-
import { type ServiceProvider, type ServiceToken } from '../lib/services';
|
|
12
|
-
import { type OptionsOf, type OptionSet } from '../config/options';
|
|
13
|
-
export { asyncHandler, escapeDnValue, unescapeDnValue, escapeLdapFilter, validateDnValue, } from '../lib/utils';
|
|
14
|
-
export { defineRoute, registeredRoutes } from '../lib/route';
|
|
15
|
-
export { serviceToken } from '../lib/services';
|
|
16
|
-
export type { ServiceProvider, ServiceToken } from '../lib/services';
|
|
17
|
-
export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UriTooLongError, TooManyRequestsError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, } from '../lib/errors';
|
|
7
|
+
import type { Config, DM } from '../bin/index.js';
|
|
8
|
+
import type { Hooks, MaybePromise } from '../hooks.js';
|
|
9
|
+
import type HookBus from '../lib/hookBus.js';
|
|
10
|
+
import type { HealthStatus } from '../lib/health.js';
|
|
11
|
+
import { type ServiceProvider, type ServiceToken } from '../lib/services/index.js';
|
|
12
|
+
import { type OptionsOf, type OptionSet } from '../config/options.js';
|
|
13
|
+
export { asyncHandler, escapeDnValue, unescapeDnValue, escapeLdapFilter, validateDnValue, } from '../lib/utils.js';
|
|
14
|
+
export { defineRoute, registeredRoutes } from '../lib/route.js';
|
|
15
|
+
export { serviceToken } from '../lib/services/index.js';
|
|
16
|
+
export type { ServiceProvider, ServiceToken } from '../lib/services/index.js';
|
|
17
|
+
export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UriTooLongError, TooManyRequestsError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, } from '../lib/errors.js';
|
|
18
18
|
export type { HealthStatus };
|
|
19
19
|
export type Role = 'auth' | 'authz' | 'protect' | 'api' | 'logging' | 'demo' | 'consistency' | 'configurable';
|
|
20
20
|
export default abstract class DmPlugin {
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Request } from 'express';
|
|
7
7
|
import pLimit from 'p-limit';
|
|
8
|
-
import type { DM } from '../bin';
|
|
9
|
-
import { type HealthStatus } from '../lib/health';
|
|
10
|
-
import type { AttributesList } from '../lib/ldapActions';
|
|
11
|
-
import DmPlugin, { type Role } from './plugin';
|
|
8
|
+
import type { DM } from '../bin/index.js';
|
|
9
|
+
import { type HealthStatus } from '../lib/health.js';
|
|
10
|
+
import type { AttributesList } from '../lib/ldapActions.js';
|
|
11
|
+
import DmPlugin, { type Role } from './plugin.js';
|
|
12
12
|
/** What a Twake plugin needs to reach its WebAdmin API */
|
|
13
13
|
export interface TwakeConnection {
|
|
14
14
|
url: string;
|
package/dist/src/bin/index.d.ts
CHANGED
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
import express from 'express';
|
|
15
15
|
import type winston from 'winston';
|
|
16
16
|
import type { Request, Response } from 'express';
|
|
17
|
-
import { type Config } from '../config/args';
|
|
18
|
-
import type { Hooks } from '../hooks';
|
|
19
|
-
import ldapActions from '../lib/ldapActions';
|
|
20
|
-
import type DmPlugin from '../abstract/plugin';
|
|
21
|
-
import AuthBase from '../lib/auth/base';
|
|
22
|
-
import { type ServiceMap } from '../lib/services';
|
|
23
|
-
import HookBus from '../lib/hookBus';
|
|
17
|
+
import { type Config } from '../config/args.js';
|
|
18
|
+
import type { Hooks } from '../hooks.js';
|
|
19
|
+
import ldapActions from '../lib/ldapActions.js';
|
|
20
|
+
import type DmPlugin from '../abstract/plugin.js';
|
|
21
|
+
import AuthBase from '../lib/auth/base.js';
|
|
22
|
+
import { type ServiceMap } from '../lib/services/index.js';
|
|
23
|
+
import HookBus from '../lib/hookBus.js';
|
|
24
24
|
export type { Config };
|
|
25
|
-
export * from '../lib/utils';
|
|
26
|
-
export { asyncHandler } from '../lib/utils';
|
|
27
|
-
export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, AuthzRefusedError, NotFoundError, ConflictError, UriTooLongError, TooManyRequestsError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, } from '../lib/errors';
|
|
25
|
+
export * from '../lib/utils.js';
|
|
26
|
+
export { asyncHandler } from '../lib/utils.js';
|
|
27
|
+
export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, AuthzRefusedError, NotFoundError, ConflictError, UriTooLongError, TooManyRequestsError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, } from '../lib/errors.js';
|
|
28
28
|
/**
|
|
29
29
|
* @class DM
|
|
30
30
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Client of the low-level LDAP API (`core/ldap/raw` plugin).
|
|
3
3
|
* @module browser/ldap-browser/api/RawApiClient
|
|
4
4
|
*/
|
|
5
|
-
import type { LdapSchema, RawChildren, RawEntry, RawSearchResult } from '../types';
|
|
5
|
+
import type { LdapSchema, RawChildren, RawEntry, RawSearchResult } from '../types.js';
|
|
6
6
|
export declare class RawApiClient {
|
|
7
7
|
private baseUrl;
|
|
8
8
|
private authToken?;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Lazy directory tree: one root per exposed base, children fetched on expand.
|
|
3
3
|
* @module browser/ldap-browser/components/EntryTree
|
|
4
4
|
*/
|
|
5
|
-
import { DisposableComponent } from '../../shared/components/DisposableComponent';
|
|
6
|
-
import type { RawApiClient } from '../api/RawApiClient';
|
|
5
|
+
import { DisposableComponent } from '../../shared/components/DisposableComponent.js';
|
|
6
|
+
import type { RawApiClient } from '../api/RawApiClient.js';
|
|
7
7
|
export declare class EntryTree extends DisposableComponent {
|
|
8
8
|
private container;
|
|
9
9
|
private api;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Attribute table of one entry, annotated with the directory schema.
|
|
3
3
|
* @module browser/ldap-browser/components/EntryView
|
|
4
4
|
*/
|
|
5
|
-
import type { SchemaView } from '../schema';
|
|
6
|
-
import type { RawEntry } from '../types';
|
|
5
|
+
import type { SchemaView } from '../schema.js';
|
|
6
|
+
import type { RawEntry } from '../types.js';
|
|
7
7
|
export declare class EntryView {
|
|
8
8
|
private container;
|
|
9
9
|
private schema;
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* LDAP Browser - low-level directory browser (read-only)
|
|
3
3
|
* @author Xavier Guimard
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export type { BrowserOptions, LdapSchema, RawAttribute, RawChild, RawEntry, RawSearchResult, ObjectClassDefinition, AttributeTypeDefinition, } from './types';
|
|
5
|
+
export { LdapBrowser } from './LdapBrowser.js';
|
|
6
|
+
export { RawApiClient } from './api/RawApiClient.js';
|
|
7
|
+
export { SchemaView } from './schema.js';
|
|
8
|
+
export type { BrowserOptions, LdapSchema, RawAttribute, RawChild, RawEntry, RawSearchResult, ObjectClassDefinition, AttributeTypeDefinition, } from './types.js';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module browser/ldap-browser/schema
|
|
9
9
|
*/
|
|
10
|
-
import type { AttributeTypeDefinition, LdapSchema, ObjectClassDefinition } from './types';
|
|
10
|
+
import type { AttributeTypeDefinition, LdapSchema, ObjectClassDefinition } from './types.js';
|
|
11
11
|
export declare class SchemaView {
|
|
12
12
|
readonly schema: LdapSchema;
|
|
13
13
|
private objectClasses;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* LDAP Group Editor - Main class for editing group properties
|
|
3
3
|
* @author Xavier Guimard
|
|
4
4
|
*/
|
|
5
|
-
import type { GroupEditorOptions, Config } from './types';
|
|
6
|
-
import { GroupApiClient } from './api/GroupApiClient';
|
|
5
|
+
import type { GroupEditorOptions, Config } from './types.js';
|
|
6
|
+
import { GroupApiClient } from './api/GroupApiClient.js';
|
|
7
7
|
export declare class LdapGroupEditor {
|
|
8
8
|
private options;
|
|
9
9
|
private api;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create Group Modal Component - Modal for creating a new group
|
|
3
3
|
*/
|
|
4
|
-
import type { GroupApiClient } from '../api/GroupApiClient';
|
|
5
|
-
import type { Config } from '../types';
|
|
4
|
+
import type { GroupApiClient } from '../api/GroupApiClient.js';
|
|
5
|
+
import type { Config } from '../types.js';
|
|
6
6
|
export declare class CreateGroupModal {
|
|
7
7
|
private api;
|
|
8
8
|
private config;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Group Property Editor Component - Edits properties of a selected group
|
|
3
3
|
*/
|
|
4
|
-
import type { GroupApiClient } from '../api/GroupApiClient';
|
|
4
|
+
import type { GroupApiClient } from '../api/GroupApiClient.js';
|
|
5
5
|
export declare class GroupPropertyEditor {
|
|
6
6
|
private container;
|
|
7
7
|
private api;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Move Group Modal Component - Modal for selecting target organization when moving a group
|
|
3
3
|
*/
|
|
4
|
-
import type { GroupApiClient } from '../api/GroupApiClient';
|
|
4
|
+
import type { GroupApiClient } from '../api/GroupApiClient.js';
|
|
5
5
|
export declare class MoveGroupModal {
|
|
6
6
|
private api;
|
|
7
7
|
private currentOrgDn;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LDAP Resource Editor - Generic API Client
|
|
3
3
|
*/
|
|
4
|
-
import type { Config, LdapResource, PointerOption, Schema, ResourceType } from '../types';
|
|
5
|
-
import { CacheManager } from '../cache/CacheManager';
|
|
4
|
+
import type { Config, LdapResource, PointerOption, Schema, ResourceType } from '../types.js';
|
|
5
|
+
import { CacheManager } from '../cache/CacheManager.js';
|
|
6
6
|
export declare class ResourceApiClient {
|
|
7
7
|
private baseUrl;
|
|
8
8
|
private cache;
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* LDAP Resource Editor - Generic browser library
|
|
3
3
|
* @author Xavier Guimard
|
|
4
4
|
*/
|
|
5
|
-
export { ResourceApiClient } from './api/ResourceApiClient';
|
|
6
|
-
export type { EditorOptions, LdapResource, Schema, SchemaAttribute, PointerOption, Config, ResourceType, NavigationType, ResourceTypeConfig, } from './types';
|
|
5
|
+
export { ResourceApiClient } from './api/ResourceApiClient.js';
|
|
6
|
+
export type { EditorOptions, LdapResource, Schema, SchemaAttribute, PointerOption, Config, ResourceType, NavigationType, ResourceTypeConfig, } from './types.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LDAP Resource Editor - Generic Type Definitions
|
|
3
3
|
*/
|
|
4
|
-
import type { LocalizedText } from '../shared/types';
|
|
4
|
+
import type { LocalizedText } from '../shared/types/index.js';
|
|
5
5
|
export type ResourceType = 'users' | 'groups' | 'organizations';
|
|
6
6
|
export type NavigationType = 'flat' | 'tree';
|
|
7
7
|
export interface EditorOptions {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TreeNode component - renders individual tree nodes
|
|
3
3
|
*/
|
|
4
|
-
import type { TreeState } from '../types';
|
|
5
|
-
import type { Store } from '../store/Store';
|
|
4
|
+
import type { TreeState } from '../types.js';
|
|
5
|
+
import type { Store } from '../store/Store.js';
|
|
6
6
|
export declare class TreeNodeComponent {
|
|
7
7
|
private dn;
|
|
8
8
|
private store;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TreeRoot component - renders the root container and tree
|
|
3
3
|
*/
|
|
4
|
-
import type { TreeState } from '../types';
|
|
5
|
-
import type { Store } from '../store/Store';
|
|
4
|
+
import type { TreeState } from '../types.js';
|
|
5
|
+
import type { Store } from '../store/Store.js';
|
|
6
6
|
export declare class TreeRoot {
|
|
7
7
|
private store;
|
|
8
8
|
private onClick;
|
|
@@ -2,6 +2,5 @@
|
|
|
2
2
|
* LDAP Tree Viewer - Browser library
|
|
3
3
|
* @author Xavier Guimard
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
export type { ViewerOptions, TreeNode, TreeState, NodeType, FilterType, } from './types';
|
|
5
|
+
export { LdapTreeViewer } from './LdapTreeViewer.js';
|
|
6
|
+
export type { ViewerOptions, TreeNode, TreeState, NodeType, FilterType, } from './types.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Action types and action creators
|
|
3
3
|
*/
|
|
4
|
-
import type { TreeNode } from '../types';
|
|
5
|
-
import type { Action } from './Store';
|
|
4
|
+
import type { TreeNode } from '../types.js';
|
|
5
|
+
import type { Action } from './Store.js';
|
|
6
6
|
export declare const Actions: {
|
|
7
7
|
readonly SET_ROOT: "SET_ROOT";
|
|
8
8
|
readonly ADD_NODE: "ADD_NODE";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reducers for tree state management
|
|
3
3
|
*/
|
|
4
|
-
import type { TreeState } from '../types';
|
|
5
|
-
import type { Action } from './Store';
|
|
4
|
+
import type { TreeState } from '../types.js';
|
|
5
|
+
import type { Action } from './Store.js';
|
|
6
6
|
export declare const initialState: TreeState;
|
|
7
7
|
export declare function treeReducer(state: TreeState, action: Action): TreeState;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* LDAP Unit Editor - Main component for editing organizational units
|
|
3
3
|
*/
|
|
4
4
|
import { UnitApiClient } from './api/UnitApiClient.js';
|
|
5
|
-
import type { UnitEditorOptions, Config } from './types';
|
|
5
|
+
import type { UnitEditorOptions, Config } from './types.js';
|
|
6
6
|
export declare class LdapUnitEditor {
|
|
7
7
|
private container;
|
|
8
8
|
private options;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* LDAP Unit Editor - Move Unit Modal Component
|
|
3
3
|
* Modal dialog for selecting target organization when moving a unit
|
|
4
4
|
*/
|
|
5
|
-
import type { UnitApiClient } from '../api/UnitApiClient';
|
|
5
|
+
import type { UnitApiClient } from '../api/UnitApiClient.js';
|
|
6
6
|
export declare class MoveUnitModal {
|
|
7
7
|
private modal;
|
|
8
8
|
private api;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unit Property Editor Component - Edits properties of a selected organizational unit
|
|
3
3
|
*/
|
|
4
|
-
import type { UnitApiClient } from '../api/UnitApiClient';
|
|
4
|
+
import type { UnitApiClient } from '../api/UnitApiClient.js';
|
|
5
5
|
export declare class UnitPropertyEditor {
|
|
6
6
|
private container;
|
|
7
7
|
private api;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* LDAP User Editor - Main class
|
|
3
3
|
* @author Xavier Guimard
|
|
4
4
|
*/
|
|
5
|
-
import type { EditorOptions, Config, LdapUser } from './types';
|
|
6
|
-
import { UserApiClient } from './api/UserApiClient';
|
|
5
|
+
import type { EditorOptions, Config, LdapUser } from './types.js';
|
|
6
|
+
import { UserApiClient } from './api/UserApiClient.js';
|
|
7
7
|
export declare class LdapUserEditor {
|
|
8
8
|
private options;
|
|
9
9
|
private api;
|