{"version":3,"sources":["jsdelivr-header.js","/npm/ldap-authentication@4.0.3/index.js"],"names":[],"mappings":"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","file":"/npm/ldap-authentication@4.0.3/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/ldap-authentication@4.0.3/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","const assert = require('assert')\nconst ldapts = require('ldapts')\n// escape the , in CN in DN\nfunction _ldapEscapeDN(s) {\n  let ret = ''\n  let comaPositions = []\n  let done = false\n  let countEq = 0\n  for (let i = 0; !done && i < s.length; i++) {\n    switch (s[i]) {\n      case '\\\\':\n        // user already escapped, continue\n        i++\n        break\n      case ',':\n        if (countEq == 1) {\n          comaPositions.push(i)\n        }\n        break\n      case '=':\n        countEq++\n        if (countEq == 2) {\n          done = true\n        }\n        break\n    }\n  }\n  if (done) {\n    comaPositions.pop()\n  }\n  let lastIndex = 0\n  for (let i of comaPositions) {\n    ret += s.substring(lastIndex, i)\n    ret += '\\\\,'\n    lastIndex = i + 1\n  }\n  ret += s.substring(lastIndex)\n  return ret\n}\n\nconst AUTH_RESULT_FAILURE = 0\nconst AUTH_RESULT_SUCCESS = 1\nconst AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND = -1\nconst AUTH_RESULT_FAILURE_IDENTITY_AMBIGUOUS = -2\nconst AUTH_RESULT_FAILURE_CREDENTIAL_INVALID = -3\nconst AUTH_RESULT_FAILURE_UNCATEGORIZED = -4\n\nclass AuthenticationResult {\n  #authCode = AUTH_RESULT_FAILURE_UNCATEGORIZED\n  #identity\n  #user\n  #messages = []\n  #client\n\n  constructor(authCode, identity, user, messages, client) {\n    this.#authCode = authCode // one of the above constants\n    this.#identity = identity // identity supplied as string\n    this.#user     = user // user object found on ldap server OR null\n    this.#messages = messages // authentication messages array, which contains server messages\n    this.#client   = client // ldapClient instance\n  }\n\n  get code() {\n    return this.#authCode\n  }\n\n  get identity() {\n    return this.#identity\n  }\n\n  get messages() {\n    return this.#messages\n  }\n\n  get client() {\n    return this.#client\n  }\n\n  get user() {\n    return this.#user\n  }\n}\n\nconst authenticationMessages = {\n  AUTH_RESULT_FAILURE: 'Authentication failed',\n  AUTH_RESULT_SUCCESS: 'Authentication successful',\n  AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND: 'Authentication identity not found',\n  AUTH_RESULT_FAILURE_IDENTITY_AMBIGUOUS: 'Authentication identity ambiguous',\n  AUTH_RESULT_FAILURE_CREDENTIAL_INVALID: 'Invalid credentials',\n  AUTH_RESULT_FAILURE_UNCATEGORIZED: 'Uncategorized authentication failure',\n}\n\n// bind and return the ldap client\nasync function _ldapBind(dn, password, starttls, ldapOpts) {\n  // TODO: check if ldapts expects escaped dn or not (possible double escaping problems?)\n  dn = _ldapEscapeDN(dn)\n  ldapOpts.connectTimeout = ldapOpts.connectTimeout || 5000\n\n  // When using StartTLS, we need to exclude tlsOptions from the Client constructor\n  // and only pass them to the startTLS() method to avoid connection conflicts.\n  // According to ldapts documentation:\n  // - For LDAPS (ldaps://): pass tlsOptions to Client constructor\n  // - For StartTLS (ldap://): do NOT pass tlsOptions to Client constructor, only to startTLS()\n  // - For plain LDAP (ldap://): do NOT pass tlsOptions to Client constructor\n  let clientOpts = ldapOpts\n  const isLdaps = ldapOpts.url && ldapOpts.url.startsWith('ldaps://')\n\n  // Only pass tlsOptions to Client constructor if using ldaps:// protocol\n  // For ldap:// protocol (plain or StartTLS), exclude tlsOptions from constructor\n  if (!isLdaps && ldapOpts.tlsOptions) {\n    // Create a shallow copy of ldapOpts without tlsOptions for the Client constructor\n    const { tlsOptions, ...optsWithoutTls } = ldapOpts\n    clientOpts = optsWithoutTls\n  }\n\n  let client = new ldapts.Client(clientOpts)\n\n  if (starttls) {\n    await client.startTLS(ldapOpts.tlsOptions)\n  }\n\n  await client.bind(dn, password)\n  ldapOpts.log && ldapOpts.log.trace('bind success!')\n  return client\n}\n\n// search a user and return the object\nasync function _searchUser(\n  ldapClient,\n  searchBase,\n  usernameAttribute,\n  username,\n  attributes = null,\n  explicitBufferAttributes = null\n) {\n  let filter = new ldapts.EqualityFilter({\n    attribute: usernameAttribute,\n    value: username,\n  })\n  let searchOptions = {\n    filter: filter,\n    scope: 'sub',\n    attributes: attributes,\n  }\n  if (attributes) {\n    searchOptions.attributes = attributes\n  }\n  if(explicitBufferAttributes) {\n    searchOptions.explicitBufferAttributes = explicitBufferAttributes\n  }\n\n  // TODO: we don't support reference yet\n  // If the server was able to locate the entry referred to by the baseObject\n  // but could not search one or more non-local entries,\n  // the server may return one or more SearchResultReference messages,\n  // each containing a reference to another set of servers for continuing the operation.\n  // referral.uris\n  const { searchEntries, searchReferences } = await ldapClient.search(\n    searchBase,\n    searchOptions\n  )\n\n  let user\n  if (\n    !searchEntries ||\n    searchEntries.length < 1 ||\n    !searchEntries[0] ||\n    !searchEntries[0].dn\n  ) {\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND,\n      username,\n      null,\n      [authenticationMessages.AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND],\n      ldapClient\n    )\n  } else {\n    if (searchEntries.length > 1) {\n      return new AuthenticationResult(\n        AUTH_RESULT_FAILURE_IDENTITY_AMBIGUOUS,\n        username,\n        null,\n        [authenticationMessages.AUTH_RESULT_FAILURE_IDENTITY_AMBIGUOUS],\n        ldapClient\n      )\n    }\n\n    user = searchEntries[0]\n  }\n\n  // when attribute endwith ;binary, ldapts returns Buffer, we convert them into base64 string\n  if (user != null && attributes != null) {\n    for (let attr of attributes) {\n      if (attr.endsWith(';binary') && Buffer.isBuffer(user[attr])) {\n        user[attr] = user[attr].toString('base64')\n      }\n    }\n  }\n  // when attribute is one of the explicitBufferAttributes, should convert to base64 string\n  if (user != null && explicitBufferAttributes != null) {\n    for (let attr of explicitBufferAttributes) {\n      if (Buffer.isBuffer(user[attr])) {\n        user[attr] = user[attr].toString('base64')\n      }\n    }\n  }\n\n  return new AuthenticationResult(\n    AUTH_RESULT_SUCCESS,\n    username,\n    user,\n    [authenticationMessages.AUTH_RESULT_SUCCESS],\n    ldapClient\n  )\n}\n\n// search a groups which user is member\nasync function _searchUserGroups(\n  ldapClient,\n  searchBase,\n  user,\n  groupClass,\n  groupMemberAttribute = 'member',\n  groupMemberUserAttribute = 'dn'\n) {\n  // Below works, but prefer using ldapts Filter subclasses to build this search, so that correct escaping is done\n  // const filter = `(&(objectclass=${groupClass})(${groupMemberAttribute}=${user[groupMemberUserAttribute]}))`\n  const filter = new ldapts.AndFilter({\n    filters: [\n      new ldapts.EqualityFilter({\n        attribute: 'objectclass',\n        value: groupClass,\n      }),\n      new ldapts.EqualityFilter({\n        attribute: groupMemberAttribute,\n        value: user[groupMemberUserAttribute],\n      }),\n    ],\n  })\n\n  const { searchEntries, searchReferences } = await ldapClient.search(\n    searchBase,\n    {\n      filter: filter,\n      scope: 'sub',\n    }\n  )\n\n  let groups\n  if (!searchEntries || searchEntries.length < 1) {\n    groups = []\n  } else {\n    groups = searchEntries\n  }\n  // ldapjs has group.objectName, ldapts does not have it. instead, use dn\n  // add objectName back for backward compatibility\n  for (let group of groups) {\n    if (typeof group.objectName === 'undefined') {\n      group.objectName = group.dn\n    }\n  }\n  return groups\n}\n\nasync function authenticateWithAdmin(\n  adminDn,\n  adminPassword,\n  userSearchBase,\n  usernameAttribute,\n  username,\n  userPassword,\n  starttls,\n  ldapOpts,\n  groupsSearchBase,\n  groupClass,\n  groupMemberAttribute = 'member',\n  groupMemberUserAttribute = 'dn',\n  attributes = null,\n  explicitBufferAttributes = null\n) {\n  let ldapAdminClient\n  try {\n    ldapAdminClient = await _ldapBind(\n      adminDn,\n      adminPassword,\n      starttls,\n      ldapOpts\n    )\n  } catch (error) {\n    if (ldapAdminClient && ldapAdminClient.isConnected) {\n      await ldapAdminClient.unbind()\n    }\n\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE,\n      username,\n      null,\n      [authenticationMessages.AUTH_RESULT_FAILURE, error.message || 'admin bind failed'],\n      ldapAdminClient\n    )\n  }\n\n  let searchResult = await _searchUser(\n    ldapAdminClient,\n    userSearchBase,\n    usernameAttribute,\n    username,\n    attributes,\n    explicitBufferAttributes\n  )\n\n  let user = searchResult.user\n\n  if (!user || !user.dn) {\n    ldapOpts.log &&\n      ldapOpts.log.trace(\n        `admin did not find user! (${usernameAttribute}=${username})`\n      )\n    await ldapAdminClient.unbind()\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND,\n      username,\n      null,\n      [authenticationMessages.AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND],\n      ldapAdminClient\n    )\n  }\n  let userDn = user.dn\n  let ldapUserClient\n  try {\n    ldapUserClient = await _ldapBind(userDn, userPassword, starttls, ldapOpts)\n  } catch (error) {\n    if (ldapUserClient && ldapUserClient.isConnected) {\n      await ldapUserClient.unbind()\n    }\n\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE_CREDENTIAL_INVALID,\n      username,\n      null,\n      [authenticationMessages.AUTH_RESULT_FAILURE_CREDENTIAL_INVALID, error.message || 'invalid credentials'],\n      ldapAdminClient\n    )\n  }\n  if (groupsSearchBase && groupClass && groupMemberAttribute) {\n    let groups = await _searchUserGroups(\n      ldapAdminClient,\n      groupsSearchBase,\n      user,\n      groupClass,\n      groupMemberAttribute,\n      groupMemberUserAttribute\n    )\n    user.groups = groups\n  }\n  await ldapAdminClient.unbind()\n  await ldapUserClient.unbind()\n\n  return new AuthenticationResult(\n    AUTH_RESULT_SUCCESS,\n    username,\n    user,\n    [authenticationMessages.AUTH_RESULT_SUCCESS],\n    ldapAdminClient\n  )\n}\n\nasync function authenticateWithUser(\n  userDn,\n  userSearchBase,\n  usernameAttribute,\n  username,\n  userPassword,\n  starttls,\n  ldapOpts,\n  groupsSearchBase,\n  groupClass,\n  groupMemberAttribute = 'member',\n  groupMemberUserAttribute = 'dn',\n  attributes = null,\n  explicitBufferAttributes = null\n) {\n  let ldapUserClient\n  try {\n    ldapUserClient = await _ldapBind(userDn, userPassword, starttls, ldapOpts)\n  } catch (error) {\n    if (ldapUserClient && ldapUserClient.isConnected) {\n      await ldapUserClient.unbind()\n    }\n\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE,\n      username,\n      null,\n      [authenticationMessages.AUTH_RESULT_FAILURE, error.message || 'user bind failed'],\n      ldapUserClient\n    )\n  }\n  if (!usernameAttribute || !userSearchBase) {\n    // if usernameAttribute is not provided, no user detail is needed.\n    await ldapUserClient.unbind()\n    return new AuthenticationResult(\n      AUTH_RESULT_SUCCESS,\n      username,\n      {},\n      [authenticationMessages.AUTH_RESULT_SUCCESS],\n      ldapUserClient\n    )\n  }\n\n  let searchResult = await _searchUser(\n    ldapUserClient,\n    userSearchBase,\n    usernameAttribute,\n    username,\n    attributes,\n    explicitBufferAttributes\n  )\n\n  let user = searchResult.user\n\n  if (!user || !user.dn) {\n    ldapOpts.log &&\n      ldapOpts.log.trace(\n        `user logged in, but user details could not be found. (${usernameAttribute}=${username}). Probabaly wrong attribute or searchBase?`\n      )\n    await ldapUserClient.unbind()\n\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE,\n      username,\n      null,\n      [\n        authenticationMessages.AUTH_RESULT_FAILURE,\n        'user logged in, but user details could not be found. Probabaly usernameAttribute or userSearchBase is wrong?',\n      ],\n      ldapUserClient\n    )\n  }\n  if (groupsSearchBase && groupClass && groupMemberAttribute) {\n    let groups = await _searchUserGroups(\n      ldapUserClient,\n      groupsSearchBase,\n      user,\n      groupClass,\n      groupMemberAttribute,\n      groupMemberUserAttribute\n    )\n    user.groups = groups\n  }\n  await ldapUserClient.unbind()\n\n  return new AuthenticationResult(\n    AUTH_RESULT_SUCCESS,\n    username,\n    user,\n    [authenticationMessages.AUTH_RESULT_SUCCESS],\n    ldapUserClient\n  )\n}\n\nasync function verifyUserExists(\n  adminDn,\n  adminPassword,\n  userSearchBase,\n  usernameAttribute,\n  username,\n  starttls,\n  ldapOpts,\n  groupsSearchBase,\n  groupClass,\n  groupMemberAttribute = 'member',\n  groupMemberUserAttribute = 'dn',\n  attributes = null,\n  explicitBufferAttributes = null\n) {\n  let ldapAdminClient\n  try {\n    ldapAdminClient = await _ldapBind(\n      adminDn,\n      adminPassword,\n      starttls,\n      ldapOpts\n    )\n  } catch (error) {\n    if (ldapAdminClient && ldapAdminClient.isConnected) {\n      await ldapAdminClient.unbind()\n    }\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE,\n      username,\n      null,\n      [authenticationMessages.AUTH_RESULT_FAILURE, error.message || 'admin bind failed'],\n      ldapAdminClient\n    )\n  }\n\n  let searchResult = await _searchUser(\n    ldapAdminClient,\n    userSearchBase,\n    usernameAttribute,\n    username,\n    attributes,\n    explicitBufferAttributes\n  )\n\n  let user = searchResult.user\n\n  if (!user || !user.dn) {\n    ldapOpts.log &&\n      ldapOpts.log.trace(\n        `admin did not find user! (${usernameAttribute}=${username})`\n      )\n    await ldapAdminClient.unbind()\n    return new AuthenticationResult(\n      AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND,\n      username,\n      null,\n      [\n        authenticationMessages.AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND,\n        'user not found or usernameAttribute is wrong'\n      ],\n      ldapAdminClient\n    )\n  }\n  if (groupsSearchBase && groupClass && groupMemberAttribute) {\n    let groups = await _searchUserGroups(\n      ldapAdminClient,\n      groupsSearchBase,\n      user,\n      groupClass,\n      groupMemberAttribute,\n      groupMemberUserAttribute\n    )\n    user.groups = groups\n  }\n  await ldapAdminClient.unbind()\n  return new AuthenticationResult(\n    AUTH_RESULT_SUCCESS,\n    username,\n    user,\n    [authenticationMessages.AUTH_RESULT_SUCCESS],\n    ldapAdminClient\n  )\n}\n\nasync function authenticate(options) {\n  const result = await authenticateResult(options)\n\n  if (result.code !== AUTH_RESULT_SUCCESS) {\n    throw new LdapAuthenticationError(\n      result.messages[result.messages.length - 1]\n    )\n  }\n\n  return result.user\n}\n\nasync function authenticateResult(options) {\n  if (!options.userDn) {\n    assert(options.adminDn, 'Admin mode adminDn must be provided')\n    assert(options.adminPassword, 'Admin mode adminPassword must be provided')\n    assert(options.userSearchBase, 'Admin mode userSearchBase must be provided')\n    assert(\n      options.usernameAttribute,\n      'Admin mode usernameAttribute must be provided'\n    )\n    assert(options.username, 'Admin mode username must be provided')\n  } else {\n    assert(options.userDn, 'User mode userDn must be provided')\n  }\n  assert(\n    options.ldapOpts && options.ldapOpts.url,\n    'ldapOpts.url must be provided'\n  )\n\n  if (options.verifyUserExists) {\n    assert(options.adminDn, 'Admin mode adminDn must be provided')\n    assert(\n      options.adminPassword,\n      'adminDn and adminPassword must be both provided.'\n    )\n    return await verifyUserExists(\n      options.adminDn,\n      options.adminPassword,\n      options.userSearchBase,\n      options.usernameAttribute,\n      options.username,\n      options.starttls,\n      options.ldapOpts,\n      options.groupsSearchBase,\n      options.groupClass,\n      options.groupMemberAttribute,\n      options.groupMemberUserAttribute,\n      options.attributes,\n      options.explicitBufferAttributes\n    )\n  }\n\n  assert(options.userPassword, 'userPassword must be provided')\n  if (options.adminDn) {\n    assert(\n      options.adminPassword,\n      'adminDn and adminPassword must be both provided.'\n    )\n    return await authenticateWithAdmin(\n      options.adminDn,\n      options.adminPassword,\n      options.userSearchBase,\n      options.usernameAttribute,\n      options.username,\n      options.userPassword,\n      options.starttls,\n      options.ldapOpts,\n      options.groupsSearchBase,\n      options.groupClass,\n      options.groupMemberAttribute,\n      options.groupMemberUserAttribute,\n      options.attributes,\n      options.explicitBufferAttributes\n    )\n  }\n\n  assert(options.userDn, 'adminDn/adminPassword OR userDn must be provided')\n  return await authenticateWithUser(\n    options.userDn,\n    options.userSearchBase,\n    options.usernameAttribute,\n    options.username,\n    options.userPassword,\n    options.starttls,\n    options.ldapOpts,\n    options.groupsSearchBase,\n    options.groupClass,\n    options.groupMemberAttribute,\n    options.groupMemberUserAttribute,\n    options.attributes,\n    options.explicitBufferAttributes\n  )\n}\n\nclass LdapAuthenticationError extends Error {\n  constructor(message) {\n    super(message)\n    // Ensure the name of this error is the same as the class name\n    this.name = this.constructor.name\n    // This clips the constructor invocation from the stack trace.\n    // It's not absolutely essential, but it does make the stack trace a little nicer.\n    //  @see Node.js reference (bottom)\n    Error.captureStackTrace(this, this.constructor)\n  }\n}\n\nmodule.exports.AUTH_RESULT_FAILURE = AUTH_RESULT_FAILURE\nmodule.exports.AUTH_RESULT_SUCCESS = AUTH_RESULT_SUCCESS\nmodule.exports.AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND =\n  AUTH_RESULT_FAILURE_IDENTITY_NOT_FOUND\nmodule.exports.AUTH_RESULT_FAILURE_IDENTITY_AMBIGUOUS =\n  AUTH_RESULT_FAILURE_IDENTITY_AMBIGUOUS\nmodule.exports.AUTH_RESULT_FAILURE_CREDENTIAL_INVALID =\n  AUTH_RESULT_FAILURE_CREDENTIAL_INVALID\nmodule.exports.AUTH_RESULT_FAILURE_UNCATEGORIZED =\n  AUTH_RESULT_FAILURE_UNCATEGORIZED\n\nmodule.exports.AuthenticationResult = AuthenticationResult\n\nmodule.exports.authenticate = authenticate\nmodule.exports.authenticateResult = authenticateResult\nmodule.exports.LdapAuthenticationError = LdapAuthenticationError\n\nmodule.exports.exportForTesting = {\n  _ldapEscapeDN,\n}\n"]}