implement pool group and user get routes,
improvements to http return codes, add localdb backend handler
This commit is contained in:
@@ -16,6 +16,12 @@ type PVEConfig struct {
|
|||||||
PAASClientRole string `json:"paas-client-role"`
|
PAASClientRole string `json:"paas-client-role"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LDAPConfig struct {
|
||||||
|
BaseDN string `json:""`
|
||||||
|
LdapURL string
|
||||||
|
StartTLS bool
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ListenPort int `json:"listenPort"`
|
ListenPort int `json:"listenPort"`
|
||||||
SessionCookieName string `json:"sessionCookieName"`
|
SessionCookieName string `json:"sessionCookieName"`
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ import paas "proxmoxaas-common-lib"
|
|||||||
|
|
||||||
type Backend interface {
|
type Backend interface {
|
||||||
NewPool(poolname string) (int, error)
|
NewPool(poolname string) (int, error)
|
||||||
|
GetPool(poolname string) (Pool, []string, int, error) // []string members
|
||||||
DelPool(poolname string) (int, error)
|
DelPool(poolname string) (int, error)
|
||||||
NewGroup(groupname Groupname) (int, error)
|
NewGroup(groupname Groupname) (int, error)
|
||||||
|
GetGroup(groupname Groupname) (Group, []string, int, error) // []string members
|
||||||
DelGroup(groupname Groupname) (int, error)
|
DelGroup(groupname Groupname) (int, error)
|
||||||
AddGroupToPool(groupname Groupname, poolname string) (int, error)
|
AddGroupToPool(groupname Groupname, poolname string) (int, error)
|
||||||
DelGroupFromPool(groupname Groupname, poolname string) (int, error)
|
DelGroupFromPool(groupname Groupname, poolname string) (int, error)
|
||||||
NewUser(username Username, user User) (int, error)
|
NewUser(username Username, user User) (int, error)
|
||||||
|
GetUser(username Username) (User, int, error)
|
||||||
DelUser(username Username) (int, error)
|
DelUser(username Username) (int, error)
|
||||||
AddUserToGroup(username Username, groupname Groupname) (int, error)
|
AddUserToGroup(username Username, groupname Groupname) (int, error)
|
||||||
DelUserFromGroup(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 MatchResource = paas.MatchResource
|
||||||
type MatchLimit = paas.MatchLimit
|
type MatchLimit = paas.MatchLimit
|
||||||
type ResourceTemplate = paas.ResourceTemplate
|
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
@@ -13,12 +13,12 @@ import (
|
|||||||
|
|
||||||
// LDAPClient wrapper struct containing the connection, baseDN, peopleDN, and groupsDN
|
// LDAPClient wrapper struct containing the connection, baseDN, peopleDN, and groupsDN
|
||||||
type LDAPClient struct {
|
type LDAPClient struct {
|
||||||
config *LDAPConfig
|
config *common.LDAPConfig
|
||||||
client *ldap.Conn
|
client *ldap.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a new LDAPClient from the config
|
// 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)
|
LDAPConn, err := ldap.DialURL(config.LdapURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, http.StatusInternalServerError, err
|
return nil, http.StatusInternalServerError, err
|
||||||
@@ -65,6 +65,7 @@ func (l LDAPClient) GetUser(username common.Username) (common.User, int, error)
|
|||||||
entry := searchResponse.Entries[0]
|
entry := searchResponse.Entries[0]
|
||||||
|
|
||||||
user = LDAPEntryToUser(entry)
|
user = LDAPEntryToUser(entry)
|
||||||
|
user.Username = username
|
||||||
|
|
||||||
return user, http.StatusOK, nil
|
return user, http.StatusOK, nil
|
||||||
}
|
}
|
||||||
@@ -146,8 +147,9 @@ func (l LDAPClient) DelUser(username common.Username) (int, error) {
|
|||||||
return http.StatusOK, nil
|
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{}
|
group := common.Group{}
|
||||||
|
members := []string{}
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest( // setup search for user by uid
|
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
|
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
|
searchResponse, err := l.client.Search(searchRequest) // perform search
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return group, http.StatusBadRequest, err
|
return group, members, http.StatusBadRequest, err
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := searchResponse.Entries[0]
|
entry := searchResponse.Entries[0]
|
||||||
group = LDAPEntryToGroup(entry)
|
group = LDAPEntryToGroup(entry)
|
||||||
|
group.Groupname = groupname
|
||||||
return group, http.StatusOK, nil
|
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) {
|
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) {
|
func (l LDAPClient) NewPool(poolname string) (int, error) {
|
||||||
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
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) {
|
func (l LDAPClient) DelPool(poolname string) (int, error) {
|
||||||
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l LDAPClient) AddGroupToPool(groupname common.Groupname, poolname string) (int, error) {
|
func (l LDAPClient) AddGroupToPool(groupname common.Groupname, poolname string) (int, error) {
|
||||||
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l LDAPClient) DelGroupFromPool(groupname common.Groupname, poolname string) (int, error) {
|
func (l LDAPClient) DelGroupFromPool(groupname common.Groupname, poolname string) (int, error) {
|
||||||
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
return http.StatusNotImplemented, fmt.Errorf("ldap does not implement pools")
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-7
@@ -1,18 +1,16 @@
|
|||||||
package ldap
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-ldap/ldap/v3"
|
"github.com/go-ldap/ldap/v3"
|
||||||
|
|
||||||
common "user-manager-api/app/common"
|
common "user-manager-api/app/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LDAPConfig struct {
|
|
||||||
BaseDN string
|
|
||||||
LdapURL string
|
|
||||||
StartTLS bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func LDAPEntryToUser(entry *ldap.Entry) common.User {
|
func LDAPEntryToUser(entry *ldap.Entry) common.User {
|
||||||
return common.User{
|
return common.User{
|
||||||
CN: entry.GetAttributeValue("cn"),
|
CN: entry.GetAttributeValue("cn"),
|
||||||
@@ -37,9 +35,18 @@ func ParseLDAPError(err error) gin.H {
|
|||||||
} else {
|
} else {
|
||||||
return gin.H{
|
return gin.H{
|
||||||
"ok": true,
|
"ok": true,
|
||||||
"code": 200,
|
"code": http.StatusOK,
|
||||||
"result": "OK",
|
"result": "OK",
|
||||||
"message": "",
|
"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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -12,6 +12,7 @@ import (
|
|||||||
paas "proxmoxaas-common-lib"
|
paas "proxmoxaas-common-lib"
|
||||||
common "user-manager-api/app/common"
|
common "user-manager-api/app/common"
|
||||||
ldap "user-manager-api/app/ldap"
|
ldap "user-manager-api/app/ldap"
|
||||||
|
localdb "user-manager-api/app/localdb"
|
||||||
pve "user-manager-api/app/pve"
|
pve "user-manager-api/app/pve"
|
||||||
|
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
@@ -26,7 +27,7 @@ var Config common.Config
|
|||||||
var UserSessions map[string]*UserSession
|
var UserSessions map[string]*UserSession
|
||||||
var Realms map[string]Realm
|
var Realms map[string]Realm
|
||||||
|
|
||||||
func Run(configPath *string) {
|
func Run(configPath *string, localDBPath *string) {
|
||||||
// load config values
|
// load config values
|
||||||
var err error
|
var err error
|
||||||
Config, err = common.GetConfig(*configPath)
|
Config, err = common.GetConfig(*configPath)
|
||||||
@@ -35,6 +36,13 @@ func Run(configPath *string) {
|
|||||||
}
|
}
|
||||||
log.Printf("Read in config from %s\n", *configPath)
|
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
|
// setup router
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
router := SetupAPISessionStore(&Config)
|
router := SetupAPISessionStore(&Config)
|
||||||
@@ -47,7 +55,7 @@ func Run(configPath *string) {
|
|||||||
UserSessions = make(map[string]*UserSession)
|
UserSessions = make(map[string]*UserSession)
|
||||||
|
|
||||||
router.GET("/version", func(c *gin.Context) {
|
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) {
|
router.POST("/ticket", func(c *gin.Context) {
|
||||||
@@ -78,7 +86,7 @@ func Run(configPath *string) {
|
|||||||
|
|
||||||
// bind ldap backend if backend is ldap
|
// bind ldap backend if backend is ldap
|
||||||
if handler == "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)
|
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()})
|
c.JSON(code, gin.H{"auth": false, "error": err.Error()})
|
||||||
@@ -88,6 +96,8 @@ func Run(configPath *string) {
|
|||||||
userbackends.Realm.Handler = LDAPClient
|
userbackends.Realm.Handler = LDAPClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userbackends.DB = &db
|
||||||
|
|
||||||
// successful binding at this point
|
// successful binding at this point
|
||||||
// create new session
|
// create new session
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
@@ -120,6 +130,27 @@ func Run(configPath *string) {
|
|||||||
c.JSON(http.StatusUnauthorized, gin.H{"auth": false})
|
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) {
|
router.POST("/pools/:poolid", func(c *gin.Context) {
|
||||||
poolid, ok := c.Params.Get("poolid")
|
poolid, ok := c.Params.Get("poolid")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -137,7 +168,7 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -158,7 +189,33 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} 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 {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -212,7 +269,7 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -245,7 +302,7 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -278,7 +335,33 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} 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 {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -345,7 +428,7 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -384,7 +467,7 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -423,7 +506,7 @@ func Run(configPath *string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(code, gin.H{"error": err.Error()})
|
c.JSON(code, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
c.Status(200)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -496,7 +579,7 @@ func GetRealmsFromPVE(config *common.Config) map[string]Realm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if realm.Type == "ldap" {
|
if realm.Type == "ldap" {
|
||||||
ldapconfig := ldap.LDAPConfig{
|
ldapconfig := common.LDAPConfig{
|
||||||
BaseDN: realm.BaseDN,
|
BaseDN: realm.BaseDN,
|
||||||
LdapURL: fmt.Sprintf("ldap://%s", realm.Server1),
|
LdapURL: fmt.Sprintf("ldap://%s", realm.Server1),
|
||||||
StartTLS: realm.Mode == "ldap+starttls",
|
StartTLS: realm.Mode == "ldap+starttls",
|
||||||
|
|||||||
@@ -4,12 +4,51 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
common "user-manager-api/app/common"
|
common "user-manager-api/app/common"
|
||||||
|
"user-manager-api/app/ldap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewPool(backends *UserSession, poolname string) (int, error) {
|
func NewPool(backends *UserSession, poolname string) (int, error) {
|
||||||
// only pve backend handles pools
|
// only pve backend handles pools
|
||||||
return backends.PVE.NewPool(poolname)
|
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) {
|
func DelPool(backends *UserSession, poolname string) (int, error) {
|
||||||
// only pve backend handles pools
|
// only pve backend handles pools
|
||||||
return backends.PVE.DelPool(poolname)
|
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) {
|
func DelGroup(backends *UserSession, groupname common.Groupname) (int, error) {
|
||||||
if groupname.Realm == "pve" {
|
if groupname.Realm == "pve" {
|
||||||
return backends.PVE.DelGroup(groupname)
|
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) {
|
func DelUser(backends *UserSession, username common.Username) (int, error) {
|
||||||
if username.Realm == "pve" {
|
if username.Realm == "pve" {
|
||||||
return backends.PVE.DelUser(username)
|
return backends.PVE.DelUser(username)
|
||||||
|
|||||||
+124
-50
@@ -39,16 +39,15 @@ func NewClientFromCredentials(config common.PVEConfig, username common.Username,
|
|||||||
return nil, http.StatusUnauthorized, err
|
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
|
return &ProxmoxClient{config: &config, client: client}, http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pve ProxmoxClient) SyncRealms() (int, error) {
|
func (pve ProxmoxClient) SyncRealms() (int, error) {
|
||||||
domains, err := pve.client.Domains(context.Background())
|
domains, err := pve.client.Domains(context.Background())
|
||||||
if proxmox.IsNotAuthorized(err) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
if domain.Type != "pam" && domain.Type != "pve" { // pam and pve are not external realm types that require sync
|
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)
|
RemoveVanished: "acl;entry;properties", // remove deleted objects from ACL, entry in pve, and remove properties (probably not necessary)
|
||||||
})
|
})
|
||||||
if proxmox.IsNotAuthorized(err) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} 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) {
|
func (pve ProxmoxClient) NewPool(poolname string) (int, error) {
|
||||||
err := pve.client.NewPool(context.Background(), poolname, "")
|
err := pve.client.NewPool(context.Background(), poolname, "")
|
||||||
if proxmox.IsNotAuthorized(err) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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) {
|
func (pve ProxmoxClient) DelPool(poolname string) (int, error) {
|
||||||
pvepool, err := pve.client.Pool(context.Background(), poolname)
|
pvepool, err := pve.client.Pool(context.Background(), poolname)
|
||||||
if proxmox.IsNotFound(err) { // errors if pool does not exist
|
if proxmox.IsNotAuthorized(err) { // not authorized to delete
|
||||||
return 404, err
|
return http.StatusUnauthorized, err
|
||||||
|
} else if proxmox.IsNotFound(err) { // errors if pool does not exist
|
||||||
|
return http.StatusNotFound, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pvepool.Delete(context.Background())
|
err = pvepool.Delete(context.Background())
|
||||||
if proxmox.IsNotAuthorized(err) { // not authorized to delete
|
if proxmox.IsNotAuthorized(err) { // not authorized to delete
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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
|
// add new group ny ID only
|
||||||
err := pve.client.NewGroup(context.Background(), groupname.GroupID, "")
|
err := pve.client.NewGroup(context.Background(), groupname.GroupID, "")
|
||||||
if proxmox.IsNotAuthorized(err) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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) {
|
func (pve ProxmoxClient) DelGroup(groupname common.Groupname) (int, error) {
|
||||||
pvegroup, err := pve.client.Group(context.Background(), groupname.GroupID)
|
pvegroup, err := pve.client.Group(context.Background(), groupname.GroupID)
|
||||||
if proxmox.IsNotFound(err) { // errors if group does not exist
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 404, err
|
return http.StatusUnauthorized, err
|
||||||
|
} else if proxmox.IsNotFound(err) {
|
||||||
|
return http.StatusNotFound, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pvegroup.Delete(context.Background())
|
err = pvegroup.Delete(context.Background())
|
||||||
if proxmox.IsNotAuthorized(err) { // not authorized to delete
|
if proxmox.IsNotAuthorized(err) { // not authorized to delete
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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,
|
Password: user.Password,
|
||||||
})
|
})
|
||||||
if proxmox.IsNotAuthorized(err) {
|
if proxmox.IsNotAuthorized(err) {
|
||||||
return 401, err
|
return http.StatusUnauthorized, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} 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) {
|
func (pve ProxmoxClient) DelUser(username common.Username) (int, error) {
|
||||||
user, err := pve.client.User(context.Background(), username.ToString())
|
user, err := pve.client.User(context.Background(), username.ToString())
|
||||||
if proxmox.IsNotAuthorized(err) {
|
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 {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume that user cannot be nil if no error was returned
|
// assume that user cannot be nil if no error was returned
|
||||||
err = user.Delete(context.Background())
|
err = user.Delete(context.Background())
|
||||||
if proxmox.IsNotAuthorized(err) {
|
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 {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} else {
|
||||||
return 200, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pve ProxmoxClient) AddUserToGroup(username common.Username, groupname common.Groupname) (int, error) {
|
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) {
|
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 {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newGroups := append(user.Groups, groupname.ToString())
|
newGroups := append(user.Groups, groupname.ToString())
|
||||||
@@ -213,20 +285,22 @@ func (pve ProxmoxClient) AddUserToGroup(username common.Username, groupname comm
|
|||||||
Groups: newGroups,
|
Groups: newGroups,
|
||||||
})
|
})
|
||||||
if proxmox.IsNotAuthorized(err) {
|
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 {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} else {
|
||||||
return 200, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pve ProxmoxClient) DelUserFromGroup(username common.Username, groupname common.Groupname) (int, error) {
|
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) {
|
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 {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
idx := slices.Index(user.Groups, groupname.ToString())
|
idx := slices.Index(user.Groups, groupname.ToString())
|
||||||
@@ -239,10 +313,10 @@ func (pve ProxmoxClient) DelUserFromGroup(username common.Username, groupname co
|
|||||||
Groups: newGroups,
|
Groups: newGroups,
|
||||||
})
|
})
|
||||||
if proxmox.IsNotAuthorized(err) {
|
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 {
|
} else if err != nil {
|
||||||
return 500, err
|
return http.StatusInternalServerError, err
|
||||||
} else {
|
} else {
|
||||||
return 200, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-27
@@ -1,15 +1,13 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
common "user-manager-api/app/common"
|
localdb "user-manager-api/app/localdb"
|
||||||
pve "user-manager-api/app/pve"
|
pve "user-manager-api/app/pve"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,6 +22,7 @@ type UserSession struct {
|
|||||||
Name string
|
Name string
|
||||||
Handler any
|
Handler any
|
||||||
}
|
}
|
||||||
|
DB *localdb.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserSessionFromContext(c *gin.Context) (*UserSession, int, error) {
|
func GetUserSessionFromContext(c *gin.Context) (*UserSession, int, error) {
|
||||||
@@ -36,27 +35,3 @@ 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 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
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-1
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
configPath := flag.String("config", "config.json", "path to config.json file")
|
configPath := flag.String("config", "config.json", "path to config.json file")
|
||||||
|
localDBPath := flag.String("localdb", "localdb.json", "path to localdb.json file")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
app.Run(configPath)
|
app.Run(configPath, localDBPath)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user