add debug output to lldap with mitmdump module

This commit is contained in:
ibizaman 2025-07-30 23:21:19 +02:00 committed by Pierre Penninckx
parent d824da617c
commit 3184015d67
3 changed files with 102 additions and 48 deletions

View file

@ -342,7 +342,7 @@ in
allow ${cfg.restrictAccessIPRange};
deny all;
'');
proxyPass = "http://${toString config.services.lldap.settings.http_host}:${toString config.services.lldap.settings.http_port}/";
proxyPass = "http://${toString config.services.lldap.settings.http_host}:${toString config.shb.lldap.webUIListenPort}/";
};
};
};
@ -366,10 +366,10 @@ in
settings = {
http_url = "https://${fqdn}";
http_host = "127.0.0.1";
http_port = cfg.webUIListenPort;
http_port = if !cfg.debug then cfg.webUIListenPort else cfg.webUIListenPort + 1;
ldap_host = "127.0.0.1";
ldap_port = cfg.ldapPort;
ldap_port = cfg.ldapPort; # Would be great to be able to inspect this but it requires tcpdump instead of mitmproxy.
ldap_base_dn = cfg.dcdomain;
ldap_user_pass_file = toString cfg.ldapUserPassword.result.path;
@ -384,5 +384,15 @@ in
"password_file" = toString v.password.result.path;
}) cfg.ensureUsers;
};
shb.mitmdump.instances."lldap-web" = lib.mkIf cfg.debug {
listenPort = config.shb.lldap.webUIListenPort;
upstreamPort = config.shb.lldap.webUIListenPort + 1;
after = [ "lldap.service" ];
enabledAddons = [ config.shb.mitmdump.addons.logger ];
extraArgs = [
"--set" "verbose_pattern=/api"
];
};
};
}

View file

@ -168,6 +168,15 @@ so you will want to revert this at some point.
To see the logs, then run `journalctl -u lldap.service`.
Setting the `debug` option to `true` will also
add an [shb.mitmdump][] instance in front of the LLDAP [web UI port](#blocks-lldap-options-shb.lldap.webUIListenPort)
which prints all requests and responses headers and body
to the systemd service `mitmdump-lldap.service`. Note the you won't
see the query done using something like `ldapsearch` since those
go through the [`LDAP` port](#blocks-lldap-options-shb.lldap.ldapPort).
[shb.mitmdump]: ./blocks-mitmdump.html
## Tests {#blocks-lldap-tests}
Specific integration tests are defined in [`/test/blocks/lldap.nix`](@REPO@/test/blocks/lldap.nix).

View file

@ -20,6 +20,7 @@ in
}
../../modules/blocks/hardcodedsecret.nix
../../modules/blocks/lldap.nix
../../modules/blocks/mitmdump.nix
];
shb.lldap = {
@ -29,7 +30,6 @@ in
domain = "example.com";
ldapUserPassword.result = config.shb.hardcodedsecret.ldapUserPassword.result;
jwtSecret.result = config.shb.hardcodedsecret.jwtSecret.result;
debug = true;
ensureUsers = {
"charlie" = {
@ -56,64 +56,99 @@ in
};
networking.firewall.allowedTCPPorts = [ 80 ]; # nginx port
environment.systemPackages = [ pkgs.openldap ];
specialisation = {
withDebug.configuration = {
shb.lldap.debug = true;
};
};
};
nodes.client = {};
# Inspired from https://github.com/lldap/lldap/blob/33f50d13a2e2d24a3e6bb05a148246bc98090df0/example_configs/lldap-ha-auth.sh
testScript = { nodes, ... }: ''
testScript = { nodes, ... }:
let
specializations = "${nodes.server.system.build.toplevel}/specialisation";
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"
)
def tests():
server.wait_for_unit("lldap.service")
server.wait_for_open_port(${toString nodes.server.shb.lldap.webUIListenPort})
server.wait_for_open_port(${toString nodes.server.shb.lldap.ldapPort})
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("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("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']
with subtest("fail authenticating with wrong credentials"):
resp = 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"}'"""
)
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ """ -H "Authorization: Bearer {token}" """.format(token=token)
+ " http://server/api/graphql "
+ """ -d '{"variables": {"id": "admin"}, "query":"query($id:String!){user(userId:$id){displayName groups{displayName}}}"}' """
))['data']
print(resp)
assert data['user']['displayName'] == "Administrator"
assert data['user']['groups'][0]['displayName'] == "lldap_admin"
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']
with subtest("succeed charlie"):
client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login "
+ """ -d '{"username": "charlie", "password": "${charliePassword}"}' """
)
data = json.loads(client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ """ -H "Authorization: Bearer {token}" """.format(token=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"
with subtest("succeed charlie"):
resp = client.succeed(
"curl -f -s -X POST "
+ """ -H "Content-type: application/json" """
+ """ -H "Host: ldap.example.com" """
+ " http://server/auth/simple/login "
+ """ -d '{"username": "charlie", "password": "${charliePassword}"}' """
)
print(resp)
with subtest("ldap user search"):
resp = server.succeed('ldapsearch -H ldap://127.0.0.1:${toString nodes.server.shb.lldap.ldapPort} -D uid=admin,ou=people,dc=example,dc=com -b "ou=people,dc=example,dc=com" -w ${password}')
print(resp)
if "uid=admin" not in resp:
raise Exception("Expected to find admin")
if "uid=charlie" not in resp:
raise Exception("Expected to find charlie")
with subtest("no debug"):
tests()
with subtest("with debug"):
server.succeed('${specializations}/withDebug/bin/switch-to-configuration test')
tests()
'';
};
}