haraka/haraka-plugin-ldap

View on GitHub
index.js

Summary

Maintainability
A
3 hrs
Test Coverage
'use strict';

const util     = require('util');
const authn    = require('./authn');
const aliases  = require('./aliases');
const rcpt_to  = require('./rcpt_to');
const authz    = require('./authz');
const LdapPool = require('./pool').LdapPool;

const AUTH_COMMAND = 'AUTH';
const AUTH_METHOD_PLAIN = 'PLAIN';
const AUTH_METHOD_LOGIN = 'LOGIN';

exports.handle_authn = function (next, connection, params) {
    // we use this as hook so we can ignore auth calls with disabled auth plugin
    // see: auth/auth_base.js, exports.hook_unrecognized_command
    if (!connection.server.notes.ldappool.config.authn) return next();

    if (params[0].toUpperCase() === AUTH_COMMAND && params[1]) {
        return this.select_auth_method(next, connection, params.slice(1).join(' '));
    }

    if (!connection.notes.authenticating) return next();

    switch (connection.notes.auth_method) {
        case AUTH_METHOD_LOGIN:
            this.auth_login(next, connection, params);
            break;
        case AUTH_METHOD_PLAIN:
            this.auth_plain(next, connection, params);
            break;
        default:
            next();
    }
}

exports.hook_capabilities = (next, connection) => {
    // default: don't offer AUTH unless session is encrypted
    if (connection.using_tls) {
        const methods = [ 'PLAIN', 'LOGIN' ];
        connection.capabilities.push(`AUTH ${  methods.join(' ')}`);
        connection.notes.allowed_auth_methods = methods;
    }
    next();
}

exports.check_plain_passwd = function () {
    authn.check_plain_passwd(...arguments);
}

exports.aliases = function (next, connection, params) {
    if (!connection.server.notes.ldappool.config.aliases) return next();

    aliases.aliases(...arguments);
}

exports.check_rcpt = function (next, connection, params) {
    if (!connection.server.notes.ldappool.config.rcpt_to) return next();

    rcpt_to.check_rcpt.apply(rcpt_to, arguments);
}

exports.check_authz = function (next, connection, params) {
    if (!connection.server.notes.ldappool.config.authz) return next();

    authz.check_authz.apply(authz, arguments);
}

exports.register = function () {
    this.inherits('auth/auth_base');
    this.register_hook('init_master',  '_init_ldappool');
    this.register_hook('init_child',   '_init_ldappool');
    this.register_hook('rcpt', 'aliases');
    this.register_hook('rcpt', 'check_rcpt');
    this.register_hook('mail', 'check_authz');
    this.register_hook('unrecognized_command', 'handle_authn');
    this._load_ldap_ini();
}

exports._load_ldap_ini = function () {

    this.loginfo("loading ldap.ini");
    const cfg = this.config.get('ldap.ini', () => {
        this._load_ldap_ini();
    });

    if (this._pool) {
        this._pool._set_config(cfg);
        this.logdebug(`Current config: ${  util.inspect(this._pool.config)}`);
    }
    else {
        this._tmp_pool_config = cfg;
    }
}

exports._init_ldappool = function (next, server) {

    if (!server.notes.ldappool) {
        server.notes.ldappool = new LdapPool();
        if (this._tmp_pool_config) {
            server.notes.ldappool._set_config(this._tmp_pool_config);
            this._tmp_pool_config = undefined;
            this.logdebug(`Current config: ${  util.inspect(server.notes.ldappool.config)}`);
        }
    }
    this._pool = server.notes.ldappool;
    next();
}

exports.shutdown = function (next) {
    if (this._pool) this._pool.close(next || function () { });
}