Files
hyung-hwan 7f3a8b24ff no request-wide transaction for api.RepoRPMUpload and api.RepoRPMRebuildSubdirMetadata
defined some more constants and places them in models/constannts.go
2026-06-20 21:46:58 +09:00

221 lines
6.9 KiB
Go

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"})
}