nixosTests.ldap: remove
This seems to have worked in 15f105d41f
(5
months ago) but broke somewhere in the meantime.
The current module doesn't seem to be underdocumented and might need a
serious refactor. It requires quite some hacks to get it to work (see
https://github.com/NixOS/nixpkgs/issues/86305#issuecomment-621129942),
or how the ldap.nix test used systemd.services.openldap.preStart and
made quite some assumptions on internals.
Mic92 agreed on being added as a maintainer for the module, as he uses
it a lot and can possibly fix eventual breakages. For the most basic
startup breakages, the remaining openldap.nix test might suffice.
This commit is contained in:
parent
19d2c0601b
commit
450f8a44f9
|
@ -231,6 +231,10 @@ in
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
maintainers = lib.maintainers.mic92;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,6 @@ in
|
||||||
kubernetes.rbac = handleTestOn ["x86_64-linux"] ./kubernetes/rbac.nix {};
|
kubernetes.rbac = handleTestOn ["x86_64-linux"] ./kubernetes/rbac.nix {};
|
||||||
latestKernel.hardened = handleTest ./hardened.nix { latestKernel = true; };
|
latestKernel.hardened = handleTest ./hardened.nix { latestKernel = true; };
|
||||||
latestKernel.login = handleTest ./login.nix { latestKernel = true; };
|
latestKernel.login = handleTest ./login.nix { latestKernel = true; };
|
||||||
ldap = handleTest ./ldap.nix {};
|
|
||||||
leaps = handleTest ./leaps.nix {};
|
leaps = handleTest ./leaps.nix {};
|
||||||
lidarr = handleTest ./lidarr.nix {};
|
lidarr = handleTest ./lidarr.nix {};
|
||||||
lightdm = handleTest ./lightdm.nix {};
|
lightdm = handleTest ./lightdm.nix {};
|
||||||
|
|
|
@ -1,405 +0,0 @@
|
||||||
import ./make-test-python.nix ({ pkgs, lib, ...} :
|
|
||||||
|
|
||||||
let
|
|
||||||
unlines = lib.concatStringsSep "\n";
|
|
||||||
unlinesAttrs = f: as: unlines (lib.mapAttrsToList f as);
|
|
||||||
|
|
||||||
dbDomain = "example.com";
|
|
||||||
dbSuffix = "dc=example,dc=com";
|
|
||||||
dbAdminDn = "cn=admin,${dbSuffix}";
|
|
||||||
dbAdminPwd = "admin-password";
|
|
||||||
# NOTE: slappasswd -h "{SSHA}" -s '${dbAdminPwd}'
|
|
||||||
dbAdminPwdHash = "{SSHA}i7FopSzkFQMrHzDMB1vrtkI0rBnwouP8";
|
|
||||||
ldapUser = "test-ldap-user";
|
|
||||||
ldapUserId = 10000;
|
|
||||||
ldapUserPwd = "user-password";
|
|
||||||
# NOTE: slappasswd -h "{SSHA}" -s '${ldapUserPwd}'
|
|
||||||
ldapUserPwdHash = "{SSHA}v12XICMZNGT6r2KJ26rIkN8Vvvp4QX6i";
|
|
||||||
ldapGroup = "test-ldap-group";
|
|
||||||
ldapGroupId = 10000;
|
|
||||||
|
|
||||||
mkClient = useDaemon:
|
|
||||||
{ lib, ... }:
|
|
||||||
{
|
|
||||||
virtualisation.memorySize = 256;
|
|
||||||
virtualisation.vlans = [ 1 ];
|
|
||||||
security.pam.services.su.rootOK = lib.mkForce false;
|
|
||||||
users.ldap.enable = true;
|
|
||||||
users.ldap.daemon = {
|
|
||||||
enable = useDaemon;
|
|
||||||
rootpwmoddn = "cn=admin,${dbSuffix}";
|
|
||||||
rootpwmodpwFile = "/etc/nslcd.rootpwmodpw";
|
|
||||||
};
|
|
||||||
users.ldap.loginPam = true;
|
|
||||||
users.ldap.nsswitch = true;
|
|
||||||
users.ldap.server = "ldap://server";
|
|
||||||
users.ldap.base = "ou=posix,${dbSuffix}";
|
|
||||||
users.ldap.bind = {
|
|
||||||
distinguishedName = "cn=admin,${dbSuffix}";
|
|
||||||
passwordFile = "/etc/ldap/bind.password";
|
|
||||||
};
|
|
||||||
# NOTE: passwords stored in clear in Nix's store, but this is a test.
|
|
||||||
environment.etc."ldap/bind.password".source = pkgs.writeText "password" dbAdminPwd;
|
|
||||||
environment.etc."nslcd.rootpwmodpw".source = pkgs.writeText "rootpwmodpw" dbAdminPwd;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
name = "ldap";
|
|
||||||
meta = with pkgs.stdenv.lib.maintainers; {
|
|
||||||
maintainers = [ montag451 ];
|
|
||||||
};
|
|
||||||
|
|
||||||
nodes = {
|
|
||||||
|
|
||||||
server =
|
|
||||||
{ pkgs, config, ... }:
|
|
||||||
let
|
|
||||||
inherit (config.services) openldap;
|
|
||||||
|
|
||||||
slapdConfig = pkgs.writeText "cn=config.ldif" (''
|
|
||||||
dn: cn=config
|
|
||||||
objectClass: olcGlobal
|
|
||||||
#olcPidFile: /run/slapd/slapd.pid
|
|
||||||
# List of arguments that were passed to the server
|
|
||||||
#olcArgsFile: /run/slapd/slapd.args
|
|
||||||
# Read slapd-config(5) for possible values
|
|
||||||
olcLogLevel: none
|
|
||||||
# The tool-threads parameter sets the actual amount of CPU's
|
|
||||||
# that is used for indexing.
|
|
||||||
olcToolThreads: 1
|
|
||||||
|
|
||||||
dn: olcDatabase={-1}frontend,cn=config
|
|
||||||
objectClass: olcDatabaseConfig
|
|
||||||
objectClass: olcFrontendConfig
|
|
||||||
# The maximum number of entries that is returned for a search operation
|
|
||||||
olcSizeLimit: 500
|
|
||||||
# Allow unlimited access to local connection from the local root user
|
|
||||||
olcAccess: to *
|
|
||||||
by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
|
|
||||||
by * break
|
|
||||||
# Allow unauthenticated read access for schema and base DN autodiscovery
|
|
||||||
olcAccess: to dn.exact=""
|
|
||||||
by * read
|
|
||||||
olcAccess: to dn.base="cn=Subschema"
|
|
||||||
by * read
|
|
||||||
|
|
||||||
dn: olcDatabase=config,cn=config
|
|
||||||
objectClass: olcDatabaseConfig
|
|
||||||
olcRootDN: cn=admin,cn=config
|
|
||||||
#olcRootPW:
|
|
||||||
# NOTE: access to cn=config, system root can be manager
|
|
||||||
# with SASL mechanism (-Y EXTERNAL) over unix socket (-H ldapi://)
|
|
||||||
olcAccess: to *
|
|
||||||
by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
|
|
||||||
by * break
|
|
||||||
|
|
||||||
dn: cn=schema,cn=config
|
|
||||||
objectClass: olcSchemaConfig
|
|
||||||
|
|
||||||
include: file://${pkgs.openldap}/etc/schema/core.ldif
|
|
||||||
include: file://${pkgs.openldap}/etc/schema/cosine.ldif
|
|
||||||
include: file://${pkgs.openldap}/etc/schema/nis.ldif
|
|
||||||
include: file://${pkgs.openldap}/etc/schema/inetorgperson.ldif
|
|
||||||
|
|
||||||
dn: cn=module{0},cn=config
|
|
||||||
objectClass: olcModuleList
|
|
||||||
# Where the dynamically loaded modules are stored
|
|
||||||
#olcModulePath: /usr/lib/ldap
|
|
||||||
olcModuleLoad: back_mdb
|
|
||||||
|
|
||||||
''
|
|
||||||
+ unlinesAttrs (olcSuffix: {conf, ...}:
|
|
||||||
"include: file://" + pkgs.writeText "config.ldif" conf
|
|
||||||
) slapdDatabases
|
|
||||||
);
|
|
||||||
|
|
||||||
slapdDatabases = {
|
|
||||||
${dbSuffix} = {
|
|
||||||
conf = ''
|
|
||||||
dn: olcBackend={1}mdb,cn=config
|
|
||||||
objectClass: olcBackendConfig
|
|
||||||
|
|
||||||
dn: olcDatabase={1}mdb,cn=config
|
|
||||||
olcSuffix: ${dbSuffix}
|
|
||||||
olcDbDirectory: ${openldap.dataDir}/${dbSuffix}
|
|
||||||
objectClass: olcDatabaseConfig
|
|
||||||
objectClass: olcMdbConfig
|
|
||||||
# NOTE: checkpoint the database periodically in case of system failure
|
|
||||||
# and to speed up slapd shutdown.
|
|
||||||
olcDbCheckpoint: 512 30
|
|
||||||
# Database max size is 1G
|
|
||||||
olcDbMaxSize: 1073741824
|
|
||||||
olcLastMod: TRUE
|
|
||||||
# NOTE: database superuser. Needed for syncrepl,
|
|
||||||
# and used to auth as admin through a TCP connection.
|
|
||||||
olcRootDN: cn=admin,${dbSuffix}
|
|
||||||
olcRootPW: ${dbAdminPwdHash}
|
|
||||||
#
|
|
||||||
olcDbIndex: objectClass eq
|
|
||||||
olcDbIndex: cn,uid eq
|
|
||||||
olcDbIndex: uidNumber,gidNumber eq
|
|
||||||
olcDbIndex: member,memberUid eq
|
|
||||||
#
|
|
||||||
olcAccess: to attrs=userPassword
|
|
||||||
by self write
|
|
||||||
by anonymous auth
|
|
||||||
by dn="cn=admin,${dbSuffix}" write
|
|
||||||
by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
|
|
||||||
by * none
|
|
||||||
olcAccess: to attrs=shadowLastChange
|
|
||||||
by self write
|
|
||||||
by dn="cn=admin,${dbSuffix}" write
|
|
||||||
by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
|
|
||||||
by * none
|
|
||||||
olcAccess: to dn.sub="ou=posix,${dbSuffix}"
|
|
||||||
by self read
|
|
||||||
by dn="cn=admin,${dbSuffix}" read
|
|
||||||
by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
|
|
||||||
olcAccess: to *
|
|
||||||
by self read
|
|
||||||
by * none
|
|
||||||
'';
|
|
||||||
data = ''
|
|
||||||
dn: ${dbSuffix}
|
|
||||||
objectClass: top
|
|
||||||
objectClass: dcObject
|
|
||||||
objectClass: organization
|
|
||||||
o: ${dbDomain}
|
|
||||||
|
|
||||||
dn: cn=admin,${dbSuffix}
|
|
||||||
objectClass: simpleSecurityObject
|
|
||||||
objectClass: organizationalRole
|
|
||||||
description: ${dbDomain} LDAP administrator
|
|
||||||
roleOccupant: ${dbSuffix}
|
|
||||||
userPassword: ${ldapUserPwdHash}
|
|
||||||
|
|
||||||
dn: ou=posix,${dbSuffix}
|
|
||||||
objectClass: top
|
|
||||||
objectClass: organizationalUnit
|
|
||||||
|
|
||||||
dn: ou=accounts,ou=posix,${dbSuffix}
|
|
||||||
objectClass: top
|
|
||||||
objectClass: organizationalUnit
|
|
||||||
|
|
||||||
dn: ou=groups,ou=posix,${dbSuffix}
|
|
||||||
objectClass: top
|
|
||||||
objectClass: organizationalUnit
|
|
||||||
''
|
|
||||||
+ lib.concatMapStrings posixAccount [
|
|
||||||
{ uid=ldapUser; uidNumber=ldapUserId; gidNumber=ldapGroupId; userPassword=ldapUserPwdHash; }
|
|
||||||
]
|
|
||||||
+ lib.concatMapStrings posixGroup [
|
|
||||||
{ gid=ldapGroup; gidNumber=ldapGroupId; members=[]; }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# NOTE: create a user account using the posixAccount objectClass.
|
|
||||||
posixAccount =
|
|
||||||
{ uid
|
|
||||||
, uidNumber ? null
|
|
||||||
, gidNumber ? null
|
|
||||||
, cn ? ""
|
|
||||||
, sn ? ""
|
|
||||||
, userPassword ? ""
|
|
||||||
, loginShell ? "/bin/sh"
|
|
||||||
}: ''
|
|
||||||
|
|
||||||
dn: uid=${uid},ou=accounts,ou=posix,${dbSuffix}
|
|
||||||
objectClass: person
|
|
||||||
objectClass: posixAccount
|
|
||||||
objectClass: shadowAccount
|
|
||||||
cn: ${cn}
|
|
||||||
gecos:
|
|
||||||
${if gidNumber == null then "#" else "gidNumber: ${toString gidNumber}"}
|
|
||||||
homeDirectory: /home/${uid}
|
|
||||||
loginShell: ${loginShell}
|
|
||||||
sn: ${sn}
|
|
||||||
${if uidNumber == null then "#" else "uidNumber: ${toString uidNumber}"}
|
|
||||||
${if userPassword == "" then "#" else "userPassword: ${userPassword}"}
|
|
||||||
'';
|
|
||||||
|
|
||||||
# NOTE: create a group using the posixGroup objectClass.
|
|
||||||
posixGroup =
|
|
||||||
{ gid
|
|
||||||
, gidNumber
|
|
||||||
, members
|
|
||||||
}: ''
|
|
||||||
|
|
||||||
dn: cn=${gid},ou=groups,ou=posix,${dbSuffix}
|
|
||||||
objectClass: top
|
|
||||||
objectClass: posixGroup
|
|
||||||
gidNumber: ${toString gidNumber}
|
|
||||||
${lib.concatMapStrings (member: "memberUid: ${member}\n") members}
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
virtualisation.memorySize = 256;
|
|
||||||
virtualisation.vlans = [ 1 ];
|
|
||||||
networking.firewall.allowedTCPPorts = [ 389 ];
|
|
||||||
services.openldap.enable = true;
|
|
||||||
services.openldap.dataDir = "/var/db/openldap";
|
|
||||||
services.openldap.configDir = "/var/db/slapd";
|
|
||||||
services.openldap.urlList = [
|
|
||||||
"ldap:///"
|
|
||||||
"ldapi:///"
|
|
||||||
];
|
|
||||||
systemd.services.openldap = {
|
|
||||||
preStart = ''
|
|
||||||
set -e
|
|
||||||
# NOTE: slapd's config is always re-initialized.
|
|
||||||
rm -rf "${openldap.configDir}"/cn=config \
|
|
||||||
"${openldap.configDir}"/cn=config.ldif
|
|
||||||
install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${openldap.configDir}"
|
|
||||||
# NOTE: olcDbDirectory must be created before adding the config.
|
|
||||||
'' +
|
|
||||||
unlinesAttrs (olcSuffix: {data, ...}: ''
|
|
||||||
# NOTE: database is always re-initialized.
|
|
||||||
rm -rf "${openldap.dataDir}/${olcSuffix}"
|
|
||||||
install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" \
|
|
||||||
"${openldap.dataDir}/${olcSuffix}"
|
|
||||||
'') slapdDatabases
|
|
||||||
+ ''
|
|
||||||
# NOTE: slapd is supposed to be stopped while in preStart,
|
|
||||||
# hence slap* commands can safely be used.
|
|
||||||
umask 0077
|
|
||||||
${pkgs.openldap}/bin/slapadd -n 0 \
|
|
||||||
-F "${openldap.configDir}" \
|
|
||||||
-l ${slapdConfig}
|
|
||||||
chown -R "${openldap.user}:${openldap.group}" "${openldap.configDir}"
|
|
||||||
# NOTE: slapadd(8): To populate the config database slapd-config(5),
|
|
||||||
# use -n 0 as it is always the first database.
|
|
||||||
# It must physically exist on the filesystem prior to this, however.
|
|
||||||
'' +
|
|
||||||
unlinesAttrs (olcSuffix: {data, ...}: ''
|
|
||||||
# NOTE: load database ${olcSuffix}
|
|
||||||
# (as root to avoid depending on sudo or chpst)
|
|
||||||
${pkgs.openldap}/bin/slapadd \
|
|
||||||
-F "${openldap.configDir}" \
|
|
||||||
-l ${pkgs.writeText "data.ldif" data}
|
|
||||||
'' + ''
|
|
||||||
# NOTE: redundant with default openldap's preStart, but do not harm.
|
|
||||||
chown -R "${openldap.user}:${openldap.group}" \
|
|
||||||
"${openldap.dataDir}/${olcSuffix}"
|
|
||||||
'') slapdDatabases;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
client1 = mkClient true; # use nss_pam_ldapd
|
|
||||||
client2 = mkClient false; # use nss_ldap and pam_ldap
|
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
|
||||||
def expect_script(*commands):
|
|
||||||
script = ";".join(commands)
|
|
||||||
return f"${pkgs.expect}/bin/expect -c '{script}'"
|
|
||||||
|
|
||||||
|
|
||||||
server.start()
|
|
||||||
server.wait_for_unit("default.target")
|
|
||||||
|
|
||||||
with subtest("slapd: auth as database admin with SASL and check a POSIX account"):
|
|
||||||
server.succeed(
|
|
||||||
'test "$(ldapsearch -LLL -H ldapi:// -Y EXTERNAL '
|
|
||||||
+ "-b 'uid=${ldapUser},ou=accounts,ou=posix,${dbSuffix}' "
|
|
||||||
+ "-s base uidNumber | "
|
|
||||||
+ "sed -ne 's/^uidNumber: \\(.*\\)/\\1/p')\" -eq ${toString ldapUserId}"
|
|
||||||
)
|
|
||||||
|
|
||||||
with subtest("slapd: auth as database admin with password and check a POSIX account"):
|
|
||||||
server.succeed(
|
|
||||||
"test \"$(ldapsearch -LLL -H ldap://server -D 'cn=admin,${dbSuffix}' "
|
|
||||||
+ "-w '${dbAdminPwd}' -b 'uid=${ldapUser},ou=accounts,ou=posix,${dbSuffix}' "
|
|
||||||
+ "-s base uidNumber | "
|
|
||||||
+ "sed -ne 's/^uidNumber: \\(.*\\)/\\1/p')\" -eq ${toString ldapUserId}"
|
|
||||||
)
|
|
||||||
|
|
||||||
client1.start()
|
|
||||||
client1.wait_for_unit("default.target")
|
|
||||||
|
|
||||||
with subtest("password: su with password to a POSIX account"):
|
|
||||||
client1.succeed(
|
|
||||||
expect_script(
|
|
||||||
'spawn su "${ldapUser}"',
|
|
||||||
'expect "Password:"',
|
|
||||||
'send "${ldapUserPwd}\n"',
|
|
||||||
'expect "*"',
|
|
||||||
'send "whoami\n"',
|
|
||||||
'expect -ex "${ldapUser}" {exit}',
|
|
||||||
"exit 1",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
with subtest("password: change password of a POSIX account as root"):
|
|
||||||
client1.succeed(
|
|
||||||
"chpasswd <<<'${ldapUser}:new-password'",
|
|
||||||
expect_script(
|
|
||||||
'spawn su "${ldapUser}"',
|
|
||||||
'expect "Password:"',
|
|
||||||
'send "new-password\n"',
|
|
||||||
'expect "*"',
|
|
||||||
'send "whoami\n"',
|
|
||||||
'expect -ex "${ldapUser}" {exit}',
|
|
||||||
"exit 1",
|
|
||||||
),
|
|
||||||
"chpasswd <<<'${ldapUser}:${ldapUserPwd}'",
|
|
||||||
)
|
|
||||||
|
|
||||||
with subtest("password: change password of a POSIX account from itself"):
|
|
||||||
client1.succeed(
|
|
||||||
"chpasswd <<<'${ldapUser}:${ldapUserPwd}' ",
|
|
||||||
expect_script(
|
|
||||||
"spawn su --login ${ldapUser} -c passwd",
|
|
||||||
'expect "Password: "',
|
|
||||||
'send "${ldapUserPwd}\n"',
|
|
||||||
'expect "(current) UNIX password: "',
|
|
||||||
'send "${ldapUserPwd}\n"',
|
|
||||||
'expect "New password: "',
|
|
||||||
'send "new-password\n"',
|
|
||||||
'expect "Retype new password: "',
|
|
||||||
'send "new-password\n"',
|
|
||||||
'expect "passwd: password updated successfully" {exit}',
|
|
||||||
"exit 1",
|
|
||||||
),
|
|
||||||
expect_script(
|
|
||||||
'spawn su "${ldapUser}"',
|
|
||||||
'expect "Password:"',
|
|
||||||
'send "${ldapUserPwd}\n"',
|
|
||||||
'expect "su: Authentication failure" {exit}',
|
|
||||||
"exit 1",
|
|
||||||
),
|
|
||||||
expect_script(
|
|
||||||
'spawn su "${ldapUser}"',
|
|
||||||
'expect "Password:"',
|
|
||||||
'send "new-password\n"',
|
|
||||||
'expect "*"',
|
|
||||||
'send "whoami\n"',
|
|
||||||
'expect -ex "${ldapUser}" {exit}',
|
|
||||||
"exit 1",
|
|
||||||
),
|
|
||||||
"chpasswd <<<'${ldapUser}:${ldapUserPwd}'",
|
|
||||||
)
|
|
||||||
|
|
||||||
client2.start()
|
|
||||||
client2.wait_for_unit("default.target")
|
|
||||||
|
|
||||||
with subtest("NSS"):
|
|
||||||
client1.succeed(
|
|
||||||
"test \"$(id -u '${ldapUser}')\" -eq ${toString ldapUserId}",
|
|
||||||
"test \"$(id -u -n '${ldapUser}')\" = '${ldapUser}'",
|
|
||||||
"test \"$(id -g '${ldapUser}')\" -eq ${toString ldapGroupId}",
|
|
||||||
"test \"$(id -g -n '${ldapUser}')\" = '${ldapGroup}'",
|
|
||||||
"test \"$(id -u '${ldapUser}')\" -eq ${toString ldapUserId}",
|
|
||||||
"test \"$(id -u -n '${ldapUser}')\" = '${ldapUser}'",
|
|
||||||
"test \"$(id -g '${ldapUser}')\" -eq ${toString ldapGroupId}",
|
|
||||||
"test \"$(id -g -n '${ldapUser}')\" = '${ldapGroup}'",
|
|
||||||
)
|
|
||||||
|
|
||||||
with subtest("PAM"):
|
|
||||||
client1.succeed(
|
|
||||||
"echo ${ldapUserPwd} | su -l '${ldapUser}' -c true",
|
|
||||||
"echo ${ldapUserPwd} | su -l '${ldapUser}' -c true",
|
|
||||||
)
|
|
||||||
'';
|
|
||||||
})
|
|
Loading…
Reference in New Issue