Move access-control feature to typescript
parent
57278a7306
commit
40e02d23bf
|
@ -14,9 +14,9 @@ type UserName = string;
|
||||||
type GroupName = string;
|
type GroupName = string;
|
||||||
type DomainPattern = string;
|
type DomainPattern = string;
|
||||||
|
|
||||||
type ACLDefaultRules = Array<DomainPattern>;
|
export type ACLDefaultRules = DomainPattern[];
|
||||||
type ACLGroupsRules = Object;
|
export type ACLGroupsRules = { [group: string]: string[]; };
|
||||||
type ACLUsersRules = Object;
|
export type ACLUsersRules = { [user: string]: string[]; };
|
||||||
|
|
||||||
export interface ACLConfiguration {
|
export interface ACLConfiguration {
|
||||||
default: ACLDefaultRules;
|
default: ACLDefaultRules;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
import * as winston from "winston";
|
||||||
|
|
||||||
|
export interface ILogger {
|
||||||
|
debug: winston.LeveledLogMethod;
|
||||||
|
}
|
||||||
|
|
|
@ -11,9 +11,10 @@ import * as BodyParser from "body-parser";
|
||||||
import * as Path from "path";
|
import * as Path from "path";
|
||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
|
|
||||||
|
import AccessController from "./access_control/AccessController";
|
||||||
|
|
||||||
const setup_endpoints = require("./setup_endpoints");
|
const setup_endpoints = require("./setup_endpoints");
|
||||||
const Ldap = require("./ldap");
|
const Ldap = require("./ldap");
|
||||||
const AccessControl = require("./access_control");
|
|
||||||
|
|
||||||
export default class Server {
|
export default class Server {
|
||||||
private httpServer: http.Server;
|
private httpServer: http.Server;
|
||||||
|
@ -56,7 +57,7 @@ export default class Server {
|
||||||
const regulator = new AuthenticationRegulator(data_store, five_minutes);
|
const regulator = new AuthenticationRegulator(data_store, five_minutes);
|
||||||
const notifier = NotifierFactory.build(config.notifier, deps);
|
const notifier = NotifierFactory.build(config.notifier, deps);
|
||||||
const ldap = new Ldap(deps, config.ldap);
|
const ldap = new Ldap(deps, config.ldap);
|
||||||
const access_control = AccessControl(deps.winston, config.access_control);
|
const accessController = new AccessController(config.access_control, deps.winston);
|
||||||
|
|
||||||
app.set("logger", deps.winston);
|
app.set("logger", deps.winston);
|
||||||
app.set("ldap", ldap);
|
app.set("ldap", ldap);
|
||||||
|
@ -66,7 +67,8 @@ export default class Server {
|
||||||
app.set("notifier", notifier);
|
app.set("notifier", notifier);
|
||||||
app.set("authentication regulator", regulator);
|
app.set("authentication regulator", regulator);
|
||||||
app.set("config", config);
|
app.set("config", config);
|
||||||
app.set("access control", access_control);
|
app.set("access controller", accessController);
|
||||||
|
|
||||||
setup_endpoints(app);
|
setup_endpoints(app);
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
|
|
||||||
module.exports = function(logger, acl_config) {
|
|
||||||
return {
|
|
||||||
builder: new AccessControlBuilder(logger, acl_config),
|
|
||||||
matcher: new AccessControlMatcher(logger)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var objectPath = require('object-path');
|
|
||||||
|
|
||||||
// *************** PER DOMAIN MATCHER ***************
|
|
||||||
function AccessControlMatcher(logger) {
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessControlMatcher.prototype.is_domain_allowed = function(domain, allowed_domains) {
|
|
||||||
// Allow all matcher
|
|
||||||
if(allowed_domains.length == 1 && allowed_domains[0] == '*') return true;
|
|
||||||
|
|
||||||
this.logger.debug('ACL: trying to match %s with %s', domain,
|
|
||||||
JSON.stringify(allowed_domains));
|
|
||||||
for(var i = 0; i < allowed_domains.length; ++i) {
|
|
||||||
var allowed_domain = allowed_domains[i];
|
|
||||||
if(allowed_domain.startsWith('*') &&
|
|
||||||
domain.endsWith(allowed_domain.substr(1))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(domain == allowed_domain) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// *************** MATCHER BUILDER ***************
|
|
||||||
function AccessControlBuilder(logger, acl_config) {
|
|
||||||
this.logger = logger;
|
|
||||||
this.config = acl_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessControlBuilder.prototype.extract_per_group = function(groups) {
|
|
||||||
var allowed_domains = [];
|
|
||||||
var groups_policy = objectPath.get(this.config, 'groups');
|
|
||||||
if(groups_policy) {
|
|
||||||
for(var i=0; i<groups.length; ++i) {
|
|
||||||
var group = groups[i];
|
|
||||||
if(group in groups_policy) {
|
|
||||||
allowed_domains = allowed_domains.concat(groups_policy[group]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return allowed_domains;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessControlBuilder.prototype.extract_per_user = function(user) {
|
|
||||||
var allowed_domains = [];
|
|
||||||
var users_policy = objectPath.get(this.config, 'users');
|
|
||||||
if(users_policy) {
|
|
||||||
if(user in users_policy) {
|
|
||||||
allowed_domains = allowed_domains.concat(users_policy[user]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return allowed_domains;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessControlBuilder.prototype.get_allowed_domains = function(user, groups) {
|
|
||||||
var allowed_domains = [];
|
|
||||||
var default_policy = objectPath.get(this.config, 'default');
|
|
||||||
if(default_policy) {
|
|
||||||
allowed_domains = allowed_domains.concat(default_policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
allowed_domains = allowed_domains.concat(this.extract_per_group(groups));
|
|
||||||
allowed_domains = allowed_domains.concat(this.extract_per_user(user));
|
|
||||||
|
|
||||||
this.logger.debug('ACL: user \'%s\' is allowed access to %s', user,
|
|
||||||
JSON.stringify(allowed_domains));
|
|
||||||
return allowed_domains;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessControlBuilder.prototype.get_any_domain = function() {
|
|
||||||
return ['*'];
|
|
||||||
}
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
import { ACLConfiguration } from "../Configuration";
|
||||||
|
import PatternBuilder from "./PatternBuilder";
|
||||||
|
import { ILogger } from "../ILogger";
|
||||||
|
|
||||||
|
export default class AccessController {
|
||||||
|
private logger: ILogger;
|
||||||
|
private patternBuilder: PatternBuilder;
|
||||||
|
|
||||||
|
constructor(configuration: ACLConfiguration, logger_: ILogger) {
|
||||||
|
this.logger = logger_;
|
||||||
|
this.patternBuilder = new PatternBuilder(configuration, logger_);
|
||||||
|
}
|
||||||
|
|
||||||
|
isDomainAllowedForUser(domain: string, user: string, groups: string[]): boolean {
|
||||||
|
const allowed_domains = this.patternBuilder.getAllowedDomains(user, groups);
|
||||||
|
|
||||||
|
// Allow all matcher
|
||||||
|
if (allowed_domains.length == 1 && allowed_domains[0] == "*") return true;
|
||||||
|
|
||||||
|
this.logger.debug("ACL: trying to match %s with %s", domain,
|
||||||
|
JSON.stringify(allowed_domains));
|
||||||
|
for (let i = 0; i < allowed_domains.length; ++i) {
|
||||||
|
const allowed_domain = allowed_domains[i];
|
||||||
|
if (allowed_domain.startsWith("*") &&
|
||||||
|
domain.endsWith(allowed_domain.substr(1))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (domain == allowed_domain) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
import { ILogger } from "../ILogger";
|
||||||
|
import { ACLConfiguration, ACLGroupsRules, ACLUsersRules, ACLDefaultRules } from "../Configuration";
|
||||||
|
import objectPath = require("object-path");
|
||||||
|
|
||||||
|
export default class AccessControlPatternBuilder {
|
||||||
|
logger: ILogger;
|
||||||
|
configuration: ACLConfiguration;
|
||||||
|
|
||||||
|
constructor(configuration: ACLConfiguration | undefined, logger_: ILogger) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.logger = logger_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildFromGroups(groups: string[]): string[] {
|
||||||
|
let allowed_domains: string[] = [];
|
||||||
|
const groups_policy = objectPath.get<ACLConfiguration, ACLGroupsRules>(this.configuration, "groups");
|
||||||
|
if (groups_policy) {
|
||||||
|
for (let i = 0; i < groups.length; ++i) {
|
||||||
|
const group = groups[i];
|
||||||
|
if (group in groups_policy) {
|
||||||
|
const group_policy: string[] = groups_policy[group];
|
||||||
|
allowed_domains = allowed_domains.concat(groups_policy[group]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allowed_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildFromUser(user: string): string[] {
|
||||||
|
let allowed_domains: string[] = [];
|
||||||
|
const users_policy = objectPath.get<ACLConfiguration, ACLUsersRules>(this.configuration, "users");
|
||||||
|
if (users_policy) {
|
||||||
|
if (user in users_policy) {
|
||||||
|
allowed_domains = allowed_domains.concat(users_policy[user]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allowed_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllowedDomains(user: string, groups: string[]): string[] {
|
||||||
|
if (!this.configuration) {
|
||||||
|
this.logger.debug("No access control rules found." +
|
||||||
|
"Default policy to allow all.");
|
||||||
|
return ["*"]; // No configuration means, no restrictions.
|
||||||
|
}
|
||||||
|
|
||||||
|
let allowed_domains: string[] = [];
|
||||||
|
const default_policy = objectPath.get<ACLConfiguration, ACLDefaultRules>(this.configuration, "default");
|
||||||
|
if (default_policy) {
|
||||||
|
allowed_domains = allowed_domains.concat(default_policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
allowed_domains = allowed_domains.concat(this.buildFromGroups(groups));
|
||||||
|
allowed_domains = allowed_domains.concat(this.buildFromUser(user));
|
||||||
|
|
||||||
|
this.logger.debug("ACL: user \'%s\' is allowed access to %s", user,
|
||||||
|
JSON.stringify(allowed_domains));
|
||||||
|
return allowed_domains;
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ function first_factor(req, res) {
|
||||||
var ldap = req.app.get('ldap');
|
var ldap = req.app.get('ldap');
|
||||||
var config = req.app.get('config');
|
var config = req.app.get('config');
|
||||||
var regulator = req.app.get('authentication regulator');
|
var regulator = req.app.get('authentication regulator');
|
||||||
var acl_builder = req.app.get('access control').builder;
|
var accessController = req.app.get('access controller');
|
||||||
|
|
||||||
logger.info('1st factor: Starting authentication of user "%s"', username);
|
logger.info('1st factor: Starting authentication of user "%s"', username);
|
||||||
logger.debug('1st factor: Start bind operation against LDAP');
|
logger.debug('1st factor: Start bind operation against LDAP');
|
||||||
|
@ -63,15 +63,7 @@ function first_factor(req, res) {
|
||||||
logger.debug('1st factor: Retrieved email are %s', emails);
|
logger.debug('1st factor: Retrieved email are %s', emails);
|
||||||
objectPath.set(req, 'session.auth_session.email', emails[0]);
|
objectPath.set(req, 'session.auth_session.email', emails[0]);
|
||||||
|
|
||||||
if(config.access_control) {
|
allowed_domains = accessController.isDomainAllowedForUser(username, groups);
|
||||||
allowed_domains = acl_builder.get_allowed_domains(username, groups);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
allowed_domains = acl_builder.get_any_domain();
|
|
||||||
logger.debug('1st factor: no access control rules found.' +
|
|
||||||
'Default policy to allow all.');
|
|
||||||
}
|
|
||||||
objectPath.set(req, 'session.auth_session.allowed_domains', allowed_domains);
|
|
||||||
|
|
||||||
regulator.mark(username, true);
|
regulator.mark(username, true);
|
||||||
res.status(204);
|
res.status(204);
|
||||||
|
|
|
@ -19,17 +19,8 @@ function verify_filter(req, res) {
|
||||||
if(!objectPath.has(req, 'session.auth_session.userid'))
|
if(!objectPath.has(req, 'session.auth_session.userid'))
|
||||||
return Promise.reject('No userid variable');
|
return Promise.reject('No userid variable');
|
||||||
|
|
||||||
if(!objectPath.has(req, 'session.auth_session.allowed_domains'))
|
|
||||||
return Promise.reject('No allowed_domains variable');
|
|
||||||
|
|
||||||
// Get the session ACL matcher
|
|
||||||
var allowed_domains = objectPath.get(req, 'session.auth_session.allowed_domains');
|
|
||||||
var host = objectPath.get(req, 'headers.host');
|
var host = objectPath.get(req, 'headers.host');
|
||||||
var domain = host.split(':')[0];
|
var domain = host.split(':')[0];
|
||||||
var acl_matcher = req.app.get('access control').matcher;
|
|
||||||
|
|
||||||
if(!acl_matcher.is_domain_allowed(domain, allowed_domains))
|
|
||||||
return Promise.reject('Access restricted by ACL rules');
|
|
||||||
|
|
||||||
if(!req.session.auth_session.first_factor ||
|
if(!req.session.auth_session.first_factor ||
|
||||||
!req.session.auth_session.second_factor)
|
!req.session.auth_session.second_factor)
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
import assert = require("assert");
|
||||||
|
import winston = require("winston");
|
||||||
|
import AccessController from "../../../src/lib/access_control/AccessController";
|
||||||
|
import { ACLConfiguration } from "../../../src/lib/Configuration";
|
||||||
|
|
||||||
|
describe("test access control manager", function () {
|
||||||
|
let accessController: AccessController;
|
||||||
|
let configuration: ACLConfiguration;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
configuration = {
|
||||||
|
default: [],
|
||||||
|
users: {},
|
||||||
|
groups: {}
|
||||||
|
};
|
||||||
|
accessController = new AccessController(configuration, winston);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("check access control matching", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
configuration.default = ["home.example.com", "*.public.example.com"];
|
||||||
|
configuration.users = {
|
||||||
|
user1: ["user1.example.com", "user1.mail.example.com"]
|
||||||
|
};
|
||||||
|
configuration.groups = {
|
||||||
|
group1: ["secret2.example.com"],
|
||||||
|
group2: ["secret.example.com", "secret1.example.com"]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow access to secret.example.com", function () {
|
||||||
|
assert(accessController.isDomainAllowedForUser("secret.example.com", "user", ["group1", "group2"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should deny access to secret3.example.com", function () {
|
||||||
|
assert(!accessController.isDomainAllowedForUser("secret3.example.com", "user", ["group1", "group2"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow access to home.example.com", function () {
|
||||||
|
assert(accessController.isDomainAllowedForUser("home.example.com", "user", ["group1", "group2"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow access to user1.example.com", function () {
|
||||||
|
assert(accessController.isDomainAllowedForUser("user1.example.com", "user1", ["group1", "group2"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow access *.public.example.com", function () {
|
||||||
|
assert(accessController.isDomainAllowedForUser("user.public.example.com", "nouser", []));
|
||||||
|
assert(accessController.isDomainAllowedForUser("test.public.example.com", "nouser", []));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,120 @@
|
||||||
|
|
||||||
|
import assert = require("assert");
|
||||||
|
import winston = require("winston");
|
||||||
|
|
||||||
|
import PatternBuilder from "../../../src/lib/access_control/PatternBuilder";
|
||||||
|
import { ACLConfiguration } from "../../../src/lib/Configuration";
|
||||||
|
|
||||||
|
describe("test access control manager", function () {
|
||||||
|
describe("test access control pattern builder when no configuration is provided", () => {
|
||||||
|
it("should allow access to the user", () => {
|
||||||
|
const patternBuilder = new PatternBuilder(undefined, winston);
|
||||||
|
|
||||||
|
const allowed_domains = patternBuilder.getAllowedDomains("user", ["group1"]);
|
||||||
|
assert.deepEqual(allowed_domains, ["*"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("test access control pattern builder", function () {
|
||||||
|
let patternBuilder: PatternBuilder;
|
||||||
|
let configuration: ACLConfiguration;
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
configuration = {
|
||||||
|
default: [],
|
||||||
|
users: {},
|
||||||
|
groups: {}
|
||||||
|
};
|
||||||
|
patternBuilder = new PatternBuilder(configuration, winston);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should deny all if nothing is defined in the config", function () {
|
||||||
|
const allowed_domains = patternBuilder.getAllowedDomains("user", ["group1", "group2"]);
|
||||||
|
assert.deepEqual(allowed_domains, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow domain test.example.com to all users if defined in" +
|
||||||
|
" default policy", function () {
|
||||||
|
configuration.default = ["test.example.com"];
|
||||||
|
const allowed_domains = patternBuilder.getAllowedDomains("user", ["group1", "group2"]);
|
||||||
|
assert.deepEqual(allowed_domains, ["test.example.com"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow domain test.example.com to all users in group mygroup", function () {
|
||||||
|
const allowed_domains0 = patternBuilder.getAllowedDomains("user", ["group1", "group1"]);
|
||||||
|
assert.deepEqual(allowed_domains0, []);
|
||||||
|
|
||||||
|
configuration.groups = {
|
||||||
|
mygroup: ["test.example.com"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowed_domains1 = patternBuilder.getAllowedDomains("user", ["group1", "group2"]);
|
||||||
|
assert.deepEqual(allowed_domains1, []);
|
||||||
|
|
||||||
|
const allowed_domains2 = patternBuilder.getAllowedDomains("user", ["group1", "mygroup"]);
|
||||||
|
assert.deepEqual(allowed_domains2, ["test.example.com"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow domain test.example.com based on per user config", function () {
|
||||||
|
const allowed_domains0 = patternBuilder.getAllowedDomains("user", ["group1"]);
|
||||||
|
assert.deepEqual(allowed_domains0, []);
|
||||||
|
|
||||||
|
configuration.users = {
|
||||||
|
user1: ["test.example.com"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowed_domains1 = patternBuilder.getAllowedDomains("user", ["group1", "mygroup"]);
|
||||||
|
assert.deepEqual(allowed_domains1, []);
|
||||||
|
|
||||||
|
const allowed_domains2 = patternBuilder.getAllowedDomains("user1", ["group1", "mygroup"]);
|
||||||
|
assert.deepEqual(allowed_domains2, ["test.example.com"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow domains from user and groups", function () {
|
||||||
|
configuration.groups = {
|
||||||
|
group2: ["secret.example.com", "secret1.example.com"]
|
||||||
|
};
|
||||||
|
configuration.users = {
|
||||||
|
user: ["test.example.com"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowed_domains0 = patternBuilder.getAllowedDomains("user", ["group1", "group2"]);
|
||||||
|
assert.deepEqual(allowed_domains0, [
|
||||||
|
"secret.example.com",
|
||||||
|
"secret1.example.com",
|
||||||
|
"test.example.com",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow domains from several groups", function () {
|
||||||
|
configuration.groups = {
|
||||||
|
group1: ["secret2.example.com"],
|
||||||
|
group2: ["secret.example.com", "secret1.example.com"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowed_domains0 = patternBuilder.getAllowedDomains("user", ["group1", "group2"]);
|
||||||
|
assert.deepEqual(allowed_domains0, [
|
||||||
|
"secret2.example.com",
|
||||||
|
"secret.example.com",
|
||||||
|
"secret1.example.com",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow domains from several groups and default policy", function () {
|
||||||
|
configuration.default = ["home.example.com"];
|
||||||
|
configuration.groups = {
|
||||||
|
group1: ["secret2.example.com"],
|
||||||
|
group2: ["secret.example.com", "secret1.example.com"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowed_domains0 = patternBuilder.getAllowedDomains("user", ["group1", "group2"]);
|
||||||
|
assert.deepEqual(allowed_domains0, [
|
||||||
|
"home.example.com",
|
||||||
|
"secret2.example.com",
|
||||||
|
"secret.example.com",
|
||||||
|
"secret1.example.com",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,7 +6,6 @@ var winston = require('winston');
|
||||||
var first_factor = require('../../../src/lib/routes/first_factor');
|
var first_factor = require('../../../src/lib/routes/first_factor');
|
||||||
var exceptions = require('../../../src/lib/exceptions');
|
var exceptions = require('../../../src/lib/exceptions');
|
||||||
var Ldap = require('../../../src/lib/ldap');
|
var Ldap = require('../../../src/lib/ldap');
|
||||||
var AccessControl = require('../../../src/lib/access_control');
|
|
||||||
|
|
||||||
describe('test the first factor validation route', function() {
|
describe('test the first factor validation route', function() {
|
||||||
var req, res;
|
var req, res;
|
||||||
|
@ -14,7 +13,7 @@ describe('test the first factor validation route', function() {
|
||||||
var emails;
|
var emails;
|
||||||
var search_res_ok;
|
var search_res_ok;
|
||||||
var regulator;
|
var regulator;
|
||||||
var access_control;
|
var access_controller;
|
||||||
var config;
|
var config;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -36,14 +35,8 @@ describe('test the first factor validation route', function() {
|
||||||
regulator.mark.returns(Promise.resolve());
|
regulator.mark.returns(Promise.resolve());
|
||||||
regulator.regulate.returns(Promise.resolve());
|
regulator.regulate.returns(Promise.resolve());
|
||||||
|
|
||||||
access_control = {
|
access_controller = {
|
||||||
builder: {
|
isDomainAllowedForUser: sinon.stub().returns(true)
|
||||||
get_allowed_domains: sinon.stub(),
|
|
||||||
get_any_domain: sinon.stub(),
|
|
||||||
},
|
|
||||||
matcher: {
|
|
||||||
is_domain_allowed: sinon.stub()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var app_get = sinon.stub();
|
var app_get = sinon.stub();
|
||||||
|
@ -51,7 +44,7 @@ describe('test the first factor validation route', function() {
|
||||||
app_get.withArgs('config').returns(config);
|
app_get.withArgs('config').returns(config);
|
||||||
app_get.withArgs('logger').returns(winston);
|
app_get.withArgs('logger').returns(winston);
|
||||||
app_get.withArgs('authentication regulator').returns(regulator);
|
app_get.withArgs('authentication regulator').returns(regulator);
|
||||||
app_get.withArgs('access control').returns(access_control);
|
app_get.withArgs('access controller').returns(access_controller);
|
||||||
|
|
||||||
req = {
|
req = {
|
||||||
app: {
|
app: {
|
||||||
|
@ -87,40 +80,6 @@ describe('test the first factor validation route', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('store the ACL matcher in the auth session', function() {
|
|
||||||
it('should store the allowed domains in the auth session', function() {
|
|
||||||
config.access_control = {};
|
|
||||||
access_control.builder.get_allowed_domains.returns(['example.com', 'test.example.com']);
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
res.send = sinon.spy(function(data) {
|
|
||||||
assert.deepEqual(['example.com', 'test.example.com'],
|
|
||||||
req.session.auth_session.allowed_domains);
|
|
||||||
assert.equal(204, res.status.getCall(0).args[0]);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
ldap_interface_mock.bind.withArgs('username').returns(Promise.resolve());
|
|
||||||
ldap_interface_mock.get_emails.returns(Promise.resolve(emails));
|
|
||||||
ldap_interface_mock.get_groups.returns(Promise.resolve(groups));
|
|
||||||
first_factor(req, res);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should store the allow all ACL matcher in the auth session', function() {
|
|
||||||
access_control.builder.get_any_domain.returns(['*']);
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
res.send = sinon.spy(function(data) {
|
|
||||||
assert(req.session.auth_session.allowed_domains);
|
|
||||||
assert.equal(204, res.status.getCall(0).args[0]);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
ldap_interface_mock.bind.withArgs('username').returns(Promise.resolve());
|
|
||||||
ldap_interface_mock.get_emails.returns(Promise.resolve(emails));
|
|
||||||
ldap_interface_mock.get_groups.returns(Promise.resolve(groups));
|
|
||||||
first_factor(req, res);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should retrieve email from LDAP', function(done) {
|
it('should retrieve email from LDAP', function(done) {
|
||||||
res.send = sinon.spy(function(data) { done(); });
|
res.send = sinon.spy(function(data) { done(); });
|
||||||
ldap_interface_mock.bind.returns(Promise.resolve());
|
ldap_interface_mock.bind.returns(Promise.resolve());
|
||||||
|
|
|
@ -93,25 +93,6 @@ describe('test authentication token verification', function() {
|
||||||
return test_unauthorized(undefined);
|
return test_unauthorized(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reply unauthorized when the domain is restricted', function() {
|
|
||||||
acl_matcher.is_domain_allowed.returns(false);
|
|
||||||
return test_unauthorized({
|
|
||||||
first_factor: true,
|
|
||||||
second_factor: true,
|
|
||||||
userid: 'user',
|
|
||||||
allowed_domains: []
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reply authorized when the domain is allowed', function() {
|
|
||||||
return test_authorized({
|
|
||||||
first_factor: true,
|
|
||||||
second_factor: true,
|
|
||||||
userid: 'user',
|
|
||||||
allowed_domains: ['secret.example.com']
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not be authenticated when session is partially initialized', function() {
|
it('should not be authenticated when session is partially initialized', function() {
|
||||||
return test_unauthorized({ first_factor: true });
|
return test_unauthorized({ first_factor: true });
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
|
|
||||||
var assert = require('assert');
|
|
||||||
var winston = require('winston');
|
|
||||||
var AccessControl = require('../../src/lib/access_control');
|
|
||||||
|
|
||||||
describe('test access control manager', function() {
|
|
||||||
var access_control;
|
|
||||||
var acl_config;
|
|
||||||
var acl_builder;
|
|
||||||
var acl_matcher;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
acl_config = {};
|
|
||||||
access_control = AccessControl(winston, acl_config);
|
|
||||||
acl_builder = access_control.builder;
|
|
||||||
acl_matcher = access_control.matcher;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('building user group access control matcher', function() {
|
|
||||||
it('should deny all if nothing is defined in the config', function() {
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert.deepEqual(allowed_domains, []);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow domain test.example.com to all users if defined in' +
|
|
||||||
' default policy', function() {
|
|
||||||
acl_config.default = ['test.example.com'];
|
|
||||||
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert.deepEqual(allowed_domains, ['test.example.com']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow domain test.example.com to all users in group mygroup', function() {
|
|
||||||
var allowed_domains0 = acl_builder.get_allowed_domains('user', ['group1', 'group1']);
|
|
||||||
assert.deepEqual(allowed_domains0, []);
|
|
||||||
|
|
||||||
acl_config.groups = {
|
|
||||||
mygroup: ['test.example.com']
|
|
||||||
};
|
|
||||||
|
|
||||||
var allowed_domains1 = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert.deepEqual(allowed_domains1, []);
|
|
||||||
|
|
||||||
var allowed_domains2 = acl_builder.get_allowed_domains('user', ['group1', 'mygroup']);
|
|
||||||
assert.deepEqual(allowed_domains2, ['test.example.com']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow domain test.example.com based on per user config', function() {
|
|
||||||
var allowed_domains0 = acl_builder.get_allowed_domains('user', ['group1']);
|
|
||||||
assert.deepEqual(allowed_domains0, []);
|
|
||||||
|
|
||||||
acl_config.users = {
|
|
||||||
user1: ['test.example.com']
|
|
||||||
};
|
|
||||||
|
|
||||||
var allowed_domains1 = acl_builder.get_allowed_domains('user', ['group1', 'mygroup']);
|
|
||||||
assert.deepEqual(allowed_domains1, []);
|
|
||||||
|
|
||||||
var allowed_domains2 = acl_builder.get_allowed_domains('user1', ['group1', 'mygroup']);
|
|
||||||
assert.deepEqual(allowed_domains2, ['test.example.com']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow domains from user and groups', function() {
|
|
||||||
acl_config.groups = {
|
|
||||||
group2: ['secret.example.com', 'secret1.example.com']
|
|
||||||
};
|
|
||||||
acl_config.users = {
|
|
||||||
user: ['test.example.com']
|
|
||||||
};
|
|
||||||
|
|
||||||
var allowed_domains0 = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert.deepEqual(allowed_domains0, [
|
|
||||||
'secret.example.com',
|
|
||||||
'secret1.example.com',
|
|
||||||
'test.example.com',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow domains from several groups', function() {
|
|
||||||
acl_config.groups = {
|
|
||||||
group1: ['secret2.example.com'],
|
|
||||||
group2: ['secret.example.com', 'secret1.example.com']
|
|
||||||
};
|
|
||||||
|
|
||||||
var allowed_domains0 = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert.deepEqual(allowed_domains0, [
|
|
||||||
'secret2.example.com',
|
|
||||||
'secret.example.com',
|
|
||||||
'secret1.example.com',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow domains from several groups and default policy', function() {
|
|
||||||
acl_config.default = ['home.example.com'];
|
|
||||||
acl_config.groups = {
|
|
||||||
group1: ['secret2.example.com'],
|
|
||||||
group2: ['secret.example.com', 'secret1.example.com']
|
|
||||||
};
|
|
||||||
|
|
||||||
var allowed_domains0 = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert.deepEqual(allowed_domains0, [
|
|
||||||
'home.example.com',
|
|
||||||
'secret2.example.com',
|
|
||||||
'secret.example.com',
|
|
||||||
'secret1.example.com',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('building user group access control matcher', function() {
|
|
||||||
it('should allow access to any subdomain', function() {
|
|
||||||
var allowed_domains = acl_builder.get_any_domain();
|
|
||||||
assert(acl_matcher.is_domain_allowed('example.com', allowed_domains));
|
|
||||||
assert(acl_matcher.is_domain_allowed('mail.example.com', allowed_domains));
|
|
||||||
assert(acl_matcher.is_domain_allowed('test.example.com', allowed_domains));
|
|
||||||
assert(acl_matcher.is_domain_allowed('user.mail.example.com', allowed_domains));
|
|
||||||
assert(acl_matcher.is_domain_allowed('public.example.com', allowed_domains));
|
|
||||||
assert(acl_matcher.is_domain_allowed('example2.com', allowed_domains));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('check access control matching', function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
acl_config.default = ['home.example.com', '*.public.example.com'];
|
|
||||||
acl_config.users = {
|
|
||||||
user1: ['user1.example.com', 'user1.mail.example.com']
|
|
||||||
};
|
|
||||||
acl_config.groups = {
|
|
||||||
group1: ['secret2.example.com'],
|
|
||||||
group2: ['secret.example.com', 'secret1.example.com']
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow access to secret.example.com', function() {
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert(acl_matcher.is_domain_allowed('secret.example.com', allowed_domains));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should deny access to secret3.example.com', function() {
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert(!acl_matcher.is_domain_allowed('secret3.example.com', allowed_domains));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow access to home.example.com', function() {
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('user', ['group1', 'group2']);
|
|
||||||
assert(acl_matcher.is_domain_allowed('home.example.com', allowed_domains));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow access to user1.example.com', function() {
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('user1', ['group1', 'group2']);
|
|
||||||
assert(acl_matcher.is_domain_allowed('user1.example.com', allowed_domains));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow access *.public.example.com', function() {
|
|
||||||
var allowed_domains = acl_builder.get_allowed_domains('nouser', []);
|
|
||||||
assert(acl_matcher.is_domain_allowed('user.public.example.com', allowed_domains));
|
|
||||||
assert(acl_matcher.is_domain_allowed('test.public.example.com', allowed_domains));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue