package handlers import "net/http" import "strings" import "codit/internal/db" import "codit/internal/auth" import "codit/config" import "codit/internal/models" func (api *API) ListAuthProviders(w http.ResponseWriter, r *http.Request, _ map[string]string) { var providers []models.AuthProvider var err error if !api.requireAdmin(w, r) { return } providers, err = api.store(r).ListAuthProvidersWithGroupMappings() if err != nil { WriteJSONWithErrorReason(w, r, http.StatusInternalServerError, err.Error()) return } WriteJSON(w, http.StatusOK, providers) } func (api *API) GetAuthProvider(w http.ResponseWriter, r *http.Request, params map[string]string) { var provider models.AuthProvider var err error if !api.requireAdmin(w, r) { return } provider, err = api.store(r).GetAuthProviderWithGroupMappings(params["id"]) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusNotFound, "auth provider not found") return } WriteJSON(w, http.StatusOK, provider) } func (api *API) CreateAuthProvider(w http.ResponseWriter, r *http.Request, _ map[string]string) { var req models.AuthProvider var created models.AuthProvider var err error if !api.requireAdmin(w, r) { return } err = DecodeJSON(r, &req) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "invalid json") return } if strings.TrimSpace(req.Name) == "" { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "name is required") return } if req.Type != models.AuthProviderTypeLDAP && req.Type != models.AuthProviderTypeOIDC { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "type must be ldap or oidc") return } if req.Type == models.AuthProviderTypeOIDC && strings.TrimSpace(req.OIDCAdmissionExpr) != "" { err = oidcCompileAdmissionExpr(strings.TrimSpace(req.OIDCAdmissionExpr)) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "invalid admission expression: "+err.Error()) return } } created, err = api.store(r).CreateAuthProvider(r.Context(), req) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, err.Error()) return } WriteJSON(w, http.StatusCreated, created) } func (api *API) UpdateAuthProvider(w http.ResponseWriter, r *http.Request, params map[string]string) { var req models.AuthProvider var updated models.AuthProvider var existing models.AuthProvider var err error if !api.requireAdmin(w, r) { return } existing, err = api.store(r).GetAuthProvider(params["id"]) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusNotFound, "auth provider not found") return } err = DecodeJSON(r, &req) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "invalid json") return } req.ID = existing.ID req.Type = existing.Type if req.Type == models.AuthProviderTypeOIDC && strings.TrimSpace(req.OIDCAdmissionExpr) != "" { err = oidcCompileAdmissionExpr(strings.TrimSpace(req.OIDCAdmissionExpr)) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "invalid admission expression: "+err.Error()) return } } if existing.ID == db.BuiltinDBProviderPublicID { existing.Enabled = req.Enabled if strings.TrimSpace(req.Name) != "" { existing.Name = strings.TrimSpace(req.Name) } updated, err = api.store(r).UpdateAuthProvider(r.Context(), existing) } else { if strings.TrimSpace(req.Name) == "" { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "name is required") return } updated, err = api.store(r).UpdateAuthProvider(r.Context(), req) } if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, err.Error()) return } WriteJSON(w, http.StatusOK, updated) } func (api *API) DeleteAuthProvider(w http.ResponseWriter, r *http.Request, params map[string]string) { var err error var force bool var count int if !api.requireAdmin(w, r) { return } if params["id"] == db.BuiltinDBProviderPublicID { WriteJSONWithErrorReason(w, r, http.StatusForbidden, "builtin provider cannot be deleted") return } force = strings.EqualFold(r.URL.Query().Get("force"), "true") if !force { count, err = api.store(r).CountAuthProviderUsers(params["id"]) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusInternalServerError, err.Error()) return } if count > 0 { WriteJSON(w, http.StatusConflict, map[string]any{ "error": "provider has associated users", "user_count": count, }) return } } err = api.store(r).DeleteAuthProvider(r.Context(), params["id"], force) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusInternalServerError, err.Error()) return } WriteJSON(w, http.StatusOK, map[string]string{"status": "ok"}) } func (api *API) TestAuthProvider(w http.ResponseWriter, r *http.Request, params map[string]string) { var provider models.AuthProvider var req testLDAPSettingsRequest var cfg config.Config var ldapUser auth.LDAPUser var err error if !api.requireAdmin(w, r) { return } provider, err = api.store(r).GetAuthProvider(params["id"]) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusNotFound, "auth provider not found") return } if provider.Type != models.AuthProviderTypeLDAP { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "test is only supported for ldap providers") return } err = DecodeJSON(r, &req) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "invalid json") return } cfg = api.Cfg cfg.LDAPURL = provider.LDAPUrl cfg.LDAPBindDN = provider.LDAPBindDN cfg.LDAPBindPassword = provider.LDAPBindPassword cfg.LDAPUserBaseDN = provider.LDAPUserBaseDN cfg.LDAPUserFilter = provider.LDAPUserFilter if cfg.LDAPUserFilter == "" { cfg.LDAPUserFilter = "(uid={username})" } cfg.LDAPTLSInsecureSkipVerify = provider.LDAPTLSInsecureSkipVerify if strings.TrimSpace(req.LDAPURL) != "" { cfg.LDAPURL = strings.TrimSpace(req.LDAPURL) } if strings.TrimSpace(req.LDAPBindDN) != "" { cfg.LDAPBindDN = strings.TrimSpace(req.LDAPBindDN) } if req.LDAPBindPassword != "" { cfg.LDAPBindPassword = req.LDAPBindPassword } if strings.TrimSpace(req.LDAPUserBaseDN) != "" { cfg.LDAPUserBaseDN = strings.TrimSpace(req.LDAPUserBaseDN) } if strings.TrimSpace(req.LDAPUserFilter) != "" { cfg.LDAPUserFilter = strings.TrimSpace(req.LDAPUserFilter) } if req.LDAPTLSInsecureSkipVerify != nil { cfg.LDAPTLSInsecureSkipVerify = *req.LDAPTLSInsecureSkipVerify } err = auth.LDAPTestConnectionContext(r.Context(), cfg) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, err.Error()) return } if strings.TrimSpace(req.Username) != "" && strings.TrimSpace(req.Password) != "" { ldapUser, err = auth.LDAPAuthenticateContext(r.Context(), cfg, strings.TrimSpace(req.Username), req.Password) if err != nil { WriteJSONWithErrorReason(w, r, http.StatusBadRequest, err.Error()) return } WriteJSON(w, http.StatusOK, map[string]string{"status": "ok", "user": ldapUser.Username}) return } WriteJSON(w, http.StatusOK, map[string]string{"status": "ok"}) }