infrastructure/modules/nixos/ldap/object.nix
2024-03-26 18:35:44 -07:00

175 lines
6 KiB
Nix

{
config,
lib,
inputs,
...
}: let
inherit (inputs.self.lib.lib) unmerged mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.attrsets) filterAttrs mapAttrsToList nameValuePair;
inherit (lib.lists) optional toList;
inherit (lib.strings) toLower removeSuffix concatMapStrings concatStringsSep optionalString;
ldap'lib = {
specialArgs = {
nixosConfig = config;
ldap = config.users.ldap // {
lib = config.lib.ldap;
};
};
objectModule = ldapObjectModule;
objectType = lib.types.submoduleWith {
modules = [ ldapObjectModule ];
inherit (ldap'lib) specialArgs;
};
objectSettingType' = lib.types.submoduleWith {
modules = [ ldapObjectSettingModule ];
inherit (ldap'lib) specialArgs;
};
objectSettingType = let
mapToObjectSetting = value: {
inherit value;
};
in lib.types.coercedTo ldapValueType mapToObjectSetting ldap'lib.objectSettingType';
objectSettingsModule = ldapObjectSettingsModule;
objectSettingsType = lib.types.submoduleWith {
modules = [ ldapObjectSettingsModule ];
inherit (ldap'lib) specialArgs;
};
mapObjectSettingsToPair = settings: nameValuePair
(removeSuffix ",${config.users.ldap.base}" settings.dn)
(unmerged.mergeAttrs settings.settings);
mapObjectSettingsToAttr = settings: let
pair = ldap'lib.mapObjectSettingsToPair settings;
in {
${pair.name} = pair.value;
};
mkLdapModifyObjectSettingValues = let
mkLdapModifyValues = setting: concatMapStrings (value: ''
${setting.key}: ${toString value}
'') (toList setting.value);
in mkLdapModifyValues;
mkLdapModifyObjectSettings = let
mkLdapModifySetting = setting: ''
${setting.modifyType}: ${setting.key}
'' + ldap'lib.mkLdapModifyObjectSettingValues setting;
in settings: mapAttrsToList (_: mkLdapModifySetting) settings;
mkLdapAddObjectSettings = settings: mapAttrsToList (_: ldap'lib.mkLdapModifyObjectSettingValues) settings;
mkLdapModifyObject = let
mkHeader = changeType: object: ''
dn: ${object.dn}
changetype: ${changeType}
'';
in {
modify = object: let
enabledSettings' = filterAttrs (_: setting: setting.enable) object.settings;
enabledSettings = ldap'lib.mkLdapModifyObjectSettings enabledSettings';
replaceSettings' = filterAttrs (_: setting: setting.modifyType == "replace") enabledSettings';
replaceSettings = ldap'lib.mkLdapModifyObjectSettings replaceSettings';
addSettings' = filterAttrs (_: setting: setting.modifyType == "add") enabledSettings';
replaceText = mkHeader "modify" object + concatStringsSep "-\n" replaceSettings;
text = mkHeader "modify" object + concatStringsSep "-\n" enabledSettings;
in concatStringsSep "-\n\n" (
[ text ]
++ optional (addSettings' != { }) replaceText
);
add = object: let
enabledSettings = filterAttrs (_: setting: setting.enable) object.settings;
addSettings = ldap'lib.mkLdapAddObjectSettings enabledSettings;
in mkHeader "add" object + concatStringsSep "-\n" addSettings;
delete = object: mkHeader "delete" object;
modrdn = object: { newrdn, deleteoldrdn, newsuperior }: let
modifySettings = ''
newrdn: ${newrdn}
deleteoldrdn: ${if deleteoldrdn == true then "1" else if deleteoldrdn == "false" then "0" else toString deleteoldrdn}
'' + optionalString (newsuperior != null) ''
newsuperior: ${newsuperior}
'';
in mkHeader "modrdn" + modifySettings;
moddn = object: { deleteoldrdn, newsuperior }: let
modifySettings = ''
deleteoldrdn: ${if deleteoldrdn == true then "1" else if deleteoldrdn == "false" then "0" else toString deleteoldrdn}
newsuperior: ${newsuperior}
'';
in mkHeader "moddn" + modifySettings;
};
};
ldapPrimitiveType = with lib.types; oneOf [ str int ];
ldapValueType = with lib.types; oneOf [ ldapPrimitiveType (listOf ldapPrimitiveType) ];
ldapObjectSettingModule = {config, name, ...}: {
options = with lib.types; {
enable = mkEnableOption "setting" // {
default = true;
};
key = mkOption {
type = str;
default = name;
};
value = mkOption {
type = ldapValueType;
};
modifyType = mkOption {
type = enum [ "replace" "add" "delete" ];
default = if toLower config.key == "objectclass" then "add" else "replace";
};
};
};
ldapObjectSettingsModule = {config, ...}: {
options = with lib.types; {
enable = mkEnableOption "object" // {
default = true;
};
dn = mkOption {
type = str;
};
settings = mkOption {
type = unmerged.types.attrs;
};
};
config = {
settings = {
dn = mkAlmostOptionDefault config.dn;
};
};
};
ldapObjectModule = {config, name, ldap, ...}: {
options = with lib.types; {
enable = mkEnableOption "object creation" // {
default = true;
};
dn = mkOption {
type = str;
default = "${name},${ldap.base}";
};
changeType = mkOption {
type = enum [ "modify" "add" "delete" "modrdn" "moddn" ];
default = "modify";
};
changeText = mkOption {
type = lines;
};
objectClasses = mkOption {
type = listOf str;
default = [ ];
};
settings = mkOption {
type = attrsOf ldap.lib.objectSettingType;
default = { };
};
};
config = {
settings = {
objectClass = mkIf (config.objectClasses != [ ]) (mkOptionDefault config.objectClasses);
};
changeText = mkOptionDefault (ldap'lib.mkLdapModifyObject.${config.changeType} config);
};
};
in {
options.users.ldap = with lib.types; {
management.objects = mkOption {
type = attrsOf ldap'lib.objectType;
default = { };
};
};
config.lib.ldap = ldap'lib;
}