From d8f9dcfbd34bace6da54462f2ea08e0f19e21378 Mon Sep 17 00:00:00 2001 From: Vincent Haupert Date: Mon, 22 Nov 2021 12:10:11 +0100 Subject: [PATCH] pam: add yubico option Write YubiKey token IDs in the format yubico_pam expects. See https://developers.yubico.com/yubico-pam/ for details. Also refer to the NixOS option security.pam.services..yubicoAuth. Closes #2502 --- modules/misc/pam.nix | 48 +++++++++++++++++++--- tests/modules/misc/pam/default.nix | 6 ++- tests/modules/misc/pam/yubico-no-ids.nix | 7 ++++ tests/modules/misc/pam/yubico-with-ids.nix | 15 +++++++ 4 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 tests/modules/misc/pam/yubico-no-ids.nix create mode 100644 tests/modules/misc/pam/yubico-with-ids.nix diff --git a/modules/misc/pam.nix b/modules/misc/pam.nix index c94efb50..cf3321ff 100644 --- a/modules/misc/pam.nix +++ b/modules/misc/pam.nix @@ -4,10 +4,10 @@ with lib; let - vars = config.pam.sessionVariables; + cfg = config.pam; in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = with maintainers; [ rycee veehaitch ]; options = { pam.sessionVariables = mkOption { @@ -26,10 +26,46 @@ in { therefore discouraged. ''; }; + + pam.yubico.authorizedYubiKeys = { + ids = mkOption { + type = with types; + let + yubiKeyId = addCheck str (s: stringLength s == 12) // { + name = "yubiKeyId"; + description = "string of length 12"; + }; + in listOf yubiKeyId; + default = [ ]; + description = '' + List of authorized YubiKey token IDs. Refer to + + for details on how to obtain the token ID of a YubiKey. + ''; + }; + + path = mkOption { + type = types.str; + default = ".yubico/authorized_yubikeys"; + description = '' + File path to write the authorized YubiKeys, + relative to HOME. + ''; + }; + }; }; - config = mkIf (vars != { }) { - home.file.".pam_environment".text = concatStringsSep "\n" - (mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') vars) + "\n"; - }; + config = mkMerge [ + (mkIf (cfg.sessionVariables != { }) { + home.file.".pam_environment".text = concatStringsSep "\n" + (mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') + cfg.sessionVariables) + "\n"; + }) + + (mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) { + home.file.${cfg.yubico.authorizedYubiKeys.path}.text = + concatStringsSep ":" + ([ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids); + }) + ]; } diff --git a/tests/modules/misc/pam/default.nix b/tests/modules/misc/pam/default.nix index 81c435e7..a5707389 100644 --- a/tests/modules/misc/pam/default.nix +++ b/tests/modules/misc/pam/default.nix @@ -1 +1,5 @@ -{ pam-session-variables = ./session-variables.nix; } +{ + pam-session-variables = ./session-variables.nix; + pam-yubico-with-ids = ./yubico-with-ids.nix; + pam-yubico-no-ids = ./yubico-with-ids.nix; +} diff --git a/tests/modules/misc/pam/yubico-no-ids.nix b/tests/modules/misc/pam/yubico-no-ids.nix new file mode 100644 index 00000000..0236ccd5 --- /dev/null +++ b/tests/modules/misc/pam/yubico-no-ids.nix @@ -0,0 +1,7 @@ +{ + config = { + nmt.script = '' + assertPathNotExists home-files/.yubico/authorized_yubikeys + ''; + }; +} diff --git a/tests/modules/misc/pam/yubico-with-ids.nix b/tests/modules/misc/pam/yubico-with-ids.nix new file mode 100644 index 00000000..af722e95 --- /dev/null +++ b/tests/modules/misc/pam/yubico-with-ids.nix @@ -0,0 +1,15 @@ +{ + config = { + pam.yubico.authorizedYubiKeys.ids = [ "abcdefghijkl" "012345678912" ]; + + nmt.script = '' + assertFileExists home-files/.yubico/authorized_yubikeys + assertFileContent \ + home-files/.yubico/authorized_yubikeys \ + ${ + builtins.toFile "yubico-with-ids-expected.txt" + "hm-user:abcdefghijkl:012345678912" + } + ''; + }; +}