Merge pull request #127 from clems4ever/adapt-acl-config

Adapt ACL configuration to make it more flexible
pull/129/head
Clément Michaud 2017-10-08 17:31:19 +02:00 committed by GitHub
commit 26418278bc
9 changed files with 281 additions and 36 deletions

View File

@ -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
}; };
} }

View File

@ -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;
}
}

View File

@ -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",

View File

@ -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);
}); });
});
}); });

View File

@ -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: {}
});
});
});
});

View File

@ -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

View File

@ -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 |

View File

@ -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);
}); });

View File

@ -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();
}) })