selfhostblocks/test/blocks/ldap.nix

422 lines
16 KiB
Nix

{ pkgs, lib, ... }:
let
pkgs' = pkgs;
password = "securepassword";
in
{
auth = pkgs.testers.runNixOSTest {
name = "ldap-auth";
nodes.server = { config, pkgs, ... }: {
imports = [
(pkgs'.path + "/nixos/modules/profiles/headless.nix")
(pkgs'.path + "/nixos/modules/profiles/qemu-guest.nix")
{
options = {
shb.ssl.enable = lib.mkEnableOption "ssl";
};
}
../../modules/blocks/hardcodedsecret.nix
../../modules/blocks/ldap.nix
];
shb.ldap = {
enable = true;
dcdomain = "dc=example,dc=com";
subdomain = "ldap";
domain = "example.com";
ldapUserPassword.result = config.shb.hardcodedsecret.ldapUserPassword.result;
jwtSecret.result = config.shb.hardcodedsecret.jwtSecret.result;
deleteUnmanagedUsers = true;
debug = false; # Really verbose.
};
shb.hardcodedsecret.ldapUserPassword = {
request = config.shb.ldap.ldapUserPassword.request;
settings.content = password;
};
shb.hardcodedsecret.jwtSecret = {
request = config.shb.ldap.jwtSecret.request;
settings.content = "jwtSecret";
};
specialisation.withGroupA.configuration = {
shb.ldap = {
groups."groupA" = {};
};
};
specialisation.withUserA.configuration = {
shb.ldap = {
groups."groupA" = {};
users = {
"user_a" = {
email = "userA@test.com";
displayName = "UserA";
firstName = "User";
lastName = "A";
groups = [ "groupA" ];
password.result = config.specialisation.withUserA.configuration.shb.hardcodedsecret.user_a.result;
};
};
};
shb.hardcodedsecret.user_a = {
request = config.specialisation.withUserA.configuration.shb.ldap.users."user_a".password.request;
settings.content = "userpasswordA"; # must be longer than 8 characters.
};
};
specialisation.withOtherGroup.configuration = {
shb.ldap = {
groups."groupB" = {};
groups."groupC" = {};
users = {
"user_a" = {
email = "userA@test.com";
displayName = "UserA";
firstName = "User";
lastName = "A";
groups = [ "groupB" "groupC" ];
password.result = config.specialisation.withUserA.configuration.shb.hardcodedsecret.user_a.result;
};
};
};
shb.hardcodedsecret.user_a = {
request = config.specialisation.withUserA.configuration.shb.ldap.users."user_a".password.request;
settings.content = "userpasswordA"; # must be longer than 8 characters.
};
};
specialisation.removeFromGroup.configuration = {
shb.ldap = {
groups."groupB" = {};
groups."groupC" = {};
users = {
"user_a" = {
email = "userA@test.com";
displayName = "UserA";
firstName = "User";
lastName = "A";
groups = [ "groupB" ];
password.result = config.specialisation.withUserA.configuration.shb.hardcodedsecret.user_a.result;
};
};
};
shb.hardcodedsecret.user_a = {
request = config.specialisation.withUserA.configuration.shb.ldap.users."user_a".password.request;
settings.content = "userpasswordA"; # must be longer than 8 characters.
};
};
specialisation.changeAttributes.configuration = {
shb.ldap = {
groups."groupB" = {};
users = {
"user_a" = {
email = "userA_2@test.com";
displayName = "UserA_2";
firstName = "User_2";
lastName = "A_2";
groups = [ "groupB" ];
password.result = config.specialisation.withUserA.configuration.shb.hardcodedsecret.user_a.result;
};
};
};
shb.hardcodedsecret.user_a = {
request = config.specialisation.withUserA.configuration.shb.ldap.users."user_a".password.request;
settings.content = "userpasswordA_2"; # must be longer than 8 characters.
};
};
specialisation.noChangeAttributes.configuration = {
shb.ldap = {
groups."groupB" = {};
users = {
"user_a" = {
initialEmail = "userA_3@test.com";
initialDisplayName = "UserA_3";
initialFirstName = "User_3";
initialLastName = "A_3";
groups = [ "groupB" ];
initialPassword.result = config.specialisation.withUserA.configuration.shb.hardcodedsecret.user_a.result;
};
};
};
shb.hardcodedsecret.user_a = {
request = config.specialisation.withUserA.configuration.shb.ldap.users."user_a".password.request;
settings.content = "userpasswordA_3"; # must be longer than 8 characters.
};
};
specialisation.leaveUnmanagedUser.configuration = {
shb.ldap = {
deleteUnmanagedUsers = lib.mkForce false;
groups."groupA" = {};
users = {};
};
};
networking.firewall.allowedTCPPorts = [ 80 ]; # nginx port
};
nodes.client = {};
# Inspired from https://github.com/lldap/lldap/blob/33f50d13a2e2d24a3e6bb05a148246bc98090df0/example_configs/lldap-ha-auth.sh
testScript = { nodes, ... }: let
withGroupA = "${nodes.server.system.build.toplevel}/specialisation/withGroupA";
withUserA = "${nodes.server.system.build.toplevel}/specialisation/withUserA";
withOtherGroup = "${nodes.server.system.build.toplevel}/specialisation/withOtherGroup";
removeFromGroup = "${nodes.server.system.build.toplevel}/specialisation/removeFromGroup";
changeAttributes = "${nodes.server.system.build.toplevel}/specialisation/changeAttributes";
noChangeAttributes = "${nodes.server.system.build.toplevel}/specialisation/noChangeAttributes";
leaveUnmanagedUser = "${nodes.server.system.build.toplevel}/specialisation/leaveUnmanagedUser";
in ''
import json
start_all()
server.wait_for_unit("lldap.service")
server.wait_for_open_port(${toString nodes.server.services.lldap.settings.http_port})
with subtest("fail without authenticating"):
client.fail(
"curl -f -s -X GET"
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/api/graphql"
)
with subtest("fail authenticating with wrong credentials"):
client.fail(
"curl -f -s -X POST"
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login"
+ """ -d '{"username": "admin", "password": "wrong"}'"""
)
with subtest("succeed with correct authentication"):
token = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login "
+ """ -d '{"username": "admin", "password": "${password}"}' """
))['token']
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ f""" -H "Authorization: Bearer {token}" """
+ " http://server/api/graphql "
+ """ -d '{"variables": {"id": "admin"}, "query":"query($id:String!){user(userId:$id){displayName groups{displayName}}}"}' """
))['data']
assert data['user']['displayName'] == "Administrator"
assert data['user']['groups'][0]['displayName'] == "lldap_admin"
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ f""" -H "Authorization: Bearer {token}" """
+ " http://server/api/graphql "
+ """ -d '{"variables": {"id": "user_a"}, "query":"query($id:String!){user(userId:$id){displayName groups{displayName}}}"}' """
))['data']
print(server.succeed("cat /run/current-system/sw/bin/lldap-cli"))
with subtest("Add groupA"):
groups = [x["displayName"] for x in json.loads(server.succeed("lldap-cli group list"))]
print("GROUPS=", groups)
if "groupA" in groups:
raise Exception("Shouldn't have found groupA yet.")
server.succeed(
"${withGroupA}/bin/switch-to-configuration test >&2"
)
groups = [x["displayName"] for x in json.loads(server.succeed("lldap-cli group list"))]
print("GROUPS=", groups)
if "groupA" not in groups:
raise Exception("Should have found groupA.")
with subtest("Add user_a"):
users = [x["id"] for x in json.loads(server.succeed("lldap-cli user list all"))]
print("USERS=", users)
if "user_a" in users:
raise Exception("Shouldn't have found user_a yet.")
server.succeed(
"${withUserA}/bin/switch-to-configuration test >&2"
)
users = [x["id"] for x in json.loads(server.succeed("lldap-cli user list all"))]
print("USERS=", users)
if "user_a" not in users:
raise Exception("Should have found user_a.")
groups = server.succeed("lldap-cli user group list user_a").splitlines()
if "groupA" not in groups:
raise Exception("Should have found groupA.")
with subtest("auth with user_a"):
token = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login "
+ """ -d '{"username": "user_a", "password": "userpasswordA"}' """
))['token']
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ f""" -H "Authorization: Bearer {token}" """
+ " http://server/api/graphql "
+ """ -d '{"variables": {"id": "user_a"}, "query":"query($id:String!){user(userId:$id){displayName groups{displayName}}}"}' """
))['data']
if data['user']['displayName'] != "UserA":
raise Exception("DisplayName is not UserA, got:", data['user']['displayName'])
with subtest("With other group"):
server.succeed(
"${withOtherGroup}/bin/switch-to-configuration test >&2"
)
groups = [x["displayName"] for x in json.loads(server.succeed("lldap-cli group list"))]
print("GROUPS=", groups)
if "groupA" in groups:
raise Exception("Should not have found groupA.")
if "groupB" not in groups:
raise Exception("Should have found groupB.")
if "groupC" not in groups:
raise Exception("Should have found groupC.")
groups = server.succeed("lldap-cli user group list user_a").splitlines()
if "groupA" in groups:
raise Exception("Should not have found groupA.")
if "groupB" not in groups:
raise Exception("Should have found groupB.")
if "groupC" not in groups:
raise Exception("Should have found groupC.")
with subtest("Remove from group"):
server.succeed(
"${removeFromGroup}/bin/switch-to-configuration test >&2"
)
groups = [x["displayName"] for x in json.loads(server.succeed("lldap-cli group list"))]
print("GROUPS=", groups)
if "groupA" in groups:
raise Exception("Should not have found groupA.")
if "groupB" not in groups:
raise Exception("Should have found groupB.")
if "groupC" not in groups:
raise Exception("Should have found groupC.")
groups = server.succeed("lldap-cli user group list user_a").splitlines()
if "groupA" in groups:
raise Exception("Should not have found groupA.")
if "groupB" not in groups:
raise Exception("Should have found groupB.")
if "groupC" in groups:
raise Exception("Should not have found groupC.")
with subtest("change attributes"):
server.succeed(
"${changeAttributes}/bin/switch-to-configuration test >&2"
)
token = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login "
+ """ -d '{"username": "user_a", "password": "userpasswordA_2"}' """
))['token']
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ f""" -H "Authorization: Bearer {token}" """
+ " http://server/api/graphql "
+ """ -d '{"variables": {"id": "user_a"}, "query":"query($id:String!){user(userId:$id){email displayName firstName lastName}}"}' """
))['data']
if data['user']['email'] != "userA_2@test.com":
raise Exception("email is not userA_2@test.com_2, got:", data['user']['email'])
if data['user']['displayName'] != "UserA_2":
raise Exception("displayName is not UserA_2, got:", data['user']['displayName'])
if data['user']['firstName'] != "User_2":
raise Exception("firstName is not User_2_2, got:", data['user']['firstName'])
if data['user']['lastName'] != "A_2":
raise Exception("lastName is not A_2, got:", data['user']['lastName'])
with subtest("do not change attributes"):
server.succeed(
"${noChangeAttributes}/bin/switch-to-configuration test >&2"
)
token = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login "
+ """ -d '{"username": "user_a", "password": "userpasswordA_2"}' """
))['token']
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ f""" -H "Authorization: Bearer {token}" """
+ " http://server/api/graphql "
+ """ -d '{"variables": {"id": "user_a"}, "query":"query($id:String!){user(userId:$id){email displayName firstName lastName}}"}' """
))['data']
if data['user']['email'] != "userA_2@test.com":
raise Exception("email is not userA_2@test.com_2, got:", data['user']['email'])
if data['user']['displayName'] != "UserA_2":
raise Exception("displayName is not UserA_2, got:", data['user']['displayName'])
if data['user']['firstName'] != "User_2":
raise Exception("firstName is not User_2_2, got:", data['user']['firstName'])
if data['user']['lastName'] != "A_2":
raise Exception("lastName is not A_2, got:", data['user']['lastName'])
with subtest("Delete user"):
server.succeed(
"${withGroupA}/bin/switch-to-configuration test >&2"
)
users = [x["id"] for x in json.loads(server.succeed("lldap-cli user list all"))]
print("USERS=", users)
if "user_a" in users:
raise Exception("Should not have found user_a.")
with subtest("Add again user_a"):
server.succeed(
"${withUserA}/bin/switch-to-configuration test >&2"
)
users = [x["id"] for x in json.loads(server.succeed("lldap-cli user list all"))]
print("USERS=", users)
if "user_a" not in users:
raise Exception("Should have found user_a.")
server.succeed(
"${leaveUnmanagedUser}/bin/switch-to-configuration test >&2"
)
users = [x["id"] for x in json.loads(server.succeed("lldap-cli user list all"))]
print("USERS=", users)
if "user_a" not in users:
raise Exception("Should have found user_a.")
'';
};
}