OWASP/SSO_Project

View on GitHub
js-backend/utils/audit.js

Summary

Maintainability
B
6 hrs
Test Coverage
const ipCountry = require("ip-country");
const syslogPro = require("syslog-pro");

class Audit {
    constructor(dbConnection, ipCountrySettings) {
        this.db = dbConnection;
        
        ipCountry.init(ipCountrySettings);
    }
    prepareLoggers(customPages, version) {
        this.customPages = customPages;
        this.version = version;
        
        // Send hello
        const scheduledPromises = [];
        for (let websiteIndex of Object.keys(this.customPages)) {
            const thisPage = this.customPages[websiteIndex];
            if(!thisPage.hasOwnProperty("syslog")) continue;

            scheduledPromises.push(this.cefSend(thisPage.syslog, {
                "meta": "start",
            }));
        }
        
        Promise.all(scheduledPromises).then(() => {});
        
        // Stop previous and start new heartbeat
        if(this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer);
        }
        this.heartbeatTimer = setInterval(this.heartbeat.bind(this), (process.env.SYSLOGHEARTBEAT || 60) * 1000);
    }
    add(req, object, action, attribute) {
        return new Promise((resolve, reject) => {
            const userId = req.user ? req.user.id : null;
            const userName = req.user && req.user.username ? req.user.username : null;
            const ip = this.getIP(req);
            const ipInfo = ipCountry.lookup(ip);
            const country = (ipInfo && ipInfo.country) ? ipInfo.country.iso_code : null;
            
            const loggers = [];
            if(this.customPages["default"].hasOwnProperty("syslog")) {
                loggers.push(this.customPages["default"].syslog);
            }
            if(req.ssoRequest) {
                const thisPage = this.customPages[req.ssoRequest.pageId.toString()];
                if(thisPage.hasOwnProperty("syslog")) {
                    loggers.push(thisPage.syslog);
                }
            }
            
            this.databaseAdd(userId, ip, country, object, action, attribute).then(auditId => {
                const scheduledPromises = [];
                loggers.forEach(syslogItem => {
                    scheduledPromises.push(this.cefSend(syslogItem, {userName, userId, auditId, ip, country, object, action, attribute}));
                });
                
                Promise.all(scheduledPromises).then(results => {
                    resolve(auditId);
                }).catch(err => {
                    console.error(err);
                    reject(err);
                });
            });
        });
    }
    getList(userId, offset, length) {
        return new Promise((resolve, reject) => {
            this.db.execute("SELECT * FROM audit where user = ? ORDER BY created DESC LIMIT ?, ?", [userId, offset, length], (err, results) => {
                if(err) return reject(err);
                resolve(results);
            });
        });
    }
    get(id) {
        return new Promise((resolve, reject) => {
            this.db.execute("SELECT * FROM audit where id = ?", [id], (err, results) => {
                if(err) return reject(err);
                resolve(results);
            });
        });
    }
    databaseAdd(userId, ip, country, object, action, attribute) {
        return new Promise((resolve, reject) => {
            this.db.execute("INSERT INTO audit (user, ip, country, object, action, attribute1) VALUES (?, ?, ?, ?, ?, ?)", [userId, ip, country, object, action, attribute], (err, result) => {
                if(err) return reject(err);
                resolve(result.insertId);
            });
        });
    }
    heartbeat() {
        const scheduledPromises = [];
        for (let websiteIndex of Object.keys(this.customPages)) {
            const thisPage = this.customPages[websiteIndex];
            if(!thisPage.hasOwnProperty("syslog")) continue;
            
            scheduledPromises.push(this.cefSend(thisPage.syslog, {
                "meta": "heartbeat",
            }));
        }
        
        Promise.all(scheduledPromises).then(() => {}).catch(err => {
            console.error("Heartbeat failed", err);
        });
    }
    cefSend(syslogDst, attributes) {
        const currentDate = new Date();
        attributes.time = currentDate.toISOString();
        const cefMessage = new syslogPro.CEF({
            deviceVendor: "OWASP Foundation",
            deviceProduct: "OWASP SSO",
            deviceVersion: this.version,
            deviceEventClassId: "audit",
            name: "OWASP SSO",
            extensions: attributes,
            server: syslogDst,
        });
        return cefMessage.send();
    }
    getIP(req) {
        const forwardedFor = req.headers["x-forwarded-for"];
        const clientIP = req.connection.remoteAddress;
        
        if(forwardedFor) {
            if(forwardedFor.indexOf(",") != -1) {
                return ((forwardedFor.split(","))[0]).trim();
            } else {
                return forwardedFor;
            }
        } else {
            return clientIP;
        }
    }
}

exports.Audit = Audit;