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