feat(ldap): perform user/group writes via the FreeIPA API
Raw LDAP adds/modifies bypassed FreeIPA's framework, so group/user creates failed with Object Class Violation (no gidNumber/uidNumber/ipaUniqueID) and deletes/mods needed ACIs the bind account couldn't exercise as a plain LDAP write. Route all MUTATIONS through the FreeIPA JSON-RPC API instead; reads stay on direct LDAP. - internal/client/freeipa.go: new JSON-RPC client (form login_password → ipa_session cookie, re-auth on 401, multi-server failover, TLS via the configured CA). Derives the API host + login uid from the LDAP config. - internal/service/ldap.go: CreateGroup/UpdateGroup/DeleteGroup/AddGroupMembers/ RemoveGroupMember → group_add/_mod/_del/_add_member/_remove_member; CreateUser/UpdateUser/DisableUser/ResetPassword → user_add/_mod/_disable (+_enable)/passwd. Services map → addattr(objectclass)/setattr. Writes error cleanly when the IPA client is unconfigured. - cmd/server/main.go: build the FreeIPA client from the LDAP config and inject it into the LDAP service. Verified live: group create (IPA-assigned gidNumber), get, add/remove member, delete all succeed; reads unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,19 @@ func main() {
|
||||
logger.Info().Int("poolSize", cfg.LDAP.PoolSize).Msg("Connected to LDAP")
|
||||
}
|
||||
|
||||
// Initialize FreeIPA management-API client (for user/group MUTATIONS).
|
||||
// Reads stay on direct LDAP; writes go through the IPA API so gid/uid
|
||||
// Numbers, ipaUniqueID and objectClasses are assigned by the framework.
|
||||
var ipaClient *client.FreeIPAClient
|
||||
if len(cfg.LDAP.Servers) > 0 {
|
||||
ipaClient, err = client.NewFreeIPAClient(cfg.LDAP.Servers, cfg.LDAP.BindDN, cfg.LDAP.BindPass, cfg.LDAP.CAFile, logger)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msg("Failed to create FreeIPA API client (LDAP writes disabled)")
|
||||
} else {
|
||||
logger.Info().Int("servers", len(cfg.LDAP.Servers)).Msg("FreeIPA management-API client initialized")
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize PowerDNS client
|
||||
var pdnsClient *client.PowerDNSClient
|
||||
if cfg.PowerDNS.BaseURL != "" {
|
||||
@@ -193,7 +206,7 @@ func main() {
|
||||
logger.Info().Int("attrs", len(registry.AllUserAttrs())).Int("entities", len(registry.AllEntityTypes())).Msg("Schema registry initialized")
|
||||
|
||||
// Create services
|
||||
ldapSvc := service.NewLDAPService(ldapClient, cfg.LDAP.BaseDN, logger, registry)
|
||||
ldapSvc := service.NewLDAPService(ldapClient, ipaClient, cfg.LDAP.BaseDN, logger, registry)
|
||||
ldapEntitySvc := service.NewLDAPEntityService(ldapClient, cfg.LDAP.BaseDN, registry, logger)
|
||||
dnsSvc := service.NewDNSService(pdnsClient, logger)
|
||||
dbSvc := service.NewDatabaseService(coreDB.Pool(), logger)
|
||||
|
||||
Reference in New Issue
Block a user