rewrite using net/http

This commit is contained in:
alu committed 2026-10-26 18:26:03 +00:00
1 parent 67a6cdffa3
commit b97524d1ae
6 files changed
+236 -248

No files matched your search

File renamed without changes.
+2 -2
View File
@@ -1,7 +1,7 @@
package app package app
type Login struct { // login body struct type Login struct { // login body struct
UsernameRaw string `json:"username" binding:"required"` UsernameRaw string `json:"username"`
Username Username Username Username
Password string `json:"password" binding:"required"` Password string `json:"password"`
} }
+3 -4
View File
@@ -5,7 +5,6 @@ import (
"net/http" "net/http"
"regexp" "regexp"
"github.com/gin-gonic/gin"
"github.com/go-ldap/ldap/v3" "github.com/go-ldap/ldap/v3"
common "access-manager-api/app/common" common "access-manager-api/app/common"
@@ -23,17 +22,17 @@ func LDAPEntryToGroup(entry *ldap.Entry) common.Group {
return common.Group{} return common.Group{}
} }
func ParseLDAPError(err error) gin.H { func ParseLDAPError(err error) map[string]any {
if err != nil { if err != nil {
LDAPerr := err.(*ldap.Error) LDAPerr := err.(*ldap.Error)
return gin.H{ return map[string]any{
"ok": false, "ok": false,
"code": LDAPerr.ResultCode, "code": LDAPerr.ResultCode,
"result": ldap.LDAPResultCodeMap[LDAPerr.ResultCode], "result": ldap.LDAPResultCodeMap[LDAPerr.ResultCode],
"message": LDAPerr.Err.Error(), "message": LDAPerr.Err.Error(),
} }
} else { } else {
return gin.H{ return map[string]any{
"ok": true, "ok": true,
"code": http.StatusOK, "code": http.StatusOK,
"result": "OK", "result": "OK",
+52 -38
View File
@@ -7,13 +7,13 @@ import (
"log" "log"
"net/http" "net/http"
"strconv" "strconv"
"time"
common "access-manager-api/app/common" common "access-manager-api/app/common"
"access-manager-api/app/pve" "access-manager-api/app/pve"
paas "proxmoxaas-common-lib"
"github.com/gin-contrib/sessions" "github.com/gorilla/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
) )
type UserSession struct { type UserSession struct {
@@ -30,6 +30,7 @@ var Config common.Config
var RootSession *UserSession var RootSession *UserSession
var UserSessions map[string]*UserSession var UserSessions map[string]*UserSession
var Realms map[string]common.Realm var Realms map[string]common.Realm
var Store *sessions.CookieStore
func Run() { func Run() {
configPath := flag.String("config", "config.json", "path to config.json file") configPath := flag.String("config", "config.json", "path to config.json file")
@@ -38,14 +39,13 @@ func Run() {
// load config values // load config values
Config = common.GetConfig(*configPath) Config = common.GetConfig(*configPath)
// already exits if failed // already exits if failed
log.Printf("Read in config from %s\n", *configPath) log.Printf("[INFO] Read in config from %s\n", *configPath)
// setup gin // setup http router
gin.SetMode(gin.ReleaseMode) router := http.NewServeMux()
router := gin.Default()
// setup api auth cookies // setup api auth cookies
SetupAPISessionStore(router, &Config) SetupAPISessionStore(&Config)
// setup root api token // setup root api token
client, code, err := pve.NewClientFromAPIToken(Config.PVE, Config.PVE.Token) client, code, err := pve.NewClientFromAPIToken(Config.PVE, Config.PVE.Token)
@@ -63,35 +63,33 @@ func Run() {
// make global session map // make global session map
UserSessions = make(map[string]*UserSession) UserSessions = make(map[string]*UserSession)
router.GET("/version", func(c *gin.Context) { router.HandleFunc("GET /version", func(w http.ResponseWriter, r *http.Request) {
c.JSON(http.StatusOK, gin.H{"version": Version}) paas.HTTPWriteJson(w, http.StatusOK, map[string]any{"version": Version})
}) })
router.POST("/ticket", POST_Ticket) router.HandleFunc("POST /ticket", POST_Ticket)
router.DELETE("/ticket", DELETE_Ticket) router.HandleFunc("DELETE /ticket", DELETE_Ticket)
router.GET("/pools/:poolid", GET_Pool) router.HandleFunc("GET /pools/{poolid}", GET_Pool)
router.POST("/pools/:poolid", POST_Pool) router.HandleFunc("POST /pools/{poolid}", POST_Pool)
router.DELETE("/pools/:poolid", DELETE_Pool) router.HandleFunc("DELETE /pools/{poolid}", DELETE_Pool)
router.GET("/groups/:groupname", GET_Group) router.HandleFunc("GET /groups/{groupname}", GET_Group)
router.POST("/groups/:groupname", POST_Group) router.HandleFunc("POST /groups/{groupname}", POST_Group)
router.DELETE("/groups/:groupname", DELETE_Group) router.HandleFunc("DELETE /groups/{groupname}", DELETE_Group)
router.POST("/pools/:poolid/groups/:groupname", POST_Pool_Group) router.HandleFunc("POST /pools/{poolid}/groups/{groupname}", POST_Pool_Group)
router.DELETE("/pools/:poolid/groups/:groupname") router.HandleFunc("DELETE /pools/{poolid}/groups/{groupname}", DELETE_Pool_Group)
router.GET("/users/:username", GET_User) router.HandleFunc("GET /users/{username}", GET_User)
router.POST("/users/:username", POST_User) router.HandleFunc("POST /users/{username}", POST_User)
router.DELETE("/users/:username", DELETE_User) router.HandleFunc("DELETE /users/{username}", DELETE_User)
router.POST("/groups/:groupname/users/:username", POST_Group_User) router.HandleFunc("POST /groups/{groupname}/users/{username}", POST_Group_User)
router.DELETE("/groups/:groupname/users/:username", DELETE_Group_User) router.HandleFunc("DELETE /groups/{groupname}/users/{username}", DELETE_Group_User)
log.Printf("Starting Access Manager API on port %s\n", strconv.Itoa(Config.ListenPort)) server := LoggingMiddleware(router)
err = router.Run("0.0.0.0:" + strconv.Itoa(Config.ListenPort)) log.Printf("[INFO] starting API listening on 0.0.0.0:%d", Config.ListenPort)
if err != nil { log.Fatalf("[ERR ] Error starting router: %s", http.ListenAndServe("0.0.0.0:"+strconv.Itoa(Config.ListenPort), server))
log.Fatalf("Error starting router: %s", err.Error())
}
} }
func SetupAPISessionStore(router *gin.Engine, config *common.Config) { func SetupAPISessionStore(config *common.Config) {
authKey := make([]byte, 32) authKey := make([]byte, 32)
encrKey := make([]byte, 32) encrKey := make([]byte, 32)
n, _ := rand.Read(authKey) // rand Read never returns an error, always crashes on error n, _ := rand.Read(authKey) // rand Read never returns an error, always crashes on error
@@ -99,21 +97,29 @@ func SetupAPISessionStore(router *gin.Engine, config *common.Config) {
n, _ = rand.Read(encrKey) // rand Read never returns an error, always crashes on error n, _ = rand.Read(encrKey) // rand Read never returns an error, always crashes on error
log.Printf("Generated cookie session encryption key of length %d\n", n) log.Printf("Generated cookie session encryption key of length %d\n", n)
store := cookie.NewStore(authKey, encrKey) Store = sessions.NewCookieStore(authKey, encrKey)
store.Options(sessions.Options{ Store.Options = &sessions.Options{
Path: config.SessionCookie.Path, Path: config.SessionCookie.Path,
HttpOnly: config.SessionCookie.HttpOnly, HttpOnly: config.SessionCookie.HttpOnly,
Secure: config.SessionCookie.Secure, Secure: config.SessionCookie.Secure,
MaxAge: config.SessionCookie.MaxAge, MaxAge: config.SessionCookie.MaxAge,
}) }
router.Use(sessions.Sessions(config.SessionCookieName, store))
log.Printf("Started cookie store (Name: %s Params: %+v)\n", config.SessionCookieName, config.SessionCookie) log.Printf("Started cookie store (Name: %s Params: %+v)\n", config.SessionCookieName, config.SessionCookie)
} }
func GetUserSessionFromContext(c *gin.Context) (*UserSession, int, error) { // get the cookie session from the request, returns a new session if the cookie is missing or invalid
session := sessions.Default(c) func GetCookieSession(r *http.Request) *sessions.Session {
SessionUUID := session.Get("SessionUUID") session, err := Store.Get(r, Config.SessionCookieName)
if err != nil {
log.Printf("Error getting session cookie: %s\n", err.Error())
}
return session
}
func GetUserSessionFromRequest(r *http.Request) (*UserSession, int, error) {
session := GetCookieSession(r)
SessionUUID := session.Values["SessionUUID"]
if SessionUUID == nil { if SessionUUID == nil {
return nil, http.StatusUnauthorized, fmt.Errorf("no auth session found") return nil, http.StatusUnauthorized, fmt.Errorf("no auth session found")
} }
@@ -121,3 +127,11 @@ func GetUserSessionFromContext(c *gin.Context) (*UserSession, int, error) {
usersession := UserSessions[uuid] usersession := UserSessions[uuid]
return usersession, http.StatusOK, nil return usersession, http.StatusOK, nil
} }
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start))
})
}
+172 -168
View File
@@ -5,27 +5,31 @@ import (
ldap "access-manager-api/app/ldap" ldap "access-manager-api/app/ldap"
"access-manager-api/app/localdb" "access-manager-api/app/localdb"
pve "access-manager-api/app/pve" pve "access-manager-api/app/pve"
"encoding/json"
"fmt" "fmt"
"net/http" "net/http"
paas "proxmoxaas-common-lib" paas "proxmoxaas-common-lib"
"uuid" "uuid"
"github.com/gin-contrib/sessions" "github.com/gorilla/sessions"
"github.com/gin-gonic/gin"
) )
func POST_Ticket(c *gin.Context) { func POST_Ticket(w http.ResponseWriter, r *http.Request) {
body := common.Login{} body := common.Login{}
err := c.ShouldBindJSON(&body) err := json.NewDecoder(r.Body).Decode(&body)
if err != nil { // bad request from binding if err != nil { // bad request from decoding
c.JSON(http.StatusBadRequest, gin.H{"auth": false, "error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"auth": false, "error": err.Error()})
return
}
if body.UsernameRaw == "" || body.Password == "" { // username and password are required
paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"auth": false, "error": "missing required field username or password"})
return return
} }
// attempt to parse username // attempt to parse username
body.Username, err = paas.ParseUsername(body.UsernameRaw) body.Username, err = paas.ParseUsername(body.UsernameRaw)
if err != nil { // username format incorrect if err != nil { // username format incorrect
c.JSON(http.StatusBadRequest, gin.H{"auth": false, "error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"auth": false, "error": err.Error()})
return return
} }
handler := Realms[body.Username.Realm].Type handler := Realms[body.Username.Realm].Type
@@ -35,7 +39,7 @@ func POST_Ticket(c *gin.Context) {
// always bind proxmox backend // always bind proxmox backend
PVEClient, code, err := pve.NewClientFromCredentials(Config.PVE, body.Username, body.Password) PVEClient, code, err := pve.NewClientFromCredentials(Config.PVE, body.Username, body.Password)
if err != nil { // pve client failed to bind if err != nil { // pve client failed to bind
c.JSON(code, gin.H{"auth": false, "error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"auth": false, "error": err.Error()})
return return
} }
userbackends.PVE = PVEClient userbackends.PVE = PVEClient
@@ -47,102 +51,102 @@ func POST_Ticket(c *gin.Context) {
config := Realms[body.Username.Realm].Config.(common.LDAPConfig) config := Realms[body.Username.Realm].Config.(common.LDAPConfig)
LDAPClient, code, err := ldap.NewClientFromCredentials(config, body.Username, body.Password) LDAPClient, code, err := ldap.NewClientFromCredentials(config, body.Username, body.Password)
if err != nil { // ldap client failed to bind if err != nil { // ldap client failed to bind
c.JSON(code, gin.H{"auth": false, "error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"auth": false, "error": err.Error()})
return return
} }
userbackends.Realm.Name = body.Username.Realm userbackends.Realm.Name = body.Username.Realm
userbackends.Realm.Handler = LDAPClient userbackends.Realm.Handler = LDAPClient
default: default:
c.JSON(code, gin.H{"auth": false, "error": fmt.Errorf("user realm %s is not supported", body.Username.Realm)}) paas.HTTPWriteJson(w, code, map[string]any{"auth": false, "error": fmt.Errorf("user realm %s is not supported", body.Username.Realm)})
return return
} }
// failing to load lcoaldb is a fatal error // failing to load lcoaldb is a fatal error
userbackends.DB, code, err = localdb.NewClientFromCredentials(Config.LocalDB, body.Username, body.Password) userbackends.DB, code, err = localdb.NewClientFromCredentials(Config.LocalDB, body.Username, body.Password)
if err != nil { if err != nil {
c.JSON(code, gin.H{"auth": false, "error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"auth": false, "error": err.Error()})
return return
} }
// successful binding at this point // successful binding at this point
// create new session // create new session
session := sessions.Default(c) session := GetCookieSession(r)
// create random uuid to map user to backends // create random uuid to map user to backends
uuid := uuid.NewV4() uuid := uuid.NewV4()
// set uuid mapping in session // set uuid mapping in session
session.Set("SessionUUID", uuid.String()) session.Values["SessionUUID"] = uuid.String()
// set uuid mapping in LDAPSessions // set uuid mapping in LDAPSessions
UserSessions[uuid.String()] = &userbackends UserSessions[uuid.String()] = &userbackends
// save the session // save the session
err = session.Save() err = session.Save(r, w)
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"auth": false, "error": err.Error()}) paas.HTTPWriteJson(w, http.StatusInternalServerError, map[string]any{"auth": false, "error": err.Error()})
} else { } else {
// return successful auth // return successful auth
c.JSON(http.StatusOK, gin.H{"auth": true}) paas.HTTPWriteJson(w, http.StatusOK, map[string]any{"auth": true})
} }
} }
func DELETE_Ticket(c *gin.Context) { func DELETE_Ticket(w http.ResponseWriter, r *http.Request) {
// get session uuid from session cookie // get session uuid from session cookie
session := sessions.Default(c) session := GetCookieSession(r)
SessionUUID := session.Get("SessionUUID") SessionUUID := session.Values["SessionUUID"]
if SessionUUID == nil { if SessionUUID == nil {
c.JSON(http.StatusUnauthorized, gin.H{"auth": false}) paas.HTTPWriteJson(w, http.StatusUnauthorized, map[string]any{"auth": false})
return return
} }
uuid := SessionUUID.(string) uuid := SessionUUID.(string)
// delete uuid entry from user sessions // delete uuid entry from user sessions
delete(UserSessions, uuid) // deletes uuid mapping delete(UserSessions, uuid) // deletes uuid mapping
session.Options(sessions.Options{MaxAge: -1}) // set max age to -1 so session cookie is deleted session.Options = &sessions.Options{MaxAge: -1} // set max age to -1 so session cookie is deleted
err := session.Save() // if save somehow fails, it should be ok since the uuid mapping is already deleted err := session.Save(r, w) // if save somehow fails, it should be ok since the uuid mapping is already deleted
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"auth": false}) paas.HTTPWriteJson(w, http.StatusInternalServerError, map[string]any{"auth": false})
} else { } else {
c.JSON(http.StatusUnauthorized, gin.H{"auth": false}) paas.HTTPWriteJson(w, http.StatusUnauthorized, map[string]any{"auth": false})
} }
} }
func GET_Pool(c *gin.Context) { func GET_Pool(w http.ResponseWriter, r *http.Request) {
poolid, ok := c.Params.Get("poolid") poolid := r.PathValue("poolid")
if !ok { if poolid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
pool, code, err := GetPool(backends, poolid) pool, code, err := GetPool(backends, poolid)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.JSON(http.StatusOK, gin.H{"pool": pool}) paas.HTTPWriteJson(w, http.StatusOK, map[string]any{"pool": pool})
} }
} }
func POST_Pool(c *gin.Context) { func POST_Pool(w http.ResponseWriter, r *http.Request) {
poolid, ok := c.Params.Get("poolid") poolid := r.PathValue("poolid")
if !ok { if poolid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
// read request body // read request body
pool := common.Pool{} pool := common.Pool{}
err = c.ShouldBindJSON(&pool) err = json.NewDecoder(r.Body).Decode(&pool)
if err != nil { // failed binding, usually missing user field if err != nil { // failed decoding, usually malformed json
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err.Error()})
return return
} }
@@ -151,91 +155,91 @@ func POST_Pool(c *gin.Context) {
if code == http.StatusNotFound { // pool does not already exist, create new pool if code == http.StatusNotFound { // pool does not already exist, create new pool
code, err = NewPool(backends, poolid, pool) code, err = NewPool(backends, poolid, pool)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} else { } else {
code, err = ModPool(backends, poolid, pool) code, err = ModPool(backends, poolid, pool)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
} }
func DELETE_Pool(c *gin.Context) { func DELETE_Pool(w http.ResponseWriter, r *http.Request) {
poolid, ok := c.Params.Get("poolid") poolid := r.PathValue("poolid")
if !ok { if poolid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = DelPool(backends, poolid) code, err = DelPool(backends, poolid)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
func GET_Group(c *gin.Context) { func GET_Group(w http.ResponseWriter, r *http.Request) {
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
groupname, err := common.ParseGroupname(groupname_str) groupname, err := common.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err.Error()})
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
group, code, err := GetGroup(backends, groupname) group, code, err := GetGroup(backends, groupname)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.JSON(http.StatusOK, gin.H{"group": group}) paas.HTTPWriteJson(w, http.StatusOK, map[string]any{"group": group})
} }
} }
func POST_Group(c *gin.Context) { func POST_Group(w http.ResponseWriter, r *http.Request) {
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
groupname, err := paas.ParseGroupname(groupname_str) groupname, err := paas.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
// read request body // read request body
group := common.Group{} group := common.Group{}
err = c.ShouldBindJSON(&group) err = json.NewDecoder(r.Body).Decode(&group)
if err != nil { // failed binding, usually missing user field if err != nil { // failed decoding, usually malformed json
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err.Error()})
return return
} }
@@ -244,163 +248,163 @@ func POST_Group(c *gin.Context) {
if code == http.StatusNotFound { // group does not already exist, create new group if code == http.StatusNotFound { // group does not already exist, create new group
code, err = NewGroup(backends, groupname, group) code, err = NewGroup(backends, groupname, group)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} else { } else {
code, err = ModGroup(backends, groupname, group) code, err = ModGroup(backends, groupname, group)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
} }
func DELETE_Group(c *gin.Context) { func DELETE_Group(w http.ResponseWriter, r *http.Request) {
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
groupname, err := paas.ParseGroupname(groupname_str) groupname, err := paas.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = DelGroup(backends, groupname) code, err = DelGroup(backends, groupname)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
func POST_Pool_Group(c *gin.Context) { func POST_Pool_Group(w http.ResponseWriter, r *http.Request) {
poolid, ok := c.Params.Get("poolid") poolid := r.PathValue("poolid")
if !ok { if poolid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
groupname, err := paas.ParseGroupname(groupname_str) groupname, err := paas.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = AddGroupToPool(backends, groupname, poolid) code, err = AddGroupToPool(backends, groupname, poolid)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
func DELETE_Pool_Group(c *gin.Context) { func DELETE_Pool_Group(w http.ResponseWriter, r *http.Request) {
poolid, ok := c.Params.Get("poolid") poolid := r.PathValue("poolid")
if !ok { if poolid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
groupname, err := paas.ParseGroupname(groupname_str) groupname, err := paas.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = DelGroupFromPool(backends, groupname, poolid) code, err = DelGroupFromPool(backends, groupname, poolid)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
func GET_User(c *gin.Context) { func GET_User(w http.ResponseWriter, r *http.Request) {
username_str, ok := c.Params.Get("username") username_str := r.PathValue("username")
if !ok { if username_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter poolid")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter poolid")})
return return
} }
username, err := common.ParseUsername(username_str) username, err := common.ParseUsername(username_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err.Error()})
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
user, code, err := GetUser(backends, username) user, code, err := GetUser(backends, username)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.JSON(http.StatusOK, gin.H{"user": user}) paas.HTTPWriteJson(w, http.StatusOK, map[string]any{"user": user})
} }
} }
func POST_User(c *gin.Context) { func POST_User(w http.ResponseWriter, r *http.Request) {
username_str, ok := c.Params.Get("username") username_str := r.PathValue("username")
if !ok { if username_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
username, err := paas.ParseUsername(username_str) username, err := paas.ParseUsername(username_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
// read request body // read request body
user := common.User{} user := common.User{}
err = c.ShouldBindJSON(&user) err = json.NewDecoder(r.Body).Decode(&user)
if err != nil { // failed binding, usually missing user field if err != nil { // failed decoding, usually malformed json
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err.Error()})
return return
} }
@@ -409,121 +413,121 @@ func POST_User(c *gin.Context) {
if code == http.StatusNotFound { // user does not already exist, create new user if code == http.StatusNotFound { // user does not already exist, create new user
code, err = NewUser(backends, username, user) code, err = NewUser(backends, username, user)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} else { } else {
code, err = ModUser(backends, username, user) code, err = ModUser(backends, username, user)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
} }
func DELETE_User(c *gin.Context) { func DELETE_User(w http.ResponseWriter, r *http.Request) {
username_str, ok := c.Params.Get("username") username_str := r.PathValue("username")
if !ok { if username_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
username, err := paas.ParseUsername(username_str) username, err := paas.ParseUsername(username_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = DelUser(backends, username) code, err = DelUser(backends, username)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
func POST_Group_User(c *gin.Context) { func POST_Group_User(w http.ResponseWriter, r *http.Request) {
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
username_str, ok := c.Params.Get("username") username_str := r.PathValue("username")
if !ok { if username_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter username")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter username")})
return return
} }
groupname, err := paas.ParseGroupname(groupname_str) groupname, err := paas.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
username, err := paas.ParseUsername(username_str) username, err := paas.ParseUsername(username_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = AddUserToGroup(backends, username, groupname) code, err = AddUserToGroup(backends, username, groupname)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
func DELETE_Group_User(c *gin.Context) { func DELETE_Group_User(w http.ResponseWriter, r *http.Request) {
groupname_str, ok := c.Params.Get("groupname") groupname_str := r.PathValue("groupname")
if !ok { if groupname_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter groupname")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter groupname")})
return return
} }
username_str, ok := c.Params.Get("username") username_str := r.PathValue("username")
if !ok { if username_str == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("missing required path parameter username")}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": fmt.Errorf("missing required path parameter username")})
return return
} }
groupname, err := paas.ParseGroupname(groupname_str) groupname, err := paas.ParseGroupname(groupname_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
username, err := paas.ParseUsername(username_str) username, err := paas.ParseUsername(username_str)
if err != nil { if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err}) paas.HTTPWriteJson(w, http.StatusBadRequest, map[string]any{"error": err})
return return
} }
backends, code, err := GetUserSessionFromContext(c) backends, code, err := GetUserSessionFromRequest(r)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
return return
} }
code, err = DelUserFromGroup(backends, username, groupname) code, err = DelUserFromGroup(backends, username, groupname)
if err != nil { if err != nil {
c.JSON(code, gin.H{"error": err.Error()}) paas.HTTPWriteJson(w, code, map[string]any{"error": err.Error()})
} else { } else {
c.Status(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
} }
+7 -36
View File
@@ -1,12 +1,11 @@
module access-manager-api module access-manager-api
go 1.27.0 go 1.27.3
require ( require (
github.com/gin-contrib/sessions v1.1.0 github.com/go-ldap/ldap/v3 v3.4.15
github.com/gin-gonic/gin v1.12.0 github.com/gorilla/sessions v1.4.0
github.com/go-ldap/ldap/v3 v3.4.14 github.com/luthermonson/go-proxmox v0.8.2
github.com/luthermonson/go-proxmox v0.8.1
proxmoxaas-common-lib v0.0.0 proxmoxaas-common-lib v0.0.0
) )
@@ -15,43 +14,15 @@ replace proxmoxaas-common-lib => ./proxmoxaas-common-lib
require ( require (
github.com/Azure/go-ntlmssp v0.1.1 // indirect github.com/Azure/go-ntlmssp v0.1.1 // indirect
github.com/buger/goterm v1.0.4 // indirect github.com/buger/goterm v1.0.4 // indirect
github.com/bytedance/gopkg v0.1.4 // indirect
github.com/bytedance/sonic v1.15.2 // indirect
github.com/bytedance/sonic/loader v0.5.2 // indirect
github.com/cloudwego/base64x v0.1.7 // indirect
github.com/diskfs/go-diskfs v1.9.4 // indirect github.com/diskfs/go-diskfs v1.9.4 // indirect
github.com/djherbis/times v1.6.0 // indirect github.com/djherbis/times v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.15 // indirect
github.com/gin-contrib/sse v1.1.1 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.30.3 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.4.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect github.com/gorilla/websocket v1.5.3 // indirect
github.com/jinzhu/copier v0.4.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
github.com/leodido/go-urn v1.5.0 // indirect
github.com/magefile/mage v1.17.2 // indirect github.com/magefile/mage v1.17.2 // indirect
github.com/mattn/go-isatty v0.0.24 // indirect github.com/stretchr/testify v1.11.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect golang.org/x/crypto v0.58.0 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect golang.org/x/sys v0.49.0 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.61.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.2 // indirect
go.mongodb.org/mongo-driver/v2 v2.8.1 // indirect
golang.org/x/arch v0.30.0 // indirect
golang.org/x/crypto v0.55.0 // indirect
golang.org/x/net v0.58.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.41.0 // indirect
google.golang.org/protobuf v1.36.12 // indirect
) )