package app import ( common "access-manager-api/app/common" "access-manager-api/app/ldap" proxmox "access-manager-api/app/pve" "fmt" "net/http" ) func NewPool(backends *UserSession, poolname string, pool common.Pool) (int, error) { code, err := backends.PVE.NewPool(poolname, pool) if err != nil { return code, err } code, err = backends.DB.NewPool(poolname, pool) if err != nil { // try to undo pve add pool operation backends.PVE.DelPool(poolname) return code, err } return http.StatusOK, nil } func ModPool(backends *UserSession, poolname string, pool common.Pool) (int, error) { oldpool, code, err := GetPool(backends, poolname) if err != nil { return code, err } code, err = backends.PVE.ModPool(poolname, pool) if err != nil { return code, err } code, err = backends.DB.ModPool(poolname, pool) if err != nil { // try to undo pve mod pool operation backends.PVE.ModPool(poolname, oldpool) return code, err } return http.StatusOK, nil } // 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 and pool members 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 } // members already are filtered by PAASClientRole group.Role = Config.PVE.PAASClientRole pool.Groups = append(pool.Groups, group) } return pool, http.StatusOK, nil } func DelPool(backends *UserSession, poolname string) (int, error) { codepve, errpve := backends.PVE.DelPool(poolname) codedb, errdb := backends.DB.DelPool(poolname) if errpve != nil || errdb != nil { return http.StatusInternalServerError, fmt.Errorf("error deleting pool: (pve:%d, %s) (db:%d, %s)", codepve, errpve, codedb, errdb) } else { return http.StatusOK, nil } } func NewGroup(backends *UserSession, groupname common.Groupname, group common.Group) (int, error) { if groupname.Realm == "pve" { return backends.PVE.NewGroup(groupname, group) } else if groupname.Realm == backends.Realm.Name { realm_handler := backends.Realm.Handler code, err := realm_handler.NewGroup(groupname, group) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { return http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested group") } } func ModGroup(backends *UserSession, groupname common.Groupname, group common.Group) (int, error) { if groupname.Realm == "pve" { return backends.PVE.ModGroup(groupname, group) } else if groupname.Realm == backends.Realm.Name { realm_handler := backends.Realm.Handler code, err := realm_handler.ModGroup(groupname, group) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { return http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested group") } } 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.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) } else if groupname.Realm == backends.Realm.Name { realm_handler := backends.Realm.Handler code, err := realm_handler.DelGroup(groupname) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { return http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested group") } } func AddGroupToPool(backends *UserSession, groupname common.Groupname, poolname string) (int, error) { // only pve backend handles pool-group membership return backends.PVE.AddGroupToPool(groupname, poolname) } func DelGroupFromPool(backends *UserSession, groupname common.Groupname, poolname string) (int, error) { // only pve backend handles pool-group membership return backends.PVE.DelGroupFromPool(groupname, poolname) } func NewUser(backends *UserSession, username common.Username, user common.User) (int, error) { if username.Realm == "pve" { return backends.PVE.NewUser(username, user) } else if username.Realm == backends.Realm.Name { realm_handler := backends.Realm.Handler code, err := realm_handler.NewUser(username, user) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { return http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested user") } } func ModUser(backends *UserSession, username common.Username, user common.User) (int, error) { if username.Realm == "pve" { return backends.PVE.ModUser(username, user) } else if username.Realm == backends.Realm.Name { realm_handler := backends.Realm.Handler code, err := realm_handler.ModUser(username, user) if err != nil { return code, err } // todo, most users will not have access to sync realms, but should be able to modify their own user // will probably use priviledge escalation to give priviledge for modify user operations return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { return http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested 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.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) } else if username.Realm == backends.Realm.Name { realm_handler := backends.Realm.Handler code, err := realm_handler.DelUser(username) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { return http.StatusUnauthorized, fmt.Errorf("user is not in the same realm as requested user") } } func AddUserToGroup(backends *UserSession, username common.Username, groupname common.Groupname) (int, error) { if username.Realm == "pve" && groupname.Realm == "pve" { // both req user and req group are in proxmox return backends.PVE.AddUserToGroup(username, groupname) } else if username.Realm == backends.Realm.Name && groupname.Realm == "pve" { // requested user in realm and req group in proxmox // this is a special case that is only supported because proxmox allows it // if user@realm is added to a pve group, then sync realm DOES NOT clear the group from the user // therefore adding user@realm to pve group should be allowed // in the future support may be removed return backends.PVE.AddUserToGroup(username, groupname) } else if username.Realm == backends.Realm.Name && groupname.Realm == backends.Realm.Name { // both req user and req group are in realm realm_handler := backends.Realm.Handler code, err := realm_handler.AddUserToGroup(username, groupname) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { // req user in proxmox and req group in realm (not possible to do) return http.StatusUnauthorized, fmt.Errorf("cannot add %s to %s", username.ToString(), groupname.ToString()) } } func DelUserFromGroup(backends *UserSession, username common.Username, groupname common.Groupname) (int, error) { if username.Realm == "pve" && groupname.Realm == "pve" { /// both req user and req group are in proxmox return backends.PVE.DelUserFromGroup(username, groupname) } else if username.Realm == backends.Realm.Name && groupname.Realm == "pve" { // requested user in realm and req group in proxmox // this is a special case that is only supported because proxmox allows it // if user@realm was added to a pve group, then sync realm DOES NOT clear the group from the user // therefore removing user@realm from pve group should be allowed // in the future support may be removed return backends.PVE.DelUserFromGroup(username, groupname) } else if username.Realm == backends.Realm.Name && groupname.Realm == backends.Realm.Name { // both req user and req group are in realm realm_handler := backends.Realm.Handler code, err := realm_handler.DelUserFromGroup(username, groupname) if err != nil { return code, err } return backends.PVE.(proxmox.ProxmoxClient).SyncRealms() } else { // req user in proxmox and req group in realm (not possible to do) return http.StatusUnauthorized, fmt.Errorf("cannot delete %s from %s", username.ToString(), groupname.ToString()) } }