From 9624aa63114e3c69e0bb02e9e7e073c02ce711ea Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Mon, 9 Oct 2017 23:13:57 +0200 Subject: [PATCH] Adapt authentication methods configuration to be backward compatible Prior version of configuration file can be used, the authentication methods will be set to default values (two_factor as default method). --- .../lib/configuration/ConfigurationAdapter.ts | 20 ++----- .../lib/configuration/adapters/ACLAdapter.ts | 7 +-- .../adapters/AuthenticationMethodsAdapter.ts | 30 ++++++++++ server/src/lib/utils/ObjectCloner.ts | 6 ++ .../AuthenticationMethodsAdapter.test.ts | 59 +++++++++++++++++++ 5 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts create mode 100644 server/src/lib/utils/ObjectCloner.ts create mode 100644 server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts diff --git a/server/src/lib/configuration/ConfigurationAdapter.ts b/server/src/lib/configuration/ConfigurationAdapter.ts index 49bf5c32..da5807bd 100644 --- a/server/src/lib/configuration/ConfigurationAdapter.ts +++ b/server/src/lib/configuration/ConfigurationAdapter.ts @@ -4,10 +4,11 @@ import { AppConfiguration, UserConfiguration, NotifierConfiguration, ACLConfiguration, LdapConfiguration, SessionRedisOptions, MongoStorageConfiguration, LocalStorageConfiguration, - UserLdapConfiguration, AuthenticationMethodsConfiguration + UserLdapConfiguration } from "./Configuration"; import Util = require("util"); import { ACLAdapter } from "./adapters/ACLAdapter"; +import { AuthenticationMethodsAdapter } from "./adapters/AuthenticationMethodsAdapter"; const LDAP_URL_ENV_VARIABLE = "LDAP_URL"; @@ -55,25 +56,16 @@ function adaptLdapConfiguration(userConfig: UserLdapConfiguration): LdapConfigur }; } -function adaptAuthenticationMethods(authentication_methods: AuthenticationMethodsConfiguration) - : AuthenticationMethodsConfiguration { - if (!authentication_methods) { - return { - default_method: "two_factor", - per_subdomain_methods: {} - }; - } - return authentication_methods; -} - -function adaptFromUserConfiguration(userConfiguration: UserConfiguration): AppConfiguration { +function adaptFromUserConfiguration(userConfiguration: UserConfiguration) + : AppConfiguration { ensure_key_existence(userConfiguration, "ldap"); ensure_key_existence(userConfiguration, "session.secret"); ensure_key_existence(userConfiguration, "regulation"); const port = userConfiguration.port || 8080; const ldapConfiguration = adaptLdapConfiguration(userConfiguration.ldap); - const authenticationMethods = adaptAuthenticationMethods(userConfiguration.authentication_methods); + const authenticationMethods = AuthenticationMethodsAdapter + .adapt(userConfiguration.authentication_methods); return { port: port, diff --git a/server/src/lib/configuration/adapters/ACLAdapter.ts b/server/src/lib/configuration/adapters/ACLAdapter.ts index 53e0801c..d9fca60b 100644 --- a/server/src/lib/configuration/adapters/ACLAdapter.ts +++ b/server/src/lib/configuration/adapters/ACLAdapter.ts @@ -1,8 +1,5 @@ import { ACLConfiguration } from "../Configuration"; - -function clone(obj: any): any { - return JSON.parse(JSON.stringify(obj)); -} +import { ObjectCloner } from "../../utils/ObjectCloner"; const DEFAULT_POLICY = "deny"; @@ -32,7 +29,7 @@ export class ACLAdapter { static adapt(configuration: ACLConfiguration): ACLConfiguration { if (!configuration) return; - const newConfiguration: ACLConfiguration = clone(configuration); + const newConfiguration: ACLConfiguration = ObjectCloner.clone(configuration); adaptDefaultPolicy(newConfiguration); adaptAny(newConfiguration); adaptGroups(newConfiguration); diff --git a/server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts b/server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts new file mode 100644 index 00000000..462d6bc6 --- /dev/null +++ b/server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts @@ -0,0 +1,30 @@ +import { AuthenticationMethodsConfiguration } from "../Configuration"; +import { ObjectCloner } from "../../utils/ObjectCloner"; + +function clone(obj: any): any { + return JSON.parse(JSON.stringify(obj)); +} + +export class AuthenticationMethodsAdapter { + static adapt(authentication_methods: AuthenticationMethodsConfiguration) + : AuthenticationMethodsConfiguration { + if (!authentication_methods) { + return { + default_method: "two_factor", + per_subdomain_methods: {} + }; + } + + const newAuthMethods: AuthenticationMethodsConfiguration + = ObjectCloner.clone(authentication_methods); + + if (!newAuthMethods.default_method) + newAuthMethods.default_method = "two_factor"; + + if (!newAuthMethods.per_subdomain_methods || + newAuthMethods.per_subdomain_methods.constructor !== Object) + newAuthMethods.per_subdomain_methods = {}; + + return newAuthMethods; + } +} diff --git a/server/src/lib/utils/ObjectCloner.ts b/server/src/lib/utils/ObjectCloner.ts new file mode 100644 index 00000000..3e125d74 --- /dev/null +++ b/server/src/lib/utils/ObjectCloner.ts @@ -0,0 +1,6 @@ + +export class ObjectCloner { + static clone(obj: any): any { + return JSON.parse(JSON.stringify(obj)); + } +} \ No newline at end of file diff --git a/server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts b/server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts new file mode 100644 index 00000000..e26abba7 --- /dev/null +++ b/server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts @@ -0,0 +1,59 @@ +import { AuthenticationMethodsAdapter } from "../../../src/lib/configuration/adapters/AuthenticationMethodsAdapter"; +import Assert = require("assert"); + +describe("test authentication methods configuration adapter", function () { + describe("no authentication methods defined", function () { + it("should adapt a configuration when no authentication methods config is defined", function () { + const userConfiguration: any = undefined; + + const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); + Assert.deepStrictEqual(appConfiguration, { + default_method: "two_factor", + per_subdomain_methods: {} + }); + }); + }); + + describe("partial authentication methods config", function() { + it("should adapt a configuration when default_method is not defined", function () { + const userConfiguration: any = { + per_subdomain_methods: { + "example.com": "basic_auth" + } + }; + + const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); + Assert.deepStrictEqual(appConfiguration, { + default_method: "two_factor", + per_subdomain_methods: { + "example.com": "basic_auth" + } + }); + }); + + it("should adapt a configuration when per_subdomain_methods is not defined", function () { + const userConfiguration: any = { + default_method: "basic_auth" + }; + + const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); + Assert.deepStrictEqual(appConfiguration, { + default_method: "basic_auth", + per_subdomain_methods: {} + }); + }); + + it("should adapt a configuration when per_subdomain_methods has wrong type", function () { + const userConfiguration: any = { + default_method: "basic_auth", + per_subdomain_methods: [] + }; + + const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); + Assert.deepStrictEqual(appConfiguration, { + default_method: "basic_auth", + per_subdomain_methods: {} + }); + }); + }); +}); \ No newline at end of file