2bab61209c
Go-Modul in go.mod und allen 45 Go-Dateien umbenannt.
135 lines
3.9 KiB
Go
135 lines
3.9 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"archivmail/internal/audit"
|
|
"archivmail/internal/ldapauth"
|
|
ldapcfg "archivmail/internal/ldapconfig"
|
|
)
|
|
|
|
// syncResult is the JSON response returned by LDAP sync endpoints.
|
|
type syncResult struct {
|
|
Synced int `json:"synced"`
|
|
Errors []string `json:"errors"`
|
|
}
|
|
|
|
// handleSyncTenantLDAP imports all LDAP users into the tenant (domain_admin).
|
|
func (s *Server) handleSyncTenantLDAP(w http.ResponseWriter, r *http.Request) {
|
|
if s.tenantLdapStore == nil {
|
|
writeError(w, http.StatusServiceUnavailable, "tenant ldap store not available")
|
|
return
|
|
}
|
|
sess := sessionFromCtx(r.Context())
|
|
if sess.TenantID == nil {
|
|
writeError(w, http.StatusBadRequest, "no tenant context")
|
|
return
|
|
}
|
|
res := s.doSyncTenantLDAP(r, *sess.TenantID)
|
|
s.audlog.Log(audit.Entry{
|
|
EventType: "tenant_ldap_sync",
|
|
Username: sess.Username,
|
|
IPAddress: s.remoteIP(r),
|
|
Success: len(res.Errors) == 0,
|
|
Detail: fmt.Sprintf("%d Benutzer synchronisiert", res.Synced),
|
|
})
|
|
writeJSON(w, http.StatusOK, res)
|
|
}
|
|
|
|
// handleAdminSyncTenantLDAP imports all LDAP users into any tenant (superadmin).
|
|
func (s *Server) handleAdminSyncTenantLDAP(w http.ResponseWriter, r *http.Request) {
|
|
if s.tenantLdapStore == nil {
|
|
writeError(w, http.StatusServiceUnavailable, "tenant ldap store not available")
|
|
return
|
|
}
|
|
id, err := parseTenantID(r)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid tenant id")
|
|
return
|
|
}
|
|
res := s.doSyncTenantLDAP(r, id)
|
|
sess := sessionFromCtx(r.Context())
|
|
s.audlog.Log(audit.Entry{
|
|
EventType: "tenant_ldap_sync",
|
|
Username: sess.Username,
|
|
IPAddress: s.remoteIP(r),
|
|
Success: len(res.Errors) == 0,
|
|
Detail: fmt.Sprintf("%d Benutzer synchronisiert (tenant %d)", res.Synced, id),
|
|
})
|
|
writeJSON(w, http.StatusOK, res)
|
|
}
|
|
|
|
// doSyncTenantLDAP is the shared sync logic: fetch all LDAP users and upsert
|
|
// them into the local userstore with source='ldap'.
|
|
func (s *Server) doSyncTenantLDAP(r *http.Request, tenantID int64) syncResult {
|
|
saved, err := s.tenantLdapStore.GetWithPassword(r.Context(), tenantID)
|
|
if err != nil || saved == nil {
|
|
return syncResult{Errors: []string{"keine LDAP-Konfiguration vorhanden"}}
|
|
}
|
|
|
|
cfg := ldapauth.Config{
|
|
URL: saved.URL,
|
|
BindDN: saved.BindDN,
|
|
BindPassword: saved.BindPassword,
|
|
BaseDN: saved.BaseDN,
|
|
UserFilter: saved.UserFilter,
|
|
TLS: saved.TLS,
|
|
TLSSkipVerify: saved.TLSSkipVerify,
|
|
}
|
|
|
|
ldapUsers, err := ldapauth.FetchUsers(cfg)
|
|
if err != nil {
|
|
return syncResult{Errors: []string{err.Error()}}
|
|
}
|
|
|
|
defaultRole := saved.DefaultRole
|
|
if defaultRole == "" {
|
|
defaultRole = "user"
|
|
}
|
|
|
|
var res syncResult
|
|
res.Errors = []string{}
|
|
for _, u := range ldapUsers {
|
|
mail := u.Mail
|
|
if mail == "" {
|
|
mail = u.UID + "@ldap.local"
|
|
}
|
|
if _, uErr := s.users.UpsertLDAPUser(u.UID, mail, defaultRole, &tenantID); uErr != nil {
|
|
res.Errors = append(res.Errors, fmt.Sprintf("%s: %s", u.UID, uErr.Error()))
|
|
} else {
|
|
res.Synced++
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// buildTenantTestConfig constructs an ldapauth.Config for testing, either from
|
|
// the saved tenant config or from the provided request body.
|
|
func (s *Server) buildTenantTestConfig(r *http.Request, useSaved bool, tenantID int64, provided ldapcfg.TenantLDAPConfig) *ldapauth.Config {
|
|
if useSaved {
|
|
saved, err := s.tenantLdapStore.GetWithPassword(r.Context(), tenantID)
|
|
if err != nil || saved == nil {
|
|
return nil
|
|
}
|
|
return &ldapauth.Config{
|
|
URL: saved.URL,
|
|
BindDN: saved.BindDN,
|
|
BindPassword: saved.BindPassword,
|
|
BaseDN: saved.BaseDN,
|
|
UserFilter: saved.UserFilter,
|
|
TLS: saved.TLS,
|
|
TLSSkipVerify: saved.TLSSkipVerify,
|
|
}
|
|
}
|
|
return &ldapauth.Config{
|
|
URL: provided.URL,
|
|
BindDN: provided.BindDN,
|
|
BindPassword: provided.BindPassword,
|
|
BaseDN: provided.BaseDN,
|
|
UserFilter: provided.UserFilter,
|
|
TLS: provided.TLS,
|
|
TLSSkipVerify: provided.TLSSkipVerify,
|
|
}
|
|
}
|