Merge pull request #127 from clems4ever/adapt-acl-config
Adapt ACL configuration to make it more flexiblepull/129/head
commit
26418278bc
|
@ -7,10 +7,10 @@ import {
|
||||||
UserLdapConfiguration
|
UserLdapConfiguration
|
||||||
} from "./Configuration";
|
} from "./Configuration";
|
||||||
import Util = require("util");
|
import Util = require("util");
|
||||||
|
import { ACLAdapter } from "./adapters/ACLAdapter";
|
||||||
|
|
||||||
const LDAP_URL_ENV_VARIABLE = "LDAP_URL";
|
const LDAP_URL_ENV_VARIABLE = "LDAP_URL";
|
||||||
|
|
||||||
|
|
||||||
function get_optional<T>(config: object, path: string, default_value: T): T {
|
function get_optional<T>(config: object, path: string, default_value: T): T {
|
||||||
let entry = default_value;
|
let entry = default_value;
|
||||||
if (ObjectPath.has(config, path)) {
|
if (ObjectPath.has(config, path)) {
|
||||||
|
@ -80,7 +80,7 @@ function adaptFromUserConfiguration(userConfiguration: UserConfiguration): AppCo
|
||||||
},
|
},
|
||||||
logs_level: get_optional<string>(userConfiguration, "logs_level", "info"),
|
logs_level: get_optional<string>(userConfiguration, "logs_level", "info"),
|
||||||
notifier: ObjectPath.get<object, NotifierConfiguration>(userConfiguration, "notifier"),
|
notifier: ObjectPath.get<object, NotifierConfiguration>(userConfiguration, "notifier"),
|
||||||
access_control: ObjectPath.get<object, ACLConfiguration>(userConfiguration, "access_control"),
|
access_control: ACLAdapter.adapt(userConfiguration.access_control),
|
||||||
regulation: userConfiguration.regulation
|
regulation: userConfiguration.regulation
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { ACLConfiguration } from "../Configuration";
|
||||||
|
|
||||||
|
function clone(obj: any): any {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_POLICY = "deny";
|
||||||
|
|
||||||
|
function adaptDefaultPolicy(configuration: ACLConfiguration) {
|
||||||
|
if (!configuration.default_policy)
|
||||||
|
configuration.default_policy = DEFAULT_POLICY;
|
||||||
|
if (configuration.default_policy != "deny" && configuration.default_policy != "allow")
|
||||||
|
configuration.default_policy = DEFAULT_POLICY;
|
||||||
|
}
|
||||||
|
|
||||||
|
function adaptAny(configuration: ACLConfiguration) {
|
||||||
|
if (!configuration.any || !(configuration.any.constructor === Array))
|
||||||
|
configuration.any = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function adaptGroups(configuration: ACLConfiguration) {
|
||||||
|
if (!configuration.groups || !(configuration.groups.constructor === Object))
|
||||||
|
configuration.groups = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function adaptUsers(configuration: ACLConfiguration) {
|
||||||
|
if (!configuration.users || !(configuration.users.constructor === Object))
|
||||||
|
configuration.users = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ACLAdapter {
|
||||||
|
static adapt(configuration: ACLConfiguration): ACLConfiguration {
|
||||||
|
if (!configuration) return;
|
||||||
|
|
||||||
|
const newConfiguration: ACLConfiguration = clone(configuration);
|
||||||
|
adaptDefaultPolicy(newConfiguration);
|
||||||
|
adaptAny(newConfiguration);
|
||||||
|
adaptGroups(newConfiguration);
|
||||||
|
adaptUsers(newConfiguration);
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
||||||
|
}
|
|
@ -173,8 +173,8 @@ describe("test access control manager", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("check all rules", function () {
|
describe("check any rules", function () {
|
||||||
it("should control access when all rules are defined", function () {
|
it("should control access when any rules are defined", function () {
|
||||||
configuration.any = [{
|
configuration.any = [{
|
||||||
domain: "home.example.com",
|
domain: "home.example.com",
|
||||||
policy: "allow",
|
policy: "allow",
|
||||||
|
@ -307,7 +307,7 @@ describe("test access control manager", function () {
|
||||||
Assert(!accessController.isAccessAllowed("home.example.com", "/dev/bob", "john", ["dev"]));
|
Assert(!accessController.isAccessAllowed("home.example.com", "/dev/bob", "john", ["dev"]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should control access when allowed at all level and denied at user level", function () {
|
it("should control access when allowed at 'any' level and denied at user level", function () {
|
||||||
configuration.any = [{
|
configuration.any = [{
|
||||||
domain: "home.example.com",
|
domain: "home.example.com",
|
||||||
policy: "allow",
|
policy: "allow",
|
||||||
|
@ -323,7 +323,7 @@ describe("test access control manager", function () {
|
||||||
Assert(!accessController.isAccessAllowed("home.example.com", "/dev/bob", "john", ["dev"]));
|
Assert(!accessController.isAccessAllowed("home.example.com", "/dev/bob", "john", ["dev"]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should control access when allowed at all level and denied at group level", function () {
|
it("should control access when allowed at 'any' level and denied at group level", function () {
|
||||||
configuration.any = [{
|
configuration.any = [{
|
||||||
domain: "home.example.com",
|
domain: "home.example.com",
|
||||||
policy: "allow",
|
policy: "allow",
|
||||||
|
|
|
@ -43,6 +43,7 @@ describe("test config adapter", function () {
|
||||||
return yaml_config;
|
return yaml_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe("port", function () {
|
||||||
it("should read the port from the yaml file", function () {
|
it("should read the port from the yaml file", function () {
|
||||||
const yaml_config = build_yaml_config();
|
const yaml_config = build_yaml_config();
|
||||||
yaml_config.port = 7070;
|
yaml_config.port = 7070;
|
||||||
|
@ -56,6 +57,7 @@ describe("test config adapter", function () {
|
||||||
const config = ConfigurationAdapter.adapt(yaml_config);
|
const config = ConfigurationAdapter.adapt(yaml_config);
|
||||||
Assert.equal(config.port, 8080);
|
Assert.equal(config.port, 8080);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should get the session attributes", function () {
|
it("should get the session attributes", function () {
|
||||||
const yaml_config = build_yaml_config();
|
const yaml_config = build_yaml_config();
|
||||||
|
@ -94,15 +96,45 @@ describe("test config adapter", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should get the access_control config", function () {
|
describe("access_control", function() {
|
||||||
|
it("should adapt access_control when it is already ok", function () {
|
||||||
const yaml_config = build_yaml_config();
|
const yaml_config = build_yaml_config();
|
||||||
yaml_config.access_control = {
|
yaml_config.access_control = {
|
||||||
default_policy: "deny",
|
default_policy: "deny",
|
||||||
any: [],
|
any: [{
|
||||||
users: {},
|
domain: "public.example.com",
|
||||||
|
policy: "allow"
|
||||||
|
}],
|
||||||
|
users: {
|
||||||
|
"user": [{
|
||||||
|
domain: "www.example.com",
|
||||||
|
policy: "allow"
|
||||||
|
}]
|
||||||
|
},
|
||||||
groups: {}
|
groups: {}
|
||||||
};
|
};
|
||||||
const config = ConfigurationAdapter.adapt(yaml_config);
|
const config = ConfigurationAdapter.adapt(yaml_config);
|
||||||
|
Assert.deepEqual(config.access_control, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [{
|
||||||
|
domain: "public.example.com",
|
||||||
|
policy: "allow"
|
||||||
|
}],
|
||||||
|
users: {
|
||||||
|
"user": [{
|
||||||
|
domain: "www.example.com",
|
||||||
|
policy: "allow"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
groups: {}
|
||||||
|
} as ACLConfiguration);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should adapt access_control when it is empty", function () {
|
||||||
|
const yaml_config = build_yaml_config();
|
||||||
|
yaml_config.access_control = {} as any;
|
||||||
|
const config = ConfigurationAdapter.adapt(yaml_config);
|
||||||
Assert.deepEqual(config.access_control, {
|
Assert.deepEqual(config.access_control, {
|
||||||
default_policy: "deny",
|
default_policy: "deny",
|
||||||
any: [],
|
any: [],
|
||||||
|
@ -110,4 +142,5 @@ describe("test config adapter", function () {
|
||||||
groups: {}
|
groups: {}
|
||||||
} as ACLConfiguration);
|
} as ACLConfiguration);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
import { ACLAdapter } from "../../../src/lib/configuration/adapters/ACLAdapter";
|
||||||
|
import Assert = require("assert");
|
||||||
|
|
||||||
|
describe("test ACL configuration adapter", function () {
|
||||||
|
|
||||||
|
describe("bad default_policy", function () {
|
||||||
|
it("should adapt a configuration missing default_policy", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should adapt a configuration with bad default_policy value", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "anything", // it should be 'allow' or 'deny'
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should adapt a configuration with bad default_policy type", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: {}, // it should be 'allow' or 'deny'
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("bad any", function () {
|
||||||
|
it("should adapt a configuration missing any key", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "deny",
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should adapt a configuration with any not being an array", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: "abc",
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("bad groups", function () {
|
||||||
|
it("should adapt a configuration missing groups key", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should adapt configuration with groups being of wrong type", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: [],
|
||||||
|
users: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("bad users", function () {
|
||||||
|
it("should adapt a configuration missing users key", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should adapt a configuration with users being of wrong type", function () {
|
||||||
|
const userConfiguration: any = {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfiguration = ACLAdapter.adapt(userConfiguration);
|
||||||
|
Assert.deepStrictEqual(appConfiguration, {
|
||||||
|
default_policy: "deny",
|
||||||
|
any: [],
|
||||||
|
groups: {},
|
||||||
|
users: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -8,6 +8,7 @@ Feature: User is correctly redirected
|
||||||
Scenario: User is redirected to home page after several authentication tries
|
Scenario: User is redirected to home page after several authentication tries
|
||||||
When I visit "https://public.test.local:8080/secret.html"
|
When I visit "https://public.test.local:8080/secret.html"
|
||||||
And I login with user "john" and password "badpassword"
|
And I login with user "john" and password "badpassword"
|
||||||
|
And I wait for notification to disappear
|
||||||
And I clear field "username"
|
And I clear field "username"
|
||||||
And I login with user "john" and password "password"
|
And I login with user "john" and password "password"
|
||||||
And I use "REGISTERED" as TOTP token handle
|
And I use "REGISTERED" as TOTP token handle
|
||||||
|
|
|
@ -37,6 +37,4 @@ Feature: Authelia regulates authentication to avoid brute force
|
||||||
And I click on "Sign in"
|
And I click on "Sign in"
|
||||||
And I use "REGISTERED" as TOTP token handle
|
And I use "REGISTERED" as TOTP token handle
|
||||||
And I click on "TOTP"
|
And I click on "TOTP"
|
||||||
Then I have access to:
|
Then I'm redirected to "https://public.test.local:8080/secret.html"
|
||||||
| url |
|
|
||||||
| https://public.test.local:8080/secret.html |
|
|
|
@ -11,6 +11,15 @@ Cucumber.defineSupportCode(function ({ Given, When, Then }) {
|
||||||
return this.visit(link);
|
return this.visit(link);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
When("I wait for notification to disappear", function() {
|
||||||
|
const that = this;
|
||||||
|
const notificationEl = this.driver.findElement(seleniumWebdriver.By.className("notification"));
|
||||||
|
return this.driver.wait(seleniumWebdriver.until.elementIsVisible(notificationEl), 15000)
|
||||||
|
.then(function() {
|
||||||
|
return that.driver.wait(seleniumWebdriver.until.elementIsNotVisible(notificationEl), 15000);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
When("I set field {stringInDoubleQuotes} to {stringInDoubleQuotes}", function (fieldName: string, content: string) {
|
When("I set field {stringInDoubleQuotes} to {stringInDoubleQuotes}", function (fieldName: string, content: string) {
|
||||||
return this.setFieldTo(fieldName, content);
|
return this.setFieldTo(fieldName, content);
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ Cucumber.defineSupportCode(function ({ Given, When, Then }) {
|
||||||
function (notificationType: string, notificationMessage: string) {
|
function (notificationType: string, notificationMessage: string) {
|
||||||
const that = this;
|
const that = this;
|
||||||
const notificationEl = this.driver.findElement(seleniumWebdriver.By.className("notification"));
|
const notificationEl = this.driver.findElement(seleniumWebdriver.By.className("notification"));
|
||||||
return this.driver.wait(seleniumWebdriver.until.elementIsVisible(notificationEl), 2000)
|
return this.driver.wait(seleniumWebdriver.until.elementIsVisible(notificationEl), 5000)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return notificationEl.getText();
|
return notificationEl.getText();
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue