{ config, lib, pkgs, ... }: let svc_domain = "ldap.${config.mine.shared.settings.domain}"; resetPasswordStartPatch = pkgs.writeText "lldap-reset-password-start.patch" '' diff --git a/server/src/main.rs b/server/src/main.rs index 71e4928..63be13c 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -158,7 +158,7 @@ async fn set_up_server(config: Configuration) -> Result { ))?; } if config.force_update_private_key || config.force_ldap_user_pass_reset { - bail!("Restart the server without --force-update-private-key or --force-ldap-user-pass-reset to continue."); + // bail!("Restart the server without --force-update-private-key or --force-ldap-user-pass-reset to continue."); } let server_builder = infra::ldap_server::build_ldap_server( &config, ''; in { services.lldap = { enable = true; package = pkgs.lldap.overrideAttrs (old: { patches = old.patches ++ [ resetPasswordStartPatch ]; }); settings = { verbose = true; ldap_user_email = "fricloudlldap.grief462@simplelogin.com"; ldap_base_dn = config.mine.shared.settings.ldap.dc; }; environment = { # always set admin password on startup LLDAP_LDAP_USER_PASS_FILE = config.age.secrets.lldap-admin-user-pass.path; LLDAP_FORCE_LDAP_USER_PASS_RESET = "true"; }; }; services.nginx.virtualHosts."${svc_domain}" = { forceSSL = true; enableACME = true; locations."/".proxyPass = "http://localhost:${builtins.toString config.services.lldap.settings.http_port}"; }; # persistent files environment.persistence.root.directories = [ { directory = "/var/lib/private/lldap"; mode = "0700"; } ]; # lldap user + setup secrets owner (need to add user for secrets to work) users.users.lldap = { group = "lldap"; isSystemUser = true; }; users.groups.lldap = {}; age.secrets = { lldap-admin-user-pass.owner = "lldap"; }; # set settings other services can use # CN = Common Name # OU = Organizational Unit # DC = Domain Component # # The users are all located in ou=people, + the base DN, so by default user bob is at cn=bob,ou=people,dc=example,dc=com. # Similarly, the groups are located in ou=groups, so the group family will be at cn=family,ou=groups,dc=example,dc=com. # Testing group membership through memberOf is supported, so you can have a filter like: (memberOf=cn=admins,ou=groups,dc=example,dc=com). mine.shared.settings.ldap = rec { host = "localhost"; port = 3890; url = "ldap://${host}:${builtins.toString port}"; dc = "dc=${config.mine.shared.settings.domain_sld},dc=${config.mine.shared.settings.domain_tld}"; bind_dn = "uid=${users.bind},ou=${ou.users},${dc}"; search_base = "ou=${ou.users},${dc}"; user_filter = ph: let attrs = [ attr.uid attr.email ]; in config.mine.shared.lib.ldap.mkFilter (lconfig: llib: llib.mkAnd [ (llib.mkGroup lconfig.groups.member) (llib.mkOr (lib.forEach attrs (v: llib.mkSearch v ph))) ] ); oc = { person = "person"; mailAccount = "mailAccount"; groupOfUniqueNames = "groupOfUniqueNames"; }; users = { admin = "admin"; bind = "bind_user"; }; groups = { admin = "lldap_admin"; member = "base_member"; }; ou = { groups = "groups"; users = "people"; }; attr = { uid = "uid"; firstname = "givenName"; lastname = "sn"; email = "mail"; avatar = "jpegPhoto"; groupname = "cn"; }; age_secret = config.age.secrets.lldap-bind-user-pass.path; }; mine.shared.lib.ldap = rec { mkGroup = group_name: "memberof=cn=${group_name},ou=${config.mine.shared.settings.ldap.ou.groups},${config.mine.shared.settings.ldap.dc}"; mkOC = object_class_name: "objectclass=${object_class_name}"; mkSearch = attribute: ph: "${attribute}=${ph}"; mkFilterAdvanced = expr: let isExpr = value: if value ? type then true else false; __mkExpr = value: if isExpr value then mkFilterAdvanced value else "(${value})"; _mkExpr = op: value: "(${op}" + (builtins.concatStringsSep "" (lib.forEach value (v: __mkExpr v))) + ")"; mkExpr = expr: assert isExpr expr; if expr.type == "and" then _mkExpr "&" expr.values else _mkExpr "|" expr.values; in mkExpr expr; mkAndOr = andExprs: orExprs: mkFilterAdvanced { type = "and"; values = andExprs ++ [ { type = "or"; values = orExprs; } ]; }; mkFilter = t: mkFilterAdvanced (t config.mine.shared.settings.ldap config.mine.shared.lib.ldap); mkScope = t: t config.mine.shared.settings.ldap config.mine.shared.lib.ldap; mkAnd = v: { type = "and"; values = v; }; mkOr = v: { type = "or"; values = v; }; }; mine.shared.meta.lldap = { name = "LDAP"; description = "We host our own LDAP server, you can use it to change your displayname, name, password, etc."; url = "https://${svc_domain}"; package = let pkg = config.services.lldap.package; in { name = pkg.pname; version = pkg.version; meta = pkg.meta; }; }; }