Fix issue with domain access during first factor phase

This commit is contained in:
Clement Michaud 2017-05-21 23:32:09 +02:00
parent 9e89a690fb
commit 9fddcc7e93
5 changed files with 74 additions and 33 deletions

View File

@ -46,3 +46,11 @@ export class InvalidTOTPError extends Error {
Object.setPrototypeOf(this, InvalidTOTPError.prototype);
}
}
export class DomainAccessDenied extends Error {
constructor(message?: string) {
super(message);
this.name = "DomainAccessDenied";
Object.setPrototypeOf(this, DomainAccessDenied.prototype);
}
}

View File

@ -2,9 +2,12 @@
import objectPath = require("object-path");
import BluebirdPromise = require("bluebird");
import express = require("express");
import AccessController from "../access_control/AccessController";
import exceptions = require("../Exceptions");
function verify_filter(req: express.Request, res: express.Response) {
const logger = req.app.get("logger");
const accessController: AccessController = req.app.get("access controller");
if (!objectPath.has(req, "session.auth_session"))
return BluebirdPromise.reject("No auth_session variable");
@ -18,12 +21,19 @@ function verify_filter(req: express.Request, res: express.Response) {
if (!objectPath.has(req, "session.auth_session.userid"))
return BluebirdPromise.reject("No userid variable");
const username = objectPath.get<express.Request, string>(req, "session.auth_session.userid");
const groups = objectPath.get<express.Request, string[]>(req, "session.auth_session.groups");
const host = objectPath.get<express.Request, string>(req, "headers.host");
const domain = host.split(":")[0];
const isAllowed = accessController.isDomainAllowedForUser(domain, username, groups);
if (!isAllowed) return BluebirdPromise.reject(
new exceptions.DomainAccessDenied("User '" + username + "' does not have access to " + domain));
if (!req.session.auth_session.first_factor ||
!req.session.auth_session.second_factor)
return BluebirdPromise.reject("First or second factor not validated");
return BluebirdPromise.reject(new exceptions.AccessDeniedError("First or second factor not validated"));
return BluebirdPromise.resolve();
}

View File

@ -3,10 +3,13 @@ import exceptions = require("../Exceptions");
import objectPath = require("object-path");
import BluebirdPromise = require("bluebird");
import express = require("express");
import AccessController from "../access_control/AccessController";
import AuthenticationRegulator from "../AuthenticationRegulator";
import { LdapClient } from "../LdapClient";
export = function (req: express.Request, res: express.Response) {
const username = req.body.username;
const password = req.body.password;
const username: string = req.body.username;
const password: string = req.body.password;
if (!username || !password) {
res.status(401);
res.send();
@ -14,10 +17,10 @@ export = function (req: express.Request, res: express.Response) {
}
const logger = req.app.get("logger");
const ldap = req.app.get("ldap");
const ldap: LdapClient = req.app.get("ldap");
const config = req.app.get("config");
const regulator = req.app.get("authentication regulator");
const accessController = req.app.get("access controller");
const regulator: AuthenticationRegulator = req.app.get("authentication regulator");
const accessController: AccessController = req.app.get("access controller");
logger.info("1st factor: Starting authentication of user \"%s\"", username);
logger.debug("1st factor: Start bind operation against LDAP");
@ -34,16 +37,14 @@ export = function (req: express.Request, res: express.Response) {
logger.debug("1st factor: Retrieve email from LDAP");
return BluebirdPromise.join(ldap.get_emails(username), ldap.get_groups(username));
})
.then(function (data: string[2]) {
const emails = data[0];
const groups = data[1];
.then(function (data: [string[], string[]]) {
const emails: string[] = data[0];
const groups: string[] = data[1];
if (!emails && emails.length <= 0) throw new Error("No email found");
logger.debug("1st factor: Retrieved email are %s", emails);
objectPath.set(req, "session.auth_session.email", emails[0]);
const isAllowed = accessController.isDomainAllowedForUser(username, groups);
if (!isAllowed) throw new Error("User not allowed to visit this domain");
objectPath.set(req, "session.auth_session.groups", groups);
regulator.mark(username, true);
res.status(204);
@ -67,6 +68,11 @@ export = function (req: express.Request, res: express.Response) {
res.status(403);
res.send("Access has been restricted for a few minutes...");
})
.catch(exceptions.DomainAccessDenied, (err: Error) => {
logger.error("1st factor: ", err);
res.status(401);
res.send("Access denied...");
})
.catch(function (err: Error) {
console.log(err.stack);
logger.error("1st factor: Unhandled error %s", err);

View File

@ -105,6 +105,20 @@ describe("test authentication token verification", function () {
it("should not be authenticated when session is partially initialized", function () {
return test_unauthorized({ first_factor: true });
});
it.only("should not be authenticated when domain is not allowed for user", function () {
req.headers.host = "test.example.com";
accessController.isDomainAllowedForUser.returns(false);
accessController.isDomainAllowedForUser.withArgs("test.example.com", "user", ["group1", "group2"]).returns(true);
return test_authorized({
first_factor: true,
second_factor: true,
userid: "user",
groups: ["group1", "group2"]
});
});
});
});

View File

@ -61,6 +61,9 @@ describe("test the first factor validation route", function() {
FirstFactor: false,
second_factor: false
}
},
headers: {
host: "home.example.com"
}
};
res = ExpressMock.ResponseMock();