ldapAuthenticationHandler.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { Client } from "ldapts";
  2. import { IAuthenticationHandler } from "./index.js";
  3. import { TotpChecker } from "./totpChecker.js";
  4. export interface LdapAuthenticationConfiguration {
  5. ldapUrl: string;
  6. bindDnField: string;
  7. bindBase: string;
  8. usernameField: string;
  9. totpField?: string|null;
  10. }
  11. interface AccountInformations {
  12. username: string;
  13. totp: string|null;
  14. }
  15. export class LdapAuthenticationHandler implements IAuthenticationHandler {
  16. private configuration: LdapAuthenticationConfiguration;
  17. public constructor(configuration: LdapAuthenticationConfiguration) {
  18. this.configuration = configuration;
  19. }
  20. private async tryBind(username: string, password: string): Promise<AccountInformations|null> {
  21. if (!username || !password)
  22. return null;
  23. const client = new Client({
  24. url: this.configuration.ldapUrl,
  25. timeout: 0,
  26. connectTimeout: 0,
  27. tlsOptions: {
  28. minVersion: 'TLSv1.2',
  29. },
  30. strictDN: true,
  31. });
  32. const bindDn = `${this.configuration.bindDnField}=${username},${this.configuration.bindBase}`;
  33. let totp: string|null = null;
  34. try {
  35. await client.bind(bindDn, password);
  36. if (this.configuration.totpField) {
  37. const data = await client.search(bindDn);
  38. let totpData = data.searchEntries[0]?.[this.configuration.totpField];
  39. if (typeof totpData === "string")
  40. totp = totpData;
  41. if (Array.isArray(totpData))
  42. totp = totpData.join("");
  43. else
  44. totp = totpData.toString("utf8");
  45. }
  46. }
  47. catch (ex) {
  48. console.error(ex);
  49. return null;
  50. }
  51. finally {
  52. client.unbind();
  53. }
  54. return <AccountInformations> {
  55. username: username,
  56. totp: totp
  57. };
  58. }
  59. public async tryLogin(username: string, password: string, totp?: string): Promise<boolean | null> {
  60. const account = await this.tryBind(username, password);
  61. if (!account)
  62. return null;
  63. return TotpChecker.ValidateTotp(account.totp, totp);
  64. }
  65. public async needTotp(username: string, password: string): Promise<boolean | null> {
  66. const account = await this.tryBind(username, password);
  67. if (!account)
  68. return null;
  69. return !!account.totp;
  70. }
  71. }