implement pool group and user get routes,

improvements to http return codes,
add localdb backend handler
This commit is contained in:
2026-04-29 21:15:20 +00:00
parent 136dc90f13
commit de7ac282db
10 changed files with 434 additions and 105 deletions
+6
View File
@@ -16,6 +16,12 @@ type PVEConfig struct {
PAASClientRole string `json:"paas-client-role"`
}
type LDAPConfig struct {
BaseDN string `json:""`
LdapURL string
StartTLS bool
}
type Config struct {
ListenPort int `json:"listenPort"`
SessionCookieName string `json:"sessionCookieName"`
+11
View File
@@ -4,12 +4,15 @@ import paas "proxmoxaas-common-lib"
type Backend interface {
NewPool(poolname string) (int, error)
GetPool(poolname string) (Pool, []string, int, error) // []string members
DelPool(poolname string) (int, error)
NewGroup(groupname Groupname) (int, error)
GetGroup(groupname Groupname) (Group, []string, int, error) // []string members
DelGroup(groupname Groupname) (int, error)
AddGroupToPool(groupname Groupname, poolname string) (int, error)
DelGroupFromPool(groupname Groupname, poolname string) (int, error)
NewUser(username Username, user User) (int, error)
GetUser(username Username) (User, int, error)
DelUser(username Username) (int, error)
AddUserToGroup(username Username, groupname Groupname) (int, error)
DelUserFromGroup(username Username, groupname Groupname) (int, error)
@@ -28,3 +31,11 @@ type SimpleLimit = paas.SimpleLimit
type MatchResource = paas.MatchResource
type MatchLimit = paas.MatchLimit
type ResourceTemplate = paas.ResourceTemplate
func ParseGroupname(groupname string) (Groupname, error) {
return paas.ParseGroupname(groupname)
}
func ParseUsername(username string) (Username, error) {
return paas.ParseUsername(username)
}
+20 -6
View File
@@ -13,12 +13,12 @@ import (
// LDAPClient wrapper struct containing the connection, baseDN, peopleDN, and groupsDN
type LDAPClient struct {
config *LDAPConfig
config *common.LDAPConfig
client *ldap.Conn
}
// returns a new LDAPClient from the config
func NewClientFromCredentials(config LDAPConfig, username common.Username, password string) (*LDAPClient, int, error) {
func NewClientFromCredentials(config common.LDAPConfig, username common.Username, password string) (*LDAPClient, int, error) {
LDAPConn, err := ldap.DialURL(config.LdapURL)
if err != nil {
return nil, http.StatusInternalServerError, err
@@ -65,6 +65,7 @@ func (l LDAPClient) GetUser(username common.Username) (common.User, int, error)
entry := searchResponse.Entries[0]
user = LDAPEntryToUser(entry)
user.Username = username
return user, http.StatusOK, nil
}
@@ -146,8 +147,9 @@ func (l LDAPClient) DelUser(username common.Username) (int, error) {
return http.StatusOK, nil
}
func (l LDAPClient) GetGroup(groupname common.Groupname) (common.Group, int, error) {
func (l LDAPClient) GetGroup(groupname common.Groupname) (common.Group, []string, int, error) {
group := common.Group{}
members := []string{}
searchRequest := ldap.NewSearchRequest( // setup search for user by uid
fmt.Sprintf("cn=%s,ou=groups,%s", groupname.GroupID, l.config.BaseDN), // The base dn to search
@@ -159,13 +161,18 @@ func (l LDAPClient) GetGroup(groupname common.Groupname) (common.Group, int, err
searchResponse, err := l.client.Search(searchRequest) // perform search
if err != nil {
return group, http.StatusBadRequest, err
return group, members, http.StatusBadRequest, err
}
entry := searchResponse.Entries[0]
group = LDAPEntryToGroup(entry)
return group, http.StatusOK, nil
group.Groupname = groupname
for _, member := range entry.GetAttributeValues("member") {
if member != "" {
members = append(members, member)
}
}
return group, members, http.StatusOK, nil
}
func (l LDAPClient) NewGroup(groupname common.Groupname) (int, error) {
@@ -261,12 +268,19 @@ func (l LDAPClient) DelUserFromGroup(username common.Username, groupname common.
func (l LDAPClient) NewPool(poolname string) (int, error) {
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
}
func (l LDAPClient) GetPool(poolname string) (common.Pool, []string, int, error) {
return common.Pool{}, []string{}, http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
}
func (l LDAPClient) DelPool(poolname string) (int, error) {
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
}
func (l LDAPClient) AddGroupToPool(groupname common.Groupname, poolname string) (int, error) {
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
}
func (l LDAPClient) DelGroupFromPool(groupname common.Groupname, poolname string) (int, error) {
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
}
+14 -7
View File
@@ -1,18 +1,16 @@
package ldap
import (
"fmt"
"net/http"
"regexp"
"github.com/gin-gonic/gin"
"github.com/go-ldap/ldap/v3"
common "user-manager-api/app/common"
)
type LDAPConfig struct {
BaseDN string
LdapURL string
StartTLS bool
}
func LDAPEntryToUser(entry *ldap.Entry) common.User {
return common.User{
CN: entry.GetAttributeValue("cn"),
@@ -37,9 +35,18 @@ func ParseLDAPError(err error) gin.H {
} else {
return gin.H{
"ok": true,
"code": 200,
"code": http.StatusOK,
"result": "OK",
"message": "",
}
}
}
func ExtractUIDFromUserDN(dn string) (string, error) {
m := regexp.MustCompilePOSIX("uid=([[:alnum:]]+)")
x := m.FindStringSubmatch(dn)
if len(x) != 2 {
return "", fmt.Errorf("could not find uid in dn %s", dn)
}
return x[1], nil
}
+46
View File
@@ -0,0 +1,46 @@
package localdb
import (
"encoding/json"
"fmt"
"net/http"
"os"
common "user-manager-api/app/common"
)
type DB struct {
data map[string]common.Pool
}
func LoadDB(localDBPath string) (DB, error) {
db := DB{}
content, err := os.ReadFile(localDBPath)
if err != nil {
//log.Fatal("Error when opening file: ", err)
return db, err
}
err = json.Unmarshal(content, &db.data)
if err != nil {
//log.Fatal("Error during Unmarshal(): ", err)
return db, err
}
return db, nil
}
func SaveDB(localDBPath string, db DB) error {
json, err := json.Marshal(db.data)
if err != nil {
return err
}
err = os.WriteFile(localDBPath, []byte(json), 0644)
return err
}
func (localdb DB) GetPool(poolname string) (common.Pool, []string, int, error) {
pool := common.Pool{}
pool, ok := localdb.data[poolname]
if !ok {
return pool, []string{}, http.StatusNotFound, fmt.Errorf("Pool %s not in localdb", poolname)
}
return pool, []string{}, http.StatusOK, nil
}
+97 -14
View File
@@ -12,6 +12,7 @@ import (
paas "proxmoxaas-common-lib"
common "user-manager-api/app/common"
ldap "user-manager-api/app/ldap"
localdb "user-manager-api/app/localdb"
pve "user-manager-api/app/pve"
"github.com/gin-contrib/sessions"
@@ -26,7 +27,7 @@ var Config common.Config
var UserSessions map[string]*UserSession
var Realms map[string]Realm
func Run(configPath *string) {
func Run(configPath *string, localDBPath *string) {
// load config values
var err error
Config, err = common.GetConfig(*configPath)
@@ -35,6 +36,13 @@ func Run(configPath *string) {
}
log.Printf("Read in config from %s\n", *configPath)
// load localdb
db, err := localdb.LoadDB(*localDBPath)
if err != nil {
log.Fatalf("Error when reading localdb file: %s\n", err)
}
log.Printf("Read in localdb from %s\n", *localDBPath)
// setup router
gin.SetMode(gin.ReleaseMode)
router := SetupAPISessionStore(&Config)
@@ -47,7 +55,7 @@ func Run(configPath *string) {
UserSessions = make(map[string]*UserSession)
router.GET("/version", func(c *gin.Context) {
c.JSON(200, gin.H{"version": Version})
c.JSON(http.StatusOK, gin.H{"version": Version})
})
router.POST("/ticket", func(c *gin.Context) {
@@ -78,7 +86,7 @@ func Run(configPath *string) {
// bind ldap backend if backend is ldap
if handler == "ldap" {
config := Realms[body.Username.Realm].Config.(ldap.LDAPConfig)
config := Realms[body.Username.Realm].Config.(common.LDAPConfig)
LDAPClient, code, err := ldap.NewClientFromCredentials(config, body.Username, body.Password)
if err != nil { // ldap client failed to bind
c.JSON(code, gin.H{"auth": false, "error": err.Error()})
@@ -88,6 +96,8 @@ func Run(configPath *string) {
userbackends.Realm.Handler = LDAPClient
}
userbackends.DB = &db
// successful binding at this point
// create new session
session := sessions.Default(c)
@@ -120,6 +130,27 @@ func Run(configPath *string) {
c.JSON(http.StatusUnauthorized, gin.H{"auth": false})
})
router.GET("/pools/:poolid", func(c *gin.Context) {
poolid, ok := c.Params.Get("poolid")
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("Missing required path parameter poolid")})
return
}
backends, code, err := GetUserSessionFromContext(c)
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
return
}
pool, code, err := GetPool(backends, poolid)
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, gin.H{"pool": pool})
}
})
router.POST("/pools/:poolid", func(c *gin.Context) {
poolid, ok := c.Params.Get("poolid")
if !ok {
@@ -137,7 +168,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -158,7 +189,33 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
router.GET("/groups/:groupid", func(c *gin.Context) {
groupid, ok := c.Params.Get("groupid")
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("Missing required path parameter poolid")})
return
}
groupname, err := common.ParseGroupname(groupid)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
backends, code, err := GetUserSessionFromContext(c)
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
return
}
group, code, err := GetGroup(backends, groupname)
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, gin.H{"group": group})
}
})
@@ -185,7 +242,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -212,7 +269,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -245,7 +302,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -278,7 +335,33 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
router.GET("/users/:userid", func(c *gin.Context) {
userid, ok := c.Params.Get("userid")
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("Missing required path parameter poolid")})
return
}
username, err := common.ParseUsername(userid)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
backends, code, err := GetUserSessionFromContext(c)
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
return
}
user, code, err := GetUser(backends, username)
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, gin.H{"user": user})
}
})
@@ -318,7 +401,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -345,7 +428,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -384,7 +467,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -423,7 +506,7 @@ func Run(configPath *string) {
if err != nil {
c.JSON(code, gin.H{"error": err.Error()})
} else {
c.Status(200)
c.Status(http.StatusOK)
}
})
@@ -496,7 +579,7 @@ func GetRealmsFromPVE(config *common.Config) map[string]Realm {
}
if realm.Type == "ldap" {
ldapconfig := ldap.LDAPConfig{
ldapconfig := common.LDAPConfig{
BaseDN: realm.BaseDN,
LdapURL: fmt.Sprintf("ldap://%s", realm.Server1),
StartTLS: realm.Mode == "ldap+starttls",
+112
View File
@@ -4,12 +4,51 @@ import (
"fmt"
"net/http"
common "user-manager-api/app/common"
"user-manager-api/app/ldap"
)
func NewPool(backends *UserSession, poolname string) (int, error) {
// only pve backend handles pools
return backends.PVE.NewPool(poolname)
}
// get pool recursive resolving groups
func GetPool(backends *UserSession, poolname string) (common.Pool, int, error) {
pool := common.Pool{}
// get pool from PVE
pvepool, members, code, err := backends.PVE.GetPool(poolname)
if err != nil {
return pool, code, err
}
// get pool from DB
dbpool, _, code, err := backends.DB.GetPool(poolname)
if err != nil {
return pool, code, err
}
// assign pool id from PVE, assign everything else from DB
pool.PoolID = pvepool.PoolID
pool.Resources = dbpool.Resources
pool.AllowedNodes = dbpool.AllowedNodes
pool.AllowedVMIDRange = dbpool.AllowedVMIDRange
pool.AllowedBackups = dbpool.AllowedBackups
pool.Templates = dbpool.Templates
// pool members are groups
for _, groupid := range members {
groupname, err := common.ParseGroupname(groupid)
if err != nil {
return pool, code, fmt.Errorf("pool %s had member %s which is not a valid groupname", poolname, groupid)
}
group, code, err := GetGroup(backends, groupname)
if err != nil {
return pool, code, err
}
group.Role = Config.PVE.PAASClientRole
pool.Groups = append(pool.Groups, group)
}
return pool, http.StatusOK, nil
}
func DelPool(backends *UserSession, poolname string) (int, error) {
// only pve backend handles pools
return backends.PVE.DelPool(poolname)
@@ -30,6 +69,60 @@ func NewGroup(backends *UserSession, groupname common.Groupname) (int, error) {
}
}
func GetGroup(backends *UserSession, groupname common.Groupname) (common.Group, int, error) {
// resolve group from relevant backend
if groupname.Realm == "pve" {
group, members, code, err := backends.PVE.GetGroup(groupname)
if err != nil {
return group, code, err
}
// group members are users
for _, userid := range members {
username, err := common.ParseUsername(userid)
if err != nil {
return group, http.StatusInternalServerError, fmt.Errorf("group %s had member %s which is not a valid username", groupname.ToString(), userid)
}
// fetch and append user
user, code, err := GetUser(backends, username)
if err != nil {
return group, code, err
}
group.Users = append(group.Users, user)
}
return group, http.StatusOK, nil
} else if groupname.Realm == backends.Realm.Name {
group, members, code, err := backends.Realm.Handler.(common.Backend).GetGroup(groupname)
if err != nil {
return common.Group{}, code, err
}
// group mambers are users
for _, userdn := range members {
// member list is of ldap user DN instead of pve userid
ldapuid, err := ldap.ExtractUIDFromUserDN(userdn)
if err != nil {
return group, http.StatusInternalServerError, fmt.Errorf("group %s had member %s which is not a valid user DN", groupname.ToString(), userdn)
}
// generate username from user DN (slightly inefficient)
userid := fmt.Sprintf("%s@%s", ldapuid, backends.Realm.Name)
username, err := common.ParseUsername(userid)
if err != nil {
return group, http.StatusInternalServerError, fmt.Errorf("group %s had member %s which is not a valid username", groupname.ToString(), userid)
}
// fetch and append user
user, code, err := GetUser(backends, username)
if err != nil {
return group, code, err
}
group.Users = append(group.Users, user)
}
return group, http.StatusOK, nil
} else {
return common.Group{}, http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested group")
}
}
func DelGroup(backends *UserSession, groupname common.Groupname) (int, error) {
if groupname.Realm == "pve" {
return backends.PVE.DelGroup(groupname)
@@ -70,6 +163,25 @@ func NewUser(backends *UserSession, username common.Username, user common.User)
}
}
func GetUser(backends *UserSession, username common.Username) (common.User, int, error) {
// fetch user from relevant realm
if username.Realm == "pve" {
pveuser, code, err := backends.PVE.GetUser(username)
if err != nil {
return common.User{}, code, err
}
return pveuser, http.StatusOK, nil
} else if username.Realm == backends.Realm.Name {
realmuser, code, err := backends.Realm.Handler.(common.Backend).GetUser(username)
if err != nil {
return common.User{}, code, err
}
return realmuser, http.StatusOK, nil
} else {
return common.User{}, http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested user")
}
}
func DelUser(backends *UserSession, username common.Username) (int, error) {
if username.Realm == "pve" {
return backends.PVE.DelUser(username)
+124 -50
View File
@@ -39,16 +39,15 @@ func NewClientFromCredentials(config common.PVEConfig, username common.Username,
return nil, http.StatusUnauthorized, err
}
// todo this should return an error code if the binding failed (ie fetch version to check if the auth was actually ok)
return &ProxmoxClient{config: &config, client: client}, http.StatusOK, nil
}
func (pve ProxmoxClient) SyncRealms() (int, error) {
domains, err := pve.client.Domains(context.Background())
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
for _, domain := range domains {
if domain.Type != "pam" && domain.Type != "pve" { // pam and pve are not external realm types that require sync
@@ -59,41 +58,73 @@ func (pve ProxmoxClient) SyncRealms() (int, error) {
RemoveVanished: "acl;entry;properties", // remove deleted objects from ACL, entry in pve, and remove properties (probably not necessary)
})
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
}
}
return 200, nil
return http.StatusOK, nil
}
func (pve ProxmoxClient) NewPool(poolname string) (int, error) {
err := pve.client.NewPool(context.Background(), poolname, "")
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
func (pve ProxmoxClient) GetPool(poolname string) (common.Pool, []string, int, error) {
pool := common.Pool{}
members := []string{}
pvepool, err := pve.client.Pool(context.Background(), poolname)
if proxmox.IsNotFound(err) { // errors if pool does not exist
return pool, members, http.StatusNotFound, err
} else if err != nil {
return pool, members, http.StatusInternalServerError, err
}
pool.PoolID = pvepool.PoolID
acls, err := pve.client.ACL(context.Background())
if proxmox.IsNotAuthorized(err) { // errors if pool does not exist
return pool, members, http.StatusUnauthorized, err
} else if err != nil {
return pool, members, http.StatusInternalServerError, err
}
// iterate through ACLs and get superficial pool - group membershipm (just group names)
for _, acl := range acls {
if acl.Type == "group" && acl.RoleID == pve.config.PAASClientRole && acl.Path == fmt.Sprintf("/pool/%s", poolname) {
members = append(members, acl.UGID)
}
}
return pool, members, http.StatusOK, nil
}
func (pve ProxmoxClient) DelPool(poolname string) (int, error) {
pvepool, err := pve.client.Pool(context.Background(), poolname)
if proxmox.IsNotFound(err) { // errors if pool does not exist
return 404, err
if proxmox.IsNotAuthorized(err) { // not authorized to delete
return http.StatusUnauthorized, err
} else if proxmox.IsNotFound(err) { // errors if pool does not exist
return http.StatusNotFound, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
err = pvepool.Delete(context.Background())
if proxmox.IsNotAuthorized(err) { // not authorized to delete
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
@@ -101,29 +132,50 @@ func (pve ProxmoxClient) NewGroup(groupname common.Groupname) (int, error) {
// add new group ny ID only
err := pve.client.NewGroup(context.Background(), groupname.GroupID, "")
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
func (pve ProxmoxClient) GetGroup(groupname common.Groupname) (common.Group, []string, int, error) {
group := common.Group{}
members := []string{}
pvegroup, err := pve.client.Group(context.Background(), groupname.ToString())
if proxmox.IsNotFound(err) { // errors if pool does not exist
return group, members, http.StatusNotFound, err
} else if err != nil {
return group, members, http.StatusInternalServerError, err
}
group.Groupname, _ = common.ParseGroupname(pvegroup.GroupID)
for _, userid := range pvegroup.Members {
members = append(members, userid)
}
return group, members, http.StatusOK, nil
}
func (pve ProxmoxClient) DelGroup(groupname common.Groupname) (int, error) {
pvegroup, err := pve.client.Group(context.Background(), groupname.GroupID)
if proxmox.IsNotFound(err) { // errors if group does not exist
return 404, err
if proxmox.IsNotAuthorized(err) {
return http.StatusUnauthorized, err
} else if proxmox.IsNotFound(err) {
return http.StatusNotFound, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
err = pvegroup.Delete(context.Background())
if proxmox.IsNotAuthorized(err) { // not authorized to delete
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
@@ -137,11 +189,11 @@ func (pve ProxmoxClient) AddGroupToPool(groupname common.Groupname, poolname str
})
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
@@ -155,11 +207,11 @@ func (pve ProxmoxClient) DelGroupFromPool(groupname common.Groupname, poolname s
})
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
@@ -172,39 +224,59 @@ func (pve ProxmoxClient) NewUser(username common.Username, user common.User) (in
Password: user.Password,
})
if proxmox.IsNotAuthorized(err) {
return 401, err
return http.StatusUnauthorized, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
func (pve ProxmoxClient) GetUser(username common.Username) (common.User, int, error) {
user := common.User{}
pveuser, err := pve.client.User(context.Background(), username.ToString())
if proxmox.IsNotFound(err) { // errors if pool does not exist
return user, http.StatusNotFound, err
} else if err != nil {
return user, http.StatusInternalServerError, err
} else {
user.Username, _ = common.ParseUsername(pveuser.UserID)
user.CN = pveuser.Firstname
user.SN = pveuser.Lastname
user.Mail = pveuser.Email
return user, http.StatusOK, nil
}
}
func (pve ProxmoxClient) DelUser(username common.Username) (int, error) {
user, err := pve.client.User(context.Background(), username.ToString())
if proxmox.IsNotAuthorized(err) {
return 401, err // not authorized to read the user = not authorized to delete the user, this may be slightly different from ldap
return http.StatusUnauthorized, err
} else if proxmox.IsNotFound(err) {
return http.StatusNotFound, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
// assume that user cannot be nil if no error was returned
err = user.Delete(context.Background())
if proxmox.IsNotAuthorized(err) {
return 401, err // not authorized to delete the user
return http.StatusUnauthorized, err // not authorized to delete the user
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
func (pve ProxmoxClient) AddUserToGroup(username common.Username, groupname common.Groupname) (int, error) {
user, err := pve.client.User(context.Background(), groupname.ToString())
user, err := pve.client.User(context.Background(), username.ToString())
if proxmox.IsNotAuthorized(err) {
return 401, err // not authorized to read the user = not authorized to delete the user, this may be slightly different from ldap
return http.StatusUnauthorized, err
} else if proxmox.IsNotFound(err) {
return http.StatusNotFound, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
newGroups := append(user.Groups, groupname.ToString())
@@ -213,20 +285,22 @@ func (pve ProxmoxClient) AddUserToGroup(username common.Username, groupname comm
Groups: newGroups,
})
if proxmox.IsNotAuthorized(err) {
return 401, err // not authorized to delete the user
return http.StatusUnauthorized, err // not authorized to delete the user
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
func (pve ProxmoxClient) DelUserFromGroup(username common.Username, groupname common.Groupname) (int, error) {
user, err := pve.client.User(context.Background(), groupname.ToString())
user, err := pve.client.User(context.Background(), username.ToString())
if proxmox.IsNotAuthorized(err) {
return 401, err // not authorized to read the user = not authorized to delete the user, this may be slightly different from ldap
return http.StatusUnauthorized, err
} else if proxmox.IsNotFound(err) {
return http.StatusNotFound, err
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
}
idx := slices.Index(user.Groups, groupname.ToString())
@@ -239,10 +313,10 @@ func (pve ProxmoxClient) DelUserFromGroup(username common.Username, groupname co
Groups: newGroups,
})
if proxmox.IsNotAuthorized(err) {
return 401, err // not authorized to delete the user
return http.StatusUnauthorized, err // not authorized to delete the user
} else if err != nil {
return 500, err
return http.StatusInternalServerError, err
} else {
return 200, nil
return http.StatusOK, nil
}
}
+2 -27
View File
@@ -1,15 +1,13 @@
package app
import (
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
common "user-manager-api/app/common"
localdb "user-manager-api/app/localdb"
pve "user-manager-api/app/pve"
)
@@ -24,6 +22,7 @@ type UserSession struct {
Name string
Handler any
}
DB *localdb.DB
}
func GetUserSessionFromContext(c *gin.Context) (*UserSession, int, error) {
@@ -36,27 +35,3 @@ func GetUserSessionFromContext(c *gin.Context) (*UserSession, int, error) {
usersession := UserSessions[uuid]
return usersession, http.StatusOK, nil
}
func LoadLocaldb(dbPath string) (map[string]common.User, error) {
users := map[string]common.User{}
content, err := os.ReadFile(dbPath)
if err != nil {
//log.Fatal("Error when opening file: ", err)
return users, err
}
err = json.Unmarshal(content, &users)
if err != nil {
//log.Fatal("Error during Unmarshal(): ", err)
return users, err
}
return users, nil
}
func SaveLocaldb(configPath string, users map[string]common.User) error {
json, err := json.Marshal(users)
if err != nil {
return err
}
err = os.WriteFile(configPath, []byte(json), 0644)
return err
}