lldap: automatic provision + system users + stalwart + whatever
This commit is contained in:
parent
4a0129585a
commit
82caf96d36
19 changed files with 405 additions and 285 deletions
|
@ -19,10 +19,88 @@ index 6f42473..b3746a1 100644
|
|||
&config,
|
||||
'';
|
||||
|
||||
whoamiPatch = pkgs.writeText "lldap-whoami.patch" ''
|
||||
diff --git a/server/src/infra/ldap_handler.rs b/server/src/infra/ldap_handler.rs
|
||||
index 7257c31..feda03c 100644
|
||||
--- a/server/src/infra/ldap_handler.rs
|
||||
+++ b/server/src/infra/ldap_handler.rs
|
||||
@@ -26,7 +26,7 @@ use ldap3_proto::proto::{
|
||||
LdapDerefAliases, LdapExtendedRequest, LdapExtendedResponse, LdapFilter, LdapModify,
|
||||
LdapModifyRequest, LdapModifyType, LdapOp, LdapPartialAttribute, LdapPasswordModifyRequest,
|
||||
LdapResult as LdapResultOp, LdapResultCode, LdapSearchRequest, LdapSearchResultEntry,
|
||||
- LdapSearchScope,
|
||||
+ LdapSearchScope, OID_PASSWORD_MODIFY, OID_WHOAMI,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use tracing::{debug, instrument, warn};
|
||||
@@ -181,7 +181,7 @@ fn root_dse_response(base_dn: &str) -> LdapOp {
|
||||
LdapPartialAttribute {
|
||||
atype: "supportedExtension".to_string(),
|
||||
// Password modification extension.
|
||||
- vals: vec![b"1.3.6.1.4.1.4203.1.11.1".to_vec()],
|
||||
+ vals: vec![OID_PASSWORD_MODIFY.as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "supportedControl".to_string(),
|
||||
@@ -204,6 +204,11 @@ fn root_dse_response(base_dn: &str) -> LdapOp {
|
||||
atype: "isGlobalCatalogReady".to_string(),
|
||||
vals: vec![b"false".to_vec()],
|
||||
},
|
||||
+ LdapPartialAttribute {
|
||||
+ atype: "supportedExtension".to_string(),
|
||||
+ // whoami extension.
|
||||
+ vals: vec![OID_WHOAMI.as_bytes().to_vec()],
|
||||
+ },
|
||||
],
|
||||
})
|
||||
}
|
||||
@@ -413,16 +418,33 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
async fn do_extended_request(&mut self, request: &LdapExtendedRequest) -> Vec<LdapOp> {
|
||||
- match LdapPasswordModifyRequest::try_from(request) {
|
||||
- Ok(password_request) => self
|
||||
+ if let Ok(password_request) = LdapPasswordModifyRequest::try_from(request) {
|
||||
+ return self
|
||||
.do_password_modification(&password_request)
|
||||
.await
|
||||
- .unwrap_or_else(|e: LdapError| vec![make_extended_response(e.code, e.message)]),
|
||||
- Err(_) => vec![make_extended_response(
|
||||
- LdapResultCode::UnwillingToPerform,
|
||||
- format!("Unsupported extended operation: {}", &request.name),
|
||||
- )],
|
||||
+ .unwrap_or_else(|e: LdapError| vec![make_extended_response(e.code, e.message)]);
|
||||
}
|
||||
+
|
||||
+ if request.name == OID_WHOAMI {
|
||||
+ let dn = self
|
||||
+ .user_info
|
||||
+ .as_ref()
|
||||
+ .map(|user_info| {
|
||||
+ format!(
|
||||
+ "dn:uid={},ou=people,{}",
|
||||
+ user_info.user.clone().into_string(),
|
||||
+ self.ldap_info.base_dn_str
|
||||
+ )
|
||||
+ })
|
||||
+ .unwrap_or_default();
|
||||
+
|
||||
+ return vec![make_extended_response(LdapResultCode::Success, dn)];
|
||||
+ }
|
||||
+
|
||||
+ return vec![make_extended_response(
|
||||
+ LdapResultCode::UnwillingToPerform,
|
||||
+ format!("Unsupported extended operation: {}", &request.name),
|
||||
+ )];
|
||||
}
|
||||
|
||||
async fn handle_modify_change(
|
||||
'';
|
||||
|
||||
pkgLLDAPCli = pkgs.callPackage ./../../../../shared/pkgs/lldap-cli.nix {};
|
||||
in {
|
||||
imports = [
|
||||
# ./test.nix
|
||||
./provision.nix
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
|
@ -33,7 +111,7 @@ in {
|
|||
enable = true;
|
||||
|
||||
package = pkgs.lldap.overrideAttrs (old: {
|
||||
patches = old.patches ++ [ resetPasswordStartPatch ];
|
||||
patches = old.patches ++ [ resetPasswordStartPatch whoamiPatch ];
|
||||
});
|
||||
|
||||
settings = {
|
||||
|
@ -100,22 +178,29 @@ in {
|
|||
|
||||
users = {
|
||||
admin = "admin";
|
||||
bind = "bind_user";
|
||||
};
|
||||
# bind = "bind_user";
|
||||
} // (lib.mapAttrs (n: v: v.user_id) config.services.lldap.provision.users);
|
||||
|
||||
groups = {
|
||||
admin = "lldap_admin";
|
||||
member = "base_member";
|
||||
system = "system_service";
|
||||
system_email = "system_email";
|
||||
};
|
||||
password_manager = "lldap_password_manager";
|
||||
strict_readonly = "lldap_strict_readonly";
|
||||
# system = "system_service";
|
||||
# system_email = "system_email";
|
||||
} // (lib.mapAttrs (n: v: v.display_name) config.services.lldap.provision.groups);
|
||||
|
||||
ou = {
|
||||
groups = "groups";
|
||||
users = "people";
|
||||
};
|
||||
|
||||
attr = {
|
||||
attr = let
|
||||
toCamelCase = w: let
|
||||
parts = lib.splitString "_" w;
|
||||
cap = lib.imap0 (i: v: if i == 0 then v else (lib.toUpper (lib.substring 0 1 v)) + (lib.substring 1 (lib.stringLength v) v));
|
||||
in lib.concatStrings (cap parts);
|
||||
in {
|
||||
uid = "uid";
|
||||
firstname = "givenName";
|
||||
lastname = "sn";
|
||||
|
@ -124,9 +209,9 @@ in {
|
|||
groupname = "cn";
|
||||
|
||||
# custom
|
||||
member_email = "member_email";
|
||||
mail_disk_quota = "mail_disk_quota";
|
||||
};
|
||||
# member_email = "member_email";
|
||||
# mail_disk_quota = "mail_disk_quota";
|
||||
} // (lib.mapAttrs (n: v: toCamelCase v.name) config.services.lldap.provision.user_attributes);
|
||||
|
||||
age_secret = config.age.secrets.lldap-bind-user-pass.path;
|
||||
};
|
||||
|
@ -156,6 +241,31 @@ in {
|
|||
|
||||
mkAnd = v: { type = "and"; values = v; };
|
||||
mkOr = v: { type = "or"; values = v; };
|
||||
|
||||
# mkProvision helpers for creating users
|
||||
mkProvisionEmail = name: "${name}@${config.mine.shared.settings.domain}";
|
||||
mkProvisionUserNormal = name: config.mine.shared.lib.ldap.mkScope (lconfig: llib: {
|
||||
user_id = name;
|
||||
membermail = mkProvisionEmail name;
|
||||
mail = "env:EMAIL_${lib.toUpper name}";
|
||||
groups = [ lconfig.groups.member ];
|
||||
membermaildiskquota = 100*1024*1024; # mb
|
||||
});
|
||||
|
||||
mkProvisionUserSystem = name: password_file: config.mine.shared.lib.ldap.mkScope (lconfig: llib: {
|
||||
user_id = name;
|
||||
membermail = mkProvisionEmail name;
|
||||
password = "file:${password_file}";
|
||||
groups = [ lconfig.groups.system_mail lconfig.groups.system_service ];
|
||||
membermaildiskquota = 10*1024*1024; # mb
|
||||
});
|
||||
|
||||
mkProvisionUserAdmin = name: config.mine.shared.lib.ldap.mkScope (lconfig: llib: {
|
||||
user_id = name;
|
||||
membermail = mkProvisionEmail name;
|
||||
groups = [ lconfig.groups.admin lconfig.groups.member ];
|
||||
membermaildiskquota = 100*1024*1024; # mb
|
||||
});
|
||||
};
|
||||
|
||||
mine.shared.meta.lldap = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue