diff --git a/docs/redirects.json b/docs/redirects.json index bd8fbfb..b19f6b8 100644 --- a/docs/redirects.json +++ b/docs/redirects.json @@ -4013,6 +4013,9 @@ "services-home-assistant-options-shb.home-assistant.ldap": [ "services-home-assistant.html#services-home-assistant-options-shb.home-assistant.ldap" ], + "services-home-assistant-options-shb.home-assistant.ldap.adminGroup": [ + "services-home-assistant.html#services-home-assistant-options-shb.home-assistant.ldap.adminGroup" + ], "services-home-assistant-options-shb.home-assistant.ldap.enable": [ "services-home-assistant.html#services-home-assistant-options-shb.home-assistant.ldap.enable" ], diff --git a/modules/services/home-assistant.nix b/modules/services/home-assistant.nix index 7fc57d5..692f4eb 100644 --- a/modules/services/home-assistant.nix +++ b/modules/services/home-assistant.nix @@ -139,10 +139,16 @@ in userGroup = lib.mkOption { type = lib.types.str; - description = "Group users must belong to to be able to login to Nextcloud."; + description = "Group users must belong to to be able to login as a user."; default = "homeassistant_user"; }; + adminGroup = lib.mkOption { + type = lib.types.str; + description = "Group users must belong to to be able to login as an admin."; + default = "homeassistant_admin"; + }; + keepDefaultAuth = lib.mkOption { type = lib.types.bool; description = '' @@ -277,6 +283,7 @@ in args = [ "http://${cfg.ldap.host}:${toString cfg.ldap.port}" cfg.ldap.userGroup + cfg.ldap.adminGroup ]; meta = true; } diff --git a/modules/services/home-assistant/docs/default.md b/modules/services/home-assistant/docs/default.md index c99c61b..2f9f047 100644 --- a/modules/services/home-assistant/docs/default.md +++ b/modules/services/home-assistant/docs/default.md @@ -127,16 +127,34 @@ shb.home-assistant.ldap enable = true; host = "127.0.0.1"; port = config.shb.lldap.webUIListenPort; - userGroup = "homeassistant_user"; + + # This is the default: + # userGroup = "homeassistant_user"; + # adminGroup = "homeassistant_admin"; +}; + +shb.lldap.ensureGroups = { + ${config.shb.home-assistant.ldap.userGroup} = { }; + ${config.shb.home-assistant.ldap.adminGroup} = { }; +}; + +shb.lldap.ensureUsers.homeAssistantAdmin = { + groups = [ + config.shb.home-assistant.ldap.adminGroup + ]; +}; + +shb.lldap.ensureUsers.homeAssistantUser = { + groups = [ + config.shb.home-assistant.ldap.userGroup + ]; }; ``` -And that's it. -Now, go to the LDAP server at `http://ldap.example.com`, -create the `home-assistant_user` group, -create a user and add it to one or both groups. -When that's done, go back to the Home-Assistant server at -`http://home-assistant.example.com` and login with that user. +This will create a LDAP group declaratively +and add the user `homeAssitantUser` as a user +and the user `homeAssitantAdmin` as an admin. +LDAP users can be added to the groups imperatively too through the LLDAP web UI. ### With SSO Support {#services-home-assistant-usage-sso} diff --git a/modules/services/home-assistant/lldap_ha_auth.nix b/modules/services/home-assistant/lldap_ha_auth.nix index 82084e0..5ba66d9 100644 --- a/modules/services/home-assistant/lldap_ha_auth.nix +++ b/modules/services/home-assistant/lldap_ha_auth.nix @@ -7,10 +7,10 @@ stdenvNoCC.mkDerivation { name = "lldap-ha-auth"; src = pkgs.fetchFromGitHub { - owner = "lldap"; + owner = "ibizaman"; repo = "lldap"; - rev = "7d1f5abc137821c500de99c94f7579761fc949d8"; - sha256 = "sha256-8D+7ww70Ja6Qwdfa+7MpjAAHewtCWNf/tuTAExoUrg0="; + rev = "adaf17c70336ec2562d23d1b9775579d62691b51"; + sha256 = "sha256-4FqfglEss5MlnxvjP40zbxqtwvB/GGMs7HwK9CBNBUQ="; }; nativeBuildInputs = [ diff --git a/test/common.nix b/test/common.nix index 99f3391..c7fb636 100644 --- a/test/common.nix +++ b/test/common.nix @@ -533,11 +533,14 @@ in ensureUsers = { alice = { email = "alice@example.com"; + # Display name is required by at least home-assistant. + displayName = "Alice Alice"; groups = [ "user_group" ]; password.result = config.shb.hardcodedsecret.alice.result; }; bob = { email = "bob@example.com"; + displayName = "Bob Bob"; # Purposely not adding bob to the user_group # so we can make sure users only part admins # can also login normally. @@ -546,6 +549,7 @@ in }; charlie = { email = "charlie@example.com"; + displayName = "Charlie Charlie"; groups = [ "other_group" ]; password.result = config.shb.hardcodedsecret.charlie.result; }; diff --git a/test/services/home-assistant.nix b/test/services/home-assistant.nix index 5afea59..491d16d 100644 --- a/test/services/home-assistant.nix +++ b/test/services/home-assistant.nix @@ -1,4 +1,9 @@ -{ pkgs, shb, ... }: +{ + pkgs, + shb, + lib, + ... +}: let commonTestScript = shb.test.mkScripts { hasSSL = { node, ... }: !(isNull node.config.shb.home-assistant.ssl); @@ -87,6 +92,9 @@ let test.login = { startUrl = "http://${config.test.fqdn}"; + usernameFieldSelector = ''get_by_role("textbox", name="Username")''; + passwordFieldSelector = ''get_by_role("textbox", name="Password")''; + loginButtonSelector = ''get_by_role("button", name="Log in")''; testLoginWith = [ { nextPageExpect = [ @@ -109,6 +117,71 @@ let }; }; + clientLdapLogin = + { config, ... }: + { + imports = [ + shb.test.baseModule + shb.test.clientLoginModule + ]; + + config = { + virtualisation.memorySize = 4096; + + test = { + subdomain = "ha"; + }; + + test.login = { + startUrl = "http://${config.test.fqdn}"; + usernameFieldSelector = ''get_by_role("textbox", name="Username")''; + passwordFieldSelector = ''get_by_role("textbox", name="Password")''; + loginButtonSelector = ''get_by_role("button", name="Log in")''; + testLoginWith = [ + { + username = "alice"; + password = "AlicePassword"; + nextPageExpect = [ + "expect(page.get_by_text('All set!')).to_be_visible(timeout=30000)" + "page.get_by_role('button', name=re.compile('Finish')).click()" + "expect(page).to_have_title(re.compile('Overview'), timeout=15000)" + ]; + } + { + username = "alice"; + password = "notAlicePassword"; + nextPageExpect = [ + "expect(page.get_by_text('Invalid!')).to_be_visible()" + ]; + } + { + username = "bob"; + password = "BobPassword"; + nextPageExpect = [ + "expect(page.get_by_text('All set!')).to_be_visible(timeout=30000)" + "page.get_by_role('button', name=re.compile('Finish')).click()" + "expect(page).to_have_title(re.compile('Overview'), timeout=15000)" + ]; + } + { + username = "bob"; + password = "notBobPassword"; + nextPageExpect = [ + "expect(page.get_by_text('Invalid!')).to_be_visible()" + ]; + } + { + username = "charlie"; + password = "CharliePassword"; + nextPageExpect = [ + "expect(page.get_by_text('Invalid!')).to_be_visible()" + ]; + } + ]; + }; + }; + }; + https = { config, ... }: { @@ -120,12 +193,13 @@ let ldap = { config, ... }: { + shb.lldap.debug = lib.mkForce true; shb.home-assistant = { ldap = { enable = true; host = "127.0.0.1"; port = config.shb.lldap.webUIListenPort; - userGroup = "homeassistant_user"; + userGroup = "user_group"; }; }; }; @@ -248,6 +322,11 @@ in ldap = shb.test.runNixOSTest { name = "homeassistant_ldap"; + nodes.client = { + imports = [ + clientLdapLogin + ]; + }; nodes.server = { imports = [ basic @@ -256,9 +335,14 @@ in ]; }; - nodes.client = { }; - - testScript = commonTestScript.access; + testScript = commonTestScript.access.override { + waitForPorts = + { node, ... }: + [ + 8123 + node.config.shb.lldap.webUIListenPort + ]; + }; }; # Not yet supported