import ApplicationComponent from "swaf/ApplicationComponent"; import ldap, {InvalidCredentialsError, Server} from "ldapjs"; import {logger} from "swaf/Logger"; import Throttler from "swaf/Throttler"; import User from "swaf/auth/models/User"; import UserPasswordComponent from "swaf/auth/password/UserPasswordComponent"; export default class LDAPServerComponent extends ApplicationComponent { private server?: Server; public async start(): Promise { this.server = ldap.createServer({ log: console, }); this.server.bind('ou=users,dc=toot,dc=party', async (req: Record, res: Record void>, next: (err: unknown) => void) => { const rdns = req.dn.toString().split(', ').map((rdn: string) => rdn.split('=')); let username: string = ''; let email; for (const rdn of rdns) { if (rdn[0] === 'cn') { username = rdn[1]; } else if (rdn[0] === 'email') { email = rdn[1]; } } logger.debug('Matrix authentication attempt:', username, email); try { Throttler.throttle('ldap_auth', 3, 30 * 1000, username); } catch (e) { logger.debug('Too many auth requests'); next(new InvalidCredentialsError()); return; } const user = await User.select().where('name', username).first(); if (user) { const email = await user.mainEmail.get(); if (email) { if (await user.as(UserPasswordComponent).verifyPassword(req.credentials)) { logger.debug('Success'); res.end(); return; } } } logger.debug('Fail'); next(new InvalidCredentialsError()); }); this.server.unbind((req: unknown, res: unknown, next: () => void) => { logger.debug('Unbind', req); next(); }); this.server.listen(8389, '127.0.0.1', () => { logger.info(`LDAP server listening on ${this.server?.url}`); }); this.server.on('close', () => { logger.info('LDAP server closed.'); }); } public async stop(): Promise { await new Promise(resolve => { if (this.server) { this.server.close(() => { resolve(); }); } else { resolve(); } }); } }