mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Fix issue with domain access during first factor phase
This commit is contained in:
parent
9e89a690fb
commit
9fddcc7e93
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,17 +21,24 @@ 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();
|
||||
}
|
||||
|
||||
export = function(req: express.Request, res: express.Response) {
|
||||
export = function (req: express.Request, res: express.Response) {
|
||||
verify_filter(req, res)
|
||||
.then(function () {
|
||||
res.status(204);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import AccessControllerMock = require("../mocks/AccessController");
|
|||
import { LdapClientMock } from "../mocks/LdapClient";
|
||||
import ExpressMock = require("../mocks/express");
|
||||
|
||||
describe("test the first factor validation route", function() {
|
||||
describe("test the first factor validation route", function () {
|
||||
let req: ExpressMock.RequestMock;
|
||||
let res: ExpressMock.ResponseMock;
|
||||
let emails: string[];
|
||||
|
@ -21,7 +21,7 @@ describe("test the first factor validation route", function() {
|
|||
let regulator: AuthenticationRegulatorMock.AuthenticationRegulatorMock;
|
||||
let accessController: AccessControllerMock.AccessControllerMock;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
configuration = {
|
||||
ldap: {
|
||||
base_dn: "ou=users,dc=example,dc=com",
|
||||
|
@ -29,8 +29,8 @@ describe("test the first factor validation route", function() {
|
|||
}
|
||||
};
|
||||
|
||||
emails = [ "test_ok@example.com" ];
|
||||
groups = [ "group1", "group2" ];
|
||||
emails = ["test_ok@example.com"];
|
||||
groups = ["group1", "group2" ];
|
||||
|
||||
ldapMock = LdapClientMock();
|
||||
|
||||
|
@ -61,14 +61,17 @@ describe("test the first factor validation route", function() {
|
|||
FirstFactor: false,
|
||||
second_factor: false
|
||||
}
|
||||
},
|
||||
headers: {
|
||||
host: "home.example.com"
|
||||
}
|
||||
};
|
||||
res = ExpressMock.ResponseMock();
|
||||
});
|
||||
|
||||
it("should return status code 204 when LDAP binding succeeds", function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
res.send = sinon.spy(function() {
|
||||
it("should return status code 204 when LDAP binding succeeds", function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal("username", req.session.auth_session.userid);
|
||||
assert.equal(204, res.status.getCall(0).args[0]);
|
||||
resolve();
|
||||
|
@ -79,28 +82,28 @@ describe("test the first factor validation route", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("should retrieve email from LDAP", function(done) {
|
||||
res.send = sinon.spy(function() { done(); });
|
||||
it("should retrieve email from LDAP", function (done) {
|
||||
res.send = sinon.spy(function () { done(); });
|
||||
ldapMock.bind.returns(BluebirdPromise.resolve());
|
||||
ldapMock.get_emails = sinon.stub().withArgs("username").returns(BluebirdPromise.resolve([{mail: ["test@example.com"] }]));
|
||||
ldapMock.get_emails = sinon.stub().withArgs("username").returns(BluebirdPromise.resolve([{ mail: ["test@example.com"] }]));
|
||||
FirstFactor(req as any, res as any);
|
||||
});
|
||||
|
||||
it("should set email as session variables", function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
res.send = sinon.spy(function() {
|
||||
it("should set email as session variables", function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal("test_ok@example.com", req.session.auth_session.email);
|
||||
resolve();
|
||||
});
|
||||
const emails = [ "test_ok@example.com" ];
|
||||
const emails = ["test_ok@example.com"];
|
||||
ldapMock.bind.returns(BluebirdPromise.resolve());
|
||||
ldapMock.get_emails.returns(BluebirdPromise.resolve(emails));
|
||||
FirstFactor(req as any, res as any);
|
||||
});
|
||||
});
|
||||
|
||||
it("should return status code 401 when LDAP binding throws", function(done) {
|
||||
res.send = sinon.spy(function() {
|
||||
it("should return status code 401 when LDAP binding throws", function (done) {
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal(401, res.status.getCall(0).args[0]);
|
||||
assert.equal(regulator.mark.getCall(0).args[0], "username");
|
||||
done();
|
||||
|
@ -109,8 +112,8 @@ describe("test the first factor validation route", function() {
|
|||
FirstFactor(req as any, res as any);
|
||||
});
|
||||
|
||||
it("should return status code 500 when LDAP search throws", function(done) {
|
||||
res.send = sinon.spy(function() {
|
||||
it("should return status code 500 when LDAP search throws", function (done) {
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal(500, res.status.getCall(0).args[0]);
|
||||
done();
|
||||
});
|
||||
|
@ -119,11 +122,11 @@ describe("test the first factor validation route", function() {
|
|||
FirstFactor(req as any, res as any);
|
||||
});
|
||||
|
||||
it("should return status code 403 when regulator rejects authentication", function(done) {
|
||||
it("should return status code 403 when regulator rejects authentication", function (done) {
|
||||
const err = new exceptions.AuthenticationRegulationError("Authentication regulation...");
|
||||
regulator.regulate.returns(BluebirdPromise.reject(err));
|
||||
|
||||
res.send = sinon.spy(function() {
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal(403, res.status.getCall(0).args[0]);
|
||||
done();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user