{ config, lib, pkgs, ... }: let inherit (lib) types; cfg = config.services.lldap; format = pkgs.formats.json { }; # helpers _configFile = { user_attributes = lib.mapAttrsToList (n: v: v) cfg.provision.user_attributes; group_attributes = lib.mapAttrsToList (n: v: v) cfg.provision.group_attributes; users = lib.mapAttrsToList (n: v: v) cfg.provision.users; groups = lib.mapAttrsToList (n: v: v) cfg.provision.groups; # users = lib.mapAttrsToList (n: v: v // { # user_id = if v ? user_id then v.user_id else n; # }) cfg.users; # groups = lib.mapAttrsToList (n: v: v // { # display_name = if v ? display_name then v.display_name else n; # }) cfg.groups; }; configFile = format.generate "lldap-declarative.json" _configFile; # opts optsAttributes = { name, config, ... }: { options = { name = lib.mkOption { type = types.str; default = name; description = "The name of the attribute"; }; attributeType = lib.mkOption { type = types.enum [ "STRING" "INTEGER" "JPEG_PHOTO" "DATE_TIME" ]; description = "Type of the attribute"; }; isList = lib.mkOption { type = types.bool; default = false; description = "Is this attribute a list (multiple values for this attribute)"; }; isEditable = lib.mkOption { type = types.bool; default = false; description = "Should the user be able to edit this value?"; }; isVisible = lib.mkOption { type = types.bool; default = false; description = "Should the user be able to see this value?"; }; }; }; optsUser = { name, config, ... }: { freeformType = format.type; options = { user_id = lib.mkOption { type = types.str; default = name; description = "The name of the user"; }; }; }; optsGroup = { name, config, ... }: { freeformType = format.type; options = { display_name = lib.mkOption { type = types.str; default = name; description = "The display name of the group"; }; }; }; in { options = { services.lldap = { provisionUsername = lib.mkOption { type = types.str; description = "Username to use when signing into lldap"; }; provisionPasswordFile = lib.mkOption { type = types.path; description = "Path for the password file to authenticate the user"; }; provision = { group_attributes = lib.mkOption { type = types.attrsOf (types.submodule optsAttributes); default = {}; }; user_attributes = lib.mkOption { type = types.attrsOf (types.submodule optsAttributes); default = {}; }; users = lib.mkOption { type = types.attrsOf (types.submodule optsUser); default = {}; example = { user1 = { password = "env:LLDAP_USER1_PASSWORD"; mail = "something@something.dk"; foo = "value for user attribute foo"; bar = "value for user attribute bar"; groups = [ "group1" "group2" ]; }; user2 = { user_id = "superuserawesome"; }; }; }; groups = lib.mkOption { type = types.attrsOf (types.submodule optsGroup); default = {}; example = { base_member = { foo = "value for group attribute foo"; bar = "value for group attribute bar"; }; system = { display_name = "system_service - override display_name"; }; testgroup = {}; }; }; }; }; }; config = lib.mkIf (cfg.enable && cfg.provision != {}) { systemd.services.lldapsetup = { description = "setup lldap declaratively"; wantedBy = [ config.systemd.services.lldap.name "multi-user.target" ]; after = [ config.systemd.services.lldap.name ]; environment = { LLDAP_URL = "${cfg.settings.http_url}:${builtins.toString cfg.settings.http_port}"; LLDAP_USERNAME = cfg.provisionUsername; LLDAP_PASSWORD = "file:${cfg.provisionPasswordFile}"; }; path = with pkgs; [ lldap ]; script = let pythonEnv = pkgs.python3.withPackages(ps: with ps; [ gql aiohttp requests ]); pythonDir = pkgs.runCommand "lldap-bootstrap" {} '' mkdir -p $out/bootstrap cp -a ${./bootstrap}/. $out/bootstrap ''; in '' cd ${pythonDir} ${pythonEnv}/bin/python -m bootstrap.main ${configFile} ''; }; }; }